From 93787db20d0792396ab93bd302be87a33167df90 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 19 May 2017 13:31:26 +0200 Subject: [PATCH 01/12] replaced char parameters in sound system with stl string --- DynObj.cpp | 2 +- FadeSound.cpp | 2 +- FadeSound.h | 2 +- Ground.cpp | 12 ++++- McZapkie/mctools.cpp | 95 +---------------------------------- McZapkie/mctools.h | 5 -- MdlMngr.cpp | 3 +- MdlMngr.h | 8 +-- Model3d.cpp | 58 ++++++++++++++++++---- RealSound.cpp | 29 ++--------- Sound.cpp | 116 ++++++++++--------------------------------- Sound.h | 38 +++++--------- Train.cpp | 50 +++++++++---------- VBO.cpp | 20 ++++++++ VBO.h | 7 +++ usefull.h | 24 +++++---- wavread.cpp | 33 +++--------- wavread.h | 10 ++-- 18 files changed, 184 insertions(+), 330 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 05d458ca..47e6e18b 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -5072,7 +5072,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, // plik z przyspieszaczem (upust po zlapaniu hamowania) // sBrakeAcc.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true); parser.getTokens( 1, false ); parser >> token; - sBrakeAcc = TSoundsManager::GetFromName( token.c_str(), true ); + sBrakeAcc = TSoundsManager::GetFromName( token, true ); bBrakeAcc = true; // sBrakeAcc.AM=1.0; // sBrakeAcc.AA=0.0; diff --git a/FadeSound.cpp b/FadeSound.cpp index c45d0176..fff7273f 100644 --- a/FadeSound.cpp +++ b/FadeSound.cpp @@ -25,7 +25,7 @@ void TFadeSound::Free() { } -void TFadeSound::Init(char *Name, float fNewFade) +void TFadeSound::Init(std::string const &Name, float fNewFade) { Sound = TSoundsManager::GetFromName(Name, false); if (Sound) diff --git a/FadeSound.h b/FadeSound.h index 4c93054c..6ce4e1b0 100644 --- a/FadeSound.h +++ b/FadeSound.h @@ -24,7 +24,7 @@ class TFadeSound public: TFadeSound(); ~TFadeSound(); - void Init(char *Name, float fNewFade); + void Init(std::string const &Name, float fNewFade); void TurnOn(); void TurnOff(); bool Playing() diff --git a/Ground.cpp b/Ground.cpp index 2ba293fa..d1ed6969 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -823,11 +823,19 @@ void TSubRect::LoadNodes() break; case TP_TRACK: if (n->iNumVerts) // bo tory zabezpieczające są niewidoczne - n->pTrack->RaArrayFill(m_pVNT + n->iVboPtr, m_pVNT); +#ifdef EU07_USE_OLD_VERTEXBUFFER + n->pTrack->RaArrayFill( m_pVNT + n->iVboPtr, m_pVNT ); +#else + n->pTrack->RaArrayFill(m_pVNT.data() + n->iVboPtr, m_pVNT.data()); +#endif break; case TP_TRACTION: if (n->iNumVerts) // druty mogą być niewidoczne...? - n->hvTraction->RaArrayFill(m_pVNT + n->iVboPtr); +#ifdef EU07_USE_OLD_VERTEXBUFFER + n->hvTraction->RaArrayFill( m_pVNT + n->iVboPtr ); +#else + n->hvTraction->RaArrayFill(m_pVNT.data() + n->iVboPtr); +#endif break; } n = n->nNext2; // następny z sektora diff --git a/McZapkie/mctools.cpp b/McZapkie/mctools.cpp index 37c8b148..42f6b17d 100644 --- a/McZapkie/mctools.cpp +++ b/McZapkie/mctools.cpp @@ -144,98 +144,6 @@ bool FuzzyLogicAI(double Test, double Threshold, double Probability) return false; } -std::string ReadWord(std::ifstream &infile) -{ - std::string s = ""; - char c; - bool nextword = false; - - while ((!infile.eof()) && (!nextword)) - { - infile.get(c); - if (_spacesigns.find(c) != std::string::npos) - if (s != "") - nextword = true; - if (_spacesigns.find(c) == std::string::npos) - s += c; - } - return s; -} - -std::string TrimSpace(std::string &s) -{ - /*int ii; - - switch (Just) - { - case CutLeft: - { - ii = 0; - while ((ii < s.length()) && (s[ii + 1] == (char)" ")) - ++ii; - s = s.substr(ii + 1, s.length() - ii); - } - case CutRight: - { - ii = s.length(); - while ((ii > 0) && (s[ii] == (char)" ")) - --ii; - s = s.substr(0, ii); - } - case CutBoth: - { - s = TrimSpace(s, CutLeft); - s = TrimSpace(s, CutRight); - } - } - return s;*/ - - if (s.empty()) - return ""; - size_t first = s.find_first_not_of(' '); - if (first == std::string::npos) - return ""; - size_t last = s.find_last_not_of(' '); - return s.substr(first, (last - first + 1)); -} - -char* TrimAndReduceSpaces(const char* s) -{ // redukuje spacje pomiedzy znakami do jednej - char* tmp = nullptr; - if (s) - { - - tmp = _strdup(s); - char* from = tmp + strspn(tmp, " "); - char* to = tmp; - - do if ((*to = *from++) == ' ') - from += strspn(from, " "); - while (*to++); - - while (*--to == ' ') - *to = '\0'; - } - return tmp; -} - -std::string ExtractKeyWord(std::string InS, std::string KeyWord) -{ - std::string s; - InS = InS + " "; - std::size_t kwp = InS.find(KeyWord); - if (kwp != std::string::npos) - { - s = InS.substr(kwp, InS.length()); - //s = Copy(InS, kwp, length(InS)); - s = s.substr(0, s.find_first_of(" ")); - //s = Copy(s, 1, Pos(" ", s) - 1); - } - else - s = ""; - return s; -} - std::string DUE(std::string s) /*Delete Before Equal sign*/ { //DUE = Copy(s, Pos("=", s) + 1, length(s)); @@ -473,8 +381,7 @@ void ComputeALine(double X0, double Y0, double Xn, double Yn, double L, double R bool FileExists( std::string const &Filename ) { std::ifstream file( Filename ); - if( file.is_open() == false ) { return false; } - else { return true; } + return( true == file.is_open() ); } /* diff --git a/McZapkie/mctools.h b/McZapkie/mctools.h index a0ecf5af..c6b7932b 100644 --- a/McZapkie/mctools.h +++ b/McZapkie/mctools.h @@ -105,11 +105,6 @@ bool FuzzyLogicAI(double Test, double Threshold, double Probability); /*to samo ale zawsze niezaleznie od DebugFlag*/ /*operacje na stringach*/ -std::string ReadWord( std::ifstream& infile); /*czyta slowo z wiersza pliku tekstowego*/ -//std::string Ups(std::string s); -//std::string TrimSpace(std::string &s); -//char* TrimAndReduceSpaces(const char* s); -//std::string ExtractKeyWord(std::string InS, std::string KeyWord); /*wyciaga slowo kluczowe i lancuch do pierwszej spacji*/ std::string DUE(std::string s); /*Delete Until Equal sign*/ std::string DWE(std::string s); /*Delete While Equal sign*/ std::string ExchangeCharInString(std::string const &s, const char &aim, const char &target); // zamienia jeden znak na drugi diff --git a/MdlMngr.cpp b/MdlMngr.cpp index f3663e10..fb55dfe9 100644 --- a/MdlMngr.cpp +++ b/MdlMngr.cpp @@ -56,7 +56,8 @@ void TModelsManager::Init() */ void TModelsManager::Free() { - SafeDeleteArray(Models); + delete[] Models; + Models = nullptr; } TModel3d * TModelsManager::LoadModel(std::string const &Name, bool dynamic) diff --git a/MdlMngr.h b/MdlMngr.h index bdd465cd..2162bf30 100644 --- a/MdlMngr.h +++ b/MdlMngr.h @@ -14,16 +14,12 @@ http://mozilla.org/MPL/2.0/. class TMdlContainer { friend class TModelsManager; - TMdlContainer() - { - Model = NULL; - }; ~TMdlContainer() { - SafeDelete(Model); + delete Model; }; TModel3d * LoadModel(std::string const &NewName, bool dynamic); - TModel3d *Model; + TModel3d *Model{ nullptr }; std::string Name; }; diff --git a/Model3d.cpp b/Model3d.cpp index c3f39b80..26bd823a 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1577,8 +1577,12 @@ TModel3d::~TModel3d() } else { // wczytano z pliku binarnego (jest właścicielem tablic) - m_pVNT = NULL; // nie usuwać tego, bo wskazuje na iModel - Root = NULL; +#ifdef EU07_USE_OLD_VERTEXBUFFER + m_pVNT = nullptr; // nie usuwać tego, bo wskazuje na iModel +#else + m_pVNT.clear(); +#endif + Root = nullptr; delete[] iModel; // usuwamy cały wczytany plik i to wystarczy } // później się jeszcze usuwa obiekt z którego dziedziczymy tabelę VBO @@ -1801,7 +1805,11 @@ void TModel3d::SaveToBinFile(char const *FileName) transforms[i].serialize_float32(s); MakeArray(iNumVerts); - Root->RaArrayFill(m_pVNT); +#ifdef EU07_USE_OLD_VERTEXBUFFER + Root->RaArrayFill(m_pVNT); +#else + Root->RaArrayFill( m_pVNT.data() ); +#endif sn_utils::ls_uint32(s, MAKE_ID4('V', 'N', 'T', '0')); sn_utils::ls_uint32(s, 8 + iNumVerts * 32); for (size_t i = 0; i < (size_t)iNumVerts; i++) @@ -1886,7 +1894,11 @@ void TSubModel::deserialize(std::istream &s) void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) { - m_pVNT = nullptr; +#ifdef EU07_USE_OLD_VERTEXBUFFER + m_pVNT = nullptr; +#else + m_pVNT.clear(); +#endif Root = nullptr; float4x4 *tm = nullptr; @@ -1900,13 +1912,22 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) if (type == MAKE_ID4('V', 'N', 'T', '0')) { - if (m_pVNT != nullptr) +#ifdef EU07_USE_OLD_VERTEXBUFFER + if (m_pVNT != nullptr) +#else + if( false == m_pVNT.empty() ) +#endif throw std::runtime_error("e3d: duplicated VNT chunk"); size_t vt_cnt = size / 32; iNumVerts = (int)vt_cnt; m_nVertexCount = (int)vt_cnt; - m_pVNT = new CVertNormTex[vt_cnt]; +#ifdef EU07_USE_OLD_VERTEXBUFFER + assert( m_pVNT == nullptr ); + m_pVNT = new CVertNormTex[vt_cnt]; +#else + m_pVNT.resize( vt_cnt ); +#endif for (size_t i = 0; i < vt_cnt; i++) m_pVNT[i].deserialize(s); } @@ -1967,12 +1988,20 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) if (!Root) throw std::runtime_error("e3d: no submodels"); - if (!m_pVNT) +#ifdef EU07_USE_OLD_VERTEXBUFFER + if (!m_pVNT) +#else + if(m_pVNT.empty() ) +#endif throw std::runtime_error("e3d: no vertices"); for (size_t i = 0; (int)i < iSubModelsCount; i++) { - Root[i].BinInit(Root, tm, (float8*)m_pVNT, &Textures, &Names, dynamic); +#ifdef EU07_USE_OLD_VERTEXBUFFER + Root[i].BinInit(Root, tm, (float8*)m_pVNT, &Textures, &Names, dynamic); +#else + Root[ i ].BinInit( Root, tm, (float8*)m_pVNT.data(), &Textures, &Names, dynamic ); +#endif if (Root[i].ChildGet()) Root[i].ChildGet()->Parent = &Root[i]; @@ -2151,11 +2180,18 @@ void TModel3d::Init() */ if (Global::bUseVBO) { - if (!m_pVNT) // jeśli nie ma jeszcze tablicy (wczytano z pliku - // tekstowego) +#ifdef EU07_USE_OLD_VERTEXBUFFER + if (!m_pVNT) // jeśli nie ma jeszcze tablicy (wczytano z pliku tekstowego) +#else + if( m_pVNT.empty() ) +#endif { // tworzenie tymczasowej tablicy z wierzchołkami całego modelu MakeArray(iNumVerts); // tworzenie tablic dla VBO - Root->RaArrayFill(m_pVNT); // wypełnianie tablicy +#ifdef EU07_USE_OLD_VERTEXBUFFER + Root->RaArrayFill(m_pVNT); // wypełnianie tablicy +#else + Root->RaArrayFill( m_pVNT.data() ); // wypełnianie tablicy +#endif BuildVBOs(); // tworzenie VBO i usuwanie tablicy z pamięci } else diff --git a/RealSound.cpp b/RealSound.cpp index 19b814e6..ce9c6a3b 100644 --- a/RealSound.cpp +++ b/RealSound.cpp @@ -40,7 +40,7 @@ void TRealSound::Init(std::string const &SoundName, double DistanceAttenuation, bool Dynamic, bool freqmod, double rmin) { // Nazwa=SoundName; //to tak raczej nie zadziała, (SoundName) jest tymczasowe - pSound = TSoundsManager::GetFromName(SoundName.c_str(), Dynamic, &fFrequency); + pSound = TSoundsManager::GetFromName(SoundName, Dynamic, &fFrequency); if (pSound) { if (freqmod) @@ -48,8 +48,7 @@ void TRealSound::Init(std::string const &SoundName, double DistanceAttenuation, { // dla modulowanych nie może być zmiany mnożnika, bo częstotliwość w nagłówku byłą // ignorowana, a mogła być inna niż 22050 fFrequency = 22050.0; - ErrorLog("Bad sound: " + std::string(SoundName) + - ", as modulated, should have 22.05kHz in header"); + ErrorLog("Bad sound: " + SoundName + ", as modulated, should have 22.05kHz in header"); } AM = 1.0; pSound->SetVolume(DSBVOLUME_MIN); @@ -57,7 +56,7 @@ void TRealSound::Init(std::string const &SoundName, double DistanceAttenuation, else { // nie ma dźwięku, to jest wysyp AM = 0; - ErrorLog("Missed sound: " + std::string(SoundName)); + ErrorLog("Missed sound: " + SoundName); } if (DistanceAttenuation > 0.0) { @@ -268,26 +267,8 @@ void TTextSound::Play(double Volume, int Looping, bool ListenerInside, vector3 N { // jeśli ma powiązany tekst DWORD stat; pSound->GetStatus(&stat); - if (!(stat & DSBSTATUS_PLAYING)) // jeśli nie jest aktualnie odgrywany - { -/* - std::string t( asText ); - size_t i; - do - { // na razie zrobione jakkolwiek, docelowo przenieść teksty do tablicy nazw - i = t.find('\r'); // znak nowej linii - if( i == std::string::npos ) { - Global::tranTexts.Add( t, fTime, true ); - } - else - { - Global::tranTexts.Add(t.substr(0, i), fTime, true); - t.erase(0, i + 1); - while (t.empty() ? false : (unsigned char)(t[1]) < 33) - t.erase(0, 1); - } - } while (i != std::string::npos); -*/ + if (!(stat & DSBSTATUS_PLAYING)) { + // jeśli nie jest aktualnie odgrywany Global::tranTexts.Add( asText, fTime, true ); } } diff --git a/Sound.cpp b/Sound.cpp index eb8c4893..c3101245 100644 --- a/Sound.cpp +++ b/Sound.cpp @@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/. #include "Usefull.h" #include "mczapkie/mctools.h" #include "WavRead.h" -//#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } + #define SAFE_RELEASE(p) \ { \ if (p) \ @@ -24,43 +24,31 @@ http://mozilla.org/MPL/2.0/. } \ } -char Directory[] = "sounds\\"; - LPDIRECTSOUND TSoundsManager::pDS; LPDIRECTSOUNDNOTIFY TSoundsManager::pDSNotify; int TSoundsManager::Count = 0; TSoundContainer *TSoundsManager::First = NULL; -TSoundContainer::TSoundContainer(LPDIRECTSOUND pDS, const char *Directory, const char *strFileName, - int NConcurrent) +TSoundContainer::TSoundContainer(LPDIRECTSOUND pDS, std::string const &Directory, std::string const &Filename, int NConcurrent) { // wczytanie pliku dźwiękowego int hr = 111; - DSBuffer = NULL; // na początek, gdyby uruchomić dźwięków się nie udało - + DSBuffer = nullptr; // na początek, gdyby uruchomić dźwięków się nie udało Concurrent = NConcurrent; - Oldest = 0; - // strcpy(Name, strFileName); - - strcpy(Name, Directory); - strcat(Name, strFileName); - - CWaveSoundRead *pWaveSoundRead; + m_name = Directory + Filename; // Create a new wave file class - pWaveSoundRead = new CWaveSoundRead(); + std::shared_ptr pWaveSoundRead = std::make_shared(); // Load the wave file - if (FAILED(pWaveSoundRead->Open(Name))) - if (FAILED(pWaveSoundRead->Open(strdup(strFileName)))) - { - // SetFileUI( hDlg, TEXT("Bad wave file.") ); - ErrorLog( "Missed sound: " + std::string( strFileName ) ); - return; - } + if( ( FAILED( pWaveSoundRead->Open( m_name ) ) ) + && ( FAILED( pWaveSoundRead->Open( Filename ) ) ) ) { + ErrorLog( "Missed sound: " + Filename ); + return; + } - strcpy(Name, ToLower(strFileName).c_str()); + m_name = ToLower( Filename ); // Set up the direct sound buffer, and only request the flags needed // since each requires some overhead and limits if the buffer can @@ -133,27 +121,10 @@ TSoundContainer::TSoundContainer(LPDIRECTSOUND pDS, const char *Directory, const // We dont need the wav file data buffer anymore, so delete it delete[] pbWavData; - delete pWaveSoundRead; - DSBuffers.push(DSBuffer); - - /* - for (int i=1; iDuplicateSoundBuffer(pDSBuffer[0],&(pDSBuffer[i])))) - { - Concurrent= i; - break; - }; - - - };*/ }; TSoundContainer::~TSoundContainer() { - // for (int i=Concurrent-1; i>=0; i--) - // SAFE_RELEASE( pDSBuffer[i] ); - // free(pDSBuffer); while (!DSBuffers.empty()) { SAFE_RELEASE(DSBuffers.top()); @@ -185,84 +156,51 @@ void TSoundsManager::Free() SAFE_RELEASE(pDS); }; -TSoundContainer * TSoundsManager::LoadFromFile(const char *Dir, const char *Name, int Concurrent) +TSoundContainer * TSoundsManager::LoadFromFile( std::string const &Dir, std::string const &Filename, int Concurrent) { - TSoundContainer *Tmp = First; - First = new TSoundContainer(pDS, Dir, Name, Concurrent); - First->Next = Tmp; + TSoundContainer *tmp = First; + First = new TSoundContainer(pDS, Dir, Filename, Concurrent); + First->Next = tmp; Count++; return First; // albo NULL, jak nie wyjdzie (na razie zawsze wychodzi) }; -void TSoundsManager::LoadSounds(char *Directory) -{ // wczytanie wszystkich plików z katalogu - mało elastyczne - WIN32_FIND_DATA FindFileData; - HANDLE handle = FindFirstFile("sounds\\*.wav", &FindFileData); - if (handle != INVALID_HANDLE_VALUE) - do - { - LoadFromFile(Directory, FindFileData.cFileName, 1); - } while (FindNextFile(handle, &FindFileData)); - FindClose(handle); -}; - -LPDIRECTSOUNDBUFFER TSoundsManager::GetFromName(const char *Name, bool Dynamic, float *fSamplingRate) +LPDIRECTSOUNDBUFFER TSoundsManager::GetFromName(std::string const &Name, bool Dynamic, float *fSamplingRate) { // wyszukanie dźwięku w pamięci albo wczytanie z pliku + std::string name{ ToLower(Name) }; std::string file; if (Dynamic) { // próba wczytania z katalogu pojazdu - file = Global::asCurrentDynamicPath + Name; + file = Global::asCurrentDynamicPath + name; if (FileExists(file)) - Name = file.c_str(); // nowa nazwa + name = file; // nowa nazwa else Dynamic = false; // wczytanie z "sounds/" } TSoundContainer *Next = First; for (int i = 0; i < Count; i++) { - if (strcmp(Name, Next->Name) == 0) - { + if( name == Next->m_name ) { + if (fSamplingRate) *fSamplingRate = Next->fSamplingRate; // częstotliwość return (Next->GetUnique(pDS)); - // DSBuffers. - /* - Next->pDSBuffer[Next->Oldest]->Stop(); - Next->pDSBuffer[Next->Oldest]->SetCurrentPosition(0); - if (Next->OldestConcurrent-1) - { - Next->Oldest++; - return (Next->pDSBuffer[Next->Oldest-1]); - } - else - { - Next->Oldest= 0; - return (Next->pDSBuffer[Next->Concurrent-1]); - }; - - /* for (int j=0; jConcurrent; j++) - { - - Next->pDSBuffer[j]->GetStatus(&dwStatus); - if ((dwStatus & DSBSTATUS_PLAYING) != DSBSTATUS_PLAYING) - return (Next->pDSBuffer[j]); - } */ } else Next = Next->Next; }; if (Dynamic) // wczytanie z katalogu pojazdu - Next = LoadFromFile("", Name, 1); + Next = LoadFromFile("", name, 1); else - Next = LoadFromFile(Directory, Name, 1); + Next = LoadFromFile(szSoundPath, name, 1); if (Next) { // if (fSamplingRate) *fSamplingRate = Next->fSamplingRate; // częstotliwość return Next->GetUnique(pDS); } - ErrorLog("Missed sound: " + std::string(Name) ); - return (NULL); + ErrorLog("Missed sound: " + Name ); + return (nullptr); }; void TSoundsManager::RestoreAll() @@ -299,10 +237,6 @@ void TSoundsManager::RestoreAll() }; }; -// void TSoundsManager::Init(char *Name, int Concurrent) -// TSoundsManager::TSoundsManager(HWND hWnd) -// void TSoundsManager::Init(HWND hWnd, char *NDirectory) - void TSoundsManager::Init(HWND hWnd) { diff --git a/Sound.h b/Sound.h index e003ef8d..6b77d184 100644 --- a/Sound.h +++ b/Sound.h @@ -7,56 +7,44 @@ obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef SoundH -#define SoundH +#pragma once #include #include typedef LPDIRECTSOUNDBUFFER PSound; -// inline Playing(PSound Sound) -//{ - -//} - class TSoundContainer { - public: +public: int Concurrent; int Oldest; - char Name[80]; + std::string m_name; LPDIRECTSOUNDBUFFER DSBuffer; float fSamplingRate; // częstotliwość odczytana z pliku int iBitsPerSample; // ile bitów na próbkę TSoundContainer *Next; std::stack DSBuffers; - LPDIRECTSOUNDBUFFER GetUnique(LPDIRECTSOUND pDS); - TSoundContainer(LPDIRECTSOUND pDS, const char *Directory, const char *strFileName, int NConcurrent); + + TSoundContainer(LPDIRECTSOUND pDS, std::string const &Directory, std::string const &Filename, int NConcurrent); ~TSoundContainer(); + LPDIRECTSOUNDBUFFER GetUnique( LPDIRECTSOUND pDS ); }; class TSoundsManager { - private: +private: static LPDIRECTSOUND pDS; static LPDIRECTSOUNDNOTIFY pDSNotify; - // static char Directory[80]; - static int Count; static TSoundContainer *First; - static TSoundContainer * LoadFromFile(const char *Dir, const char *Name, int Concurrent); + static int Count; - public: - // TSoundsManager(HWND hWnd); - // static void Init(HWND hWnd, char *NDirectory); - static void Init(HWND hWnd); + static TSoundContainer * LoadFromFile( std::string const &Directory, std::string const &FileName, int Concurrent); + +public: ~TSoundsManager(); + static void Init( HWND hWnd ); static void Free(); - static void Init(char *Name, int Concurrent); - static void LoadSounds(char *Directory); - static LPDIRECTSOUNDBUFFER GetFromName(const char *Name, bool Dynamic, float *fSamplingRate = NULL); + static LPDIRECTSOUNDBUFFER GetFromName( std::string const &Name, bool Dynamic, float *fSamplingRate = NULL ); static void RestoreAll(); }; - -//--------------------------------------------------------------------------- -#endif diff --git a/Train.cpp b/Train.cpp index 262f1c0c..15d79f6c 100644 --- a/Train.cpp +++ b/Train.cpp @@ -5820,6 +5820,8 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) // NOTE: yaml-style comments are disabled until conflict in use of # is resolved // parser.addCommentStyle( "#", "\n" ); //Wartości domyślne by nie wysypywało przy wybrakowanych mmd @240816 Stele + // NOTE: should be no longer needed as safety checks were added, + // but leaving the defaults for the sake of incomplete mmd files dsbPneumaticSwitch = TSoundsManager::GetFromName("silence1.wav", true); dsbBufferClamp = TSoundsManager::GetFromName("en57_bufferclamp.wav", true); dsbCouplerDetach = TSoundsManager::GetFromName("couplerdetach.wav", true); @@ -5847,67 +5849,67 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) { // nastawnik: dsbNastawnikJazdy = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "ctrlscnd:") { // hunter-081211: nastawnik bocznikowania dsbNastawnikBocz = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "reverserkey:") { // hunter-131211: dzwiek kierunkowego dsbReverserKey = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "buzzer:") { // bzyczek shp: dsbBuzzer = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "slipalarm:") { // Bombardier 011010: alarm przy poslizgu: dsbSlipAlarm = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "tachoclock:") { // cykanie rejestratora: dsbHasler = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "switch:") { // przelaczniki: dsbSwitch = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "pneumaticswitch:") { // stycznik EP: dsbPneumaticSwitch = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "wejscie_na_bezoporow:") { // hunter-111211: wydzielenie wejscia na bezoporowa i na drugi uklad do pliku dsbWejscie_na_bezoporow = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "wejscie_na_drugi_uklad:") { dsbWejscie_na_drugi_uklad = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "relay:") { // styczniki itp: dsbRelay = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); if (!dsbWejscie_na_bezoporow) { // hunter-111211: domyslne, gdy brak dsbWejscie_na_bezoporow = @@ -5923,39 +5925,37 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) { // wylaczniki pneumatyczne: dsbPneumaticRelay = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "couplerattach:") { // laczenie: dsbCouplerAttach = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "couplerstretch:") { // laczenie: - dsbCouplerStretch = TSoundsManager::GetFromName( - parser.getToken().c_str(), - true); // McZapkie-090503: PROWIZORKA!!! "en57_couplerstretch.wav" + dsbCouplerStretch = + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "couplerdetach:") { // rozlaczanie: dsbCouplerDetach = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "bufferclamp:") { // laczenie: - dsbBufferClamp = TSoundsManager::GetFromName( - parser.getToken().c_str(), - true); // McZapkie-090503: PROWIZORKA!!! "en57_bufferclamp.wav" + dsbBufferClamp = + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "ignition:") { // odpalanie silnika dsbDieselIgnition = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "brakesound:") { @@ -6073,25 +6073,25 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) { // podniesienie patyka: dsbPantUp = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "pantographdown:") { // podniesienie patyka: dsbPantDown = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "doorclose:") { // zamkniecie drzwi: dsbDoorClose = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } else if (token == "dooropen:") { // otwarcie drzwi: dsbDoorOpen = - TSoundsManager::GetFromName(parser.getToken().c_str(), true); + TSoundsManager::GetFromName(parser.getToken(), true); } } while (token != ""); diff --git a/VBO.cpp b/VBO.cpp index cd9483d3..0de6cb14 100644 --- a/VBO.cpp +++ b/VBO.cpp @@ -44,7 +44,9 @@ void CVertNormTex::serialize(std::ostream &s) CMesh::CMesh() { // utworzenie pustego obiektu +#ifdef EU07_USE_OLD_VERTEXBUFFER m_pVNT = nullptr; +#endif m_nVertexCount = -1; m_nVBOVertices = 0; // nie zarezerwowane }; @@ -57,7 +59,13 @@ CMesh::~CMesh() void CMesh::MakeArray(int n) { // tworzenie tablic m_nVertexCount = n; +#ifdef EU07_USE_OLD_VERTEXBUFFER + assert( m_pVNT == nullptr ); m_pVNT = new CVertNormTex[m_nVertexCount]; // przydzielenie pamięci dla tablicy +#else + m_pVNT.clear(); + m_pVNT.resize( m_nVertexCount ); +#endif }; void CMesh::BuildVBOs(bool del) @@ -65,11 +73,19 @@ void CMesh::BuildVBOs(bool del) // pobierz numer VBO oraz ustaw go jako aktywny glGenBuffers(1, &m_nVBOVertices); // pobierz numer glBindBuffer(GL_ARRAY_BUFFER, m_nVBOVertices); // ustaw bufor jako aktualny +#ifdef EU07_USE_OLD_VERTEXBUFFER glBufferData(GL_ARRAY_BUFFER, m_nVertexCount * sizeof(CVertNormTex), m_pVNT, GL_STATIC_DRAW); +#else + glBufferData( GL_ARRAY_BUFFER, m_nVertexCount * sizeof( CVertNormTex ), m_pVNT.data(), GL_STATIC_DRAW ); +#endif // WriteLog("Assigned VBO number "+AnsiString(m_nVBOVertices)+", vertices: // "+AnsiString(m_nVertexCount)); +#ifdef EU07_USE_OLD_VERTEXBUFFER if (del) SafeDeleteArray(m_pVNT); // wierzchołki już się nie przydadzą +#else + m_pVNT.clear(); +#endif }; void CMesh::Clear() @@ -82,7 +98,11 @@ void CMesh::Clear() } m_nVBOVertices = 0; m_nVertexCount = -1; // do ponownego zliczenia +#ifdef EU07_USE_OLD_VERTEXBUFFER SafeDeleteArray(m_pVNT); // usuwanie tablic, gdy były użyte do Vertex Array +#else + m_pVNT.clear(); +#endif }; bool CMesh::StartVBO() diff --git a/VBO.h b/VBO.h index 3c0ec334..a5e4947a 100644 --- a/VBO.h +++ b/VBO.h @@ -9,6 +9,9 @@ http://mozilla.org/MPL/2.0/. #ifndef VBOH #define VBOH + +#define EU07_USE_OLD_VERTEXBUFFER + //--------------------------------------------------------------------------- class CVertNormTex { @@ -30,7 +33,11 @@ class CMesh { // wsparcie dla VBO public: int m_nVertexCount; // liczba wierzchołków +#ifdef EU07_USE_OLD_VERTEXBUFFER CVertNormTex *m_pVNT; +#else + std::vector m_pVNT; +#endif unsigned int m_nVBOVertices; // numer VBO z wierzchołkami CMesh(); ~CMesh(); diff --git a/usefull.h b/usefull.h index 43e1683f..a5c62578 100644 --- a/usefull.h +++ b/usefull.h @@ -11,17 +11,6 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" -#define SafeDelete(a) \ - { \ - delete (a); \ - a = nullptr; \ - } -#define SafeDeleteArray(a) \ - { \ - delete[](a); \ - a = nullptr; \ - } - #define sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0)) #define DegToRad(a) ((M_PI / 180.0) * (a)) //(a) w nawiasie, bo może być dodawaniem @@ -31,9 +20,22 @@ http://mozilla.org/MPL/2.0/. #define asSceneryPath std::string("scenery\\") #define szSceneryPath "scenery\\" #define szTexturePath "textures\\" +#define szSoundPath "sounds\\" #define MAKE_ID4(a,b,c,d) (((std::uint32_t)(d)<<24)|((std::uint32_t)(c)<<16)|((std::uint32_t)(b)<<8)|(std::uint32_t)(a)) +template +void SafeDelete( _Type &Pointer ) { + delete Pointer; + Pointer = nullptr; +} + +template +void SafeDeleteArray( _Type &Pointer ) { + delete[] Pointer; + Pointer = nullptr; +} + template _Type clamp( _Type const Value, _Type const Min, _Type const Max ) { diff --git a/wavread.cpp b/wavread.cpp index d55dd9be..4dd527b1 100644 --- a/wavread.cpp +++ b/wavread.cpp @@ -17,26 +17,7 @@ http://mozilla.org/MPL/2.0/. //----------------------------------------------------------------------------- #include "stdafx.h" #include "WavRead.h" - -//----------------------------------------------------------------------------- -// Defines, constants, and global variables -//----------------------------------------------------------------------------- -#define SAFE_DELETE(p) \ - { \ - if (p) \ - { \ - delete (p); \ - (p) = NULL; \ - } \ - } -#define SAFE_RELEASE(p) \ - { \ - if (p) \ - { \ - (p)->Release(); \ - (p) = NULL; \ - } \ - } +#include "usefull.h" //----------------------------------------------------------------------------- // Name: ReadMMIO() @@ -122,13 +103,13 @@ HRESULT ReadMMIO(HMMIO hmmioIn, MMCKINFO *pckInRIFF, WAVEFORMATEX **ppwfxInfo) // so the data can be easily read with WaveReadFile. Returns 0 if // successful, the error code if not. //----------------------------------------------------------------------------- -HRESULT WaveOpenFile(CHAR *strFileName, HMMIO *phmmioIn, WAVEFORMATEX **ppwfxInfo, +HRESULT WaveOpenFile( std::string const &Filename, HMMIO *phmmioIn, WAVEFORMATEX **ppwfxInfo, MMCKINFO *pckInRIFF) { HRESULT hr; HMMIO hmmioIn = NULL; - if (NULL == (hmmioIn = mmioOpen(strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ))) + if (NULL == (hmmioIn = mmioOpen(const_cast(Filename.c_str()), NULL, MMIO_ALLOCBUF | MMIO_READ))) return E_FAIL; if (FAILED(hr = ReadMMIO(hmmioIn, pckInRIFF, ppwfxInfo))) @@ -228,20 +209,20 @@ CWaveSoundRead::CWaveSoundRead() CWaveSoundRead::~CWaveSoundRead() { Close(); - SAFE_DELETE(m_pwfx); + SafeDelete(m_pwfx); } //----------------------------------------------------------------------------- // Name: Open() // Desc: Opens a wave file for reading //----------------------------------------------------------------------------- -HRESULT CWaveSoundRead::Open(CHAR *strFilename) +HRESULT CWaveSoundRead::Open(std::string const &Filename) { - SAFE_DELETE(m_pwfx); + SafeDelete(m_pwfx); HRESULT hr; - if (FAILED(hr = WaveOpenFile(strFilename, &m_hmmioIn, &m_pwfx, &m_ckInRiff))) + if (FAILED(hr = WaveOpenFile(Filename, &m_hmmioIn, &m_pwfx, &m_ckInRiff))) return hr; if (FAILED(hr = Reset())) diff --git a/wavread.h b/wavread.h index 68ce040e..707baa2a 100644 --- a/wavread.h +++ b/wavread.h @@ -15,12 +15,12 @@ http://mozilla.org/MPL/2.0/. // // Copyright (c) 1999 Microsoft Corp. All rights reserved. //----------------------------------------------------------------------------- -#ifndef WAVE_READ_H -#define WAVE_READ_H +#pragma once #include +#include -HRESULT WaveOpenFile(CHAR *strFileName, HMMIO *phmmioIn, WAVEFORMATEX **ppwfxInfo, +HRESULT WaveOpenFile(std::string const &Filename, HMMIO *phmmioIn, WAVEFORMATEX **ppwfxInfo, MMCKINFO *pckInRIFF); HRESULT WaveStartDataRead(HMMIO *phmmioIn, MMCKINFO *pckIn, MMCKINFO *pckInRIFF); HRESULT WaveReadFile(HMMIO hmmioIn, UINT cbRead, BYTE *pbDest, MMCKINFO *pckIn, UINT *cbActualRead); @@ -41,10 +41,8 @@ class CWaveSoundRead CWaveSoundRead(); ~CWaveSoundRead(); - HRESULT Open(CHAR *strFilename); + HRESULT Open(std::string const &Filename); HRESULT Reset(); HRESULT Read(UINT nSizeToRead, BYTE *pbData, UINT *pnSizeRead); HRESULT Close(); }; - -#endif WAVE_READ_H From c38511978d80dffee342dc31083b5b7d2b161015 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 19 May 2017 20:07:23 +0200 Subject: [PATCH 02/12] build 170519. fixes for buffer overflows in segment.cpp --- Ground.cpp | 27 +++++++-- Segment.cpp | 152 ++++++++++++++++++++++++++++----------------------- Segment.h | 2 +- Track.cpp | 138 +++++++++++++++++++++++++++++++--------------- Track.h | 2 +- Traction.cpp | 22 +++++++- Traction.h | 2 +- version.h | 2 +- 8 files changed, 226 insertions(+), 121 deletions(-) diff --git a/Ground.cpp b/Ground.cpp index d1ed6969..087e76fb 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -787,6 +787,7 @@ void TSubRect::LoadNodes() return; // jeśli nie ma obiektów do wyświetlenia z VBO, to koniec if (Global::bUseVBO) { // tylko liczenie wierzchołów, gdy nie ma VBO + int debugvertexcount{ 0 }; MakeArray(m_nVertexCount); n = nRootNode; int i; @@ -808,7 +809,9 @@ void TSubRect::LoadNodes() m_pVNT[n->iVboPtr + i].nz = n->Vertices[i].Normal.z; m_pVNT[n->iVboPtr + i].u = n->Vertices[i].tu; m_pVNT[n->iVboPtr + i].v = n->Vertices[i].tv; + ++debugvertexcount; } + assert( debugvertexcount <= m_nVertexCount ); break; case GL_LINES: case GL_LINE_STRIP: @@ -819,23 +822,35 @@ void TSubRect::LoadNodes() m_pVNT[n->iVboPtr + i].y = n->Points[i].y; m_pVNT[n->iVboPtr + i].z = n->Points[i].z; // miejsce w tablicach normalnych i teksturowania się marnuje... + ++debugvertexcount; } + assert( debugvertexcount <= m_nVertexCount ); break; case TP_TRACK: - if (n->iNumVerts) // bo tory zabezpieczające są niewidoczne + if( n->iNumVerts ) { // bo tory zabezpieczające są niewidoczne #ifdef EU07_USE_OLD_VERTEXBUFFER - n->pTrack->RaArrayFill( m_pVNT + n->iVboPtr, m_pVNT ); + int const batch = n->pTrack->RaArrayFill( m_pVNT + n->iVboPtr, m_pVNT, std::min( n->iNumVerts, m_nVertexCount - n->iVboPtr ) ); #else - n->pTrack->RaArrayFill(m_pVNT.data() + n->iVboPtr, m_pVNT.data()); + int const batch = n->pTrack->RaArrayFill( m_pVNT.data() + n->iVboPtr, m_pVNT.data(), std::min( n->iNumVerts, m_nVertexCount - n->iVboPtr ) ); #endif + assert( batch == n->iNumVerts ); + assert( batch + n->iVboPtr <= m_nVertexCount ); + debugvertexcount += batch; + assert( debugvertexcount <= m_nVertexCount ); + } break; case TP_TRACTION: - if (n->iNumVerts) // druty mogą być niewidoczne...? + if( n->iNumVerts ) { // druty mogą być niewidoczne...? #ifdef EU07_USE_OLD_VERTEXBUFFER - n->hvTraction->RaArrayFill( m_pVNT + n->iVboPtr ); + int const batch = n->hvTraction->RaArrayFill( m_pVNT + n->iVboPtr ); #else - n->hvTraction->RaArrayFill(m_pVNT.data() + n->iVboPtr); + int const batch = n->hvTraction->RaArrayFill( m_pVNT.data() + n->iVboPtr ); #endif + assert( batch == n->iNumVerts ); + assert( batch + n->iVboPtr <= m_nVertexCount ); + debugvertexcount += batch; + assert( debugvertexcount <= m_nVertexCount ); + } break; } n = n->nNext2; // następny z sektora diff --git a/Segment.cpp b/Segment.cpp index 1455414b..75a8e335 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -116,26 +116,24 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI // MessageBox(0,"Length<=0","TSegment::Init",MB_OK); return false; // zerowe nie mogą być } + + if( ( pOwner->eType == tt_Switch ) + && ( fStep * 3.0 > fLength ) ) { + // NOTE: a workaround for too short switches (less than 3 segments) messing up animation/generation of blades + fStep = fLength / 3.0; + } + fStoop = std::atan2((Point2.y - Point1.y), fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie SafeDeleteArray(fTsBuffer); - if( ( bCurve ) && ( fStep > 0 ) ) { - if( fStep > 0 ) { // Ra: prosty dostanie podział, jak ma różną przechyłkę na końcach - double s = 0; - int i = 0; - iSegCount = static_cast( std::ceil( fLength / fStep )); // potrzebne do VBO - // fStep=fLength/(double)(iSegCount-1); //wyrównanie podziału - fTsBuffer = new double[ iSegCount + 1 ]; - fTsBuffer[ 0 ] = 0; /* TODO : fix fTsBuffer */ - while( s < fLength ) { - i++; - s += fStep; - if( s > fLength ) - s = fLength; - fTsBuffer[ i ] = GetTFromS( s ); - } - } + iSegCount = static_cast( std::ceil( fLength / fStep ) ); // potrzebne do VBO + fTsBuffer = new double[ iSegCount + 1 ]; + fTsBuffer[ 0 ] = 0.0; + for( int i = 1; i < iSegCount; ++i ) { + fTsBuffer[ i ] = GetTFromS( i * fStep ); } + fTsBuffer[ iSegCount ] = 1.0; + return true; } @@ -317,14 +315,16 @@ vector3 TSegment::FastGetPoint(double t) return (bCurve ? RaInterpolate(t) : ((1.0 - t) * Point1 + (t)*Point2)); } -void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, bool Onlypositions, vector3 **p, bool bRender) +int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, bool Onlypositions, vector3 **p, bool bRender) { // generowanie trójkątów dla odcinka trajektorii ruchu // standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku // po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli // podany jest przekrój końcowy // podsypka toru jest robiona za pomocą 6 punktów, szyna 12, drogi i rzeki na 3+2+3 + int debugvertexcount{ 0 }; + if( !fTsBuffer ) - return; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę + return debugvertexcount; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę vector3 pos1, pos2, dir, parallel1, parallel2, pt, norm; double s, step, fOffset, tv1, tv2, t, fEnd; @@ -348,6 +348,9 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in fEnd = fLength * double( iEnd ) / double( iSegCount ); m2 = s / fEnd; jmm2 = 1.0 - m2; + + int const debugvertexlimit = std::abs( iNumShapePoints ) * 2 * ( iEnd - iSkip ); + while( i < iEnd ) { ++i; // kolejny punkt łamanej @@ -410,6 +413,7 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in } ++Output; } + ++debugvertexcount; } if( p ) // jeśli jest wskaźnik do tablicy if( *p ) @@ -447,6 +451,7 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in } ++Output; } + ++debugvertexcount; } if( p ) // jeśli jest wskaźnik do tablicy if( *p ) @@ -455,64 +460,73 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in *( *p ) = pt; ( *p )++; } // zapamiętanie brzegu jezdni + + assert( debugvertexcount <= debugvertexlimit ); } } else { - for( int j = 0; j < iNumShapePoints; ++j ) { - //łuk z jednym profilem - pt = parallel1 * ( ShapePoints[ j ].x - fOffsetX ) + pos1; - pt.y += ShapePoints[ j ].y; - if( false == Onlypositions ) { - norm = ShapePoints[ j ].n.x * parallel1; - norm.y += ShapePoints[ j ].n.y; - } - if( Output == nullptr ) { - // immediate mode + if( bRender ) { + for( int j = 0; j < iNumShapePoints; ++j ) { + //łuk z jednym profilem + pt = parallel1 * ( ShapePoints[ j ].x - fOffsetX ) + pos1; + pt.y += ShapePoints[ j ].y; if( false == Onlypositions ) { - ::glNormal3f( norm.x, norm.y, norm.z ); - ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv1 ); + norm = ShapePoints[ j ].n.x * parallel1; + norm.y += ShapePoints[ j ].n.y; } - ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na początku odcinka - } - else { - Output->x = pt.x; - Output->y = pt.y; - Output->z = pt.z; + if( Output == nullptr ) { + // immediate mode + if( false == Onlypositions ) { + ::glNormal3f( norm.x, norm.y, norm.z ); + ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv1 ); + } + ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na początku odcinka + } + else { + Output->x = pt.x; + Output->y = pt.y; + Output->z = pt.z; + if( false == Onlypositions ) { + Output->nx = norm.x; + Output->ny = norm.y; + Output->nz = norm.z; + Output->u = ShapePoints[ j ].z / Texturescale; + Output->v = tv1; + } + ++Output; + } + ++debugvertexcount; + + pt = parallel2 * ShapePoints[ j ].x + pos2; + pt.y += ShapePoints[ j ].y; if( false == Onlypositions ) { - Output->nx = norm.x; - Output->ny = norm.y; - Output->nz = norm.z; - Output->u = ShapePoints[ j ].z / Texturescale; - Output->v = tv1; + norm = ShapePoints[ j ].n.x * parallel2; + norm.y += ShapePoints[ j ].n.y; } - ++Output; - } - pt = parallel2 * ShapePoints[ j ].x + pos2; - pt.y += ShapePoints[ j ].y; - if( false == Onlypositions ) { - norm = ShapePoints[ j ].n.x * parallel2; - norm.y += ShapePoints[ j ].n.y; - } - if( Output == nullptr ) { - // immediate mode - if( false == Onlypositions ) { - ::glNormal3f( norm.x, norm.y, norm.z ); - ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv2 ); + if( Output == nullptr ) { + // immediate mode + if( false == Onlypositions ) { + ::glNormal3f( norm.x, norm.y, norm.z ); + ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv2 ); + } + ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na końcu odcinka } - ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na końcu odcinka - } - else { - Output->x = pt.x; - Output->y = pt.y; - Output->z = pt.z; - if( false == Onlypositions ) { - Output->nx = norm.x; - Output->ny = norm.y; - Output->nz = norm.z; - Output->u = ShapePoints[ j ].z / Texturescale; - Output->v = tv2; + else { + Output->x = pt.x; + Output->y = pt.y; + Output->z = pt.z; + if( false == Onlypositions ) { + Output->nx = norm.x; + Output->ny = norm.y; + Output->nz = norm.z; + Output->u = ShapePoints[ j ].z / Texturescale; + Output->v = tv2; + } + ++Output; } - ++Output; + ++debugvertexcount; + + assert( debugvertexcount <= debugvertexlimit ); } } } @@ -526,6 +540,10 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in tv1 = tv2; } } + + assert( debugvertexcount == debugvertexlimit ); + + return debugvertexcount; }; void TSegment::Render() diff --git a/Segment.h b/Segment.h index aa303484..1c4c84ab 100644 --- a/Segment.h +++ b/Segment.h @@ -113,7 +113,7 @@ class TSegment r1 = fRoll1; r2 = fRoll2; } - void RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, bool Onlypositions = false, vector3 **p = nullptr, bool bRender = true); + int RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, bool Onlypositions = false, vector3 **p = nullptr, bool bRender = true); void Render(); inline double GetLength() { diff --git a/Track.cpp b/Track.cpp index 17cbef7f..56e21423 100644 --- a/Track.cpp +++ b/Track.cpp @@ -532,7 +532,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) // na przechyłce doliczyć jeszcze pół przechyłki } if( fRadius != 0 ) // gdy podany promień - segsize = Min0R( 5.0, 0.2 + fabs( fRadius ) * 0.02 ); // do 250m - 5, potem 1 co 50m + segsize = clamp( 0.2 + fabs( fRadius ) * 0.02, 2.5, 10.0 ); else segsize = 10.0; // for straights, 10m per segment works good enough @@ -595,13 +595,14 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) // na przechyłce doliczyć jeszcze pół przechyłki? } if (fRadiusTable[0] > 0) - segsize = Min0R(5.0, 0.2 + fRadiusTable[0] * 0.02); + segsize = clamp( 0.2 + fRadiusTable[0] * 0.02, 2.5, 5.0 ); else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne { // jak promień zerowy, to przeliczamy punkty kontrolne cp1 = (p1 + p1 + p2) / 3.0 - p1; // jak jest prosty, to się zoptymalizuje cp2 = (p1 + p2 + p2) / 3.0 - p2; segsize = 5.0; } // ułomny prosty + if (!(cp1 == vector3(0, 0, 0)) && !(cp2 == vector3(0, 0, 0))) SwitchExtension->Segments[0]->Init(p1, p1 + cp1, p2 + cp2, p2, segsize, r1, r2); else @@ -624,7 +625,8 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) } if (fRadiusTable[1] > 0) - segsize = Min0R(5.0, 0.2 + fRadiusTable[1] * 0.02); + segsize = clamp( 0.2 + fRadiusTable[ 1 ] * 0.02, 2.5, 5.0 ); + else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne { // jak promień zerowy, to przeliczamy punkty kontrolne cp3 = (p3 + p3 + p4) / 3.0 - p3; // jak jest prosty, to się zoptymalizuje @@ -641,6 +643,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) } else SwitchExtension->Segments[1]->Init(p3, p4, segsize, r3, r4); + if (eType == tt_Cross) { // Ra 2014-07: dla skrzyżowań będą dodatkowe segmenty SwitchExtension->Segments[2]->Init(p2, cp2 + p2, cp4 + p4, p4, segsize, r2, r4); // z punktu 2 do 4 @@ -1815,8 +1818,9 @@ int TTrack::RaArrayPrepare() return 0; }; -void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) +int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount) { // wypełnianie tablic VBO + int debugvertexcount{ 0 }; // Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur double fHTW = 0.5 * fabs(fTrackWidth); double side = fabs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza @@ -1951,12 +1955,15 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos } } - Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -4 : 4, fTexLength); + debugvertexcount += Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -4 : 4, fTexLength); + assert( debugvertexcount <= Vertexcount ); } if (TextureID1) { // szyny - generujemy dwie, najwyżej rysować się będzie jedną - Segment->RenderLoft(Vert, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); - Segment->RenderLoft(Vert, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + debugvertexcount += Segment->RenderLoft(Vert, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += Segment->RenderLoft(Vert, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + assert( debugvertexcount <= Vertexcount ); } break; case tt_Switch: // dla zwrotnicy dwa razy szyny @@ -1980,27 +1987,46 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) } if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa - SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength); - SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2 ); + int batch{ 0 }; + batch = SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength); + debugvertexcount += batch; + assert( debugvertexcount <= Vertexcount ); + batch = SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2 ); + debugvertexcount += batch; + assert( debugvertexcount <= Vertexcount ); SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - SwitchExtension->Segments[0]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); + batch = SwitchExtension->Segments[0]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); + debugvertexcount += batch; + assert( debugvertexcount <= Vertexcount ); SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - SwitchExtension->Segments[1]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); - SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); - SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength ); + batch = SwitchExtension->Segments[1]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); + debugvertexcount += batch; + assert( debugvertexcount <= Vertexcount ); + batch = SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); + debugvertexcount += batch; + assert( debugvertexcount <= Vertexcount ); + batch = SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength ); + debugvertexcount += batch; + assert( debugvertexcount <= Vertexcount ); } else { // lewa działa lepiej niż prawa - SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength); // lewa szyna normalna cała - SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą + debugvertexcount += SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength); // lewa szyna normalna cała + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą + assert( debugvertexcount <= Vertexcount ); SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - SwitchExtension->Segments[0]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2); // prawa iglica - + debugvertexcount += SwitchExtension->Segments[0]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2); // prawa iglica + assert( debugvertexcount <= Vertexcount ); + SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - SwitchExtension->Segments[1]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1); // lewa iglica - SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą - SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength); // prawa szyna normalnie cała + debugvertexcount += SwitchExtension->Segments[1]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1); // lewa iglica + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength); // prawa szyna normalnie cała + assert( debugvertexcount <= Vertexcount ); } } break; @@ -2034,7 +2060,8 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) } if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy - Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); + debugvertexcount += Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); + assert( debugvertexcount <= Vertexcount ); } if (TextureID2) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) @@ -2114,16 +2141,24 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) if( iTrapezoid ) // trapez albo przechyłki { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony // odcinka - if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) - Segment->RenderLoft( Vert, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej - if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) - Segment->RenderLoft( Vert, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej + if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { + debugvertexcount += Segment->RenderLoft( Vert, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej + assert( debugvertexcount <= Vertexcount ); + } + if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { + debugvertexcount += Segment->RenderLoft( Vert, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej + assert( debugvertexcount <= Vertexcount ); + } } else { // pobocza zwykłe, brak przechyłki - if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) - Segment->RenderLoft( Vert, rpts1, 3, fTexLength ); - if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) - Segment->RenderLoft( Vert, rpts2, 3, fTexLength ); + if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { + debugvertexcount += Segment->RenderLoft( Vert, rpts1, 3, fTexLength ); + assert( debugvertexcount <= Vertexcount ); + } + if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { + debugvertexcount += Segment->RenderLoft( Vert, rpts2, 3, fTexLength ); + assert( debugvertexcount <= Vertexcount ); + } } } break; @@ -2262,18 +2297,25 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) if (SwitchExtension->iRoads == 4) { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + debugvertexcount += SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + assert( debugvertexcount <= Vertexcount ); } } else { // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P2 do P4 - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P4 do P3=P1 (odwrócony) - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P1 do P2 + debugvertexcount += SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P2 do P4 + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P4 do P3=P1 (odwrócony) + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P1 do P2 + assert( debugvertexcount <= Vertexcount ); } } } @@ -2304,6 +2346,7 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) Vert->y = oxz.y; Vert->z = oxz.z; ++Vert; + ++debugvertexcount; for (i = SwitchExtension->iPoints - 2; i >= 0; --i) { Vert->nx = 0.0; @@ -2318,7 +2361,9 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) Vert->y = SwitchExtension->vPoints[ i ].y; Vert->z = SwitchExtension->vPoints[ i ].z; ++Vert; + ++debugvertexcount; } + assert( debugvertexcount <= Vertexcount ); } break; } @@ -2357,7 +2402,8 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) } if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy - Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); + debugvertexcount += Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); + assert( debugvertexcount <= Vertexcount ); } if (TextureID2) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w @@ -2379,19 +2425,24 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza - Segment->RenderLoft(Vert, rpts1, -3, fTexLength); - Segment->RenderLoft(Vert, rpts2, -3, fTexLength); + debugvertexcount += Segment->RenderLoft(Vert, rpts1, -3, fTexLength); + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += Segment->RenderLoft(Vert, rpts2, -3, fTexLength); + assert( debugvertexcount <= Vertexcount ); } else { // pobocza zwykłe, brak przechyłki - Segment->RenderLoft(Vert, rpts1, 3, fTexLength); - Segment->RenderLoft(Vert, rpts2, 3, fTexLength); + debugvertexcount += Segment->RenderLoft(Vert, rpts1, 3, fTexLength); + assert( debugvertexcount <= Vertexcount ); + debugvertexcount += Segment->RenderLoft(Vert, rpts2, 3, fTexLength); + assert( debugvertexcount <= Vertexcount ); } } } } break; } + return debugvertexcount; }; void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO @@ -2936,8 +2987,9 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer) int size = RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy CVertNormTex *Vert = new CVertNormTex[size]; // bufor roboczy // CVertNormTex *v=Vert; //zmieniane przez - RaArrayFill(Vert, Vert - SwitchExtension->iLeftVBO); // iLeftVBO powinno zostać niezmienione - glBufferSubData( + auto const debugvertexcount = RaArrayFill(Vert, Vert - SwitchExtension->iLeftVBO, size); // iLeftVBO powinno zostać niezmienione + assert( debugvertexcount == size ); + ::glBufferSubData( GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex), size * sizeof(CVertNormTex), Vert); // wysłanie fragmentu bufora VBO } diff --git a/Track.h b/Track.h index 6809afc6..8cab1b1d 100644 --- a/Track.h +++ b/Track.h @@ -240,7 +240,7 @@ class TTrack : public Resource void Render(); // renderowanie z Display Lists int RaArrayPrepare(); // zliczanie rozmiaru dla VBO sektroa - void RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start); // wypełnianie VBO + int RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount); // wypełnianie VBO void RaRenderVBO(int iPtr); // renderowanie z VBO sektora void RenderDyn(); // renderowanie nieprzezroczystych pojazdów (oba tryby) void RenderDynAlpha(); // renderowanie przezroczystych pojazdów (oba tryby) diff --git a/Traction.cpp b/Traction.cpp index 4aa4d8d3..8324854a 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -324,8 +324,10 @@ int TTraction::RaArrayPrepare() return iLines; }; -void TTraction::RaArrayFill(CVertNormTex *Vert) +int TTraction::RaArrayFill(CVertNormTex *Vert) { // wypełnianie tablic VBO + int debugvertexcount{ 0 }; + double ddp = std::hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z); if (Wires == 2) WireOffset = 0; @@ -334,10 +336,12 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) Vert->y = pPoint1.y; Vert->z = pPoint1.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; ++Vert; + ++debugvertexcount; Vert->x = pPoint2.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; Vert->y = pPoint2.y; Vert->z = pPoint2.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; ++Vert; + ++debugvertexcount; // Nie wiem co 'Marcin Math3D::vector3 pt1, pt2, pt3, pt4, v1, v2; v1 = pPoint4 - pPoint3; @@ -355,6 +359,7 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) Vert->y = pPoint3.y; Vert->z = pPoint3.z; ++Vert; + ++debugvertexcount; for (int i = 0; i < iNumSections - 1; ++i) { pt3 = pPoint3 + v1 * f; @@ -366,6 +371,7 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference; Vert->z = pt3.z; ++Vert; + ++debugvertexcount; } f += step; } @@ -373,6 +379,7 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) Vert->y = pPoint4.y; Vert->z = pPoint4.z; ++Vert; + ++debugvertexcount; } // Drugi przewod jezdny 'Winger if (Wires > 2) @@ -381,10 +388,12 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) Vert->y = pPoint1.y; Vert->z = pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; ++Vert; + ++debugvertexcount; Vert->x = pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; Vert->y = pPoint2.y; Vert->z = pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; ++Vert; + ++debugvertexcount; } f = step; @@ -394,6 +403,7 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) Vert->y = pPoint3.y - 0.65f * fHeightDifference; Vert->z = pPoint3.z; ++Vert; + ++debugvertexcount; for( int i = 0; i < iNumSections - 1; ++i ) { pt3 = pPoint3 + v1 * f; t = ( 1 - std::fabs( f - mid ) * 2 ); @@ -405,11 +415,14 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) 0.05 ); Vert->z = pt3.z; ++Vert; + ++debugvertexcount; f += step; } Vert->x = pPoint4.x; Vert->y = pPoint4.y - 0.65f * fHeightDifference; Vert->z = pPoint4.z; + ++Vert; + ++debugvertexcount; } f = step; @@ -430,20 +443,24 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ); Vert->z = pt3.z; ++Vert; + ++debugvertexcount; Vert->x = pt4.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; Vert->y = pt4.y; Vert->z = pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; ++Vert; + ++debugvertexcount; } else { Vert->x = pt3.x; Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ); Vert->z = pt3.z; ++Vert; + ++debugvertexcount; Vert->x = pt4.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; Vert->y = pt4.y; Vert->z = pt4.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; ++Vert; + ++debugvertexcount; } if( ( ( Wires == 4 ) && ( ( i == 1 ) @@ -452,14 +469,17 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - 0.05; Vert->z = pt3.z; ++Vert; + ++debugvertexcount; Vert->x = pt3.x; Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference; Vert->z = pt3.z; ++Vert; + ++debugvertexcount; } f += step; } } + return debugvertexcount; }; void TTraction::RenderVBO(float mgn, int iPtr) diff --git a/Traction.h b/Traction.h index e1484819..e276bf59 100644 --- a/Traction.h +++ b/Traction.h @@ -68,7 +68,7 @@ class TTraction // virtual void SelectedRender(); void RenderDL(float mgn); int RaArrayPrepare(); - void RaArrayFill(CVertNormTex *Vert); + int RaArrayFill(CVertNormTex *Vert); void RenderVBO(float mgn, int iPtr); int TestPoint(Math3D::vector3 *Point); void Connect(int my, TTraction *with, int to); diff --git a/version.h b/version.h index 5ecf5416..b942025d 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 517 +#define VERSION_MINOR 519 #define VERSION_REVISION 0 From e805533f54f10f9d73913c349662fde595149b03 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 20 May 2017 21:09:03 +0200 Subject: [PATCH 03/12] build 170520. compressor activation for multi-unit engines, gamepad support toggle, local brake logic fix for multi-unit engines --- Driver.cpp | 137 +++++++++++++++++++++++---------------------- DynObj.cpp | 3 +- EU07.cpp | 4 +- Globals.cpp | 6 ++ Globals.h | 2 +- McZapkie/Mover.cpp | 132 +++++++++++++++++++++++++++++-------------- Segment.cpp | 3 + Track.cpp | 6 +- World.cpp | 9 ++- version.h | 2 +- 10 files changed, 182 insertions(+), 122 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 5dc88575..779fe395 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2246,76 +2246,79 @@ bool TController::ReleaseEngine() bool TController::IncBrake() { // zwiększenie hamowania bool OK = false; - switch (mvOccupied->BrakeSystem) - { - case Individual: - if (mvOccupied->LocalBrake == ManualBrake) - OK = mvOccupied->IncManualBrakeLevel( 1 + static_cast( std::floor( 0.5 + std::fabs(AccDesired))) ); - else - OK = mvOccupied->IncLocalBrakeLevel( std::floor( 1.5 + std::abs( AccDesired ) ) ); - break; - case Pneumatic: - // NOTE: can't perform just test whether connected vehicle == nullptr, due to virtual couplers formed with nearby vehicles - if ((mvOccupied->Couplers[0].CouplingFlag == 0) && - (mvOccupied->Couplers[1].CouplingFlag == 0)) - OK = mvOccupied->IncLocalBrakeLevel( - 1 + static_cast( std::floor( 0.5 + std::fabs(AccDesired))) ); // hamowanie lokalnym bo luzem jedzie - else - { - if (mvOccupied->BrakeCtrlPos + 1 == mvOccupied->BrakeCtrlPosNo) - { - if (AccDesired < -1.5) // hamowanie nagle - OK = mvOccupied->IncBrakeLevel(); - else - OK = false; + switch( mvOccupied->BrakeSystem ) { + case Individual: { + if( mvOccupied->LocalBrake == ManualBrake ) { + OK = mvOccupied->IncManualBrakeLevel( 1 + static_cast( std::floor( 0.5 + std::fabs( AccDesired ) ) ) ); + } + else { + OK = mvOccupied->IncLocalBrakeLevel( std::floor( 1.5 + std::abs( AccDesired ) ) ); + } + break; + } + case Pneumatic: { + // NOTE: can't perform just test whether connected vehicle == nullptr, due to virtual couplers formed with nearby vehicles + bool standalone{ true }; + if( ( mvOccupied->TrainType == dt_ET41 ) + || ( mvOccupied->TrainType == dt_ET42 ) ) { + // NOTE: we're doing simplified checks full of presuptions here. + // they'll break if someone does strange thing like turning around the second unit + if( ( mvOccupied->Couplers[ 1 ].CouplingFlag & coupling::permanent ) + && ( mvOccupied->Couplers[ 1 ].Connected->Couplers[ 1 ].CouplingFlag > 0 ) ) { + standalone = false; + } + if( ( mvOccupied->Couplers[ 0 ].CouplingFlag & coupling::permanent ) + && ( mvOccupied->Couplers[ 0 ].Connected->Couplers[ 0 ].CouplingFlag > 0 ) ) { + standalone = false; + } + } + else { + standalone = + ( ( mvOccupied->Couplers[ 0 ].CouplingFlag == 0 ) + && ( mvOccupied->Couplers[ 1 ].CouplingFlag == 0 ) ); + } + if( true == standalone ) { + OK = mvOccupied->IncLocalBrakeLevel( + 1 + static_cast( std::floor( 0.5 + std::fabs( AccDesired ) ) ) ); // hamowanie lokalnym bo luzem jedzie + } + else { + if( mvOccupied->BrakeCtrlPos + 1 == mvOccupied->BrakeCtrlPosNo ) { + if( AccDesired < -1.5 ) // hamowanie nagle + OK = mvOccupied->IncBrakeLevel(); + else + OK = false; + } + else { + // dodane dla towarowego + if( mvOccupied->BrakeDelayFlag == bdelay_G ? + -AccDesired * 6.6 > std::min( 2, mvOccupied->BrakeCtrlPos ) : + true ) { + OK = mvOccupied->IncBrakeLevel(); + } + else + OK = false; + } + } + if( mvOccupied->BrakeCtrlPos > 0 ) { + mvOccupied->BrakeReleaser( 0 ); + } + break; + } + case ElectroPneumatic: { + if( mvOccupied->EngineType == ElectricInductionMotor ) { + OK = mvOccupied->IncLocalBrakeLevel( 1 ); + } + else if( mvOccupied->fBrakeCtrlPos != mvOccupied->Handle->GetPos( bh_EPB ) ) { + mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_EPB ) ); + if( mvOccupied->Handle->GetPos( bh_EPR ) - mvOccupied->Handle->GetPos( bh_EPN ) < 0.1 ) + mvOccupied->SwitchEPBrake( 1 ); // to nie chce działać + OK = true; } else - { - /* - if (AccDesired>-0.2) and ((Vel<20) or (Vel-VelNext<10))) - begin - if BrakeCtrlPos>0) - OK:=IncBrakeLevel - else; - OK:=IncLocalBrakeLevel(1); //finezyjne hamowanie lokalnym - end - else - */ - // dodane dla towarowego - if (mvOccupied->BrakeDelayFlag == bdelay_G ? - -AccDesired * 6.6 > std::min(2, mvOccupied->BrakeCtrlPos) : - true) - { - OK = mvOccupied->IncBrakeLevel(); - } - else - OK = false; - } + OK = false; + break; } - if (mvOccupied->BrakeCtrlPos > 0) - mvOccupied->BrakeReleaser(0); - break; - case ElectroPneumatic: - if (mvOccupied->EngineType == ElectricInductionMotor) - { - OK = mvOccupied->IncLocalBrakeLevel(1); - } - else if (mvOccupied->fBrakeCtrlPos != mvOccupied->Handle->GetPos(bh_EPB)) - { - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPB)); - if (mvOccupied->Handle->GetPos(bh_EPR) - mvOccupied->Handle->GetPos(bh_EPN) < 0.1) - mvOccupied->SwitchEPBrake(1); // to nie chce działać - OK = true; - } - else - OK = false; - // if (mvOccupied->BrakeCtrlPosBrakeCtrlPosNo) - // if - // (mvOccupied->BrakePressureTable[mvOccupied->BrakeCtrlPos+1+2].BrakeType==ElectroPneumatic) - // //+2 to indeks Pascala - // OK=mvOccupied->IncBrakeLevel(); - // else - // OK=false; + default: { break; } } return OK; } diff --git a/DynObj.cpp b/DynObj.cpp index 47e6e18b..3441c328 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1879,8 +1879,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" { // McZapkie-040602: jeśli coś siedzi w pojeździe if (Name == Global::asHumanCtrlVehicle) // jeśli pojazd wybrany do prowadzenia { - if (DebugModeFlag ? false : MoverParameters->EngineType != - Dumb) // jak nie Debugmode i nie jest dumbem + if ( MoverParameters->EngineType != Dumb) Controller = Humandriver; // wsadzamy tam sterującego else // w przeciwnym razie trzeba włączyć pokazywanie kabiny bDisplayCab = true; diff --git a/EU07.cpp b/EU07.cpp index 291933d4..90a57219 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -411,7 +411,9 @@ int main(int argc, char *argv[]) && GfxRenderer.Render()) { glfwPollEvents(); - input::Gamepad.poll(); + if( true == Global::InputGamepad ) { + input::Gamepad.poll(); + } } Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej) } diff --git a/Globals.cpp b/Globals.cpp index d34088fe..277b01ad 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -110,6 +110,7 @@ int Global::iWindowHeight = 600; float Global::fDistanceFactor = Global::ScreenHeight / 768.0; // baza do przeliczania odległości dla LoD int Global::iFeedbackMode = 1; // tryb pracy informacji zwrotnej int Global::iFeedbackPort = 0; // dodatkowy adres dla informacji zwrotnych +bool Global::InputGamepad{ true }; bool Global::bFreeFly = false; bool Global::bFullScreen = false; bool Global::VSync{ false }; @@ -801,6 +802,11 @@ void Global::ConfigParse(cParser &Parser) >> Global::Background[1] // g >> Global::Background[2]; // b } + else if( token == "input.gamepad" ) { + // czy grupować eventy o tych samych nazwach + Parser.getTokens(); + Parser >> Global::InputGamepad; + } // maciek001: ustawienia MWD else if (token == "mwdmasterenable") { // główne włączenie maszyny! Parser.getTokens(); diff --git a/Globals.h b/Globals.h index c44fef01..91664442 100644 --- a/Globals.h +++ b/Globals.h @@ -255,6 +255,7 @@ class Global static std::string LastGLError; static int iFeedbackMode; // tryb pracy informacji zwrotnej static int iFeedbackPort; // dodatkowy adres dla informacji zwrotnych + static bool InputGamepad; // whether gamepad support is enabled static double fLuminance; // jasność światła do automatycznego zapalania static float SunAngle; // angle of the sun relative to horizon static int iMultiplayer; // blokada działania niektórych eventów na rzecz kominikacji @@ -287,7 +288,6 @@ class Global static int iKeyLast; // ostatnio naciśnięty klawisz w celu logowania static int iPause; // globalna pauza ruchu: b0=start,b1=klawisz,b2=tło,b3=lagi,b4=wczytywanie static bool bActive; // czy jest aktywnym oknem - static void BindTexture(GLuint t); static int iConvertModels; // tworzenie plików binarnych static int iErorrCounter; // licznik sprawdzań do śledzenia błędów OpenGL static bool bInactivePause; // automatyczna pauza, gdy okno nieaktywne diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index c171722b..29475923 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -3063,56 +3063,104 @@ void TMoverParameters::CompressorCheck(double dt) CompressorFlag = false; // bez tamtego członu nie zadziała } else - CompressorFlag = (CompressorAllow) && - ((ConverterFlag) || (CompressorPower == 0)) && (Mains); + CompressorFlag = + ( ( CompressorAllow ) + && ( Mains ) + && ( ( ConverterFlag ) + || ( CompressorPower == 0 ) ) ); + if( Compressor > MaxCompressor ) { // wyłącznik ciśnieniowy jest niezależny od sposobu zasilania CompressorFlag = false; CompressorGovernorLock = true; // prevent manual activation until the pressure goes below cut-in level } - } - else // jeśli nie załączona - if( ( ( Compressor < MinCompressor ) - || ( ( Compressor < MaxCompressor ) - && ( false == CompressorGovernorLock ) ) ) - && (LastSwitchingTime > CtrlDelay) ) { - // załączenie przy małym ciśnieniu - // jeśli nie załączona, a ciśnienie za małe - // or if the switch is on and the pressure isn't maxed - if( CompressorPower == 5 ) // jeśli zasilanie z następnego członu - { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) - if (Couplers[1].Connected != NULL) - CompressorFlag = - (Couplers[1].Connected->CompressorAllow && - Couplers[1].Connected->ConverterFlag && Couplers[1].Connected->Mains); - else - CompressorFlag = false; // bez tamtego członu nie zadziała - } - else if (CompressorPower == 4) // jeśli zasilanie z poprzedniego członu - { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) - if (Couplers[0].Connected != NULL) - CompressorFlag = - (Couplers[0].Connected->CompressorAllow && - Couplers[0].Connected->ConverterFlag && Couplers[0].Connected->Mains); - else - CompressorFlag = false; // bez tamtego członu nie zadziała - } - else - CompressorFlag = (CompressorAllow) && - ((ConverterFlag) || (CompressorPower == 0)) && (Mains); - if( CompressorFlag ) { - // jeśli została załączona - LastSwitchingTime = 0; // to trzeba ograniczyć ponowne włączenie - if( Compressor < MinCompressor ) { - // if the activation took place at pressure below the cut-in level, we can reset compressor governor - CompressorGovernorLock = false; + + if( ( TrainType == dt_ET41 ) + || ( TrainType == dt_ET42 ) ) { + // for these multi-unit engines compressors turn off whenever any of them was affected by the governor + // NOTE: this is crude implementation, TODO: re-implement when a more elegant/flexible system is in place + if( ( Couplers[ 1 ].Connected != nullptr ) + && ( true == TestFlag( Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + CompressorFlag &= ( Couplers[ 1 ].Connected->CompressorGovernorLock == false ); + } + if( ( Couplers[ 0 ].Connected != nullptr ) + && ( true == TestFlag( Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { + // the second unit isn't allowed to start its compressor until first unit can start its own as well + CompressorFlag &= ( Couplers[ 0 ].Connected->CompressorGovernorLock == false ); } } } - // for b:=0 to 1 do //z Megapacka - // with Couplers[b] do - // if TestFlag(CouplingFlag,ctrain_scndpneumatic) then - // Connected.CompressorFlag:=CompressorFlag; + else { + // jeśli nie załączona + if( Compressor < MinCompressor ) { + // if the pressure drops below the cut-in level, we can reset compressor governor + CompressorGovernorLock = false; + } + + if( ( ( Compressor < MinCompressor ) + || ( ( Compressor < MaxCompressor ) + && ( false == CompressorGovernorLock ) ) ) + && ( LastSwitchingTime > CtrlDelay ) ) { + // załączenie przy małym ciśnieniu + // jeśli nie załączona, a ciśnienie za małe + // or if the switch is on and the pressure isn't maxed + if( CompressorPower == 5 ) // jeśli zasilanie z następnego członu + { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) + if( Couplers[ 1 ].Connected != nullptr ) { + CompressorFlag = + ( Couplers[ 1 ].Connected->CompressorAllow + && Couplers[ 1 ].Connected->ConverterFlag + && Couplers[ 1 ].Connected->Mains ); + } + else { + CompressorFlag = false; // bez tamtego członu nie zadziała + } + } + else if( CompressorPower == 4 ) // jeśli zasilanie z poprzedniego członu + { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) + if( Couplers[ 0 ].Connected != nullptr ) { + CompressorFlag = + ( Couplers[ 0 ].Connected->CompressorAllow + && Couplers[ 0 ].Connected->ConverterFlag + && Couplers[ 0 ].Connected->Mains ); + } + else { + CompressorFlag = false; // bez tamtego członu nie zadziała + } + } + else { + CompressorFlag = + ( ( CompressorAllow ) + && ( Mains ) + && ( ( ConverterFlag ) + || ( CompressorPower == 0 ) ) ); + } + + // NOTE: crude way to enforce simultaneous activation of compressors in multi-unit setups + // TODO: replace this with a more universal activation system down the road + if( ( TrainType == dt_ET41 ) + || ( TrainType == dt_ET42 ) ) { + + if( ( Couplers[1].Connected != nullptr ) + && ( true == TestFlag( Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + CompressorFlag &= ( Couplers[ 1 ].Connected->CompressorGovernorLock == false ); + } + if( ( Couplers[ 0 ].Connected != nullptr ) + && ( true == TestFlag( Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { + // the second unit isn't allowed to start its compressor until first unit can start its own as well + CompressorFlag &= ( Couplers[ 0 ].Connected->CompressorGovernorLock == false ); + } + } + + if( CompressorFlag ) { + // jeśli została załączona + LastSwitchingTime = 0; // to trzeba ograniczyć ponowne włączenie + } + } + } + if (CompressorFlag) if ((EngineType == DieselElectric) && (CompressorPower > 0)) CompressedVolume += dt * CompressorSpeed * (2.0 * MaxCompressor - Compressor) / diff --git a/Segment.cpp b/Segment.cpp index 75a8e335..efbb6027 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -114,7 +114,10 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI { ErrorLog( "Bad geometry (zero length) for spline \"" + pOwner->NameGet() + "\" at " + Where( Point1 ) ); // MessageBox(0,"Length<=0","TSegment::Init",MB_OK); + fLength = 0.01; // crude workaround TODO: fix this properly +/* return false; // zerowe nie mogą być +*/ } if( ( pOwner->eType == tt_Switch ) diff --git a/Track.cpp b/Track.cpp index 56e21423..49d00988 100644 --- a/Track.cpp +++ b/Track.cpp @@ -532,7 +532,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) // na przechyłce doliczyć jeszcze pół przechyłki } if( fRadius != 0 ) // gdy podany promień - segsize = clamp( 0.2 + fabs( fRadius ) * 0.02, 2.5, 10.0 ); + segsize = clamp( 0.2 + std::fabs( fRadius ) * 0.02, 2.0, 10.0 ); else segsize = 10.0; // for straights, 10m per segment works good enough @@ -595,7 +595,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) // na przechyłce doliczyć jeszcze pół przechyłki? } if (fRadiusTable[0] > 0) - segsize = clamp( 0.2 + fRadiusTable[0] * 0.02, 2.5, 5.0 ); + segsize = clamp( 0.2 + fRadiusTable[0] * 0.02, 2.0, 5.0 ); else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne { // jak promień zerowy, to przeliczamy punkty kontrolne cp1 = (p1 + p1 + p2) / 3.0 - p1; // jak jest prosty, to się zoptymalizuje @@ -625,7 +625,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) } if (fRadiusTable[1] > 0) - segsize = clamp( 0.2 + fRadiusTable[ 1 ] * 0.02, 2.5, 5.0 ); + segsize = clamp( 0.2 + fRadiusTable[ 1 ] * 0.02, 2.0, 5.0 ); else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne { // jak promień zerowy, to przeliczamy punkty kontrolne diff --git a/World.cpp b/World.cpp index 5ca62383..1a0cf45e 100644 --- a/World.cpp +++ b/World.cpp @@ -375,11 +375,12 @@ bool TWorld::Init( GLFWwindow *Window ) { WriteLog( "Load time: " + std::to_string( std::chrono::duration_cast(( std::chrono::system_clock::now() - timestart )).count() ) + " seconds"); +/* if (DebugModeFlag) // w Debugmode automatyczne włączenie AI if (Train) if (Train->Dynamic()->Mechanik) Train->Dynamic()->Mechanik->TakeControl(true); - +*/ UILayer.set_progress(); UILayer.set_background( "" ); UILayer.clear_texts(); @@ -1748,11 +1749,9 @@ TWorld::Update_UI() { Global::Bezogonkow( "| " + station + " | " + arrival + " | " + departure + " | " + vmax + " | " + tableline->StationWare, true ), ( ( owner->iStationStart < table->StationIndex ) && ( i < table->StationIndex ) - && ( time.wHour >= tableline->Dh ) - && ( time.wMinute >= tableline->Dm ) ? + && ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) ? float4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minął i odjazd był, to nazwa stacji będzie na zielono - Global::UITextColor ) - ); + Global::UITextColor ) ); // divider/footer UITable->text_lines.emplace_back( "+----------------------------+-------+-------+-----+", Global::UITextColor ); } diff --git a/version.h b/version.h index b942025d..5102dd54 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 519 +#define VERSION_MINOR 520 #define VERSION_REVISION 0 From 9f07e2b5040a324205eed9e760c1095c7155dc91 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 23 May 2017 02:25:56 +0200 Subject: [PATCH 04/12] switches for local converter and compressor, motor connector fix for multi-unit engines, crossroad generation fixes for vbo render path --- Driver.cpp | 15 +-- Ground.cpp | 40 ++----- McZapkie/MOVER.h | 4 + McZapkie/Mover.cpp | 33 ++++-- Segment.cpp | 23 ++-- Segment.h | 2 + Track.cpp | 288 ++++++++++++++++++++------------------------- Track.h | 2 +- Train.cpp | 247 ++++++++++++++++++++++++++++++++++---- Train.h | 4 + World.cpp | 4 +- command.cpp | 2 + command.h | 2 + keyboardinput.cpp | 4 + keyboardinput.h | 2 +- version.h | 2 +- 16 files changed, 425 insertions(+), 249 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 779fe395..97c7ee03 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -869,8 +869,9 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // if (p7&3) //żeby jeszcze poczekał chwilę, zanim zamknie // WaitingSet(10); //10 sekund (wziąć z rozkładu????) } - if (fStopTime > -5) // na końcu rozkładu się ustawia 60s i tu by było skrócenie - WaitingSet(10); // 10 sekund (wziąć z rozkładu????) - czekanie + + if( fStopTime > -5 ) // na końcu rozkładu się ustawia 60s i tu by było skrócenie + WaitingSet( 15.0 + Random( 15.0 ) ); // 10 sekund (wziąć z rozkładu????) - czekanie // niezależne od sposobu obsługi drzwi, bo opóźnia również kierownika } if (TrainParams->UpdateMTable( simulation::Time, asNextStop) ) @@ -980,11 +981,10 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN sSpeedTable[i].fVelNext = -1; // można jechać za W4 fLastStopExpDist = -1.0f; // nie ma rozkładu, nie ma usuwania stacji WaitingSet(60); // tak ze 2 minuty, aż wszyscy wysiądą - JumpToNextOrder(); // wykonanie kolejnego rozkazu (Change_direction - // albo Shunt) - iDrivigFlags |= moveStopHere | moveStartHorn; // ma się nie ruszać - // aż do momentu - // podania sygnału + // wykonanie kolejnego rozkazu (Change_direction albo Shunt) + JumpToNextOrder(); + // ma się nie ruszać aż do momentu podania sygnału + iDrivigFlags |= moveStopHere | moveStartHorn; continue; // nie analizować prędkości } // koniec obsługi ostatniej stacji } // if (MoverParameters->Vel==0.0) @@ -4142,6 +4142,7 @@ bool TController::UpdateSituation(double dt) ->TTVmax); // jesli nie spozniony to nie przekraczać rozkladowej if (VelDesired > 0.0) if( ( ( SemNextIndex != -1 ) + && ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s) && ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) || ( ( iDrivigFlags & moveStopHere ) == 0 ) ) { // jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w diff --git a/Ground.cpp b/Ground.cpp index 087e76fb..cbebea27 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -787,7 +787,6 @@ void TSubRect::LoadNodes() return; // jeśli nie ma obiektów do wyświetlenia z VBO, to koniec if (Global::bUseVBO) { // tylko liczenie wierzchołów, gdy nie ma VBO - int debugvertexcount{ 0 }; MakeArray(m_nVertexCount); n = nRootNode; int i; @@ -809,9 +808,7 @@ void TSubRect::LoadNodes() m_pVNT[n->iVboPtr + i].nz = n->Vertices[i].Normal.z; m_pVNT[n->iVboPtr + i].u = n->Vertices[i].tu; m_pVNT[n->iVboPtr + i].v = n->Vertices[i].tv; - ++debugvertexcount; } - assert( debugvertexcount <= m_nVertexCount ); break; case GL_LINES: case GL_LINE_STRIP: @@ -822,34 +819,24 @@ void TSubRect::LoadNodes() m_pVNT[n->iVboPtr + i].y = n->Points[i].y; m_pVNT[n->iVboPtr + i].z = n->Points[i].z; // miejsce w tablicach normalnych i teksturowania się marnuje... - ++debugvertexcount; } - assert( debugvertexcount <= m_nVertexCount ); break; case TP_TRACK: if( n->iNumVerts ) { // bo tory zabezpieczające są niewidoczne #ifdef EU07_USE_OLD_VERTEXBUFFER - int const batch = n->pTrack->RaArrayFill( m_pVNT + n->iVboPtr, m_pVNT, std::min( n->iNumVerts, m_nVertexCount - n->iVboPtr ) ); + n->pTrack->RaArrayFill( m_pVNT + n->iVboPtr, m_pVNT, std::min( n->iNumVerts, m_nVertexCount - n->iVboPtr ) ); #else - int const batch = n->pTrack->RaArrayFill( m_pVNT.data() + n->iVboPtr, m_pVNT.data(), std::min( n->iNumVerts, m_nVertexCount - n->iVboPtr ) ); + n->pTrack->RaArrayFill( m_pVNT.data() + n->iVboPtr, m_pVNT.data(), std::min( n->iNumVerts, m_nVertexCount - n->iVboPtr ) ); #endif - assert( batch == n->iNumVerts ); - assert( batch + n->iVboPtr <= m_nVertexCount ); - debugvertexcount += batch; - assert( debugvertexcount <= m_nVertexCount ); } break; case TP_TRACTION: if( n->iNumVerts ) { // druty mogą być niewidoczne...? #ifdef EU07_USE_OLD_VERTEXBUFFER - int const batch = n->hvTraction->RaArrayFill( m_pVNT + n->iVboPtr ); + n->hvTraction->RaArrayFill( m_pVNT + n->iVboPtr ); #else - int const batch = n->hvTraction->RaArrayFill( m_pVNT.data() + n->iVboPtr ); + n->hvTraction->RaArrayFill( m_pVNT.data() + n->iVboPtr ); #endif - assert( batch == n->iNumVerts ); - assert( batch + n->iVboPtr <= m_nVertexCount ); - debugvertexcount += batch; - assert( debugvertexcount <= m_nVertexCount ); } break; } @@ -1333,17 +1320,14 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) TGroundNode *tmp1; TTrack *Track; std::string token; - parser->getTokens(2); - *parser >> r >> rmin; - parser->getTokens(); - *parser >> token; - asNodeName = token; - parser->getTokens(); - *parser >> token; - str = token; + parser->getTokens(4); + *parser + >> r + >> rmin + >> asNodeName + >> str; //str = AnsiString(token.c_str()); - TGroundNode *tmp; - tmp = new TGroundNode(); + TGroundNode *tmp = new TGroundNode(); tmp->asName = (asNodeName == "none" ? "" : asNodeName); if (r >= 0) tmp->fSquareRadius = r * r; @@ -2186,7 +2170,7 @@ bool TGround::Init(std::string File) if (!LastNode->Vertices) SafeDelete(LastNode); // usuwamy nieprzezroczyste trójkąty terenu } - else if (Global::bLoadTraction ? false : LastNode->iType == TP_TRACTION) + else if ( ( LastNode->iType == TP_TRACTION ) && ( false == Global::bLoadTraction ) ) SafeDelete(LastNode); // usuwamy druty, jeśli wyłączone if (LastNode) // dopiero na koniec dopisujemy do tablic if (LastNode->iType != TP_DYNAMIC) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 95c0adad..36df83ce 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -847,12 +847,14 @@ public: bool CompressorFlag = false; /*!o czy wlaczona sprezarka*/ bool PantCompFlag = false; /*!o czy wlaczona sprezarka pantografow*/ bool CompressorAllow = false; /*! zezwolenie na uruchomienie sprezarki NBMX*/ + bool CompressorAllowLocal{ true }; // local device state override (most units don't have this fitted so it's set to true not to intefere) bool CompressorGovernorLock{ false }; // indicates whether compressor pressure switch was activated due to reaching cut-out pressure // TODO converter parameters, for when we start cleaning up mover parameters start ConverterStart{ manual }; // whether converter is started manually, or by other means float ConverterStartDelay{ 0.0f }; // delay (in seconds) before the converter is started, once its activation conditions are met double ConverterStartDelayTimer{ 0.0 }; // helper, for tracking whether converter start delay passed bool ConverterAllow = false; /*zezwolenie na prace przetwornicy NBMX*/ + bool ConverterAllowLocal{ true }; // local device state override (most units don't have this fitted so it's set to true not to intefere) bool ConverterFlag = false; /*! czy wlaczona przetwornica NBMX*/ int BrakeCtrlPos = -2; /*nastawa hamulca zespolonego*/ @@ -978,8 +980,10 @@ public: int PantRearStart = 0; double PantFrontVolt = 0.0; //pantograf pod napieciem? 'Winger 160404 double PantRearVolt = 0.0; + // TODO: move these switch types where they belong, cabin definition std::string PantSwitchType; std::string ConvSwitchType; + std::string StLinSwitchType; bool Heating = false; //ogrzewanie 'Winger 020304 int DoubleTr = 1; //trakcja ukrotniona - przedni pojazd 'Winger 160304 diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 29475923..74a80001 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1565,6 +1565,7 @@ double TMoverParameters::ShowEngineRotation(int VehN) void TMoverParameters::ConverterCheck( double const Timestep ) { // TODO: move other converter checks here, to have it all in one place for potential device object if( ( ConverterAllow ) + && ( ConverterAllowLocal ) && ( false == PantPressLockActive ) && ( Mains ) ) { // delay timer can be optionally configured, and is set anew whenever converter goes off @@ -3018,7 +3019,7 @@ void TMoverParameters::CompressorCheck(double dt) if (MaxCompressor - MinCompressor < 0.0001) { // if (Mains && (MainCtrlPos > 1)) - if (CompressorAllow && Mains && (MainCtrlPos > 0)) + if (CompressorAllow && CompressorAllowLocal && Mains && (MainCtrlPos > 0)) { if (Compressor < MaxCompressor) if ((EngineType == DieselElectric) && (CompressorPower > 0)) @@ -3048,8 +3049,10 @@ void TMoverParameters::CompressorCheck(double dt) { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) if (Couplers[1].Connected != NULL) CompressorFlag = - (Couplers[1].Connected->CompressorAllow && - Couplers[1].Connected->ConverterFlag && Couplers[1].Connected->Mains); + ( Couplers[ 1 ].Connected->CompressorAllow + && Couplers[ 1 ].Connected->CompressorAllowLocal + && Couplers[ 1 ].Connected->Mains + && Couplers[ 1 ].Connected->ConverterFlag ); else CompressorFlag = false; // bez tamtego członu nie zadziała } @@ -3057,14 +3060,17 @@ void TMoverParameters::CompressorCheck(double dt) { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) if (Couplers[0].Connected != NULL) CompressorFlag = - (Couplers[0].Connected->CompressorAllow && - Couplers[0].Connected->ConverterFlag && Couplers[0].Connected->Mains); + ( Couplers[ 0 ].Connected->CompressorAllow + && Couplers[ 0 ].Connected->CompressorAllowLocal + && Couplers[ 0 ].Connected->Mains + && Couplers[ 0 ].Connected->ConverterFlag ); else CompressorFlag = false; // bez tamtego członu nie zadziała } else CompressorFlag = ( ( CompressorAllow ) + && ( CompressorAllowLocal ) && ( Mains ) && ( ( ConverterFlag ) || ( CompressorPower == 0 ) ) ); @@ -3080,12 +3086,12 @@ void TMoverParameters::CompressorCheck(double dt) // for these multi-unit engines compressors turn off whenever any of them was affected by the governor // NOTE: this is crude implementation, TODO: re-implement when a more elegant/flexible system is in place if( ( Couplers[ 1 ].Connected != nullptr ) - && ( true == TestFlag( Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { + && ( true == TestFlag( Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { // the first unit isn't allowed to start its compressor until second unit can start its own as well CompressorFlag &= ( Couplers[ 1 ].Connected->CompressorGovernorLock == false ); } if( ( Couplers[ 0 ].Connected != nullptr ) - && ( true == TestFlag( Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { + && ( true == TestFlag( Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { // the second unit isn't allowed to start its compressor until first unit can start its own as well CompressorFlag &= ( Couplers[ 0 ].Connected->CompressorGovernorLock == false ); } @@ -3110,8 +3116,9 @@ void TMoverParameters::CompressorCheck(double dt) if( Couplers[ 1 ].Connected != nullptr ) { CompressorFlag = ( Couplers[ 1 ].Connected->CompressorAllow - && Couplers[ 1 ].Connected->ConverterFlag - && Couplers[ 1 ].Connected->Mains ); + && Couplers[ 1 ].Connected->CompressorAllowLocal + && Couplers[ 1 ].Connected->Mains + && Couplers[ 1 ].Connected->ConverterFlag ); } else { CompressorFlag = false; // bez tamtego członu nie zadziała @@ -3122,8 +3129,9 @@ void TMoverParameters::CompressorCheck(double dt) if( Couplers[ 0 ].Connected != nullptr ) { CompressorFlag = ( Couplers[ 0 ].Connected->CompressorAllow - && Couplers[ 0 ].Connected->ConverterFlag - && Couplers[ 0 ].Connected->Mains ); + && Couplers[ 0 ].Connected->CompressorAllowLocal + && Couplers[ 0 ].Connected->Mains + && Couplers[ 0 ].Connected->ConverterFlag ); } else { CompressorFlag = false; // bez tamtego członu nie zadziała @@ -3132,6 +3140,7 @@ void TMoverParameters::CompressorCheck(double dt) else { CompressorFlag = ( ( CompressorAllow ) + && ( CompressorAllowLocal ) && ( Mains ) && ( ( ConverterFlag ) || ( CompressorPower == 0 ) ) ); @@ -7303,9 +7312,11 @@ void TMoverParameters::LoadFIZ_Switches( std::string const &Input ) { extract_value( PantSwitchType, "Pantograph", Input, "" ); extract_value( ConvSwitchType, "Converter", Input, "" ); + extract_value( StLinSwitchType, "MotorConnectors", Input, "" ); // because people can't make up their minds whether it's "impulse" or "Impulse"... PantSwitchType = ToLower( PantSwitchType ); ConvSwitchType = ToLower( ConvSwitchType ); + StLinSwitchType = ToLower( StLinSwitchType ); } void TMoverParameters::LoadFIZ_MotorParamTable( std::string const &Input ) { diff --git a/Segment.cpp b/Segment.cpp index efbb6027..194c3209 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -130,6 +130,7 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI SafeDeleteArray(fTsBuffer); iSegCount = static_cast( std::ceil( fLength / fStep ) ); // potrzebne do VBO + fStep = fLength / iSegCount; // update step to equalize size of individual pieces fTsBuffer = new double[ iSegCount + 1 ]; fTsBuffer[ 0 ] = 0.0; for( int i = 1; i < iSegCount; ++i ) { @@ -324,10 +325,10 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int // po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli // podany jest przekrój końcowy // podsypka toru jest robiona za pomocą 6 punktów, szyna 12, drogi i rzeki na 3+2+3 - int debugvertexcount{ 0 }; + int vertexcount{ 0 }; if( !fTsBuffer ) - return debugvertexcount; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę + return vertexcount; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę vector3 pos1, pos2, dir, parallel1, parallel2, pt, norm; double s, step, fOffset, tv1, tv2, t, fEnd; @@ -352,8 +353,6 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int m2 = s / fEnd; jmm2 = 1.0 - m2; - int const debugvertexlimit = std::abs( iNumShapePoints ) * 2 * ( iEnd - iSkip ); - while( i < iEnd ) { ++i; // kolejny punkt łamanej @@ -416,7 +415,7 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int } ++Output; } - ++debugvertexcount; + ++vertexcount; } if( p ) // jeśli jest wskaźnik do tablicy if( *p ) @@ -454,7 +453,7 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int } ++Output; } - ++debugvertexcount; + ++vertexcount; } if( p ) // jeśli jest wskaźnik do tablicy if( *p ) @@ -463,8 +462,6 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int *( *p ) = pt; ( *p )++; } // zapamiętanie brzegu jezdni - - assert( debugvertexcount <= debugvertexlimit ); } } else { @@ -498,7 +495,7 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int } ++Output; } - ++debugvertexcount; + ++vertexcount; pt = parallel2 * ShapePoints[ j ].x + pos2; pt.y += ShapePoints[ j ].y; @@ -527,9 +524,7 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int } ++Output; } - ++debugvertexcount; - - assert( debugvertexcount <= debugvertexlimit ); + ++vertexcount; } } } @@ -544,9 +539,7 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int } } - assert( debugvertexcount == debugvertexlimit ); - - return debugvertexcount; + return vertexcount; }; void TSegment::Render() diff --git a/Segment.h b/Segment.h index 1c4c84ab..b027d123 100644 --- a/Segment.h +++ b/Segment.h @@ -17,6 +17,8 @@ http://mozilla.org/MPL/2.0/. using namespace Math3D; +#define EU07_DEBUG_VBO + // 110405 Ra: klasa punktów przekroju z normalnymi class vector6 : public vector3 diff --git a/Track.cpp b/Track.cpp index 49d00988..dd3d6a3b 100644 --- a/Track.cpp +++ b/Track.cpp @@ -405,8 +405,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) std::string token; parser->getTokens(); - *parser >> token; - str = token; // typ toru + *parser >> str; // typ toru if (str == "normal") { @@ -460,8 +459,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) if (iDamageFlag & 128) iAction |= 0x80; // flaga wykolejania z powodu uszkodzenia parser->getTokens(); - *parser >> token; - str = token; // environment + *parser >> str; // environment if (str == "flat") eEnvironment = e_flat; else if (str == "mountains" || str == "mountain") @@ -477,7 +475,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) else { eEnvironment = e_unknown; - Error("Unknown track environment: \"" + str + "\""); + Error( "Unknown track environment: \"" + str + "\"" ); } parser->getTokens(); *parser >> token; @@ -485,8 +483,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) if (bVisible) { parser->getTokens(); - *parser >> token; - str = token; // railtex + *parser >> str; // railtex TextureID1 = (str == "none" ? 0 : GfxRenderer.GetTextureId( str, szTexturePath, (iCategoryFlag & 1) ? Global::iRailProFiltering : @@ -496,8 +493,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) if (fTexLength < 0.01) fTexLength = 4; // Ra: zabezpiecznie przed zawieszeniem parser->getTokens(); - *parser >> token; - str = token; // sub || railtex + *parser >> str; // sub || railtex TextureID2 = (str == "none" ? 0 : GfxRenderer.GetTextureId( str, szTexturePath, (eType == tt_Normal) ? Global::iBallastFiltering : @@ -1232,7 +1228,7 @@ void TTrack::Compile(GLuint tex) } break; case tt_Switch: // dla zwrotnicy dwa razy szyny - if (TextureID1) // zwrotnice nie są grupowane, aby prościej było je animować + if (TextureID1 || TextureID2) // zwrotnice nie są grupowane, aby prościej było je animować { // iglice liczone tylko dla zwrotnic // Ra: TODO: oddzielna animacja każdej iglicy, opór na docisku vector6 rpts3[24], rpts4[24]; @@ -1254,27 +1250,34 @@ void TTrack::Compile(GLuint tex) // McZapkie-130302 - poprawione rysowanie szyn if (SwitchExtension->RightSwitch) { // zwrotnica prawa - GfxRenderer.Bind( TextureID1 ); - SwitchExtension->Segments[0]->RenderLoft( immediate, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2); // prawa iglica - SwitchExtension->Segments[0]->RenderLoft( immediate, rpts1, nnumPts, fTexLength, 1.0, 2); // prawa szyna za iglicą - SwitchExtension->Segments[0]->RenderLoft( immediate, rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała - if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje + if( TextureID1 ) { + GfxRenderer.Bind( TextureID1 ); + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); // prawa iglica + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts1, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts2, nnumPts, fTexLength ); // lewa szyna normalnie cała + } + if( TextureID2 ) { GfxRenderer.Bind( TextureID2 ); - SwitchExtension->Segments[1]->RenderLoft( immediate, rpts1, nnumPts, fTexLength); // prawa szyna normalna cała - SwitchExtension->Segments[1]->RenderLoft( immediate, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1); // lewa iglica - SwitchExtension->Segments[1]->RenderLoft( immediate, rpts2, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts1, nnumPts, fTexLength ); // prawa szyna normalna cała + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); // lewa iglica + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts2, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą + } } else { // lewa kiedyś działała lepiej niż prawa - GfxRenderer.Bind( TextureID1 ); - SwitchExtension->Segments[0]->RenderLoft( immediate, rpts1, nnumPts, fTexLength); // prawa szyna normalna cała - SwitchExtension->Segments[0]->RenderLoft( immediate, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2); // lewa iglica - SwitchExtension->Segments[0]->RenderLoft( immediate, rpts2, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą - if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje + if( TextureID1 ) { + GfxRenderer.Bind( TextureID1 ); + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts1, nnumPts, fTexLength ); // prawa szyna normalna cała + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // lewa iglica + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts2, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą + } + if( TextureID2 ) { + // nie wiadomo, czy OpenGL to optymalizuje GfxRenderer.Bind( TextureID2 ); - SwitchExtension->Segments[1]->RenderLoft( immediate, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1); // prawa iglica - SwitchExtension->Segments[1]->RenderLoft( immediate, rpts1, nnumPts, fTexLength, 1.0, 2); // prawa szyna za iglicą - SwitchExtension->Segments[1]->RenderLoft( immediate, rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // prawa iglica + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts1, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts2, nnumPts, fTexLength ); // lewa szyna normalnie cała + } } } break; @@ -1782,31 +1785,33 @@ int TTrack::RaArrayPrepare() if( SwitchExtension->iRoads == 3 ) { // mogą być tylko 3 drogi zamiast 4 SwitchExtension->iPoints = - 5 - + SwitchExtension->Segments[ 0 ]->RaSegCount() + SwitchExtension->Segments[ 0 ]->RaSegCount() + SwitchExtension->Segments[ 1 ]->RaSegCount() + SwitchExtension->Segments[ 2 ]->RaSegCount(); } else { SwitchExtension->iPoints = - 5 - + SwitchExtension->Segments[ 2 ]->RaSegCount() + SwitchExtension->Segments[ 2 ]->RaSegCount() + SwitchExtension->Segments[ 3 ]->RaSegCount() + SwitchExtension->Segments[ 4 ]->RaSegCount() + SwitchExtension->Segments[ 5 ]->RaSegCount(); } +/* if (fTexHeight1 >= 0) { // normalne pobocze, na razie się składa z - return SwitchExtension->iPoints * ((TextureID1 ? 1 : 0) + (TextureID2 ? 12 : 0)); + return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 12 : 0 ) ); } else { // jeśli fTexHeight1<0, to są chodniki i może któregoś nie być - return SwitchExtension->iPoints * ((TextureID1 ? 1 : 0) + (TextureID2 ? 6 : 0 )); + return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 6 : 0 ) ); } +*/ + // each sub-segment covers only one side of the road, so it has points for single sideroad, if any + return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 6 : 0 ) ); } else // standardowo dla zwykłej drogi if (fTexHeight1 >= 0) // jeśli fTexHeight1<0, to są chodniki i może któregoś nie być - return (Segment->RaSegCount()) * + return ( Segment->RaSegCount()) * ((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0)); // może nie być poziomego! else return (Segment->RaSegCount()) * @@ -1818,9 +1823,8 @@ int TTrack::RaArrayPrepare() return 0; }; -int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount) +void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount) { // wypełnianie tablic VBO - int debugvertexcount{ 0 }; // Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur double fHTW = 0.5 * fabs(fTrackWidth); double side = fabs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza @@ -1955,19 +1959,16 @@ int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos } } - debugvertexcount += Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -4 : 4, fTexLength); - assert( debugvertexcount <= Vertexcount ); + Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -4 : 4, fTexLength); } if (TextureID1) { // szyny - generujemy dwie, najwyżej rysować się będzie jedną - debugvertexcount += Segment->RenderLoft(Vert, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += Segment->RenderLoft(Vert, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); - assert( debugvertexcount <= Vertexcount ); + Segment->RenderLoft(Vert, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RenderLoft(Vert, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); } break; case tt_Switch: // dla zwrotnicy dwa razy szyny - if (TextureID1) // Ra: !!!! tu jest do poprawienia + if( TextureID1 || TextureID2 ) { // iglice liczone tylko dla zwrotnic vector6 rpts3[24], rpts4[24]; for (i = 0; i < 12; ++i) @@ -1987,46 +1988,34 @@ int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const } if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa - int batch{ 0 }; - batch = SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength); - debugvertexcount += batch; - assert( debugvertexcount <= Vertexcount ); - batch = SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2 ); - debugvertexcount += batch; - assert( debugvertexcount <= Vertexcount ); - SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - batch = SwitchExtension->Segments[0]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); - debugvertexcount += batch; - assert( debugvertexcount <= Vertexcount ); + if( TextureID1 ) { + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, nnumPts, fTexLength ); + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2 ); - SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - batch = SwitchExtension->Segments[1]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); - debugvertexcount += batch; - assert( debugvertexcount <= Vertexcount ); - batch = SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); - debugvertexcount += batch; - assert( debugvertexcount <= Vertexcount ); - batch = SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength ); - debugvertexcount += batch; - assert( debugvertexcount <= Vertexcount ); + SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); + } + if( TextureID2 ) { + SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts1, nnumPts, fTexLength ); + } } else { // lewa działa lepiej niż prawa - debugvertexcount += SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength); // lewa szyna normalna cała - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą - assert( debugvertexcount <= Vertexcount ); - SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - debugvertexcount += SwitchExtension->Segments[0]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2); // prawa iglica - assert( debugvertexcount <= Vertexcount ); - - SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - debugvertexcount += SwitchExtension->Segments[1]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1); // lewa iglica - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength); // prawa szyna normalnie cała - assert( debugvertexcount <= Vertexcount ); + if( TextureID1 ) { + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą + SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // prawa iglica + } + if( TextureID2 ) { + SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // lewa iglica + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała + } } } break; @@ -2060,8 +2049,7 @@ int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const } if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy - debugvertexcount += Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); - assert( debugvertexcount <= Vertexcount ); + Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); } if (TextureID2) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) @@ -2142,25 +2130,21 @@ int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony // odcinka if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { - debugvertexcount += Segment->RenderLoft( Vert, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej - assert( debugvertexcount <= Vertexcount ); + Segment->RenderLoft( Vert, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej } if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - debugvertexcount += Segment->RenderLoft( Vert, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej - assert( debugvertexcount <= Vertexcount ); + Segment->RenderLoft( Vert, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej } } else { // pobocza zwykłe, brak przechyłki if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { - debugvertexcount += Segment->RenderLoft( Vert, rpts1, 3, fTexLength ); - assert( debugvertexcount <= Vertexcount ); + Segment->RenderLoft( Vert, rpts1, 3, fTexLength ); } if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - debugvertexcount += Segment->RenderLoft( Vert, rpts2, 3, fTexLength ); - assert( debugvertexcount <= Vertexcount ); - } + Segment->RenderLoft( Vert, rpts2, 3, fTexLength ); } } + } break; } case tt_Cross: // skrzyżowanie dróg rysujemy inaczej @@ -2191,24 +2175,9 @@ int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const int i; // ile punktów (może byc różna ilość punktów między drogami) if (!SwitchExtension->vPoints) { // jeśli tablica punktów nie jest jeszcze utworzona, zliczamy punkty i tworzymy ją - if( SwitchExtension->iRoads == 3 ) { - // mogą być tylko 3 drogi zamiast 4 - SwitchExtension->iPoints = - 5 - + SwitchExtension->Segments[ 0 ]->RaSegCount() - + SwitchExtension->Segments[ 1 ]->RaSegCount() - + SwitchExtension->Segments[ 2 ]->RaSegCount(); - } - else { - SwitchExtension->iPoints = - 5 - + SwitchExtension->Segments[ 2 ]->RaSegCount() - + SwitchExtension->Segments[ 3 ]->RaSegCount() - + SwitchExtension->Segments[ 4 ]->RaSegCount() - + SwitchExtension->Segments[ 5 ]->RaSegCount(); - } - // tablica utworzona z zapasem, ale nie wypełniona współrzędnymi - SwitchExtension->vPoints = new vector3[SwitchExtension->iPoints]; + // points were already counted during preparation stage + // we'll need to add couple extra points for the complete fan we'll build + SwitchExtension->vPoints = new vector3[SwitchExtension->iPoints + SwitchExtension->iRoads]; } vector3 *b = SwitchExtension->bPoints ? @@ -2297,46 +2266,32 @@ int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const if (SwitchExtension->iRoads == 4) { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - debugvertexcount += SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - assert( debugvertexcount <= Vertexcount ); + SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); } } else { // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - debugvertexcount += SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P2 do P4 - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P4 do P3=P1 (odwrócony) - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P1 do P2 - assert( debugvertexcount <= Vertexcount ); + SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P2 do P4 + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P4 do P3=P1 (odwrócony) + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P1 do P2 } } } // renderowanie nawierzchni na końcu double sina0 = sin(a[0]), cosa0 = cos(a[0]); double u, v; - if (!SwitchExtension->bPoints) // jeśli tablica nie wypełniona - if (b) // ale jest wskaźnik do tablicy - może nie być? - { // coś się gubi w obliczeniach na wskaźnikach - // ustalenie liczby punktów, bo mogło wyjść inaczej niż policzone z góry - i = (int)(((size_t)(b)) - ((size_t)(SwitchExtension->vPoints))) / sizeof(vector3); - if (i > 0) - { // jeśli zostało to właśnie utworzone - SwitchExtension->iPoints = std::min( SwitchExtension->iPoints - 2, i ); - SwitchExtension->vPoints[SwitchExtension->iPoints++] = SwitchExtension->vPoints[0]; - ++SwitchExtension->iPoints; // we'll add one extra point in the middle - SwitchExtension->bPoints = true; // tablica punktów została wypełniona - } - } + if( ( false == SwitchExtension->bPoints ) // jeśli tablica nie wypełniona + && ( b != nullptr ) ) { + SwitchExtension->bPoints = true; // tablica punktów została wypełniona + } + if (TextureID1) { - // jeśli podana tekstura nawierzchni + // jeśli podana tekstura nawierzchni + // we start with a vertex in the middle... Vert->nx = 0.0; Vert->ny = 1.0; Vert->nz = 0.0; @@ -2346,8 +2301,21 @@ int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vert->y = oxz.y; Vert->z = oxz.z; ++Vert; - ++debugvertexcount; - for (i = SwitchExtension->iPoints - 2; i >= 0; --i) + // ...and add one extra vertex to close the fan... + Vert->nx = 0.0; + Vert->ny = 1.0; + Vert->nz = 0.0; + // mapowanie we współrzędnych scenerii + u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x ) / fTexLength; + v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z ) / ( fTexRatio1 * fTexLength ); + Vert->u = cosa0 * u + sina0 * v + 0.5; + Vert->v = -sina0 * u + cosa0 * v + 0.5; + Vert->x = SwitchExtension->vPoints[ 0 ].x; + Vert->y = SwitchExtension->vPoints[ 0 ].y; + Vert->z = SwitchExtension->vPoints[ 0 ].z; + ++Vert; + // ...then draw the precalculated rest + for (i = SwitchExtension->iPoints + SwitchExtension->iRoads - 1; i >= 0; --i) { Vert->nx = 0.0; Vert->ny = 1.0; @@ -2361,13 +2329,11 @@ int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vert->y = SwitchExtension->vPoints[ i ].y; Vert->z = SwitchExtension->vPoints[ i ].z; ++Vert; - ++debugvertexcount; } - assert( debugvertexcount <= Vertexcount ); } break; - } - } + } // tt_cross + } // road break; case 4: // Ra: rzeki na razie jak drogi, przechyłki na pewno nie mają switch (eType) // dalej zależnie od typu @@ -2402,8 +2368,7 @@ int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const } if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy - debugvertexcount += Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); - assert( debugvertexcount <= Vertexcount ); + Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); } if (TextureID2) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w @@ -2425,24 +2390,20 @@ int TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza - debugvertexcount += Segment->RenderLoft(Vert, rpts1, -3, fTexLength); - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += Segment->RenderLoft(Vert, rpts2, -3, fTexLength); - assert( debugvertexcount <= Vertexcount ); + Segment->RenderLoft(Vert, rpts1, -3, fTexLength); + Segment->RenderLoft(Vert, rpts2, -3, fTexLength); } else { // pobocza zwykłe, brak przechyłki - debugvertexcount += Segment->RenderLoft(Vert, rpts1, 3, fTexLength); - assert( debugvertexcount <= Vertexcount ); - debugvertexcount += Segment->RenderLoft(Vert, rpts2, 3, fTexLength); - assert( debugvertexcount <= Vertexcount ); + Segment->RenderLoft(Vert, rpts1, 3, fTexLength); + Segment->RenderLoft(Vert, rpts2, 3, fTexLength); } } } } break; } - return debugvertexcount; + return; }; void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO @@ -2456,12 +2417,12 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO if( eType == tt_Switch ) // dla zwrotnicy tylko szyny { int const bladesegmentcount = 2; - if( TextureID1 ) + if( TextureID1 ) { if( ( seg = SwitchExtension->Segments[ 0 ]->RaSegCount() ) > 0 ) { GfxRenderer.Bind( TextureID1 ); // szyny + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); iPtr += 24 * seg; - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * (seg - bladesegmentcount) ); + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * ( seg - bladesegmentcount ) ); // NOTE: due to way blades bend need to render each segment separately, or some unwanted edges may show iPtr += 24 * ( seg - bladesegmentcount ); for( int i = 0; i < bladesegmentcount; ++i ) { @@ -2469,7 +2430,8 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO iPtr += 24; } } - if( TextureID2 ) + } + if( TextureID2 ) { if( ( seg = SwitchExtension->Segments[ 1 ]->RaSegCount() ) > 0 ) { GfxRenderer.Bind( TextureID2 ); // NOTE: due to way blades bend need to render each segment separately, or some unwanted edges may show @@ -2482,6 +2444,7 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); iPtr += 24 * seg; } + } } else // dla toru podsypka plus szyny { @@ -2564,7 +2527,7 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO if( TextureID1 ) { // roads GfxRenderer.Bind( TextureID1 ); - ::glDrawArrays( GL_TRIANGLE_FAN, iPtr, SwitchExtension->iPoints ); + ::glDrawArrays( GL_TRIANGLE_FAN, iPtr, SwitchExtension->iPoints + SwitchExtension->iRoads + 2 ); iPtr += SwitchExtension->iPoints; } } @@ -2921,19 +2884,21 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer) // fetch current blade geometry std::vector bladesbuffer; bladesbuffer.resize( 2 * 2 * 24 ); // 2 blades, 2 segments each +/* ::glGetBufferSubData( GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof( CVertNormTex ), bladesbuffer.size() * sizeof( CVertNormTex ), bladesbuffer.data() ); +*/ auto bladevertices = bladesbuffer.data(); if( SwitchExtension->RightSwitch ) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa - SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2, true ); - SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1, true ); + SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 /*, true*/ ); + SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 /*, true*/ ); } else { - SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2, true ); // prawa iglica - SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1, true ); // lewa iglica + SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 /*, true*/ ); // prawa iglica + SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 /*, true*/ ); // lewa iglica } // push back updated geometry ::glBufferSubData( @@ -2987,8 +2952,7 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer) int size = RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy CVertNormTex *Vert = new CVertNormTex[size]; // bufor roboczy // CVertNormTex *v=Vert; //zmieniane przez - auto const debugvertexcount = RaArrayFill(Vert, Vert - SwitchExtension->iLeftVBO, size); // iLeftVBO powinno zostać niezmienione - assert( debugvertexcount == size ); + RaArrayFill(Vert, Vert - SwitchExtension->iLeftVBO, size); // iLeftVBO powinno zostać niezmienione ::glBufferSubData( GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex), size * sizeof(CVertNormTex), Vert); // wysłanie fragmentu bufora VBO diff --git a/Track.h b/Track.h index 8cab1b1d..be0f16c2 100644 --- a/Track.h +++ b/Track.h @@ -240,7 +240,7 @@ class TTrack : public Resource void Render(); // renderowanie z Display Lists int RaArrayPrepare(); // zliczanie rozmiaru dla VBO sektroa - int RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount); // wypełnianie VBO + void RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount); // wypełnianie VBO void RaRenderVBO(int iPtr); // renderowanie z VBO sektora void RenderDyn(); // renderowanie nieprzezroczystych pojazdów (oba tryby) void RenderDynAlpha(); // renderowanie przezroczystych pojazdów (oba tryby) diff --git a/Train.cpp b/Train.cpp index 15d79f6c..75bd2f53 100644 --- a/Train.cpp +++ b/Train.cpp @@ -175,8 +175,10 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::pantographlowerall, &TTrain::OnCommand_pantographlowerall }, { user_command::linebreakertoggle, &TTrain::OnCommand_linebreakertoggle }, { user_command::convertertoggle, &TTrain::OnCommand_convertertoggle }, + { user_command::convertertogglelocal, &TTrain::OnCommand_convertertogglelocal }, { user_command::converteroverloadrelayreset, &TTrain::OnCommand_converteroverloadrelayreset }, { user_command::compressortoggle, &TTrain::OnCommand_compressortoggle }, + { user_command::compressortogglelocal, &TTrain::OnCommand_compressortogglelocal }, { user_command::motorconnectorsopen, &TTrain::OnCommand_motorconnectorsopen }, { user_command::motordisconnect, &TTrain::OnCommand_motordisconnect }, { user_command::motoroverloadrelaythresholdtoggle, &TTrain::OnCommand_motoroverloadrelaythresholdtoggle }, @@ -1727,6 +1729,69 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma } } +void TTrain::OnCommand_convertertogglelocal( TTrain *Train, command_data const &Command ) { + + if( Train->mvOccupied->ConverterStart == start::automatic ) { + // let the automatic thing do its automatic thing... + return; + } + if( Train->ggConverterLocalButton.SubModel == nullptr ) { + return; + } + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( ( false == Train->mvOccupied->ConverterAllowLocal ) + && ( Train->ggConverterLocalButton.GetValue() < 0.5 ) ) { + // turn on + // sound feedback + if( Train->ggConverterLocalButton.GetValue() < 0.5 ) { + Train->play_sound( Train->dsbSwitch ); + } + // visual feedback + Train->ggConverterLocalButton.UpdateValue( 1.0 ); + // effect + Train->mvOccupied->ConverterAllowLocal = true; +/* + if( true == Train->mvControlled->ConverterSwitch( true, range::local ) ) { + // side effects + // control the compressor, if it's paired with the converter + if( Train->mvControlled->CompressorPower == 2 ) { + // hunter-091012: tak jest poprawnie + Train->mvControlled->CompressorSwitch( true, range::local ); + } + } +*/ + } + else { + //turn off + // sound feedback + if( Train->ggConverterLocalButton.GetValue() > 0.5 ) { + Train->play_sound( Train->dsbSwitch ); + } + // visual feedback + Train->ggConverterLocalButton.UpdateValue( 0.0 ); + // effect + Train->mvOccupied->ConverterAllowLocal = false; +/* + if( true == Train->mvControlled->ConverterSwitch( false, range::local ) ) { + // side effects + // control the compressor, if it's paired with the converter + if( Train->mvControlled->CompressorPower == 2 ) { + // hunter-091012: tak jest poprawnie + Train->mvControlled->CompressorSwitch( false, range::local ); + } + // if there's no (low voltage) power source left, drop pantographs + if( false == Train->mvControlled->Battery ) { + Train->mvControlled->PantFront( false, range::local ); + Train->mvControlled->PantRear( false, range::local ); + } + } +*/ + } + } +} + void TTrain::OnCommand_converteroverloadrelayreset( TTrain *Train, command_data const &Command ) { if( Train->ggConverterFuseButton.SubModel == nullptr ) { @@ -1824,6 +1889,42 @@ void TTrain::OnCommand_compressortoggle( TTrain *Train, command_data const &Comm */ } +void TTrain::OnCommand_compressortogglelocal( TTrain *Train, command_data const &Command ) { + + if( Train->mvOccupied->CompressorPower >= 2 ) { + return; + } + if( Train->ggCompressorLocalButton.SubModel == nullptr ) { + return; + } + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( false == Train->mvOccupied->CompressorAllowLocal ) { + // turn on + // sound feedback + if( Train->ggCompressorLocalButton.GetValue() < 0.5 ) { + Train->play_sound( Train->dsbSwitch ); + } + // visual feedback + Train->ggCompressorLocalButton.UpdateValue( 1.0 ); + // effect + Train->mvOccupied->CompressorAllowLocal = true; + } + else { + //turn off + // sound feedback + if( Train->ggCompressorLocalButton.GetValue() > 0.5 ) { + Train->play_sound( Train->dsbSwitch ); + } + // visual feedback + Train->ggCompressorLocalButton.UpdateValue( 0.0 ); + // effect + Train->mvOccupied->CompressorAllowLocal = false; + } + } +} + void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &Command ) { // TODO: don't rely on presense of 3d model to determine presence of the switch @@ -1833,31 +1934,111 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C } return; } - - if( Command.action != GLFW_RELEASE ) { - // button works while it's held down - if( true == Train->mvControlled->StLinFlag ) { + // NOTE: because we don't have modeled actual circuits this is a simplification of the real mechanics + // namely, pressing the button will flip it in the entire unit, which isn't exactly physically possible + if( Command.action == GLFW_PRESS ) { + // button works while it's held down but we can only pay attention to initial press + if( false == Train->mvControlled->StLinSwitchOff ) { + // open the connectors + Train->mvControlled->StLinSwitchOff = true; + if( ( Train->mvControlled->TrainType == dt_ET41 ) + || ( Train->mvControlled->TrainType == dt_ET42 ) ) { + // crude implementation of the butto affecting entire unit for multi-unit engines + // TODO: rework it into part of standard command propagation system + if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr ) + && ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + Train->mvControlled->Couplers[ 0 ].Connected->StLinSwitchOff = true; + } + if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr ) + && ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = true; + } + } + // sound feedback + if( Train->ggStLinOffButton.GetValue() < 0.5 ) { + Train->play_sound( Train->dsbSwitch ); + } + // visual feedback + Train->ggStLinOffButton.UpdateValue( 1.0 ); + // effect + if( true == Train->mvControlled->StLinFlag ) { + Train->play_sound( Train->dsbRelay ); + } // yBARC - zmienione na przeciwne, bo true to zalaczone Train->mvControlled->StLinFlag = false; - Train->play_sound( Train->dsbRelay ); + if( ( Train->mvControlled->TrainType == dt_ET41 ) + || ( Train->mvControlled->TrainType == dt_ET42 ) ) { + // crude implementation of the butto affecting entire unit for multi-unit engines + // TODO: rework it into part of standard command propagation system + if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr ) + && ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + Train->mvControlled->Couplers[ 0 ].Connected->StLinFlag = false; + } + if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr ) + && ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + Train->mvControlled->Couplers[ 1 ].Connected->StLinFlag = false; + } + } } - Train->mvControlled->StLinSwitchOff = true; - // sound feedback - if( Train->ggStLinOffButton.GetValue() < 0.05 ) { - Train->play_sound( Train->dsbSwitch ); + else { + if( Train->mvControlled->StLinSwitchType == "toggle" ) { + // default type of button (impulse) has only one effect on press, but the toggle type can toggle the state + Train->mvControlled->StLinSwitchOff = false; + if( ( Train->mvControlled->TrainType == dt_ET41 ) + || ( Train->mvControlled->TrainType == dt_ET42 ) ) { + // crude implementation of the butto affecting entire unit for multi-unit engines + // TODO: rework it into part of standard command propagation system + if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr ) + && ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + Train->mvControlled->Couplers[ 0 ].Connected->StLinSwitchOff = false; + } + if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr ) + && ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = false; + } + } + // sound feedback + if( Train->ggStLinOffButton.GetValue() > 0.5 ) { + Train->play_sound( Train->dsbSwitch ); + } + // visual feedback + Train->ggStLinOffButton.UpdateValue( 0.0 ); + } } - // visual feedback - Train->ggStLinOffButton.UpdateValue( 1.0 ); } - else { + else if( Command.action == GLFW_RELEASE ) { // button released - Train->mvControlled->StLinSwitchOff = false; - // sound feedback - if( Train->ggStLinOffButton.GetValue() > 0.5 ) { - Train->play_sound( Train->dsbSwitch ); + if( Train->mvControlled->StLinSwitchType != "toggle" ) { + // default button type (impulse) works on button release + Train->mvControlled->StLinSwitchOff = false; + if( ( Train->mvControlled->TrainType == dt_ET41 ) + || ( Train->mvControlled->TrainType == dt_ET42 ) ) { + // crude implementation of the butto affecting entire unit for multi-unit engines + // TODO: rework it into part of standard command propagation system + if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr ) + && ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + Train->mvControlled->Couplers[ 0 ].Connected->StLinSwitchOff = false; + } + if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr ) + && ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = false; + } + } + // sound feedback + if( Train->ggStLinOffButton.GetValue() > 0.5 ) { + Train->play_sound( Train->dsbSwitch ); + } + // visual feedback + Train->ggStLinOffButton.UpdateValue( 0.0 ); } - // visual feedback - Train->ggStLinOffButton.UpdateValue( 0.0 ); } } @@ -4674,9 +4855,11 @@ bool TTrain::Update( double const Deltatime ) ggDepartureSignalButton.Update(); // NBMX dzwignia sprezarki ggCompressorButton.Update(); + ggCompressorLocalButton.Update(); ggMainButton.Update(); ggRadioButton.Update(); ggConverterButton.Update(); + ggConverterLocalButton.Update(); ggConverterOffButton.Update(); #ifdef EU07_USE_OLD_COMMAND_SYSTEM @@ -6604,6 +6787,11 @@ void TTrain::set_cab_controls() { if( true == mvOccupied->Battery ) { ggBatteryButton.PutValue( 1.0 ); } + // motor connectors + ggStLinOffButton.PutValue( + ( mvControlled->StLinSwitchOff ? + 1.0 : + 0.0 ) ); // radio if( true == mvOccupied->Radio ) { ggRadioButton.PutValue( 1.0 ); @@ -6636,10 +6824,19 @@ void TTrain::set_cab_controls() { 1.0 : 0.0 ); } + ggConverterLocalButton.PutValue( + mvControlled->ConverterAllowLocal ? + 1.0 : + 0.0 ); // compressor - if( true == mvControlled->CompressorAllow ) { - ggCompressorButton.PutValue( 1.0 ); - } + ggCompressorButton.PutValue( + mvControlled->CompressorAllow ? + 1.0 : + 0.0 ); + ggCompressorLocalButton.PutValue( + mvControlled->CompressorAllowLocal ? + 1.0 : + 0.0 ); // motor overload relay threshold / shunt mode if( mvControlled->Imax == mvControlled->ImaxHi ) { ggMaxCurrentCtrl.PutValue( 1.0 ); @@ -7175,11 +7372,19 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con // sprezarka ggCompressorButton.Load(Parser, DynamicObject->mdKabina); } + else if( Label == "compressorlocal_sw:" ) { + // sprezarka + ggCompressorLocalButton.Load( Parser, DynamicObject->mdKabina ); + } else if (Label == "converter_sw:") { // przetwornica ggConverterButton.Load(Parser, DynamicObject->mdKabina); } + else if( Label == "converterlocal_sw:" ) { + // przetwornica + ggConverterLocalButton.Load( Parser, DynamicObject->mdKabina ); + } else if (Label == "converteroff_sw:") { // przetwornica wyl diff --git a/Train.h b/Train.h index 31482dba..aab20177 100644 --- a/Train.h +++ b/Train.h @@ -146,8 +146,10 @@ class TTrain static void OnCommand_pantographlowerall( TTrain *Train, command_data const &Command ); static void OnCommand_linebreakertoggle( TTrain *Train, command_data const &Command ); static void OnCommand_convertertoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_convertertogglelocal( TTrain *Train, command_data const &Command ); static void OnCommand_converteroverloadrelayreset( TTrain *Train, command_data const &Command ); static void OnCommand_compressortoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_compressortogglelocal( TTrain *Train, command_data const &Command ); static void OnCommand_motorconnectorsopen( TTrain *Train, command_data const &Command ); static void OnCommand_motordisconnect( TTrain *Train, command_data const &Command ); static void OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command_data const &Command ); @@ -251,7 +253,9 @@ public: // reszta może by?publiczna TGauge ggIgnitionKey; TGauge ggCompressorButton; + TGauge ggCompressorLocalButton; // controls only compressor of its own unit (et42-specific) TGauge ggConverterButton; + TGauge ggConverterLocalButton; // controls only converter of its own unit (et42-specific) TGauge ggConverterOffButton; // ABu 090305 - syrena i prad nastepnego czlonu diff --git a/World.cpp b/World.cpp index 1a0cf45e..dbafc975 100644 --- a/World.cpp +++ b/World.cpp @@ -1863,9 +1863,9 @@ TWorld::Update_UI() { uitextline3 += ( tmp->MoverParameters->PantRearUp ? ( tmp->MoverParameters->PantRearVolt > 0.0 ? "O" : "o" ) : "." );; uitextline3 += ( tmp->MoverParameters->PantFrontUp ? ( tmp->MoverParameters->PantFrontVolt > 0.0 ? "P" : "p" ) : "." );; uitextline3 += ( tmp->MoverParameters->PantPressLockActive ? "!" : ( tmp->MoverParameters->PantPressSwitchActive ? "*" : "." ) ); - uitextline3 += ( tmp->MoverParameters->ConverterAllow ? ( tmp->MoverParameters->ConverterFlag ? "X" : "x" ) : "." ); + uitextline3 += ( false == tmp->MoverParameters->ConverterAllowLocal ? "-" : ( tmp->MoverParameters->ConverterAllow ? ( tmp->MoverParameters->ConverterFlag ? "X" : "x" ) : "." ) ); uitextline3 += ( tmp->MoverParameters->ConvOvldFlag ? "!" : "." ); - uitextline3 += ( tmp->MoverParameters->CompressorAllow ? ( tmp->MoverParameters->CompressorFlag ? "C" : "c" ) : "." ); + uitextline3 += ( false == tmp->MoverParameters->CompressorAllowLocal ? "-" : ( tmp->MoverParameters->CompressorAllow ? ( tmp->MoverParameters->CompressorFlag ? "C" : "c" ) : "." ) ); uitextline3 += ( tmp->MoverParameters->CompressorGovernorLock ? "!" : "." ); uitextline3 += diff --git a/command.cpp b/command.cpp index 4ad7c4e0..426e1873 100644 --- a/command.cpp +++ b/command.cpp @@ -47,8 +47,10 @@ commanddescription_sequence Commands_descriptions = { { "reverserdecrease", command_target::vehicle }, { "linebreakertoggle", command_target::vehicle }, { "convertertoggle", command_target::vehicle }, + { "convertertogglelocal", command_target::vehicle }, { "converteroverloadrelayreset", command_target::vehicle }, { "compressortoggle", command_target::vehicle }, + { "compressortogglelocal", command_target::vehicle }, { "motoroverloadrelaythresholdtoggle", command_target::vehicle }, { "motoroverloadrelayreset", command_target::vehicle }, { "notchingrelaytoggle", command_target::vehicle }, diff --git a/command.h b/command.h index 9ba1d725..35649d9e 100644 --- a/command.h +++ b/command.h @@ -42,8 +42,10 @@ enum class user_command { reverserdecrease, linebreakertoggle, convertertoggle, + convertertogglelocal, converteroverloadrelayreset, compressortoggle, + compressortogglelocal, motoroverloadrelaythresholdtoggle, motoroverloadrelayreset, notchingrelaytoggle, diff --git a/keyboardinput.cpp b/keyboardinput.cpp index 2c32b9e4..79267cc3 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -228,10 +228,14 @@ keyboard_input::default_bindings() { { GLFW_KEY_M }, // convertertoggle { GLFW_KEY_X }, + // convertertogglelocal + { GLFW_KEY_X | keymodifier::shift }, // converteroverloadrelayreset { GLFW_KEY_N | keymodifier::control }, // compressortoggle { GLFW_KEY_C }, + // compressortoggleloal + { GLFW_KEY_C | keymodifier::shift }, // motoroverloadrelaythresholdtoggle { GLFW_KEY_F }, // motoroverloadrelayreset diff --git a/keyboardinput.h b/keyboardinput.h index e2d78708..65a4546c 100644 --- a/keyboardinput.h +++ b/keyboardinput.h @@ -70,7 +70,7 @@ private: bool m_shift{ false }; bool m_ctrl{ false }; bindings_cache m_bindingscache; - std::array m_keys; + std::array m_keys; }; //--------------------------------------------------------------------------- diff --git a/version.h b/version.h index 5102dd54..d30e7043 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 520 +#define VERSION_MINOR 522 #define VERSION_REVISION 0 From 03e231fbc16ae6c38ff15a3aa9e504f357953763 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 23 May 2017 23:57:29 +0200 Subject: [PATCH 05/12] build 170524. re-enabled support for -e3d command line option --- EU07.cpp | 34 +++++--- Track.cpp | 2 +- World.cpp | 196 +++++++++++++++++++++++-------------------- maszyna.vcxproj.user | 2 + version.h | 2 +- wavread.cpp | 4 +- wavread.h | 2 +- 7 files changed, 138 insertions(+), 104 deletions(-) diff --git a/EU07.cpp b/EU07.cpp index 90a57219..c73d9218 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -383,9 +383,15 @@ int main(int argc, char *argv[]) input::Gamepad.init(); Global::pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów - if (!World.Init(window)) - { - ErrorLog( "Failed to init TWorld" ); + try { + if( false == World.Init( window ) ) { + ErrorLog( "Failed to init TWorld" ); + return -1; + } + } + catch( std::bad_alloc const &Error ) { + + ErrorLog( "Critical error, memory allocation failure: " + std::string( Error.what() ) ); return -1; } @@ -406,15 +412,23 @@ int main(int argc, char *argv[]) } // po zrobieniu E3D odpalamy normalnie scenerię, by ją zobaczyć Console::On(); // włączenie konsoli - while (!glfwWindowShouldClose(window) - && World.Update() - && GfxRenderer.Render()) - { - glfwPollEvents(); - if( true == Global::InputGamepad ) { - input::Gamepad.poll(); + + try { + while( ( false == glfwWindowShouldClose( window ) ) + && ( true == World.Update() ) + && ( true == GfxRenderer.Render() ) ) { + glfwPollEvents(); + if( true == Global::InputGamepad ) { + input::Gamepad.poll(); + } } } + catch( std::bad_alloc const &Error ) { + + ErrorLog( "Critical error, memory allocation failure: " + std::string( Error.what() ) ); + return -1; + } + Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej) } diff --git a/Track.cpp b/Track.cpp index dd3d6a3b..c8672c80 100644 --- a/Track.cpp +++ b/Track.cpp @@ -198,7 +198,7 @@ TTrack * TTrack::Create400m(int what, double dx) trk->bVisible = false; // nie potrzeba pokazywać, zresztą i tak nie ma tekstur trk->iCategoryFlag = what; // taki sam typ plus informacja, że dodatkowy trk->Init(); // utworzenie segmentu - trk->Segment->Init(vector3(-dx, 0, 0), vector3(-dx, 0, 400), 0, 0, 0); // prosty + trk->Segment->Init(vector3(-dx, 0, 0), vector3(-dx, 0, 400), 10.0, 0, 0); // prosty tmp->pCenter = vector3(-dx, 0, 200); //środek, aby się mogło wyświetlić TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z); r->NodeAdd(tmp); // dodanie toru do segmentu diff --git a/World.cpp b/World.cpp index dbafc975..0bcfe03c 100644 --- a/World.cpp +++ b/World.cpp @@ -2384,103 +2384,119 @@ void TWorld::ModifyTGA(const std::string &dir) } */ }; + //--------------------------------------------------------------------------- -std::string last; // zmienne używane w rekurencji -double shift = 0; -void TWorld::CreateE3D(std::string const &dir, bool dyn) + +void TWorld::CreateE3D(std::string const &Path, bool Dynamic) { // rekurencyjna generowanie plików E3D -/* TODO: remove Borland file access stuff - TTrack *trk; - double at; - TSearchRec sr; - if (FindFirst(dir + "*.*", faDirectory | faArchive, sr) == 0) - { - do - { - if (sr.Name[1] != '.') - if ((sr.Attr & faDirectory)) // jeśli katalog, to rekurencja - CreateE3D(dir + sr.Name + "\\", dyn); - else if (dyn) - { - if (sr.Name.LowerCase().SubString(sr.Name.Length() - 3, 4) == ".mmd") - { - // konwersja pojazdów będzie ułomna, bo nie poustawiają się animacje na - // submodelach określonych w MMD - // TModelsManager::GetModel(AnsiString(dir+sr.Name).c_str(),true); - if (last != dir) - { // utworzenie toru dla danego pojazdu - last = dir; - trk = TTrack::Create400m(1, shift); - shift += 10.0; // następny tor będzie deczko dalej, aby nie zabić FPS - at = 400.0; - // if (shift>1000) break; //bezpiecznik + std::string last; // zmienne używane w rekurencji + TTrack *trk{ nullptr }; + double at{ 0.0 }; + double shift{ 0.0 }; + +#ifdef _WINDOWS + + std::string searchpattern( "*.*" ); + + ::WIN32_FIND_DATA filedata; + ::HANDLE search = ::FindFirstFile( ( Path + searchpattern ).c_str(), &filedata ); + + if( search == INVALID_HANDLE_VALUE ) { return; } // if nothing to do, bail out + + do { + + std::string filename = filedata.cFileName; + + if( filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { + // launch recursive search for sub-directories... + if( filename == "." ) { continue; } + if( filename == ".." ) { continue; } + CreateE3D( Path + filename + "\\", Dynamic ); + } + else { + // process the file + if( filename.size() < 4 ) { continue; } + std::string const filetype = ToLower( filename.substr( filename.size() - 4, 4 ) ); + if( filetype == ".mmd" ) { + if( false == Dynamic ) { continue; } + + // konwersja pojazdów będzie ułomna, bo nie poustawiają się animacje na submodelach określonych w MMD + if( last != Path ) { // utworzenie toru dla danego pojazdu + last = Path; + trk = TTrack::Create400m( 1, shift ); + shift += 10.0; // następny tor będzie deczko dalej, aby nie zabić FPS + at = 400.0; + } + TGroundNode *tmp = new TGroundNode(); + tmp->DynamicObject = new TDynamicObject(); + + at -= tmp->DynamicObject->Init( + "", + Path.substr( 8, Path.size() - 9 ), // skip leading "dynamic/" and trailing slash + "none", + filename.substr( 0, filename.size() - 4 ), + trk, + at, + "nobody", 0.0, "none", 0.0, "", false, "" ); + + // po wczytaniu CHK zrobić pętlę po ładunkach, aby każdy z nich skonwertować + cParser loadparser( tmp->DynamicObject->MoverParameters->LoadAccepted ); // typy ładunków + std::string loadname; + loadparser.getTokens( 1, true, "," ); loadparser >> loadname; + while( loadname != "" ) { + + if( ( true == FileExists( Path + loadname + ".t3d" ) ) + && ( false == FileExists( Path + loadname + ".e3d" ) ) ) { + // a nie ma jeszcze odpowiednika binarnego + at -= tmp->DynamicObject->Init( + "", + Path.substr( 8, Path.size() - 9 ), // skip leading "dynamic/" and trailing slash + "none", + filename.substr( 0, filename.size() - 4 ), + trk, + at, + "nobody", 0.0, "none", 1.0, loadname, false, "" ); } - TGroundNode *tmp = new TGroundNode(); - tmp->DynamicObject = new TDynamicObject(); - // Global::asCurrentTexturePath=dir; //pojazdy mają tekstury we własnych - // katalogach - at -= tmp->DynamicObject->Init( - "", string((dir.SubString(9, dir.Length() - 9)).c_str()), "none", - string(sr.Name.SubString(1, sr.Name.Length() - 4).c_str()), trk, at, "nobody", 0.0, - "none", 0.0, "", false, ""); - // po wczytaniu CHK zrobić pętlę po ładunkach, aby każdy z nich skonwertować - AnsiString loads, load; - loads = AnsiString(tmp->DynamicObject->MoverParameters->LoadAccepted.c_str()); // typy ładunków - if (!loads.IsEmpty()) - { - loads += ","; // przecinek na końcu - int i = loads.Pos(","); - while (i > 1) - { // wypadało by sprawdzić, czy T3D ładunku jest - load = loads.SubString(1, i - 1); - if (FileExists(dir + load + ".t3d")) // o ile jest plik ładunku, bo - // inaczej nie ma to sensu - if (!FileExists( - dir + load + - ".e3d")) // a nie ma jeszcze odpowiednika binarnego - at -= tmp->DynamicObject->Init( - "", dir.SubString(9, dir.Length() - 9).c_str(), "none", - sr.Name.SubString(1, sr.Name.Length() - 4).c_str(), trk, at, - "nobody", 0.0, "none", 1.0, load.c_str(), false, ""); - loads.Delete(1, i); // usunięcie z następującym przecinkiem - i = loads.Pos(","); - } - } - if (tmp->DynamicObject->iCabs) - { // jeśli ma jakąkolwiek kabinę - delete Train; - Train = new TTrain(); - if (tmp->DynamicObject->iCabs & 1) - { - tmp->DynamicObject->MoverParameters->ActiveCab = 1; - Train->Init(tmp->DynamicObject, true); - } - if (tmp->DynamicObject->iCabs & 4) - { - tmp->DynamicObject->MoverParameters->ActiveCab = -1; - Train->Init(tmp->DynamicObject, true); - } - if (tmp->DynamicObject->iCabs & 2) - { - tmp->DynamicObject->MoverParameters->ActiveCab = 0; - Train->Init(tmp->DynamicObject, true); - } - } - Global::asCurrentTexturePath = - (szTexturePath); // z powrotem defaultowa sciezka do tekstur + + loadname = ""; + loadparser.getTokens( 1, true, "," ); loadparser >> loadname; + } + + if( tmp->DynamicObject->iCabs ) { // jeśli ma jakąkolwiek kabinę + delete Train; + Train = new TTrain(); + if( tmp->DynamicObject->iCabs & 1 ) { + tmp->DynamicObject->MoverParameters->ActiveCab = 1; + Train->Init( tmp->DynamicObject, true ); + } + if( tmp->DynamicObject->iCabs & 4 ) { + tmp->DynamicObject->MoverParameters->ActiveCab = -1; + Train->Init( tmp->DynamicObject, true ); + } + if( tmp->DynamicObject->iCabs & 2 ) { + tmp->DynamicObject->MoverParameters->ActiveCab = 0; + Train->Init( tmp->DynamicObject, true ); } } - else if (sr.Name.LowerCase().SubString(sr.Name.Length() - 3, 4) == ".t3d") - { // z modelami jest prościej - Global::asCurrentTexturePath = dir.c_str(); - TModelsManager::GetModel(AnsiString(dir + sr.Name).c_str(), false); - } - } while (FindNext(sr) == 0); - FindClose(sr); - } -*/ + // z powrotem defaultowa sciezka do tekstur + Global::asCurrentTexturePath = ( szTexturePath ); + } + else if( filetype == ".t3d" ) { + // z modelami jest prościej + Global::asCurrentTexturePath = Path; + TModelsManager::GetModel( Path + filename, false ); + } + } + + } while( ::FindNextFile( search, &filedata ) ); + + // all done, clean up + ::FindClose( search ); + +#endif }; + //--------------------------------------------------------------------------- void TWorld::CabChange(TDynamicObject *old, TDynamicObject *now) { // ewentualna zmiana kabiny użytkownikowi diff --git a/maszyna.vcxproj.user b/maszyna.vcxproj.user index 803ce541..8c698752 100644 --- a/maszyna.vcxproj.user +++ b/maszyna.vcxproj.user @@ -3,6 +3,8 @@ ..\..\..\development\maszyna WindowsLocalDebugger + + ..\..\Projects\maszyna diff --git a/version.h b/version.h index d30e7043..12dfa00e 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 522 +#define VERSION_MINOR 524 #define VERSION_REVISION 0 diff --git a/wavread.cpp b/wavread.cpp index 4dd527b1..7b7e9698 100644 --- a/wavread.cpp +++ b/wavread.cpp @@ -257,6 +257,8 @@ HRESULT CWaveSoundRead::Read(UINT nSizeToRead, BYTE *pbData, UINT *pnSizeRead) //----------------------------------------------------------------------------- HRESULT CWaveSoundRead::Close() { - mmioClose(m_hmmioIn, 0); + if( m_hmmioIn != NULL ) { + mmioClose( m_hmmioIn, 0 ); + } return S_OK; } diff --git a/wavread.h b/wavread.h index 707baa2a..f0bc4357 100644 --- a/wavread.h +++ b/wavread.h @@ -33,7 +33,7 @@ class CWaveSoundRead { public: WAVEFORMATEX *m_pwfx; // Pointer to WAVEFORMATEX structure - HMMIO m_hmmioIn; // MM I/O handle for the WAVE + HMMIO m_hmmioIn{ NULL }; // MM I/O handle for the WAVE MMCKINFO m_ckIn; // Multimedia RIFF chunk MMCKINFO m_ckInRiff; // Use in opening a WAVE file From 7c5f5d3d04526dac5ec967de362be8b383230fe6 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 24 May 2017 14:19:03 +0200 Subject: [PATCH 06/12] maintenance: removed deprecated render code --- AnimModel.cpp | 125 +----------- AnimModel.h | 26 +-- Driver.cpp | 5 - DynObj.cpp | 403 +----------------------------------- DynObj.h | 19 +- EU07.cpp | 1 - Globals.cpp | 9 - Globals.h | 11 +- Ground.cpp | 158 +-------------- Model3d.cpp | 549 -------------------------------------------------- Model3d.h | 20 -- Segment.h | 2 - Track.cpp | 8 - World.cpp | 393 ++++-------------------------------- sky.cpp | 27 +-- stars.cpp | 13 +- 16 files changed, 69 insertions(+), 1700 deletions(-) diff --git a/AnimModel.cpp b/AnimModel.cpp index 5417d042..a5303f08 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -411,13 +411,7 @@ TAnimModel::TAnimModel() pModel = NULL; iNumLights = 0; fBlinkTimer = 0; -#ifdef EU07_USE_OLD_RENDERCODE - ReplacableSkinId[ 0 ] = 0; - ReplacableSkinId[ 1 ] = 0; - ReplacableSkinId[ 2 ] = 0; - ReplacableSkinId[ 3 ] = 0; - ReplacableSkinId[ 4 ] = 0; -#endif + for (int i = 0; i < iMaxNumLights; i++) { LightsOn[i] = LightsOff[i] = NULL; // normalnie nie ma @@ -443,28 +437,7 @@ bool TAnimModel::Init(TModel3d *pNewModel) pModel = pNewModel; return (pModel != NULL); } -#ifdef EU07_USE_OLD_RENDERCODE -bool TAnimModel::Init(std::string const &asName, std::string const &asReplacableTexture) -{ - if (asReplacableTexture.substr(0, 1) == - "*") // od gwiazdki zaczynają się teksty na wyświetlaczach - asText = asReplacableTexture.substr(1, asReplacableTexture.length() - 1); // zapamiętanie tekstu - else if (asReplacableTexture != "none") - ReplacableSkinId[1] = - GfxRenderer.GetTextureId( asReplacableTexture, "" ); - if( ( ReplacableSkinId[ 1 ] != 0 ) - && ( GfxRenderer.Texture( ReplacableSkinId[ 1 ] ).has_alpha ) ) { - // tekstura z kanałem alfa - nie renderować w cyklu nieprzezroczystych - iTexAlpha = 0x31310031; - } - else{ - // tekstura nieprzezroczysta - nie renderować w cyklu - iTexAlpha = 0x30300030; - } - // przezroczystych - return (Init(TModelsManager::GetModel(asName))); -} -#else + bool TAnimModel::Init(std::string const &asName, std::string const &asReplacableTexture) { if (asReplacableTexture.substr(0, 1) == @@ -485,7 +458,6 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable // przezroczystych return (Init(TModelsManager::GetModel(asName))); } -#endif bool TAnimModel::Load(cParser *parser, bool ter) { // rozpoznanie wpisu modelu i ustawienie świateł @@ -622,99 +594,18 @@ void TAnimModel::RaPrepare() // for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) //albo osobny łańcuch // pCurrent->UpdateModelIK(); //przeliczenie odwrotnej kinematyki } -/* -void TAnimModel::RenderVBO(vector3 pPosition, double fAngle) -{ // sprawdza światła i rekurencyjnie renderuje TModel3d - RaAnimate(); // jednorazowe przeliczenie animacji - RaPrepare(); - if (pModel) // renderowanie rekurencyjne submodeli - pModel->RaRender(pPosition, fAngle, ReplacableSkinId, iTexAlpha); -} -void TAnimModel::RenderAlphaVBO(vector3 pPosition, double fAngle) -{ - RaPrepare(); - if (pModel) // renderowanie rekurencyjne submodeli - pModel->RaRenderAlpha(pPosition, fAngle, ReplacableSkinId, iTexAlpha); -}; - -void TAnimModel::RenderDL(vector3 pPosition, double fAngle) -{ - RaAnimate(); // jednorazowe przeliczenie animacji - RaPrepare(); - if (pModel) // renderowanie rekurencyjne submodeli - pModel->Render(pPosition, fAngle, ReplacableSkinId, iTexAlpha); -} - -void TAnimModel::RenderAlphaDL(vector3 pPosition, double fAngle) -{ - RaPrepare(); - if (pModel) - pModel->RenderAlpha(pPosition, fAngle, ReplacableSkinId, iTexAlpha); -}; -*/ -#ifdef EU07_USE_OLD_RENDERCODE -int TAnimModel::Flags() -{ // informacja dla TGround, czy ma być w Render, RenderAlpha, czy RenderMixed - int i = pModel ? pModel->Flags() : 0; // pobranie flag całego modelu - if (ReplacableSkinId[1] > 0) // jeśli ma wymienną teksturę 0 - i |= (i & 0x01010001) * ((iTexAlpha & 1) ? 0x20 : 0x10); - // if (ReplacableSkinId[2]>0) //jeśli ma wymienną teksturę 1 - // i|=(i&0x02020002)*((iTexAlpha&1)?0x10:0x08); - // if (ReplacableSkinId[3]>0) //jeśli ma wymienną teksturę 2 - // i|=(i&0x04040004)*((iTexAlpha&1)?0x08:0x04); - // if (ReplacableSkinId[4]>0) //jeśli ma wymienną teksturę 3 - // i|=(i&0x08080008)*((iTexAlpha&1)?0x04:0x02); - return i; -}; -#else int TAnimModel::Flags() { // informacja dla TGround, czy ma być w Render, RenderAlpha, czy RenderMixed int i = pModel ? pModel->Flags() : 0; // pobranie flag całego modelu if( m_materialdata.replacable_skins[ 1 ] > 0 ) // jeśli ma wymienną teksturę 0 i |= (i & 0x01010001) * ((m_materialdata.textures_alpha & 1) ? 0x20 : 0x10); - // if (ReplacableSkinId[2]>0) //jeśli ma wymienną teksturę 1 - // i|=(i&0x02020002)*((iTexAlpha&1)?0x10:0x08); - // if (ReplacableSkinId[3]>0) //jeśli ma wymienną teksturę 2 - // i|=(i&0x04040004)*((iTexAlpha&1)?0x08:0x04); - // if (ReplacableSkinId[4]>0) //jeśli ma wymienną teksturę 3 - // i|=(i&0x08080008)*((iTexAlpha&1)?0x04:0x02); return i; }; -#endif //----------------------------------------------------------------------------- -// 2011-03-16 cztery nowe funkcje renderowania z możliwością pochylania obiektów +// 2011-03-16 funkcje renderowania z możliwością pochylania obiektów //----------------------------------------------------------------------------- -#ifdef EU07_USE_OLD_RENDERCODE -void TAnimModel::RenderDL(vector3 *vPosition) -{ - RaAnimate(); // jednorazowe przeliczenie animacji - RaPrepare(); - if( pModel ) // renderowanie rekurencyjne submodeli - pModel->Render(vPosition, &vAngle, ReplacableSkinId, iTexAlpha); -}; -void TAnimModel::RenderAlphaDL(vector3 *vPosition) -{ - RaPrepare(); - if (pModel) // renderowanie rekurencyjne submodeli - pModel->RenderAlpha(vPosition, &vAngle, ReplacableSkinId, iTexAlpha); -}; - -void TAnimModel::RenderVBO(vector3 *vPosition) -{ - RaAnimate(); // jednorazowe przeliczenie animacji - RaPrepare(); - if (pModel) // renderowanie rekurencyjne submodeli - pModel->RaRender( vPosition, &vAngle, Material()->replacable_skins, Material()->textures_alpha ); -}; -void TAnimModel::RenderAlphaVBO(vector3 *vPosition) -{ - RaPrepare(); - if (pModel) // renderowanie rekurencyjne submodeli - pModel->RaRenderAlpha( vPosition, &vAngle, Material()->replacable_skins, Material()->textures_alpha ); -}; -#else void TAnimModel::Render( vector3 *vPosition ) { RaAnimate(); // jednorazowe przeliczenie animacji RaPrepare(); @@ -726,7 +617,6 @@ void TAnimModel::RenderAlpha( vector3 *vPosition ) { if( pModel ) // renderowanie rekurencyjne submodeli GfxRenderer.Render_Alpha( pModel, Material(), *vPosition, vAngle ); }; -#endif //--------------------------------------------------------------------------- bool TAnimModel::TerrainLoaded() @@ -901,13 +791,8 @@ void TAnimModel::LightSet(int n, float v) void TAnimModel::AnimUpdate(double dt) { // wykonanie zakolejkowanych animacji, nawet gdy modele nie są aktualnie wyświetlane TAnimContainer *p = TAnimModel::acAnimList; - while (p) - { // jeśli w ogóle jest co animować - // if ((*p)->fTranslateSpeed==0.0) - // if ((*p)->fRotateSpeed==0.0) - // {//jak się naanimował, to usunąć z listy - // *p=(*p)->ListRemove(); //zwraca wskaźnik do kolejnego z listy - // } + while( p ) { + p->UpdateModel(); p = p->acAnimNext; // na razie bez usuwania z listy, bo głównie obrotnica na nią wchodzi } diff --git a/AnimModel.h b/AnimModel.h index d8800e6b..760669e8 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -12,8 +12,7 @@ http://mozilla.org/MPL/2.0/. */ -#ifndef AnimModelH -#define AnimModelH +#pragma once #include "Model3d.h" #include "Texture.h" @@ -139,11 +138,7 @@ class TAnimModel TSubModel *LightsOn[iMaxNumLights]; // Ra: te wskaźniki powinny być w ramach TModel3d TSubModel *LightsOff[iMaxNumLights]; vector3 vAngle; // bazowe obroty egzemplarza względem osi -#ifdef EU07_USE_OLD_RENDERCODE - int iTexAlpha; //żeby nie sprawdzać za każdym razem, dla 4 wymiennych tekstur -#else material_data m_materialdata; -#endif std::string asText; // tekst dla wyświetlacza znakowego TAnimAdvanced *pAdvanced; @@ -155,14 +150,9 @@ class TAnimModel void RaAnimate(); // przeliczenie animacji egzemplarza void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu public: -#ifdef EU07_USE_OLD_RENDERCODE - texture_manager::size_type ReplacableSkinId[5]; // McZapkie-020802: zmienialne skory -#endif static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania -#ifndef EU07_USE_OLD_RENDERCODE inline material_data const *Material() const { return &m_materialdata; } -#endif TAnimModel(); ~TAnimModel(); @@ -171,20 +161,8 @@ class TAnimModel bool Load(cParser *parser, bool ter = false); TAnimContainer * AddContainer(char *pName); TAnimContainer * GetContainer(char *pName); -/* void RenderDL(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0); - void RenderAlphaDL(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0); - void RenderVBO(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0); - void RenderAlphaVBO(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0); -*/ -#ifdef EU07_USE_OLD_RENDERCODE - void RenderDL( vector3 *vPosition ); - void RenderAlphaDL(vector3 *vPosition); - void RenderVBO(vector3 *vPosition); - void RenderAlphaVBO(vector3 *vPosition); -#else void Render( vector3 *vPosition ); void RenderAlpha( vector3 *vPosition ); -#endif int Flags(); void RaAnglesSet(double a, double b, double c) { @@ -201,6 +179,4 @@ class TAnimModel static void AnimUpdate(double dt); }; - //--------------------------------------------------------------------------- -#endif diff --git a/Driver.cpp b/Driver.cpp index 97c7ee03..dbb4b171 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -512,11 +512,6 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) return; } -#ifdef EU07_USE_OLD_SPEEDTABLE - // jak coś się znajdzie, zostanie wpisane w tę pozycję, którą właśnie odczytano - --iLast; -#endif - while (fCurrentDistance < fDistance) { if (pTrack != tLast) // ostatni zapisany w tabelce nie był jeszcze sprawdzony diff --git a/DynObj.cpp b/DynObj.cpp index 3441c328..16229e1d 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1531,14 +1531,6 @@ TDynamicObject::TDynamicObject() //} mdModel = NULL; mdKabina = NULL; -#ifdef EU07_USE_OLD_RENDERCODE - ReplacableSkinID[ 0 ] = 0; - ReplacableSkinID[ 1 ] = 0; - ReplacableSkinID[ 2 ] = 0; - ReplacableSkinID[ 3 ] = 0; - ReplacableSkinID[ 4 ] = 0; - iAlpha = 0x30300030; // tak gdy tekstury wymienne nie mają przezroczystości -#endif // smWiazary[0]=smWiazary[1]=NULL; smWahacze[0] = smWahacze[1] = smWahacze[2] = smWahacze[3] = NULL; fWahaczeAmp = 0; @@ -3563,262 +3555,6 @@ void TDynamicObject::TurnOff() btMechanik1.TurnOff(); btMechanik2.TurnOff(); }; -#ifdef EU07_USE_OLD_RENDERCODE -void TDynamicObject::Render() -{ // rysowanie elementów nieprzezroczystych - // youBy - sprawdzamy, czy jest sens renderowac - - if (GfxRenderer.Visible(this)) - { - TSubModel::iInstance = (size_t)this; //żeby nie robić cudzych animacji - // AnsiString asLoadName=""; - double ObjSqrDist = SquareMagnitude(Global::pCameraPosition - vPosition) / Global::ZoomFactor; - ABuLittleUpdate(ObjSqrDist); // ustawianie zmiennych submodeli dla wspólnego modelu - -// Cone(vCoulpler[0],modelRot.z,0); -// Cone(vCoulpler[1],modelRot.z,1); - -// ActualTrack= GetTrack(); //McZapkie-240702 - -#if RENDER_CONE - { // Ra: testowe renderowanie pozycji wózków w postaci ostrosłupów, wymaga - // GLUT32.DLL - double dir = RadToDeg(atan2(vLeft.z, vLeft.x)); - Axle0.Render(0); - Axle1.Render(1); // bogieRot[0] - // if (PrevConnected) //renderowanie połączenia - } -#endif - - glPushMatrix(); - // vector3 pos= vPosition; - // double ObjDist= SquareMagnitude(Global::pCameraPosition-pos); - if (this == Global::pUserDynamic) - { // specjalne ustawienie, aby nie trzęsło -#ifdef EU07_USE_OLD_LIGHTING_MODEL - if (Global::bSmudge) - { // jak jest widoczna smuga, to pojazd renderować po - // wyrenderowaniu smugi - glPopMatrix(); // a to trzeba zebrać przed wyjściem - return; - } -#endif - // if (Global::pWorld->) //tu trzeba by ustawić animacje na modelu - // zewnętrznym - glLoadIdentity(); // zacząć od macierzy jedynkowej - Global::pCamera->SetCabMatrix(vPosition); // specjalne ustawienie kamery - } - else - glTranslated(vPosition.x, vPosition.y, - vPosition.z); // standardowe przesunięcie względem początku scenerii - glMultMatrixd(mMatrix.getArray()); -#ifdef EU07_USE_OLD_LIGHTING_MODEL - if (fShade > 0.0) - { // Ra: zmiana oswietlenia w tunelu, wykopie - GLfloat ambientLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - GLfloat diffuseLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - GLfloat specularLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - // trochę problem z ambientem w wykopie... - for (int li = 0; li < 3; li++) - { - ambientLight[li] = Global::ambientDayLight[li] * fShade; - diffuseLight[li] = Global::diffuseDayLight[li] * fShade; - specularLight[li] = Global::specularDayLight[li] * fShade; - } - glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); - } -#else - if( fShade > 0.0f ) { - // change light level based on light level of the occupied track - Global::DayLight.apply_intensity( fShade ); - } -#endif - if (Global::bUseVBO) - { // wersja VBO - if (mdLowPolyInt) - if (FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab) - mdLowPolyInt->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha); - mdModel->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha); - if (mdLoad) // renderowanie nieprzezroczystego ładunku - mdLoad->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha); - } - else - { // wersja Display Lists - if( mdLowPolyInt ) { - // low poly interior - if( FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab ) { - // enable cab light if needed - if( InteriorLightLevel > 0.0f ) { - - // crude way to light the cabin, until we have something more complete in place - auto const cablight = InteriorLight * InteriorLightLevel; - ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &cablight.x ); - } - - mdLowPolyInt->Render( ObjSqrDist, ReplacableSkinID, iAlpha ); - - if( InteriorLightLevel > 0.0f ) { - // reset the overall ambient - GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); - } - } - } - mdModel->Render(ObjSqrDist, ReplacableSkinID, iAlpha); - if (mdLoad) // renderowanie nieprzezroczystego ładunku - mdLoad->Render(ObjSqrDist, ReplacableSkinID, iAlpha); - } - - // Ra: czy ta kabina tu ma sens? - // Ra: czy nie renderuje się dwukrotnie? - // Ra: dlaczego jest zablokowana w przezroczystych? - if (mdKabina) // jeśli ma model kabiny - if ((mdKabina != mdModel) && bDisplayCab && FreeFlyModeFlag) - { // rendering kabiny gdy jest oddzielnym modelem i - // ma byc wyswietlana - // ABu: tylko w trybie FreeFly, zwykly tryb w world.cpp - // Ra: świetła są ustawione dla zewnętrza danego pojazdu -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // TODO: re-mplement this - // oswietlenie kabiny - GLfloat ambientCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - GLfloat diffuseCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - GLfloat specularCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - for (int li = 0; li < 3; li++) - { - ambientCabLight[li] = Global::ambientDayLight[li] * 0.9; - diffuseCabLight[li] = Global::diffuseDayLight[li] * 0.5; - specularCabLight[li] = Global::specularDayLight[li] * 0.5; - } - switch (MyTrack->eEnvironment) - { - case e_canyon: - { - for (int li = 0; li < 3; li++) - { - diffuseCabLight[li] *= 0.6f; - specularCabLight[li] *= 0.7f; - } - } - break; - case e_tunnel: - { - for (int li = 0; li < 3; li++) - { - ambientCabLight[li] *= 0.3f; - diffuseCabLight[li] *= 0.1f; - specularCabLight[li] *= 0.2f; - } - } - break; - } - glLightfv(GL_LIGHT0, GL_AMBIENT, ambientCabLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseCabLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, specularCabLight); -#endif - if (Global::bUseVBO) - mdKabina->RaRender(ObjSqrDist, 0); - else - mdKabina->Render(ObjSqrDist, 0); -#ifdef EU07_USE_OLD_LIGHTING_MODEL - glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); -#endif - } -#ifdef EU07_USE_OLD_LIGHTING_MODEL - if( fShade != 0.0 ) // tylko jeśli było zmieniane - { // przywrócenie standardowego oświetlenia - glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); - } -#else - if( fShade > 0.0f ) { - // restore regular light level - Global::DayLight.apply_intensity(); - } -#endif - glPopMatrix(); - if (btnOn) - TurnOff(); // przywrócenie domyślnych pozycji submodeli - } // yB - koniec mieszania z grafika -}; - -void TDynamicObject::RenderAlpha() -{ // rysowanie elementów półprzezroczystych - if (renderme) - { - TSubModel::iInstance = (size_t)this; //żeby nie robić cudzych animacji - double ObjSqrDist = SquareMagnitude(Global::pCameraPosition - vPosition); - ABuLittleUpdate(ObjSqrDist); // ustawianie zmiennych submodeli dla wspólnego modelu - glPushMatrix(); - if (this == Global::pUserDynamic) - { // specjalne ustawienie, aby nie trzęsło - glPopMatrix(); // to trzeba zebrać przed wyściem - return; - glLoadIdentity(); // zacząć od macierzy jedynkowej - Global::pCamera->SetCabMatrix(vPosition); // specjalne ustawienie kamery - } - else - glTranslated(vPosition.x, vPosition.y, - vPosition.z); // standardowe przesunięcie względem początku scenerii - glMultMatrixd(mMatrix.getArray()); -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // TODO: re-implement this - if (fShade > 0.0) - { // Ra: zmiana oswietlenia w tunelu, wykopie - GLfloat ambientLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - GLfloat diffuseLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - GLfloat specularLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - // trochę problem z ambientem w wykopie... - for (int li = 0; li < 3; li++) - { - ambientLight[li] = Global::ambientDayLight[li] * fShade; - diffuseLight[li] = Global::diffuseDayLight[li] * fShade; - specularLight[li] = Global::specularDayLight[li] * fShade; - } - glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); - } -#endif - if (Global::bUseVBO) - { // wersja VBO - if (mdLowPolyInt) - if (FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab) - mdLowPolyInt->RaRenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); - mdModel->RaRenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); - if (mdLoad) - mdLoad->RaRenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); - } - else - { // wersja Display Lists - if (mdLowPolyInt) - if (FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab) - mdLowPolyInt->RenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); - mdModel->RenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); - if (mdLoad) - mdLoad->RenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); - } -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // TODO: re-implement this - if (fShade != 0.0) // tylko jeśli było zmieniane - { // przywrócenie standardowego oświetlenia - glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); - } -#endif - glPopMatrix(); - if (btnOn) - TurnOff(); // przywrócenie domyślnych pozycji submodeli - } - return; -} // koniec renderalpha -#endif void TDynamicObject::RenderSounds() { // przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem @@ -4210,26 +3946,6 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, if( token == "models:") { // modele i podmodele -#ifdef EU07_USE_OLD_RENDERCODE - iMultiTex = 0; // czy jest wiele tekstur wymiennych? - parser.getTokens(); - parser >> asModel; - if( asModel[asModel.size() - 1] == '#' ) // Ra 2015-01: nie podoba mi siê to - { // model wymaga wielu tekstur wymiennych - iMultiTex = 1; - asModel.erase( asModel.length() - 1 ); - } - std::size_t i = asModel.find( ',' ); - if ( i != std::string::npos ) - { // Ra 2015-01: może szukać przecinka w nazwie modelu, a po przecinku była by liczba tekstur? - if (i < asModel.length()) - iMultiTex = asModel[i + 1] - '0'; - if (iMultiTex < 0) - iMultiTex = 0; - else if (iMultiTex > 1) - iMultiTex = 1; // na razie ustawiamy na 1 - } -#else m_materialdata.multi_textures = 0; // czy jest wiele tekstur wymiennych? parser.getTokens(); parser >> asModel; @@ -4245,71 +3961,13 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, m_materialdata.multi_textures = asModel[i + 1] - '0'; m_materialdata.multi_textures = clamp( m_materialdata.multi_textures, 0, 1 ); // na razie ustawiamy na 1 } -#endif asModel = BaseDir + asModel; // McZapkie 2002-07-20: dynamics maja swoje // modele w dynamics/basedir Global::asCurrentTexturePath = BaseDir; // biezaca sciezka do tekstur to dynamic/... mdModel = TModelsManager::GetModel(asModel, true); assert( mdModel != nullptr ); // TODO: handle this more gracefully than all going to shit if (ReplacableSkin != "none") -#ifdef EU07_USE_OLD_RENDERCODE - { // tekstura wymienna jest raczej jedynie w "dynamic\" - ReplacableSkin = - Global::asCurrentTexturePath + ReplacableSkin; // skory tez z dynamic/... - std::string x = TextureTest(Global::asCurrentTexturePath + "nowhere"); // na razie prymitywnie - if (!x.empty()) - ReplacableSkinID[4] = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + "nowhere", "", 9); - - if (iMultiTex > 0) - { // jeśli model ma 4 tekstury - ReplacableSkinID[1] = GfxRenderer.GetTextureId( - ReplacableSkin + ",1", "", Global::iDynamicFiltering); - if (ReplacableSkinID[1]) - { // pierwsza z zestawu znaleziona - ReplacableSkinID[2] = GfxRenderer.GetTextureId( - ReplacableSkin + ",2", "", Global::iDynamicFiltering); - if (ReplacableSkinID[2]) - { - iMultiTex = 2; // już są dwie - ReplacableSkinID[3] = GfxRenderer.GetTextureId( - ReplacableSkin + ",3", "", Global::iDynamicFiltering); - if (ReplacableSkinID[3]) - { - iMultiTex = 3; // a teraz nawet trzy - ReplacableSkinID[4] = GfxRenderer.GetTextureId( - ReplacableSkin + ",4", "", Global::iDynamicFiltering); - if (ReplacableSkinID[4]) - iMultiTex = 4; // jak są cztery, to blokujemy podmianę tekstury rozkładem - } - } - } - else - { // zestaw nie zadziałał, próbujemy normanie - iMultiTex = 0; - ReplacableSkinID[1] = GfxRenderer.GetTextureId( - ReplacableSkin, "", Global::iDynamicFiltering); - } - } - else - ReplacableSkinID[1] = GfxRenderer.GetTextureId( - ReplacableSkin, "", Global::iDynamicFiltering); - if (GfxRenderer.Texture(ReplacableSkinID[1]).has_alpha) - iAlpha = 0x31310031; // tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych - else - iAlpha = 0x30300030; // wszystkie tekstury nieprzezroczyste - nie renderować w cyklu przezroczystych - if (ReplacableSkinID[2]) - if (GfxRenderer.Texture(ReplacableSkinID[2]).has_alpha) - iAlpha |= 0x02020002; // tekstura -2 z kanałem alfa - nie renderować w cyklu nieprzezroczystych - if (ReplacableSkinID[3]) - if (GfxRenderer.Texture(ReplacableSkinID[3]).has_alpha) - iAlpha |= 0x04040004; // tekstura -3 z kanałem alfa - nie renderować w cyklu nieprzezroczystych - if (ReplacableSkinID[4]) - if (GfxRenderer.Texture(ReplacableSkinID[4]).has_alpha) - iAlpha |= 0x08080008; // tekstura -4 z kanałem alfa - nie renderować w cyklu nieprzezroczystych - } -#else - { // tekstura wymienna jest raczej jedynie w "dynamic\" -// ReplacableSkin = Global::asCurrentTexturePath + ReplacableSkin; // skory tez z dynamic/... + { std::string nowheretexture = TextureTest(Global::asCurrentTexturePath + "nowhere"); // na razie prymitywnie if( false == nowheretexture.empty() ) { m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( nowheretexture, "", 9 ); @@ -4364,7 +4022,6 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, if( GfxRenderer.Texture( m_materialdata.replacable_skins[ 4 ] ).has_alpha ) m_materialdata.textures_alpha |= 0x08080008; // tekstura -4 z kanałem alfa - nie renderować w cyklu nieprzezroczystych } -#endif if (!MoverParameters->LoadAccepted.empty()) // if (MoverParameters->LoadAccepted!=AnsiString("")); // && // MoverParameters->LoadType!=AnsiString("passengers")) @@ -5655,62 +5312,16 @@ std::string TDynamicObject::TextureTest(std::string const &name) return ""; // nie znaleziona }; -#ifdef EU07_USE_OLD_RENDERCODE -void TDynamicObject::DestinationSet(std::string to, std::string numer) -{ // ustawienie stacji - // docelowej oraz wymiennej - // tekstury 4, jeśli - // istnieje plik - // w zasadzie, to każdy wagon mógłby mieć inną stację docelową - // zwłaszcza w towarowych, pod kątem zautomatyzowania maewrów albo pracy górki - // ale to jeszcze potrwa, zanim będzie możliwe, na razie można wpisać stację z - // rozkładu - if (abs(iMultiTex) >= 4) - return; // jak są 4 tekstury wymienne, to nie zmieniać rozkładem - numer = Global::Bezogonkow(numer); - asDestination = to; - to = Global::Bezogonkow(to); // do szukania pliku obcinamy ogonki - std::string x = TextureTest(asBaseDir + numer + "@" + MoverParameters->TypeName); - if (!x.empty()) - { - ReplacableSkinID[4] = GfxRenderer.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się - return; - } - x = TextureTest(asBaseDir + numer ); - if (!x.empty()) - { - ReplacableSkinID[4] = GfxRenderer.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się - return; - } - if (to.empty()) - to = "nowhere"; - x = TextureTest(asBaseDir + to + "@" + MoverParameters->TypeName); // w pierwszej kolejności z nazwą FIZ/MMD - if (!x.empty()) - { - ReplacableSkinID[4] = GfxRenderer.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się - return; - } - x = TextureTest(asBaseDir + to); // na razie prymitywnie - if (!x.empty()) - ReplacableSkinID[4] = GfxRenderer.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się - else - { - x = TextureTest(asBaseDir + "nowhere"); // jak nie znalazł dedykowanej, to niech daje nowhere - if (!x.empty()) - ReplacableSkinID[4] = GfxRenderer.GetTextureId( x, "", 9); - } - // Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa - // tekstury nr 4 -}; -#else void TDynamicObject::DestinationSet(std::string to, std::string numer) { // ustawienie stacji docelowej oraz wymiennej tekstury 4, jeśli istnieje plik // w zasadzie, to każdy wagon mógłby mieć inną stację docelową // zwłaszcza w towarowych, pod kątem zautomatyzowania maewrów albo pracy górki // ale to jeszcze potrwa, zanim będzie możliwe, na razie można wpisać stację z // rozkładu - if( std::abs( m_materialdata.multi_textures ) >= 4 ) - return; // jak są 4 tekstury wymienne, to nie zmieniać rozkładem + if( std::abs( m_materialdata.multi_textures ) >= 4 ) { + // jak są 4 tekstury wymienne, to nie zmieniać rozkładem + return; + } numer = Global::Bezogonkow(numer); asDestination = to; to = Global::Bezogonkow(to); // do szukania pliku obcinamy ogonki @@ -5743,10 +5354,8 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer) if (!x.empty()) m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( x, "", 9 ); } - // Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa - // tekstury nr 4 + // Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa tekstury nr 4 }; -#endif void TDynamicObject::OverheadTrack(float o) { // ewentualne wymuszanie jazdy diff --git a/DynObj.h b/DynObj.h index 34682611..c61254d3 100644 --- a/DynObj.h +++ b/DynObj.h @@ -137,11 +137,8 @@ class TAnim void Parovoz(); // wykonanie obliczeń animacji }; -//--------------------------------------------------------------------------- -//--------------------------------------------------------------------------- //--------------------------------------------------------------------------- -#ifndef EU07_USE_OLD_RENDERCODE // parameters for the material object, as currently used by various simulator models struct material_data { @@ -153,7 +150,6 @@ struct material_data { ::SecureZeroMemory( replacable_skins, sizeof( replacable_skins ) ); } }; -#endif class TDynamicObject { // klasa pojazdu @@ -200,15 +196,11 @@ public: // modele składowe pojazdu float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?) private: // zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe -#ifndef EU07_USE_OLD_RENDERCODE material_data m_materialdata; -#endif public: -#ifndef EU07_USE_OLD_RENDERCODE inline - material_data const *Material() const { return &m_materialdata; } -#endif + material_data const *Material() const { return &m_materialdata; } // tymczasowo udostępnione do wyszukiwania drutu int iAnimType[ ANIM_TYPES ]; // 0-osie,1-drzwi,2-obracane,3-zderzaki,4-wózki,5-pantografy,6-tłoki private: @@ -421,11 +413,6 @@ public: // modele składowe pojazdu int iCabs; // maski bitowe modeli kabin TTrack *MyTrack; // McZapkie-030303: tor na ktorym stoi, ABu std::string asBaseDir; -#ifdef EU07_USE_OLD_RENDERCODE - texture_manager::size_type ReplacableSkinID[5]; // McZapkie:zmienialne nadwozie - int iAlpha; // maska przezroczystości tekstur - int iMultiTex; //<0 tekstury wskazane wpisem, >0 tekstury z przecinkami, =0 jedna -#endif int iOverheadMask; // maska przydzielana przez AI pojazdom posiadającym pantograf, aby wymuszały // jazdę bezprądową TTractionParam tmpTraction; @@ -444,10 +431,6 @@ public: // modele składowe pojazdu bool FastUpdate(double dt); void Move(double fDistance); void FastMove(double fDistance); -#ifdef EU07_USE_OLD_RENDERCODE - void Render(); - void RenderAlpha(); -#endif void RenderSounds(); inline vector3 GetPosition() const { diff --git a/EU07.cpp b/EU07.cpp index c73d9218..280f36fc 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -9,7 +9,6 @@ http://mozilla.org/MPL/2.0/. /* MaSzyna EU07 locomotive simulator Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others - */ /* Authors: diff --git a/Globals.cpp b/Globals.cpp index 277b01ad..7dddc20f 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -83,17 +83,8 @@ GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f}; double Global::fFogStart = 1700; double Global::fFogEnd = 2000; float Global::Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere -#ifdef EU07_USE_OLD_LIGHTING_MODEL -GLfloat Global::ambientDayLight[] = {0.40f, 0.40f, 0.45f, 1.0f}; // robocze -GLfloat Global::diffuseDayLight[] = {0.55f, 0.54f, 0.50f, 1.0f}; -GLfloat Global::specularDayLight[] = {0.95f, 0.94f, 0.90f, 1.0f}; -GLfloat Global::ambientLight[] = {0.80f, 0.80f, 0.85f, 1.0f}; // stałe -GLfloat Global::diffuseLight[] = {0.85f, 0.85f, 0.80f, 1.0f}; -GLfloat Global::specularLight[] = {0.95f, 0.94f, 0.90f, 1.0f}; -#else opengl_light Global::DayLight; int Global::DynamicLightCount{ 3 }; -#endif GLfloat Global::whiteLight[] = {1.00f, 1.00f, 1.00f, 1.0f}; GLfloat Global::noLight[] = {0.00f, 0.00f, 0.00f, 1.0f}; GLfloat Global::darkLight[] = {0.03f, 0.03f, 0.03f, 1.0f}; //śladowe diff --git a/Globals.h b/Globals.h index 91664442..9e0cf512 100644 --- a/Globals.h +++ b/Globals.h @@ -221,20 +221,11 @@ class Global static GLfloat FogColor[]; static float Overcast; // static bool bTimeChange; -#ifdef EU07_USE_OLD_LIGHTING_MODEL - static opengl_light AmbientLight; - static GLfloat ambientDayLight[]; - static GLfloat diffuseDayLight[]; - static GLfloat specularDayLight[]; - static GLfloat ambientLight[]; - static GLfloat diffuseLight[]; - static GLfloat specularLight[]; -#else // TODO: put these things in the renderer static opengl_light DayLight; static int DynamicLightCount; -#endif + static GLfloat whiteLight[]; static GLfloat noLight[]; static GLfloat darkLight[]; diff --git a/Ground.cpp b/Ground.cpp index cbebea27..879d1265 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -1625,19 +1625,15 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) str4); if (tf3 != 0.0) // zero oznacza błąd { - fTrainSetDist -= - tf3; // przesunięcie dla kolejnego, minus bo idziemy w stronę punktu 1 + // przesunięcie dla kolejnego, minus bo idziemy w stronę punktu 1 + fTrainSetDist -= tf3; tmp->pCenter = tmp->DynamicObject->GetPosition(); -/* // NOTE: the ctrain_depot flag is used to mark merged together parts of modular trains - // clearing it here breaks this connection, so i'm disabling this piece of code. - // if it has some actual purpose and disabling it breaks that, a different solution has to be found - // either for modular trains, or whatever it is this code does. - if (TempConnectionType[iTrainSetWehicleNumber]) // jeśli jest sprzęg - if (tmp->DynamicObject->MoverParameters->Couplers[tf1 == -1.0 ? 0 : 1] - .AllowedFlag & - ctrain_depot) // jesli zablokowany - TempConnectionType[iTrainSetWehicleNumber] |= ctrain_depot; // będzie blokada -*/ + // automatically establish permanent connections for couplers which specify them in their definitions + if( TempConnectionType[ iTrainSetWehicleNumber ] ) { + if( tmp->DynamicObject->MoverParameters->Couplers[ ( tf1 == -1.0 ? 0 : 1 ) ].AllowedFlag & coupling::permanent ) { + TempConnectionType[ iTrainSetWehicleNumber ] |= coupling::permanent; + } + } iTrainSetWehicleNumber++; } else @@ -1825,29 +1821,12 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) parser->getTokens(); *parser >> token; } while (token.compare("endtri") != 0); - // delete tmp; //nie ma co tego trzymać - // tmp=NULL; //to jest błąd } else { -/* - i = 0; -*/ TempVerts.clear(); TGroundVertex vertex; - do - { -/* - if (i < 9999) // 3333 trójkąty - { // liczba wierzchołków nie jest nieograniczona -*/ -/* - parser->getTokens(3); - *parser >> TempVerts[i].Point.x >> TempVerts[i].Point.y >> TempVerts[i].Point.z; - parser->getTokens(3); - *parser >> TempVerts[i].Normal.x >> TempVerts[i].Normal.y >> - TempVerts[i].Normal.z; -*/ + do { parser->getTokens( 8, false ); *parser >> vertex.Point.x @@ -1858,49 +1837,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) >> vertex.Normal.z >> vertex.tu >> vertex.tv; - /* - str=Parser->GetNextSymbol().LowerCase(); - if (str==AnsiString("x")) - TempVerts[i].tu=(TempVerts[i].Point.x+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str==AnsiString("y")) - TempVerts[i].tu=(TempVerts[i].Point.y+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str==AnsiString("z")) - TempVerts[i].tu=(TempVerts[i].Point.z+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - TempVerts[i].tu=str.ToDouble();; - - str=Parser->GetNextSymbol().LowerCase(); - if (str==AnsiString("x")) - TempVerts[i].tv=(TempVerts[i].Point.x+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str==AnsiString("y")) - TempVerts[i].tv=(TempVerts[i].Point.y+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str==AnsiString("z")) - TempVerts[i].tv=(TempVerts[i].Point.z+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - TempVerts[i].tv=str.ToDouble();; - */ -/* - parser->getTokens(2); - *parser >> TempVerts[i].tu >> TempVerts[i].tv; -*/ - // tf=Parser->GetNextSymbol().ToDouble(); - // TempVerts[i].tu=tf; - // tf=Parser->GetNextSymbol().ToDouble(); - // TempVerts[i].tv=tf; -/* - TempVerts[i].Point.RotateZ(aRotate.z / 180 * M_PI); - TempVerts[i].Point.RotateX(aRotate.x / 180 * M_PI); - TempVerts[i].Point.RotateY(aRotate.y / 180 * M_PI); - TempVerts[i].Normal.RotateZ(aRotate.z / 180 * M_PI); - TempVerts[i].Normal.RotateX(aRotate.x / 180 * M_PI); - TempVerts[i].Normal.RotateY(aRotate.y / 180 * M_PI); - TempVerts[i].Point += pOrigin; - tmp->pCenter += TempVerts[i].Point; -*/ vertex.Point.RotateZ( aRotate.z / 180 * M_PI ); vertex.Point.RotateX( aRotate.x / 180 * M_PI ); vertex.Point.RotateY( aRotate.y / 180 * M_PI ); @@ -1911,27 +1847,15 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) tmp->pCenter += vertex.Point; TempVerts.emplace_back( vertex ); -/* - } - else if (i == 9999) - ErrorLog("Bad triangles: too many verices"); - i++; -*/ parser->getTokens(); *parser >> token; - // } - } while (token.compare("endtri") != 0); -/* - nv = i; -*/ + nv = (int)TempVerts.size(); tmp->Init(nv); // utworzenie tablicy wierzchołków tmp->pCenter /= (nv > 0 ? nv : 1); - // memcpy(tmp->Vertices,TempVerts,nv*sizeof(TGroundVertex)); - r = 0; for (int i = 0; i < nv; i++) { @@ -1940,7 +1864,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) if (tf > r) r = tf; } - // tmp->fSquareRadius=2000*2000+r; tmp->fSquareRadius += r; RaTriangleDivider(tmp); // Ra: dzielenie trójkątów jest teraz całkiem wydajne @@ -2123,22 +2046,6 @@ bool TGround::Init(std::string File) cParser parser(File, cParser::buffer_FILE, subpath, Global::bLoadTraction); std::string token; - /* - TFileStream *fs; - fs=new TFileStream(asFile , fmOpenRead | fmShareCompat ); - AnsiString str=""; - int size=fs->Size; - str.SetLength(size); - fs->Read(str.c_str(),size); - str+=""; - delete fs; - TQueryParserComp *Parser; - Parser=new TQueryParserComp(NULL); - Parser->TextToParse=str; - // Parser->LoadStringToParse(asFile); - Parser->First(); - AnsiString Token,asFileName; - */ const int OriginStackMaxDepth = 100; // rozmiar stosu dla zagnieżdżenia origin int OriginStackTop = 0; vector3 OriginStack[OriginStackMaxDepth]; // stos zagnieżdżenia origin @@ -2434,58 +2341,15 @@ bool TGround::Init(std::string File) else if (str == "light") { // Ra: ustawianie światła przeniesione do FirstInit WriteLog("Scenery light definition"); -#ifdef EU07_USE_OLD_LIGHTING_MODEL - vector3 lp; - parser.getTokens(); - parser >> lp.x; - parser.getTokens(); - parser >> lp.y; - parser.getTokens(); - parser >> lp.z; - lp = Normalize(lp); // kierunek padania - Global::lightPos[0] = lp.x; // daylight position - Global::lightPos[1] = lp.y; - Global::lightPos[2] = lp.z; -#else parser.getTokens(3, false); parser >> Global::DayLight.direction.x >> Global::DayLight.direction.y >> Global::DayLight.direction.z;; Global::DayLight.direction.Normalize(); -#endif parser.getTokens(9, false); -#ifdef EU07_USE_OLD_LIGHTING_MODEL - parser - >> Global::ambientDayLight[ 0 ] - >> Global::ambientDayLight[ 1 ] - >> Global::ambientDayLight[ 2 ] - >> Global::diffuseDayLight[ 0 ] - >> Global::diffuseDayLight[ 1 ] - >> Global::diffuseDayLight[ 2 ] - >> Global::specularDayLight[ 0 ] - >> Global::specularDayLight[ 1 ] - >> Global::specularDayLight[ 2 ]; -#else -/* - parser - // kolor wszechobceny - >> Global::DayLight.ambient[0] - >> Global::DayLight.ambient[1] - >> Global::DayLight.ambient[2] - // kolor padający - >> Global::DayLight.diffuse[0] - >> Global::DayLight.diffuse[1] - >> Global::DayLight.diffuse[2] - // kolor odbity - >> Global::DayLight.specular[0] - >> Global::DayLight.specular[1] - >> Global::DayLight.specular[2]; -*/ -#endif - do - { + do { parser.getTokens(); parser >> token; } while (token.compare("endlight") != 0); diff --git a/Model3d.cpp b/Model3d.cpp index 26bd823a..a6e0845f 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1036,421 +1036,6 @@ void TSubModel::RaAnimation(TAnimType a) } }; -#ifdef EU07_USE_OLD_RENDERCODE -void TSubModel::RenderDL() -{ // główna procedura renderowania przez DL - if( ( iVisible ) - && ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) ) - && ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) ) - { - if (iFlags & 0xC000) - { - glPushMatrix(); - if (fMatrix) - glMultMatrixf(fMatrix->readArray()); - if (b_Anim) - RaAnimation(b_Anim); - } - if (eType < TP_ROTATOR) - { // renderowanie obiektów OpenGL - if (iAlpha & iFlags & 0x1F) // rysuj gdy element nieprzezroczysty - { - if (TextureID < 0) // && (ReplacableSkinId!=0)) - { // zmienialne skóry - GfxRenderer.Bind(ReplacableSkinId[-TextureID]); - // TexAlpha=!(iAlpha&1); //zmiana tylko w przypadku wymienej tekstury - } - else - GfxRenderer.Bind(TextureID); // również 0 - if (Global::fLuminance < fLight) - { - glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo - glCallList(uiDisplayList); // tylko dla siatki - glMaterialfv(GL_FRONT, GL_EMISSION, emm2); - } - else - glCallList(uiDisplayList); // tylko dla siatki - } - } - else if (eType == TP_FREESPOTLIGHT) - { // wersja DL - matrix4x4 mat; // macierz opisuje układ renderowania względem kamery - glGetDoublev(GL_MODELVIEW_MATRIX, mat.getArray()); - // kąt między kierunkiem światła a współrzędnymi kamery - vector3 gdzie = mat * vector3(0, 0, 0); // pozycja punktu świecącego względem kamery - fCosViewAngle = DotProduct(Normalize(mat * vector3(0, 0, 1) - gdzie), Normalize(gdzie)); - if (fCosViewAngle > fCosFalloffAngle) // kąt większy niż maksymalny stożek swiatła - { - double Distdimm = 1.0; - if (fCosViewAngle < - fCosHotspotAngle) // zmniejszona jasność między Hotspot a Falloff - if (fCosFalloffAngle < fCosHotspotAngle) - Distdimm = 1.0 - - (fCosHotspotAngle - fCosViewAngle) / - (fCosHotspotAngle - fCosFalloffAngle); - glColor3f(f4Diffuse[0] * Distdimm, f4Diffuse[1] * Distdimm, - f4Diffuse[2] * Distdimm); - /* TODO: poprawic to zeby dzialalo - if (iFarAttenDecay>0) - switch (iFarAttenDecay) - { - case 1: - Distdimm=fFarDecayRadius/(1+sqrt(fSquareDist)); - //dorobic od kata - break; - case 2: - Distdimm=fFarDecayRadius/(1+fSquareDist); - //dorobic od kata - break; - } - if (Distdimm>1) - Distdimm=1; - glColor3f(Diffuse[0]*Distdimm,Diffuse[1]*Distdimm,Diffuse[2]*Distdimm); - */ - // glPopMatrix(); - // return; - glCallList(uiDisplayList); // wyświetlenie warunkowe - } - } - else if (eType == TP_STARS) - { - // glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie - // blendowaly - if (Global::fLuminance < fLight) - { - glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo - glCallList(uiDisplayList); // narysuj naraz wszystkie punkty z DL - glMaterialfv(GL_FRONT, GL_EMISSION, emm2); - } - } - if (Child != NULL) - if (iAlpha & iFlags & 0x001F0000) - Child->RenderDL(); - if (iFlags & 0xC000) - glPopMatrix(); - } - if (b_Anim < at_SecondsJump) - b_Anim = at_None; // wyłączenie animacji dla kolejnego użycia subm - if (Next) - if (iAlpha & iFlags & 0x1F000000) - Next->RenderDL(); // dalsze rekurencyjnie -}; // Render - -void TSubModel::RenderAlphaDL() -{ // renderowanie przezroczystych przez DL - if( ( iVisible ) - && ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) ) - && ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) ) - { - if (iFlags & 0xC000) - { - glPushMatrix(); - if (fMatrix) - glMultMatrixf(fMatrix->readArray()); - if (b_aAnim) - RaAnimation(b_aAnim); - } - if (eType < TP_ROTATOR) - { // renderowanie obiektów OpenGL - if (iAlpha & iFlags & 0x2F) // rysuj gdy element przezroczysty - { - if (TextureID < 0) // && (ReplacableSkinId!=0)) - { // zmienialne skóry - GfxRenderer.Bind(ReplacableSkinId[-TextureID]); - // TexAlpha=iAlpha&1; //zmiana tylko w przypadku wymienej tekstury - } - else - GfxRenderer.Bind(TextureID); // również 0 - if (Global::fLuminance < fLight) - { - glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo - glCallList(uiDisplayList); // tylko dla siatki - glMaterialfv(GL_FRONT, GL_EMISSION, emm2); - } - else - glCallList(uiDisplayList); // tylko dla siatki - } - } - else if (eType == TP_FREESPOTLIGHT) - { - // dorobić aureolę! - } - if (Child != NULL) - if (eType == TP_TEXT) - { // tekst renderujemy w specjalny sposób, zamiast - // submodeli z łańcucha Child - int i, j = (int)pasText->size(); - TSubModel *p; - if (!smLetter) - { // jeśli nie ma tablicy, to ją stworzyć; miejsce - // nieodpowiednie, ale tymczasowo - // może być - smLetter = new TSubModel *[256]; // tablica wskaźników submodeli dla - // wyświetlania tekstu - ZeroMemory(smLetter, 256 * sizeof(TSubModel *)); // wypełnianie zerami - p = Child; - while (p) - { - smLetter[p->pName[0]] = p; - p = p->Next; // kolejny znak - } - } - for (i = 1; i <= j; ++i) - { - p = smLetter[(*pasText)[i]]; // znak do wyświetlenia - if (p) - { // na razie tylko jako przezroczyste - p->RenderAlphaDL(); - if (p->fMatrix) - glMultMatrixf(p->fMatrix->readArray()); // przesuwanie widoku - } - } - } - else if (iAlpha & iFlags & 0x002F0000) - Child->RenderAlphaDL(); - if (iFlags & 0xC000) - glPopMatrix(); - } - if (b_aAnim < at_SecondsJump) - b_aAnim = at_None; // wyłączenie animacji dla kolejnego użycia submodelu - if (Next != NULL) - if (iAlpha & iFlags & 0x2F000000) - Next->RenderAlphaDL(); -}; // RenderAlpha - -void TSubModel::RenderVBO() -{ // główna procedura renderowania przez VBO - if( ( iVisible ) - && ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) ) - && ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) ) - { - if (iFlags & 0xC000) - { - glPushMatrix(); - if (fMatrix) - glMultMatrixf(fMatrix->readArray()); - if (b_Anim) - RaAnimation(b_Anim); - } - if (eType < TP_ROTATOR) - { // renderowanie obiektów OpenGL - if (iAlpha & iFlags & 0x1F) // rysuj gdy element nieprzezroczysty - { - if (TextureID < 0) // && (ReplacableSkinId!=0)) - { // zmienialne skóry - GfxRenderer.Bind(ReplacableSkinId[-TextureID]); - // TexAlpha=!(iAlpha&1); //zmiana tylko w przypadku wymienej tekstury - } - else - GfxRenderer.Bind(TextureID); // również 0 - glColor3fv(f4Diffuse); // McZapkie-240702: zamiast ub - // glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,f4Diffuse); //to samo, - // co glColor - if (Global::fLuminance < fLight) - { - glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo - glDrawArrays(eType, iVboPtr, - iNumVerts); // narysuj naraz wszystkie trójkąty z VBO - glMaterialfv(GL_FRONT, GL_EMISSION, emm2); - } - else - glDrawArrays(eType, iVboPtr, - iNumVerts); // narysuj naraz wszystkie trójkąty z VBO - } - } - else if (eType == TP_FREESPOTLIGHT) - { // wersja VBO -/* - matrix4x4 mat; // macierz opisuje układ renderowania względem kamery - glGetDoublev(GL_MODELVIEW_MATRIX, mat.getArray()); -*/ - matrix4x4 mat; mat.OpenGL_Matrix( OpenGLMatrices.data_array( GL_MODELVIEW ) ); - // kąt między kierunkiem światła a współrzędnymi kamery - vector3 gdzie = mat * vector3(0, 0, 0); // pozycja punktu świecącego względem kamery - fCosViewAngle = DotProduct(Normalize(mat * vector3(0, 0, 1) - gdzie), Normalize(gdzie)); - if (fCosViewAngle > fCosFalloffAngle) // kąt większy niż maksymalny stożek swiatła - { - double Distdimm = 1.0; - if (fCosViewAngle < - fCosHotspotAngle) // zmniejszona jasność między Hotspot a Falloff - if (fCosFalloffAngle < fCosHotspotAngle) - Distdimm = 1.0 - - (fCosHotspotAngle - fCosViewAngle) / - (fCosHotspotAngle - fCosFalloffAngle); - - /* TODO: poprawic to zeby dzialalo - - 2- Inverse (Applies inverse decay. The formula is luminance=R0/R, where - R0 is - the radial source of the light if no attenuation is - used, or the Near End - value of the light if Attenuation is used. R is the - radial distance of the - illuminated surface from R0.) - - 3- Inverse Square (Applies inverse-square decay. The formula for this is - (R0/R)^2. - This is actually the "real-world" decay of light, but - you might find it too dim - in the world of computer graphics.) - - .DecayRadius -- The distance over which the decay occurs. - - if (iFarAttenDecay>0) - switch (iFarAttenDecay) - { - case 1: - Distdimm=fFarDecayRadius/(1+sqrt(fSquareDist)); - //dorobic od kata - break; - case 2: - Distdimm=fFarDecayRadius/(1+fSquareDist); - //dorobic od kata - break; - } - if (Distdimm>1) - Distdimm=1; - - */ - GfxRenderer.Bind(0); // nie teksturować - // glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]); - // glColorMaterial(GL_FRONT,GL_EMISSION); - float color[4] = { (float)(f4Diffuse[0] * Distdimm), (float)(f4Diffuse[1] * Distdimm), - (float)(f4Diffuse[2] * Distdimm), 0 }; - // glColor3f(f4Diffuse[0]*Distdimm,f4Diffuse[1]*Distdimm,f4Diffuse[2]*Distdimm); - glColorMaterial(GL_FRONT, GL_EMISSION); - glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie - // blendowaly - glColor3fv(color); // inaczej są białe - glMaterialfv(GL_FRONT, GL_EMISSION, color); - glDrawArrays(GL_POINTS, iVboPtr, iNumVerts); // narysuj wierzchołek z - // VBO - glEnable(GL_LIGHTING); - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // co ma ustawiać glColor - glMaterialfv(GL_FRONT, GL_EMISSION, emm2); // bez tego słupy się świecą - } - } - else if (eType == TP_STARS) - { - // glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie - // blendowaly - if (Global::fLuminance < fLight) - { // Ra: pewnie można by to zrobić - // lepiej, bez powtarzania StartVBO() - pRoot->EndVBO(); // Ra: to też nie jest zbyt ładne - if (pRoot->StartColorVBO()) - { // wyświetlanie kolorowych punktów zamiast - // trójkątów - GfxRenderer.Bind(0); // tekstury nie ma - glColorMaterial(GL_FRONT, GL_EMISSION); - glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie - // blendowaly - // glMaterialfv(GL_FRONT,GL_EMISSION,f4Diffuse); //zeby swiecilo na - // kolorowo - glDrawArrays(GL_POINTS, iVboPtr, - iNumVerts); // narysuj naraz wszystkie punkty z VBO - glEnable(GL_LIGHTING); - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); - // glMaterialfv(GL_FRONT,GL_EMISSION,emm2); - pRoot->EndVBO(); - pRoot->StartVBO(); - } - } - } - /*Ra: tu coś jest bez sensu... - else - { - glBindTexture(GL_TEXTURE_2D, 0); - // if (eType==smt_FreeSpotLight) - // { - // if (iFarAttenDecay==0) - // glColor3f(Diffuse[0],Diffuse[1],Diffuse[2]); - // } - // else - //TODO: poprawic zeby dzialalo - glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]); - glColorMaterial(GL_FRONT,GL_EMISSION); - glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty - swiecace sie blendowaly - //glBegin(GL_POINTS); - glDrawArrays(GL_POINTS,iVboPtr,iNumVerts); //narysuj - wierzchołek z VBO - // glVertex3f(0,0,0); - //glEnd(); - glEnable(GL_LIGHTING); - glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); - glMaterialfv(GL_FRONT,GL_EMISSION,emm2); - //glEndList(); - } - */ - if (Child != NULL) - if (iAlpha & iFlags & 0x001F0000) - Child->RenderVBO(); - if (iFlags & 0xC000) - glPopMatrix(); - } - if (b_Anim < at_SecondsJump) - b_Anim = at_None; // wyłączenie animacji dla kolejnego użycia submodelu - if (Next) - if (iAlpha & iFlags & 0x1F000000) - Next->RenderVBO(); // dalsze rekurencyjnie -}; // RaRender - -void TSubModel::RenderAlphaVBO() -{ // renderowanie przezroczystych przez VBO - if( ( iVisible ) - && ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) ) - && ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) ) - { - if (iFlags & 0xC000) - { - glPushMatrix(); // zapamiętanie matrycy - if (fMatrix) - glMultMatrixf(fMatrix->readArray()); - if (b_aAnim) - RaAnimation(b_aAnim); - } - glColor3fv(f4Diffuse); - if (eType < TP_ROTATOR) - { // renderowanie obiektów OpenGL - if (iAlpha & iFlags & 0x2F) // rysuj gdy element przezroczysty - { - if (TextureID < 0) // && (ReplacableSkinId!=0)) - { // zmienialne skory - GfxRenderer.Bind(ReplacableSkinId[-TextureID]); - // TexAlpha=iAlpha&1; //zmiana tylko w przypadku wymienej tekstury - } - else - GfxRenderer.Bind(TextureID); // również 0 - if (Global::fLuminance < fLight) - { - glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo - glDrawArrays(eType, iVboPtr, - iNumVerts); // narysuj naraz wszystkie trójkąty z VBO - glMaterialfv(GL_FRONT, GL_EMISSION, emm2); - } - else - glDrawArrays(eType, iVboPtr, - iNumVerts); // narysuj naraz wszystkie trójkąty z VBO - } - } - else if (eType == TP_FREESPOTLIGHT) - { - // dorobić aureolę! - } - if (Child) - if (iAlpha & iFlags & 0x002F0000) - Child->RenderAlphaVBO(); - if (iFlags & 0xC000) - glPopMatrix(); - } - if (b_aAnim < at_SecondsJump) - b_aAnim = at_None; // wyłączenie animacji dla kolejnego użycia submodelu - if (Next) - if (iAlpha & iFlags & 0x2F000000) - Next->RenderAlphaVBO(); -}; // RaRenderAlpha -#endif //--------------------------------------------------------------------------- void TSubModel::RaArrayFill(CVertNormTex *Vert) @@ -2212,140 +1797,6 @@ void TModel3d::BreakHierarhy() Error("Not implemented yet :("); }; -#ifdef EU07_USE_OLD_RENDERCODE -void TModel3d::Render(double fSquareDistance, texture_manager::size_type *ReplacableSkinId, int iAlpha) -{ - iAlpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste - if (iAlpha & iFlags & 0x1F1F001F) // czy w ogóle jest co robić w tym cyklu? - { - TSubModel::fSquareDist = fSquareDistance; // zmienna globalna! - Root->ReplacableSet(ReplacableSkinId, iAlpha); - Root->RenderDL(); - } -}; - -void TModel3d::RenderAlpha(double fSquareDistance, texture_manager::size_type *ReplacableSkinId, int iAlpha) -{ - if (iAlpha & iFlags & 0x2F2F002F) - { - TSubModel::fSquareDist = fSquareDistance; // zmienna globalna! - Root->ReplacableSet(ReplacableSkinId, iAlpha); - Root->RenderAlphaDL(); - } -}; - -void TModel3d::RaRender(double fSquareDistance, texture_manager::size_type const *ReplacableSkinId, int iAlpha) -{ // renderowanie specjalne, np. kabiny - iAlpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste - if (iAlpha & iFlags & 0x1F1F001F) // czy w ogóle jest co robić w tym cyklu? - { - TSubModel::fSquareDist = fSquareDistance; // zmienna globalna! - if (StartVBO()) - { // odwrócenie flag, aby wyłapać nieprzezroczyste - Root->ReplacableSet(ReplacableSkinId, iAlpha); - Root->pRoot = this; - Root->RenderVBO(); - EndVBO(); - } - } -}; - -void TModel3d::RaRenderAlpha(double fSquareDistance, texture_manager::size_type const *ReplacableSkinId, int iAlpha) -{ // renderowanie specjalne, np. kabiny - if (iAlpha & iFlags & 0x2F2F002F) // czy w ogóle jest co robić w tym cyklu? - { - TSubModel::fSquareDist = fSquareDistance; // zmienna globalna! - if (StartVBO()) - { - Root->ReplacableSet(ReplacableSkinId, iAlpha); - Root->RenderAlphaVBO(); - EndVBO(); - } - } -}; -#endif -//----------------------------------------------------------------------------- -// 2011-03-16 cztery nowe funkcje renderowania z możliwością pochylania obiektów -//----------------------------------------------------------------------------- -#ifdef EU07_USE_OLD_RENDERCODE -void TModel3d::Render(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId, int iAlpha) -{ // nieprzezroczyste, Display List - glPushMatrix(); - glTranslated(vPosition->x, vPosition->y, vPosition->z); - if (vAngle->y != 0.0) - glRotated(vAngle->y, 0.0, 1.0, 0.0); - if (vAngle->x != 0.0) - glRotated(vAngle->x, 1.0, 0.0, 0.0); - if (vAngle->z != 0.0) - glRotated(vAngle->z, 0.0, 0.0, 1.0); - TSubModel::fSquareDist = - SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna! - // odwrócenie flag, aby wyłapać nieprzezroczyste - Root->ReplacableSet(ReplacableSkinId, iAlpha ^ 0x0F0F000F); - Root->RenderDL(); - glPopMatrix(); -}; -void TModel3d::RenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId, - int iAlpha) -{ // przezroczyste, Display List - glPushMatrix(); - glTranslated(vPosition->x, vPosition->y, vPosition->z); - if (vAngle->y != 0.0) - glRotated(vAngle->y, 0.0, 1.0, 0.0); - if (vAngle->x != 0.0) - glRotated(vAngle->x, 1.0, 0.0, 0.0); - if (vAngle->z != 0.0) - glRotated(vAngle->z, 0.0, 0.0, 1.0); - TSubModel::fSquareDist = - SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna! - Root->ReplacableSet(ReplacableSkinId, iAlpha); - Root->RenderAlphaDL(); - glPopMatrix(); -}; - -void TModel3d::RaRender(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type const *ReplacableSkinId, int iAlpha) -{ // nieprzezroczyste, VBO - glPushMatrix(); - glTranslated(vPosition->x, vPosition->y, vPosition->z); - if (vAngle->y != 0.0) - glRotated(vAngle->y, 0.0, 1.0, 0.0); - if (vAngle->x != 0.0) - glRotated(vAngle->x, 1.0, 0.0, 0.0); - if (vAngle->z != 0.0) - glRotated(vAngle->z, 0.0, 0.0, 1.0); - TSubModel::fSquareDist = - SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna! - if (StartVBO()) - { // odwrócenie flag, aby wyłapać nieprzezroczyste - Root->ReplacableSet(ReplacableSkinId, iAlpha ^ 0x0F0F000F); - Root->RenderVBO(); - EndVBO(); - } - glPopMatrix(); -}; -void TModel3d::RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type const *ReplacableSkinId, - int iAlpha) -{ // przezroczyste, VBO - glPushMatrix(); - glTranslated(vPosition->x, vPosition->y, vPosition->z); - if (vAngle->y != 0.0) - glRotated(vAngle->y, 0.0, 1.0, 0.0); - if (vAngle->x != 0.0) - glRotated(vAngle->x, 1.0, 0.0, 0.0); - if (vAngle->z != 0.0) - glRotated(vAngle->z, 0.0, 0.0, 1.0); - TSubModel::fSquareDist = - SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna! - if (StartVBO()) - { - Root->ReplacableSet(ReplacableSkinId, iAlpha); - Root->RenderAlphaVBO(); - EndVBO(); - } - glPopMatrix(); -}; -#endif - //----------------------------------------------------------------------------- // 2012-02 funkcje do tworzenia terenu z E3D //----------------------------------------------------------------------------- diff --git a/Model3d.h b/Model3d.h index f3942b56..ae650785 100644 --- a/Model3d.h +++ b/Model3d.h @@ -255,12 +255,6 @@ public: void SetRotateIK1(float3 vNewAngles); TSubModel * GetFromName(std::string const &search, bool i = true); TSubModel * GetFromName(char const *search, bool i = true); -#ifdef EU07_USE_OLD_RENDERCODE - void RenderDL(); - void RenderAlphaDL(); - void RenderVBO(); - void RenderAlphaVBO(); -#endif // inline matrix4x4* GetMatrix() {return dMatrix;}; inline float4x4 * GetMatrix() { @@ -361,20 +355,6 @@ public: bool LoadFromFile(std::string const &FileName, bool dynamic); void SaveToBinFile(char const *FileName); void BreakHierarhy(); - // renderowanie specjalne -#ifdef EU07_USE_OLD_RENDERCODE - void Render(double fSquareDistance, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RenderAlpha(double fSquareDistance, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); -#endif - void RaRender(double fSquareDistance, texture_manager::size_type const *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RaRenderAlpha(double fSquareDistance, texture_manager::size_type const *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - // trzy kąty obrotu -#ifdef EU07_USE_OLD_RENDERCODE - void Render( vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030 ); - void RenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); -#endif - void RaRender(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type const *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type const *ReplacableSkinId = NULL, int iAlpha = 0x30300030); // inline int GetSubModelsCount() { return (SubModelsCount); }; int Flags() const { diff --git a/Segment.h b/Segment.h index b027d123..1c4c84ab 100644 --- a/Segment.h +++ b/Segment.h @@ -17,8 +17,6 @@ http://mozilla.org/MPL/2.0/. using namespace Math3D; -#define EU07_DEBUG_VBO - // 110405 Ra: klasa punktów przekroju z normalnymi class vector6 : public vector3 diff --git a/Track.cpp b/Track.cpp index c8672c80..b0920ad9 100644 --- a/Track.cpp +++ b/Track.cpp @@ -2595,11 +2595,7 @@ void TTrack::RenderDyn() { // renderowanie nieprzezroczystych fragmentów pojazdów for( auto dynamic : Dynamics ) { // sam sprawdza, czy VBO; zmienia kontekst VBO! -#ifdef EU07_USE_OLD_RENDERCODE - dynamic->Render(); -#else GfxRenderer.Render( dynamic ); -#endif } }; @@ -2607,11 +2603,7 @@ void TTrack::RenderDynAlpha() { // renderowanie przezroczystych fragmentów pojazdów for( auto dynamic : Dynamics ) { // sam sprawdza, czy VBO; zmienia kontekst VBO! -#ifdef EU07_USE_OLD_RENDERCODE - dynamic->RenderAlpha(); -#else GfxRenderer.Render_Alpha( dynamic ); -#endif } }; diff --git a/World.cpp b/World.cpp index 0bcfe03c..d7fa9bae 100644 --- a/World.cpp +++ b/World.cpp @@ -906,43 +906,52 @@ void TWorld::DistantView( bool const Near ) Camera.RaLook(); // jednorazowe przestawienie kamery }; -void TWorld::FollowView(bool wycisz) -{ // ustawienie śledzenia pojazdu +// ustawienie śledzenia pojazdu +void TWorld::FollowView(bool wycisz) { + Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na południe + if (Controlled) // jest pojazd do prowadzenia? { - vector3 camStara = - Camera.Pos; // przestawianie kamery jest bez sensu: do przerobienia na potem - // Controlled->ABuSetModelShake(vector3(0,0,0)); + Ground.Silence( Camera.Pos ); // wyciszenie dźwięków z poprzedniej pozycji + if (FreeFlyModeFlag) { // jeżeli poza kabiną, przestawiamy w jej okolicę - OK - if (Train) - Train->Dynamic()->ABuSetModelShake( - vector3(0, 0, 0)); // wyłączenie trzęsienia na siłę? - // Camera.Pos=Train->pMechPosition+Normalize(Train->GetDirection())*20; + if( Train ) { + // wyłączenie trzęsienia na siłę? + Train->Dynamic()->ABuSetModelShake( vector3() ); + } + DistantView(); // przestawienie kamery //żeby nie bylo numerów z 'fruwajacym' lokiem - konsekwencja bujania pudła - Global::SetCameraPosition( - Camera.Pos); // tu ustawić nową, bo od niej liczą się odległości - Ground.Silence(camStara); // wyciszenie dźwięków z poprzedniej pozycji + // tu ustawić nową, bo od niej liczą się odległości + Global::SetCameraPosition( Camera.Pos ); } else if (Train) { // korekcja ustawienia w kabinie - OK - vector3 camStara = Camera.Pos; // przestawianie kamery jest bez sensu: do przerobienia na potem - // Ra: czy to tu jest potrzebne, bo przelicza się kawałek dalej? - Camera.Pos = Train->pMechPosition; // Train.GetPosition1(); + if( wycisz ) { + // wyciszenie dźwięków z poprzedniej pozycji + // trzymanie prawego w kabinie daje marny efekt + Ground.Silence( Camera.Pos ); + } + Camera.Pos = Train->pMechPosition; Camera.Roll = std::atan(Train->pMechShake.x * Train->fMechRoll); // hustanie kamery na boki Camera.Pitch -= 0.5 * std::atan(Train->vMechVelocity.z * Train->fMechPitch); // hustanie kamery przod tyl - if (Train->Dynamic()->MoverParameters->ActiveCab == 0) - Camera.LookAt = Train->pMechPosition + Train->GetDirection() * 5.0; - else // patrz w strone wlasciwej kabiny - Camera.LookAt = Train->pMechPosition + Train->GetDirection() * 5.0 * Train->Dynamic()->MoverParameters->ActiveCab; - Train->pMechOffset.x = Train->pMechSittingPosition.x; - Train->pMechOffset.y = Train->pMechSittingPosition.y; - Train->pMechOffset.z = Train->pMechSittingPosition.z; + + if( Train->Dynamic()->MoverParameters->ActiveCab == 0 ) { + Camera.LookAt = + Train->pMechPosition + + Train->GetDirection() * 5.0; + } + else { + // patrz w strone wlasciwej kabiny + Camera.LookAt = + Train->pMechPosition + + Train->GetDirection() * 5.0 * Train->Dynamic()->MoverParameters->ActiveCab; + } + Train->pMechOffset = Train->pMechSittingPosition; + Global::SetCameraPosition( Train->Dynamic() ->GetPosition()); // tu ustawić nową, bo od niej liczą się odległości - if (wycisz) // trzymanie prawego w kabinie daje marny efekt - Ground.Silence(camStara); // wyciszenie dźwięków z poprzedniej pozycji } } else @@ -1239,105 +1248,7 @@ TWorld::Update_Camera( double const Deltatime ) { void TWorld::Update_Environment() { -#ifdef EU07_USE_OLD_LIGHTING_MODEL - - if( Global::fMoveLight < 0.0 ) { - return; - } - - // double a=Global::fTimeAngleDeg/180.0*M_PI-M_PI; //kąt godzinny w radianach - double a = fmod( Global::fTimeAngleDeg, 360.0 ) / 180.0 * M_PI - - M_PI; // kąt godzinny w radianach - //(a) jest traktowane jako czas miejscowy, nie uwzględniający stref czasowych ani czasu - // letniego - // aby wyznaczyć strefę czasową, trzeba uwzględnić południk miejscowy - // aby uwzględnić czas letni, trzeba sprawdzić dzień roku - double L = Global::fLatitudeDeg / 180.0 * M_PI; // szerokość geograficzna - double H = asin( cos( L ) * cos( Global::fSunDeclination ) * cos( a ) + - sin( L ) * sin( Global::fSunDeclination ) ); // kąt ponad horyzontem - // double A=asin(cos(d)*sin(M_PI-a)/cos(H)); - // Declination=((0.322003-22.971*cos(t)-0.357898*cos(2*t)-0.14398*cos(3*t)+3.94638*sin(t)+0.019334*sin(2*t)+0.05928*sin(3*t)))*Pi/180 - // Altitude=asin(sin(Declination)*sin(latitude)+cos(Declination)*cos(latitude)*cos((15*(time-12))*(Pi/180))); - // Azimuth=(acos((cos(latitude)*sin(Declination)-cos(Declination)*sin(latitude)*cos((15*(time-12))*(Pi/180)))/cos(Altitude))); - // double A=acos(cos(L)*sin(d)-cos(d)*sin(L)*cos(M_PI-a)/cos(H)); - // dAzimuth = atan2(-sin( dHourAngle ),tan( dDeclination )*dCos_Latitude - - // dSin_Latitude*dCos_HourAngle ); - double A = atan2( sin( a ), tan( Global::fSunDeclination ) * cos( L ) - sin( L ) * cos( a ) ); - vector3 lp = vector3( sin( A ), tan( H ), cos( A ) ); - lp = Normalize( lp ); // przeliczenie na wektor długości 1.0 - Global::lightPos[ 0 ] = (float)lp.x; - Global::lightPos[ 1 ] = (float)lp.y; - Global::lightPos[ 2 ] = (float)lp.z; - glLightfv( GL_LIGHT0, GL_POSITION, Global::lightPos ); // daylight position - if( H > 0 ) { // słońce ponad horyzontem - Global::ambientDayLight[ 0 ] = Global::ambientLight[ 0 ]; - Global::ambientDayLight[ 1 ] = Global::ambientLight[ 1 ]; - Global::ambientDayLight[ 2 ] = Global::ambientLight[ 2 ]; - if( H > 0.02 ) // ponad 1.146° zaczynają się cienie - { - Global::diffuseDayLight[ 0 ] = - Global::diffuseLight[ 0 ]; // od wschodu do zachodu maksimum ??? - Global::diffuseDayLight[ 1 ] = Global::diffuseLight[ 1 ]; - Global::diffuseDayLight[ 2 ] = Global::diffuseLight[ 2 ]; - Global::specularDayLight[ 0 ] = Global::specularLight[ 0 ]; // podobnie specular - Global::specularDayLight[ 1 ] = Global::specularLight[ 1 ]; - Global::specularDayLight[ 2 ] = Global::specularLight[ 2 ]; - } - else { - Global::diffuseDayLight[ 0 ] = - 50 * H * Global::diffuseLight[ 0 ]; // wschód albo zachód - Global::diffuseDayLight[ 1 ] = 50 * H * Global::diffuseLight[ 1 ]; - Global::diffuseDayLight[ 2 ] = 50 * H * Global::diffuseLight[ 2 ]; - Global::specularDayLight[ 0 ] = - 50 * H * Global::specularLight[ 0 ]; // podobnie specular - Global::specularDayLight[ 1 ] = 50 * H * Global::specularLight[ 1 ]; - Global::specularDayLight[ 2 ] = 50 * H * Global::specularLight[ 2 ]; - } - } - else { // słońce pod horyzontem - GLfloat lum = 3.1831 * ( H > -0.314159 ? 0.314159 + H : - 0.0 ); // po zachodzie ambient się ściemnia - Global::ambientDayLight[ 0 ] = lum * Global::ambientLight[ 0 ]; - Global::ambientDayLight[ 1 ] = lum * Global::ambientLight[ 1 ]; - Global::ambientDayLight[ 2 ] = lum * Global::ambientLight[ 2 ]; - Global::diffuseDayLight[ 0 ] = - Global::noLight[ 0 ]; // od zachodu do wschodu nie ma diffuse - Global::diffuseDayLight[ 1 ] = Global::noLight[ 1 ]; - Global::diffuseDayLight[ 2 ] = Global::noLight[ 2 ]; - Global::specularDayLight[ 0 ] = Global::noLight[ 0 ]; // ani specular - Global::specularDayLight[ 1 ] = Global::noLight[ 1 ]; - Global::specularDayLight[ 2 ] = Global::noLight[ 2 ]; - } - // Calculate sky colour according to time of day. - // GLfloat sin_t = sin(PI * time_of_day / 12.0); - // back_red = 0.3 * (1.0 - sin_t); - // back_green = 0.9 * sin_t; - // back_blue = sin_t + 0.4, 1.0; - // aktualizacja świateł - glLightfv( GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight ); - glLightfv( GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight ); - glLightfv( GL_LIGHT0, GL_SPECULAR, Global::specularDayLight ); - - Global::fLuminance = // to posłuży również do zapalania latarń - +0.150 * ( Global::diffuseDayLight[ 0 ] + Global::ambientDayLight[ 0 ] ) // R - + 0.295 * ( Global::diffuseDayLight[ 1 ] + Global::ambientDayLight[ 1 ] ) // G - + 0.055 * ( Global::diffuseDayLight[ 2 ] + Global::ambientDayLight[ 2 ] ); // B - - vector3 sky = vector3( Global::AtmoColor[ 0 ], Global::AtmoColor[ 1 ], Global::AtmoColor[ 2 ] ); - if( Global::fLuminance < 0.25 ) { // przyspieszenie zachodu/wschodu - sky *= 4.0 * Global::fLuminance; // nocny kolor nieba - GLfloat fog[ 3 ]; - fog[ 0 ] = Global::FogColor[ 0 ] * 4.0 * Global::fLuminance; - fog[ 1 ] = Global::FogColor[ 1 ] * 4.0 * Global::fLuminance; - fog[ 2 ] = Global::FogColor[ 2 ] * 4.0 * Global::fLuminance; - glFogfv( GL_FOG_COLOR, fog ); // nocny kolor mgły - } - else { - glFogfv( GL_FOG_COLOR, Global::FogColor ); // kolor mgły - } -#else Environment.update(); -#endif } void TWorld::ResourceSweep() @@ -1364,11 +1275,7 @@ TWorld::Render_Cab() { // ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka return; } -/* - // ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka - if( ( Train->Dynamic()->mdKabina != Train->Dynamic()->mdModel ) && - Train->Dynamic()->bDisplayCab && !FreeFlyModeFlag ) { -*/ + glPushMatrix(); vector3 pos = dynamic->GetPosition(); // wszpółrzędne pojazdu z kabiną // glTranslatef(pos.x,pos.y,pos.z); //przesunięcie o wektor (tak było i trzęsło) @@ -1377,247 +1284,24 @@ TWorld::Render_Cab() { glLoadIdentity(); // zacząć od macierzy jedynkowej Camera.SetCabMatrix( pos ); // widok z kamery po przesunięciu glMultMatrixd( dynamic->mMatrix.getArray() ); // ta macierz nie ma przesunięcia -/* - //*yB: moje smuuugi 1 - if( Global::bSmudge ) { // Ra: uwzględniłem zacienienie pojazdu przy zapalaniu smug - - // 1. warunek na smugę wyznaczyc wcześniej - // 2. jeśli smuga włączona, nie renderować pojazdu użytkownika w DynObj - // 3. jeśli smuga właczona, wyrenderować pojazd użytkownia po dodaniu smugi do sceny - auto const &frontlights = Train->Controlled()->iLights[ 0 ]; - float frontlightstrength = 0.f + - ( ( frontlights & 1 ) ? 0.3f : 0.f ) + - ( ( frontlights & 4 ) ? 0.3f : 0.f ) + - ( ( frontlights & 16 ) ? 0.3f : 0.f ); - frontlightstrength = std::max( frontlightstrength - Global::fLuminance, 0.0 ); - auto const &rearlights = Train->Controlled()->iLights[ 1 ]; - float rearlightstrength = 0.f + - ( ( rearlights & 1 ) ? 0.3f : 0.f ) + - ( ( rearlights & 4 ) ? 0.3f : 0.f ) + - ( ( rearlights & 16 ) ? 0.3f : 0.f ); - rearlightstrength = std::max( rearlightstrength - Global::fLuminance, 0.0 ); - - if( ( Train->Controlled()->Battery ) // trochę na skróty z tą baterią - && ( ( frontlightstrength > 0.f ) - || ( rearlightstrength > 0.f ) ) ) { - - if( Global::bOldSmudge == true ) { - glBlendFunc( GL_SRC_ALPHA, GL_ONE ); - // glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_DST_COLOR); - // glBlendFunc(GL_SRC_ALPHA_SATURATE,GL_ONE); - glDisable( GL_DEPTH_TEST ); - glDisable( GL_LIGHTING ); - glDisable( GL_FOG ); - GfxRenderer.Bind( light ); // Select our texture - glBegin( GL_QUADS ); - float fSmudge = - dynamic->MoverParameters->DimHalf.y + 7; // gdzie zaczynać smugę - if( frontlightstrength > 0.f ) { // wystarczy jeden zapalony z przodu - glColor4f( 1.0f, 1.0f, 1.0f, 0.5f * frontlightstrength ); - glTexCoord2f( 0, 0 ); - glVertex3f( 15.0, 0.0, +fSmudge ); // rysowanie względem położenia modelu - glTexCoord2f( 1, 0 ); - glVertex3f( -15.0, 0.0, +fSmudge ); - glTexCoord2f( 1, 1 ); - glVertex3f( -15.0, 2.5, 250.0 ); - glTexCoord2f( 0, 1 ); - glVertex3f( 15.0, 2.5, 250.0 ); - } - if( rearlightstrength > 0.f ) { // wystarczy jeden zapalony z tyłu - glColor4f( 1.0f, 1.0f, 1.0f, 0.5f * rearlightstrength ); - glTexCoord2f( 0, 0 ); - glVertex3f( -15.0, 0.0, -fSmudge ); - glTexCoord2f( 1, 0 ); - glVertex3f( 15.0, 0.0, -fSmudge ); - glTexCoord2f( 1, 1 ); - glVertex3f( 15.0, 2.5, -250.0 ); - glTexCoord2f( 0, 1 ); - glVertex3f( -15.0, 2.5, -250.0 ); - } - glEnd(); - - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - glEnable( GL_DEPTH_TEST ); - // glEnable(GL_LIGHTING); //i tak się włączy potem - glEnable( GL_FOG ); - } - else { - - glBlendFunc( GL_DST_COLOR, GL_ONE ); - glDepthFunc( GL_GEQUAL ); - glAlphaFunc( GL_GREATER, 0.004 ); - // glDisable(GL_DEPTH_TEST); - glDisable( GL_LIGHTING ); - glDisable( GL_FOG ); - //glColor4f(0.15f, 0.15f, 0.15f, 0.25f); - GfxRenderer.Bind( light ); // Select our texture - //float ddl = (0.15*Global::diffuseDayLight[0]+0.295*Global::diffuseDayLight[1]+0.055*Global::diffuseDayLight[2]); //0.24:0 - glBegin( GL_QUADS ); - float fSmudge = dynamic->MoverParameters->DimHalf.y + 7; // gdzie zaczynać smugę - if( frontlightstrength > 0.f ) { - // wystarczy jeden zapalony z przodu - for( int i = 15; i <= 35; i++ ) { - float z = i * i * i * 0.01f;//25/4; - //float C = (36 - i*0.5)*0.005*(1.5 - sqrt(ddl)); - float C = ( 36 - i*0.5 )*0.005*sqrt( ( 1 / sqrt( Global::fLuminance + 0.015 ) ) - 1 ) * frontlightstrength; - glColor4f( C, C, C, 1.0f );// *frontlightstrength ); - glTexCoord2f( 0, 0 ); glVertex3f( -10 / 2 - 2 * i / 4, 6.0 + 0.3*z, 13 + 1.7*z / 3 ); - glTexCoord2f( 1, 0 ); glVertex3f( 10 / 2 + 2 * i / 4, 6.0 + 0.3*z, 13 + 1.7*z / 3 ); - glTexCoord2f( 1, 1 ); glVertex3f( 10 / 2 + 2 * i / 4, -5.0 - 0.5*z, 13 + 1.7*z / 3 ); - glTexCoord2f( 0, 1 ); glVertex3f( -10 / 2 - 2 * i / 4, -5.0 - 0.5*z, 13 + 1.7*z / 3 ); - } - } - if( rearlightstrength > 0.f ) { - // wystarczy jeden zapalony z tyłu - for( int i = 15; i <= 35; i++ ) { - float z = i * i * i * 0.01f;//25/4; - float C = ( 36 - i*0.5 )*0.005*sqrt( ( 1 / sqrt( Global::fLuminance + 0.015 ) ) - 1 ) * rearlightstrength; - glColor4f( C, C, C, 1.0f );// *rearlightstrength ); - glTexCoord2f( 0, 0 ); glVertex3f( 10 / 2 + 2 * i / 4, 6.0 + 0.3*z, -13 - 1.7*z / 3 ); - glTexCoord2f( 1, 0 ); glVertex3f( -10 / 2 - 2 * i / 4, 6.0 + 0.3*z, -13 - 1.7*z / 3 ); - glTexCoord2f( 1, 1 ); glVertex3f( -10 / 2 - 2 * i / 4, -5.0 - 0.5*z, -13 - 1.7*z / 3 ); - glTexCoord2f( 0, 1 ); glVertex3f( 10 / 2 + 2 * i / 4, -5.0 - 0.5*z, -13 - 1.7*z / 3 ); - } - } - glEnd(); - - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - // glEnable(GL_DEPTH_TEST); - glAlphaFunc( GL_GREATER, 0.04 ); - glDepthFunc( GL_LEQUAL ); - glEnable( GL_LIGHTING ); //i tak się włączy potem - glEnable( GL_FOG ); - } - } - - glEnable( GL_LIGHTING ); // po renderowaniu smugi jest to wyłączone - // Ra: pojazd użytkownika należało by renderować po smudze, aby go nie rozświetlała - - Global::bSmudge = false; // aby model użytkownika się teraz wyrenderował - dynamic->Render(); - dynamic->RenderAlpha(); // przezroczyste fragmenty pojazdów na torach - - } // yB: moje smuuugi 1 - koniec - else -*/ glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit + glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit if( dynamic->mdKabina ) // bo mogła zniknąć przy przechodzeniu do innego pojazdu { -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // oswietlenie kabiny - GLfloat ambientCabLight[ 4 ] = { 0.5f, 0.5f, 0.5f, 1.0f }; - GLfloat diffuseCabLight[ 4 ] = { 0.5f, 0.5f, 0.5f, 1.0f }; - GLfloat specularCabLight[ 4 ] = { 0.5f, 0.5f, 0.5f, 1.0f }; - for( int li = 0; li < 3; li++ ) { // przyciemnienie standardowe - ambientCabLight[ li ] = Global::ambientDayLight[ li ] * 0.9; - diffuseCabLight[ li ] = Global::diffuseDayLight[ li ] * 0.5; - specularCabLight[ li ] = Global::specularDayLight[ li ] * 0.5; - } - switch( dynamic->MyTrack->eEnvironment ) { // wpływ świetła zewnętrznego - case e_canyon: - { - for( int li = 0; li < 3; li++ ) { - diffuseCabLight[ li ] *= 0.6; - specularCabLight[ li ] *= 0.7; - } - } - break; - case e_tunnel: - { - for( int li = 0; li < 3; li++ ) { - ambientCabLight[ li ] *= 0.3; - diffuseCabLight[ li ] *= 0.1; - specularCabLight[ li ] *= 0.2; - } - } - break; - } - switch( Train->iCabLightFlag ) // Ra: uzeleżnic od napięcia w obwodzie sterowania - { // hunter-091012: uzaleznienie jasnosci od przetwornicy - case 0: //światło wewnętrzne zgaszone - break; - case 1: //światło wewnętrzne przygaszone (255 216 176) - if( dynamic->MoverParameters->ConverterFlag == - true ) // jasnosc dla zalaczonej przetwornicy - { - ambientCabLight[ 0 ] = Max0R( 0.700, ambientCabLight[ 0 ] ) * 0.75; // R - ambientCabLight[ 1 ] = Max0R( 0.593, ambientCabLight[ 1 ] ) * 0.75; // G - ambientCabLight[ 2 ] = Max0R( 0.483, ambientCabLight[ 2 ] ) * 0.75; // B - - for( int i = 0; i < 3; i++ ) - if( ambientCabLight[ i ] <= ( Global::ambientDayLight[ i ] * 0.9 ) ) - ambientCabLight[ i ] = Global::ambientDayLight[ i ] * 0.9; - } - else { - ambientCabLight[ 0 ] = Max0R( 0.700, ambientCabLight[ 0 ] ) * 0.375; // R - ambientCabLight[ 1 ] = Max0R( 0.593, ambientCabLight[ 1 ] ) * 0.375; // G - ambientCabLight[ 2 ] = Max0R( 0.483, ambientCabLight[ 2 ] ) * 0.375; // B - - for( int i = 0; i < 3; i++ ) - if( ambientCabLight[ i ] <= ( Global::ambientDayLight[ i ] * 0.9 ) ) - ambientCabLight[ i ] = Global::ambientDayLight[ i ] * 0.9; - } - break; - case 2: //światło wewnętrzne zapalone (255 216 176) - if( dynamic->MoverParameters->ConverterFlag == - true ) // jasnosc dla zalaczonej przetwornicy - { - ambientCabLight[ 0 ] = Max0R( 1.000, ambientCabLight[ 0 ] ); // R - ambientCabLight[ 1 ] = Max0R( 0.847, ambientCabLight[ 1 ] ); // G - ambientCabLight[ 2 ] = Max0R( 0.690, ambientCabLight[ 2 ] ); // B - - for( int i = 0; i < 3; i++ ) - if( ambientCabLight[ i ] <= ( Global::ambientDayLight[ i ] * 0.9 ) ) - ambientCabLight[ i ] = Global::ambientDayLight[ i ] * 0.9; - } - else { - ambientCabLight[ 0 ] = Max0R( 1.000, ambientCabLight[ 0 ] ) * 0.5; // R - ambientCabLight[ 1 ] = Max0R( 0.847, ambientCabLight[ 1 ] ) * 0.5; // G - ambientCabLight[ 2 ] = Max0R( 0.690, ambientCabLight[ 2 ] ) * 0.5; // B - - for( int i = 0; i < 3; i++ ) - if( ambientCabLight[ i ] <= ( Global::ambientDayLight[ i ] * 0.9 ) ) - ambientCabLight[ i ] = Global::ambientDayLight[ i ] * 0.9; - } - break; - } - glLightfv( GL_LIGHT0, GL_AMBIENT, ambientCabLight ); - glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseCabLight ); - glLightfv( GL_LIGHT0, GL_SPECULAR, specularCabLight ); -#else + // setup if( dynamic->fShade > 0.0f ) { // change light level based on light level of the occupied track Global::DayLight.apply_intensity( dynamic->fShade ); } if( dynamic->InteriorLightLevel > 0.0f ) { - // crude way to light the cabin, until we have something more complete in place auto const cablight = dynamic->InteriorLight * dynamic->InteriorLightLevel; ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &cablight.x ); } -#endif - -#ifdef EU07_USE_OLD_RENDERCODE - if( Global::bUseVBO ) { - // renderowanie z użyciem VBO. NOTE: needs update, and eventual merge into single render path down the road - dynamic->mdKabina->RaRender( 0.0, dynamic->Material()->replacable_skins, dynamic->Material()->textures_alpha ); - dynamic->mdKabina->RaRenderAlpha( 0.0, dynamic->Material()->replacable_skins, dynamic->Material()->textures_alpha ); - } - else { - // renderowanie z Display List - dynamic->mdKabina->Render( 0.0, dynamic->ReplacableSkinID, dynamic->iAlpha ); - dynamic->mdKabina->RenderAlpha( 0.0, dynamic->ReplacableSkinID, dynamic->iAlpha ); - } -#else + // render GfxRenderer.Render( dynamic->mdKabina, dynamic->Material(), 0.0 ); GfxRenderer.Render_Alpha( dynamic->mdKabina, dynamic->Material(), 0.0 ); -#endif -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // przywrócenie standardowych, bo zawsze są zmieniane - glLightfv( GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight ); - glLightfv( GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight ); - glLightfv( GL_LIGHT0, GL_SPECULAR, Global::specularDayLight ); -#else + // post-render restore if( dynamic->fShade > 0.0f ) { // change light level based on light level of the occupied track Global::DayLight.apply_intensity(); @@ -1627,7 +1311,6 @@ TWorld::Render_Cab() { GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); } -#endif } glPopMatrix(); } diff --git a/sky.cpp b/sky.cpp index 54d47a09..61aa81d1 100644 --- a/sky.cpp +++ b/sky.cpp @@ -31,39 +31,18 @@ void TSky::Render( float3 const &Tint ) { if (mdCloud) { // jeśli jest model nieba -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // TODO: re-implement this - glLightfv(GL_LIGHT0, GL_POSITION, lightPos); -#else + // setup ::glEnable( GL_LIGHTING ); GfxRenderer.Disable_Lights(); ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &Tint.x ); -#endif -#ifdef EU07_USE_OLD_RENDERCODE - if( Global::bUseVBO ) - { // renderowanie z VBO - mdCloud->RaRender( 100, 0 ); - mdCloud->RaRenderAlpha(100, 0); - } - else - { // renderowanie z Display List - mdCloud->Render(100, 0); - mdCloud->RenderAlpha(100, 0); - } -#else + // render GfxRenderer.Render( mdCloud, nullptr, 100.0 ); GfxRenderer.Render_Alpha( mdCloud, nullptr, 100.0 ); -#endif -#ifdef EU07_USE_OLD_LIGHTING_MODEL - glPopMatrix(); - // TODO: re-implement this - glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos); -#else + // post-render cleanup GLfloat noambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, noambient ); ::glEnable( GL_LIGHT0 ); // other lights will be enabled during lights update ::glDisable( GL_LIGHTING ); -#endif } }; diff --git a/stars.cpp b/stars.cpp index dd7e9650..08b2b926 100644 --- a/stars.cpp +++ b/stars.cpp @@ -14,23 +14,16 @@ cStars::init() { void cStars::render() { - + // setup ::glPushMatrix(); ::glRotatef( m_latitude, 1.0f, 0.0f, 0.0f ); // ustawienie osi OY na północ ::glRotatef( -std::fmod( (float)Global::fTimeAngleDeg, 360.0f ), 0.0f, 1.0f, 0.0f ); // obrót dobowy osi OX ::glPointSize( 2.0f ); -#ifdef EU07_USE_OLD_RENDERCODE - if( Global::bUseVBO ) { - m_stars.RaRender( 1.0, 0 ); - } - else { - m_stars.Render( 1.0 ); - } -#else + // render GfxRenderer.Render( &m_stars, nullptr, 1.0 ); -#endif + // post-render cleanup ::glPointSize( 3.0f ); ::glPopMatrix(); From ac61dbdf14a35472ca14c3bd4e48edf66c72c238 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 24 May 2017 15:31:53 +0200 Subject: [PATCH 07/12] stl-based origin stack replacement --- Ground.cpp | 60 ++++++++++++++++++------------------------------------ 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/Ground.cpp b/Ground.cpp index 879d1265..e4a6f45d 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -2046,9 +2046,7 @@ bool TGround::Init(std::string File) cParser parser(File, cParser::buffer_FILE, subpath, Global::bLoadTraction); std::string token; - const int OriginStackMaxDepth = 100; // rozmiar stosu dla zagnieżdżenia origin - int OriginStackTop = 0; - vector3 OriginStack[OriginStackMaxDepth]; // stos zagnieżdżenia origin + std::stack OriginStack; // stos zagnieżdżenia origin TGroundNode *LastNode = NULL; // do użycia w trainset iNumNodes = 0; @@ -2222,8 +2220,7 @@ bool TGround::Init(std::string File) tmp->evNext2 = RootEvent; // lista wszystkich eventów (m.in. do InitEvents) RootEvent = tmp; if (!found) - { // jeśli nazwa wystąpiła, to do kolejki i wyszukiwarki dodawany jest tylko - // pierwszy + { // jeśli nazwa wystąpiła, to do kolejki i wyszukiwarki dodawany jest tylko pierwszy if (RootEvent->Type != tp_Ignored) if (RootEvent->asName.find( "onstart") != std::string::npos) // event uruchamiany automatycznie po starcie @@ -2233,56 +2230,39 @@ bool TGround::Init(std::string File) } } } - // else - // if (str==AnsiString("include")) //Tolaris to zrobil wewnatrz parsera - // { - // Include(Parser); - // } else if (str == "rotate") { // parser.getTokens(3); - // parser >> aRotate.x >> aRotate.y >> aRotate.z; //Ra: to potrafi dawać błędne - // rezultaty + // parser >> aRotate.x >> aRotate.y >> aRotate.z; //Ra: to potrafi dawać błędne rezultaty // ??? how so TODO: investigate parser.getTokens(); parser >> aRotate.x; parser.getTokens(); parser >> aRotate.y; parser.getTokens(); parser >> aRotate.z; - // WriteLog("*** rotate "+AnsiString(aRotate.x)+" "+AnsiString(aRotate.y)+" - // "+AnsiString(aRotate.z)); } else if (str == "origin") { - // str=Parser->GetNextSymbol().LowerCase(); - // if (str=="begin") - { - if (OriginStackTop >= OriginStackMaxDepth - 1) - { - MessageBox(0, "Origin stack overflow ", "Error", MB_OK); - break; - } - parser.getTokens(3); - parser >> OriginStack[OriginStackTop].x >> OriginStack[OriginStackTop].y >> - OriginStack[OriginStackTop].z; - pOrigin += OriginStack[OriginStackTop]; // sumowanie całkowitego przesunięcia - OriginStackTop++; // zwiększenie wskaźnika stosu - } + Math3D::vector3 offset; + parser.getTokens(3); + parser + >> offset.x + >> offset.y + >> offset.z; + // sumowanie całkowitego przesunięcia + OriginStack.emplace( + offset + ( + OriginStack.empty() ? + Math3D::vector3() : + OriginStack.top() ) ); + pOrigin = OriginStack.top(); } else if (str == "endorigin") { - // else - // if (str=="end") - { - if (OriginStackTop <= 0) - { - MessageBox(0, "Origin stack underflow ", "Error", MB_OK); - break; - } - - OriginStackTop--; // zmniejszenie wskaźnika stosu - pOrigin -= OriginStack[OriginStackTop]; - } + OriginStack.pop(); + pOrigin = ( OriginStack.empty() ? + Math3D::vector3() : + OriginStack.top() ); } else if (str == "atmo") // TODO: uporzadkowac gdzie maja byc parametry mgly! { // Ra: ustawienie parametrów OpenGL przeniesione do FirstInit From 2b6ea903bc63f46a7e823b83824b17ea5e1153e6 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 25 May 2017 12:58:43 +0200 Subject: [PATCH 08/12] camera-centric rendering, initial implementation --- AnimModel.cpp | 8 +-- AnimModel.h | 4 +- Camera.cpp | 16 ++--- Camera.h | 2 +- Ground.cpp | 148 +++++++++++++++++++--------------------------- Ground.h | 14 ++--- Segment.cpp | 114 ++++++++++++++--------------------- Segment.h | 2 +- Track.cpp | 153 ++++++++++++++++++++++++----------------------- Traction.cpp | 99 ++++++++++++++++--------------- Traction.h | 2 +- World.cpp | 8 ++- frustum.h | 9 +++ renderer.cpp | 161 ++++++++++++++++++++++++++++++++++---------------- renderer.h | 2 +- 15 files changed, 385 insertions(+), 357 deletions(-) diff --git a/AnimModel.cpp b/AnimModel.cpp index a5303f08..0e183997 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -606,16 +606,16 @@ int TAnimModel::Flags() //----------------------------------------------------------------------------- // 2011-03-16 funkcje renderowania z możliwością pochylania obiektów //----------------------------------------------------------------------------- -void TAnimModel::Render( vector3 *vPosition ) { +void TAnimModel::Render( vector3 const &Position ) { RaAnimate(); // jednorazowe przeliczenie animacji RaPrepare(); if( pModel ) // renderowanie rekurencyjne submodeli - GfxRenderer.Render( pModel, Material(), *vPosition, vAngle ); + GfxRenderer.Render( pModel, Material(), Position, vAngle ); }; -void TAnimModel::RenderAlpha( vector3 *vPosition ) { +void TAnimModel::RenderAlpha( vector3 const &Position ) { RaPrepare(); if( pModel ) // renderowanie rekurencyjne submodeli - GfxRenderer.Render_Alpha( pModel, Material(), *vPosition, vAngle ); + GfxRenderer.Render_Alpha( pModel, Material(), Position, vAngle ); }; //--------------------------------------------------------------------------- diff --git a/AnimModel.h b/AnimModel.h index 760669e8..36fa9c48 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -161,8 +161,8 @@ class TAnimModel bool Load(cParser *parser, bool ter = false); TAnimContainer * AddContainer(char *pName); TAnimContainer * GetContainer(char *pName); - void Render( vector3 *vPosition ); - void RenderAlpha( vector3 *vPosition ); + void Render( vector3 const &Position ); + void RenderAlpha( vector3 const &Position ); int Flags(); void RaAnglesSet(double a, double b, double c) { diff --git a/Camera.cpp b/Camera.cpp index 06b38254..b1354746 100644 --- a/Camera.cpp +++ b/Camera.cpp @@ -410,21 +410,21 @@ bool TCamera::SetMatrix() return true; } -bool TCamera::SetMatrix( glm::mat4 &Matrix ) { +bool TCamera::SetMatrix( glm::dmat4 &Matrix ) { - Matrix = glm::rotate( Matrix, (float)-Roll, glm::vec3( 0.0f, 0.0f, 1.0f ) ); // po wyłączeniu tego kręci się pojazd, a sceneria nie - Matrix = glm::rotate( Matrix, (float)-Pitch, glm::vec3( 1.0f, 0.0f, 0.0f ) ); - Matrix = glm::rotate( Matrix, (float)-Yaw, glm::vec3( 0.0f, 1.0f, 0.0f ) ); // w zewnętrznym widoku: kierunek patrzenia + Matrix = glm::rotate( Matrix, -Roll, glm::dvec3( 0.0, 0.0, 1.0 ) ); // po wyłączeniu tego kręci się pojazd, a sceneria nie + Matrix = glm::rotate( Matrix, -Pitch, glm::dvec3( 1.0, 0.0, 0.0 ) ); + Matrix = glm::rotate( Matrix, -Yaw, glm::dvec3( 0.0, 1.0, 0.0 ) ); // w zewnętrznym widoku: kierunek patrzenia if( Type == tp_Follow ) { Matrix *= glm::lookAt( - glm::vec3( Pos.x, Pos.y, Pos.z ), - glm::vec3( LookAt.x, LookAt.y, LookAt.z ), - glm::vec3( vUp.x, vUp.y, vUp.z ) ); + glm::dvec3( Pos.x, Pos.y, Pos.z ), + glm::dvec3( LookAt.x, LookAt.y, LookAt.z ), + glm::dvec3( vUp.x, vUp.y, vUp.z ) ); } else { - Matrix = glm::translate( Matrix, glm::vec3( -Pos.x, -Pos.y, -Pos.z ) ); // nie zmienia kierunku patrzenia + Matrix = glm::translate( Matrix, glm::dvec3( -Pos.x, -Pos.y, -Pos.z ) ); // nie zmienia kierunku patrzenia } Global::SetCameraPosition( Pos ); // było +pOffset diff --git a/Camera.h b/Camera.h index c9ab5e05..760a9294 100644 --- a/Camera.h +++ b/Camera.h @@ -58,7 +58,7 @@ class TCamera void Update(); vector3 GetDirection(); bool SetMatrix(); - bool SetMatrix(glm::mat4 &Matrix); + bool SetMatrix(glm::dmat4 &Matrix); void SetCabMatrix( vector3 &p ); void RaLook(); void Stop(); diff --git a/Ground.cpp b/Ground.cpp index e4a6f45d..fff7c1ed 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -248,43 +248,6 @@ void TGroundNode::InitNormals() } } -void TGroundNode::MoveMe(vector3 pPosition) -{ // przesuwanie obiektów scenerii o wektor w celu redukcji trzęsienia - pCenter += pPosition; - switch (iType) - { - case TP_TRACTION: - hvTraction->pPoint1 += pPosition; - hvTraction->pPoint2 += pPosition; - hvTraction->pPoint3 += pPosition; - hvTraction->pPoint4 += pPosition; - hvTraction->Optimize(); - break; - case TP_MODEL: - case TP_DYNAMIC: - case TP_MEMCELL: - case TP_EVLAUNCH: - break; - case TP_TRACK: - pTrack->MoveMe(pPosition); - break; - case TP_SOUND: // McZapkie - dzwiek zapetlony w zaleznosci od odleglosci - tsStaticSound->vSoundPosition += pPosition; - break; - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - for (int i = 0; i < iNumPts; i++) - Points[i] += pPosition; - ResourceManager::Unregister(this); - break; - default: - for (int i = 0; i < iNumVerts; i++) - Vertices[i].Point += pPosition; - ResourceManager::Unregister(this); - } -} - void TGroundNode::RaRenderVBO() { // renderowanie z domyslnego bufora VBO glColor3ub(Diffuse[0], Diffuse[1], Diffuse[2]); @@ -309,7 +272,10 @@ void TGroundNode::Compile(bool many) { glBegin(iType); for (int i = 0; i < iNumPts; ++i) - glVertex3dv(&Points[i].x); + glVertex3d( + Points[i].x - m_rootposition.x, + Points[i].y - m_rootposition.y, + Points[i].z - m_rootposition.z ); glEnd(); } else if (iType == GL_TRIANGLE_STRIP || iType == GL_TRIANGLE_FAN || iType == GL_TRIANGLES) @@ -323,9 +289,14 @@ void TGroundNode::Compile(bool many) for (int i = 0; i < iNumVerts; ++i) { glNormal3dv(&Vertices[i].Normal.x); - glTexCoord2f(Vertices[i].tu, Vertices[i].tv); - glVertex3dv(&Vertices[i].Point.x); - }; + glTexCoord2f( + Vertices[i].tu, + Vertices[i].tv); + glVertex3d( + Points[i].x - m_rootposition.x, + Points[i].y - m_rootposition.y, + Points[i].z - m_rootposition.z ); + } glEnd(); } else if (iType == TP_MESH) @@ -408,6 +379,9 @@ void TSubRect::NodeAdd(TGroundNode *Node) // nRenderAlpha - lista grup renderowanych z własnych VBO albo DL z przezroczystością // nRenderWires - lista grup renderowanych z własnych VBO albo DL - druty i linie // nMeshed - obiekty do pogrupowania wg tekstur + + Node->m_rootposition = Math3D::vector3( m_area.center.x, m_area.center.y, m_area.center.z ) ; + switch (Node->iType) { case TP_SOUND: // te obiekty są sprawdzanie niezależnie od kierunku patrzenia @@ -418,11 +392,11 @@ void TSubRect::NodeAdd(TGroundNode *Node) case TP_TRACK: // TODO: tory z cieniem (tunel, canyon) też dać bez łączenia? ++iTracks; // jeden tor więcej Node->pTrack->RaOwnerSet(this); // do którego sektora ma zgłaszać animację - // if (Global::bUseVBO?false:!Node->pTrack->IsGroupable()) - if (Global::bUseVBO ? true : - !Node->pTrack->IsGroupable()) // TODO: tymczasowo dla VBO wyłączone - RaNodeAdd( - Node); // tory ruchome nie są grupowane przy Display Lists (wymagają odświeżania DL) + if( ( true == Global::bUseVBO ) + || ( false == Node->pTrack->IsGroupable() ) ) { + // tory ruchome nie są grupowane przy Display Lists (wymagają odświeżania DL) + RaNodeAdd( Node ); + } else { // tory nieruchome mogą być pogrupowane wg tekstury, przy VBO wszystkie Node->TextureID = Node->pTrack->TextureGet(0); // pobranie tekstury do sortowania @@ -800,9 +774,9 @@ void TSubRect::LoadNodes() case GL_TRIANGLES: for (i = 0; i < n->iNumVerts; ++i) { // Ra: trójkąty można od razu wczytywać do takich tablic... to może poczekać - m_pVNT[n->iVboPtr + i].x = n->Vertices[i].Point.x; - m_pVNT[n->iVboPtr + i].y = n->Vertices[i].Point.y; - m_pVNT[n->iVboPtr + i].z = n->Vertices[i].Point.z; + m_pVNT[n->iVboPtr + i].x = n->Vertices[i].Point.x - n->m_rootposition.x; + m_pVNT[n->iVboPtr + i].y = n->Vertices[i].Point.y - n->m_rootposition.y; + m_pVNT[n->iVboPtr + i].z = n->Vertices[i].Point.z - n->m_rootposition.z; m_pVNT[n->iVboPtr + i].nx = n->Vertices[i].Normal.x; m_pVNT[n->iVboPtr + i].ny = n->Vertices[i].Normal.y; m_pVNT[n->iVboPtr + i].nz = n->Vertices[i].Normal.z; @@ -815,9 +789,9 @@ void TSubRect::LoadNodes() case GL_LINE_LOOP: for (i = 0; i < n->iNumPts; ++i) { - m_pVNT[n->iVboPtr + i].x = n->Points[i].x; - m_pVNT[n->iVboPtr + i].y = n->Points[i].y; - m_pVNT[n->iVboPtr + i].z = n->Points[i].z; + m_pVNT[n->iVboPtr + i].x = n->Points[i].x - n->m_rootposition.x; + m_pVNT[n->iVboPtr + i].y = n->Points[i].y - n->m_rootposition.y; + m_pVNT[n->iVboPtr + i].z = n->Points[i].z - n->m_rootposition.z; // miejsce w tablicach normalnych i teksturowania się marnuje... } break; @@ -833,7 +807,7 @@ void TSubRect::LoadNodes() case TP_TRACTION: if( n->iNumVerts ) { // druty mogą być niewidoczne...? #ifdef EU07_USE_OLD_VERTEXBUFFER - n->hvTraction->RaArrayFill( m_pVNT + n->iVboPtr ); + n->hvTraction->RaArrayFill( m_pVNT + n->iVboPtr, n->m_rootposition ); #else n->hvTraction->RaArrayFill( m_pVNT.data() + n->iVboPtr ); #endif @@ -960,12 +934,14 @@ TGroundRect::Init() { float const subrectsize = 1000.0f / iNumSubRects; for( int column = 0; column < iNumSubRects; ++column ) { for( int row = 0; row < iNumSubRects; ++row ) { - auto &area = FastGetRect(column, row)->m_area; + auto &area = SafeGetRect(column, row)->m_area; area.center = m_area.center - - float3( 500.0f, 0.0f, 500.0f ) // 'upper left' corner of rectangle - + float3( subrectsize * 0.5f, 0.0f, subrectsize * 0.5f ) // center of sub-rectangle - + float3( subrectsize * column, 0.0f, subrectsize * row ); + - glm::vec3( 500.0f, 0.0f, 500.0f ) // 'upper left' corner of rectangle + + glm::vec3( subrectsize * 0.5f, 0.0f, subrectsize * 0.5f ) // center of sub-rectangle + + glm::vec3( subrectsize * column, 0.0f, subrectsize * row ); + // NOTE: the actual coordinates get swapped, as they're swapped in rest of the code :x + area.center = glm::vec3( area.center.z, area.center.y, area.center.x ); area.radius = subrectsize * M_SQRT2; } } @@ -1051,17 +1027,17 @@ TGround::TGround() // set bounding area information for ground rectangles float const rectsize = 1000.0f; - float3 const worldcenter( 0.0f, 0.0f, 0.0f ); + glm::vec3 const worldcenter( 0.0f, 0.0f, 0.0f ); for( int column = 0; column < iNumRects; ++column ) { for( int row = 0; row < iNumRects; ++row ) { auto &area = Rects[ column ][ row ].m_area; // NOTE: in current implementation triangles can stick out to ~200m from the area, so we add extra padding - area.radius = 200.0f + rectsize * 0.5f * M_SQRT2; + area.radius = ( rectsize * 0.5f * M_SQRT2 ) + 200.0f; area.center = worldcenter - - float3( (iNumRects / 2) * rectsize, 0.0f, (iNumRects / 2) * rectsize ) // 'upper left' corner of the world - + float3( rectsize * 0.5f, 0.0f, rectsize * 0.5f ) // center of the rectangle - + float3( rectsize * column, 0.0f, rectsize * row ); + - glm::vec3( (iNumRects / 2) * rectsize, 0.0f, (iNumRects / 2) * rectsize ) // 'upper left' corner of the world + + glm::vec3( rectsize * 0.5f, 0.0f, rectsize * 0.5f ) // center of the rectangle + + glm::vec3( rectsize * column, 0.0f, rectsize * row ); } } } @@ -1995,39 +1971,38 @@ void TGround::FirstInit() gr->RaNodeAdd(&Current->nNode[j]); } } - // else if - // ((Current->iType!=GL_TRIANGLES)&&(Current->iType!=GL_TRIANGLE_STRIP)?true - // //~czy trójkąt? - else if ((Current->iType != GL_TRIANGLES) ? - true //~czy trójkąt? - : - (Current->iFlags & 0x20) ? - true //~czy teksturę ma nieprzezroczystą? - : - (Current->fSquareMinRadius != 0.0) ? - true //~czy widoczny z bliska? - : - (Current->fSquareRadius <= 90000.0)) //~czy widoczny z daleka? - GetSubRect(Current->pCenter.x, Current->pCenter.z)->NodeAdd(Current); - else // dodajemy do kwadratu kilometrowego - GetRect(Current->pCenter.x, Current->pCenter.z)->NodeAdd(Current); + else if( ( Current->iType != GL_TRIANGLES ) + || ( Current->iFlags & 0x20 ) + || ( Current->fSquareMinRadius != 0.0 ) + || ( Current->fSquareRadius <= 90000.0 ) ) { + // add to sub-rectangle + GetSubRect( Current->pCenter.x, Current->pCenter.z )->NodeAdd( Current ); + } + else { + // dodajemy do kwadratu kilometrowego + GetRect( Current->pCenter.x, Current->pCenter.z )->NodeAdd( Current ); + } } - // if (Current->iType!=TP_DYNAMIC) - // GetSubRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current); } } for (i = 0; i < iNumRects; ++i) for (j = 0; j < iNumRects; ++j) Rects[i][j].Optimize(); // optymalizacja obiektów w sektorach + WriteLog("InitNormals OK"); + InitTracks(); //łączenie odcinków ze sobą i przyklejanie eventów WriteLog("InitTracks OK"); + InitTraction(); //łączenie drutów ze sobą WriteLog("InitTraction OK"); + InitEvents(); WriteLog("InitEvents OK"); + InitLaunchers(); WriteLog("InitLaunchers OK"); + WriteLog("FirstInit is done"); }; @@ -2077,13 +2052,14 @@ bool TGround::Init(std::string File) } else if ( ( LastNode->iType == TP_TRACTION ) && ( false == Global::bLoadTraction ) ) SafeDelete(LastNode); // usuwamy druty, jeśli wyłączone + if (LastNode) // dopiero na koniec dopisujemy do tablic if (LastNode->iType != TP_DYNAMIC) { // jeśli nie jest pojazdem - LastNode->nNext = nRootOfType[LastNode->iType]; // ostatni dodany dołączamy - // na końcu nowego - nRootOfType[LastNode->iType] = - LastNode; // ustawienie nowego na początku listy + // ostatni dodany dołączamy na końcu nowego + LastNode->nNext = nRootOfType[LastNode->iType]; + // ustawienie nowego na początku listy + nRootOfType[LastNode->iType] = LastNode; iNumNodes++; } else @@ -2437,10 +2413,6 @@ bool TGround::Init(std::string File) else // jak liczba to na pewno błąd Error("Unrecognized command: " + str); } -/* else if (str == "") - break; -*/ - // LastNode=NULL; token = ""; parser.getTokens(); diff --git a/Ground.h b/Ground.h index ee20b738..ca2aced2 100644 --- a/Ground.h +++ b/Ground.h @@ -122,19 +122,20 @@ public: TGroundNode *nNode; // obiekt renderujący grupowo ma tu wskaźnik na listę obiektów }; std::string asName; // nazwa (nie zawsze ma znaczenie) + + vector3 pCenter; // współrzędne środka do przydzielenia sektora + vector3 m_rootposition; // position of the ground (sub)rectangle holding the node, in the 3d world + // visualization-related data + // TODO: wrap these in a struct, when cleaning objects up union { int iNumVerts; // dla trójkątów int iNumPts; // dla linii int iCount; // dla terenu - // int iState; //Ra: nie używane - dźwięki zapętlone }; - vector3 pCenter; // współrzędne środka do przydzielenia sektora - double fLineThickness; // McZapkie-120702: grubosc linii double fSquareRadius; // kwadrat widoczności do double fSquareMinRadius; // kwadrat widoczności od - // TGroundNode *nMeshGroup; //Ra: obiekt grupujący trójkąty w TSubRect dla tekstury int iVersion; // wersja siatki (do wykonania rekompilacji) // union ? GLuint DisplayListID; // numer siatki DisplayLists @@ -144,6 +145,7 @@ public: int iFlags; // tryb przezroczystości: 0x10-nieprz.,0x20-przezroczysty,0x30-mieszany int Ambient[4], Diffuse[4], Specular[4]; // oświetlenie bool bVisible; + TGroundNode *nNext; // lista wszystkich w scenerii, ostatni na początku TGroundNode *nNext2; // lista obiektów w sektorze TGroundNode *nNext3; // lista obiektów renderowanych we wspólnym cyklu @@ -154,8 +156,6 @@ public: void InitCenter(); // obliczenie współrzędnych środka void InitNormals(); - void MoveMe(vector3 pPosition); // przesuwanie (nie działa) - // bool Disable(); inline TGroundNode * Find(const std::string &asNameToFind, TGroundNodeType iNodeType) { // wyszukiwanie czołgowe z typem @@ -177,7 +177,7 @@ public: struct bounding_area { - float3 center; // mid point of the rectangle + glm::vec3 center; // mid point of the rectangle float radius{ 0.0f }; // radius of the bounding sphere }; diff --git a/Segment.cpp b/Segment.cpp index 194c3209..c3fdb478 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -319,7 +319,7 @@ vector3 TSegment::FastGetPoint(double t) return (bCurve ? RaInterpolate(t) : ((1.0 - t) * Point1 + (t)*Point2)); } -int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, bool Onlypositions, vector3 **p, bool bRender) +int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, vector3 **p, bool bRender) { // generowanie trójkątów dla odcinka trajektorii ruchu // standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku // po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli @@ -368,12 +368,10 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int jmm2 = 0.0; } - if( false == Onlypositions ) { - while( tv1 < 0.0 ) { - tv1 += 1.0; - } - tv2 = tv1 - step / fTextureLength; // mapowanie na końcu segmentu + while( tv1 < 0.0 ) { + tv1 += 1.0; } + tv2 = tv1 - step / fTextureLength; // mapowanie na końcu segmentu t = fTsBuffer[ i ]; // szybsze od GetTFromS(s); pos2 = FastGetPoint( t ); @@ -389,30 +387,25 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int for( int j = 0; j < iNumShapePoints; ++j ) { pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].x - fOffsetX ) + m1 * ShapePoints[ j + iNumShapePoints ].x ) + pos1; pt.y += jmm1 * ShapePoints[ j ].y + m1 * ShapePoints[ j + iNumShapePoints ].y; - if( false == Onlypositions ) { - norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel1; - norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y; - } + pt -= Origin; + norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel1; + norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y; if( bRender ) { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów if( Output == nullptr ) { // immediate mode - if( false == Onlypositions ) { - ::glNormal3f( norm.x, norm.y, norm.z ); - ::glTexCoord2f( (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv1 ); - } + ::glNormal3f( norm.x, norm.y, norm.z ); + ::glTexCoord2f( (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv1 ); ::glVertex3f( pt.x, pt.y, pt.z ); // pt nie mamy gdzie zapamiętać? } else { Output->x = pt.x; Output->y = pt.y; Output->z = pt.z; - if( false == Onlypositions ) { - Output->nx = norm.x; - Output->ny = norm.y; - Output->nz = norm.z; - Output->u = (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; - Output->v = tv1; - } + Output->nx = norm.x; + Output->ny = norm.y; + Output->nz = norm.z; + Output->u = (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; + Output->v = tv1; ++Output; } ++vertexcount; @@ -427,30 +420,25 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int // dla trapezu drugi koniec ma inne współrzędne pt = parallel2 * ( jmm2 * ( ShapePoints[ j ].x - fOffsetX ) + m2 * ShapePoints[ j + iNumShapePoints ].x ) + pos2; pt.y += jmm2 * ShapePoints[ j ].y + m2 * ShapePoints[ j + iNumShapePoints ].y; - if( false == Onlypositions ) { - norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel2; - norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y; - } + pt -= Origin; + norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel2; + norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y; if( bRender ) { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów if( Output == nullptr ) { // immediate mode - if( false == Onlypositions ) { - ::glNormal3f( norm.x, norm.y, norm.z ); - ::glTexCoord2f( (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv2 ); - } + ::glNormal3f( norm.x, norm.y, norm.z ); + ::glTexCoord2f( (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv2 ); ::glVertex3f( pt.x, pt.y, pt.z ); } else { Output->x = pt.x; Output->y = pt.y; Output->z = pt.z; - if( false == Onlypositions ) { - Output->nx = norm.x; - Output->ny = norm.y; - Output->nz = norm.z; - Output->u = (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; - Output->v = tv2; - } + Output->nx = norm.x; + Output->ny = norm.y; + Output->nz = norm.z; + Output->u = (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; + Output->v = tv2; ++Output; } ++vertexcount; @@ -470,58 +458,48 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int //łuk z jednym profilem pt = parallel1 * ( ShapePoints[ j ].x - fOffsetX ) + pos1; pt.y += ShapePoints[ j ].y; - if( false == Onlypositions ) { - norm = ShapePoints[ j ].n.x * parallel1; - norm.y += ShapePoints[ j ].n.y; - } + pt -= Origin; + norm = ShapePoints[ j ].n.x * parallel1; + norm.y += ShapePoints[ j ].n.y; if( Output == nullptr ) { // immediate mode - if( false == Onlypositions ) { - ::glNormal3f( norm.x, norm.y, norm.z ); - ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv1 ); - } + ::glNormal3f( norm.x, norm.y, norm.z ); + ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv1 ); ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na początku odcinka } else { Output->x = pt.x; Output->y = pt.y; Output->z = pt.z; - if( false == Onlypositions ) { - Output->nx = norm.x; - Output->ny = norm.y; - Output->nz = norm.z; - Output->u = ShapePoints[ j ].z / Texturescale; - Output->v = tv1; - } + Output->nx = norm.x; + Output->ny = norm.y; + Output->nz = norm.z; + Output->u = ShapePoints[ j ].z / Texturescale; + Output->v = tv1; ++Output; } ++vertexcount; pt = parallel2 * ShapePoints[ j ].x + pos2; pt.y += ShapePoints[ j ].y; - if( false == Onlypositions ) { - norm = ShapePoints[ j ].n.x * parallel2; - norm.y += ShapePoints[ j ].n.y; - } + pt -= Origin; + norm = ShapePoints[ j ].n.x * parallel2; + norm.y += ShapePoints[ j ].n.y; if( Output == nullptr ) { // immediate mode - if( false == Onlypositions ) { - ::glNormal3f( norm.x, norm.y, norm.z ); - ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv2 ); - } + ::glNormal3f( norm.x, norm.y, norm.z ); + ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv2 ); ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na końcu odcinka } else { Output->x = pt.x; Output->y = pt.y; Output->z = pt.z; - if( false == Onlypositions ) { - Output->nx = norm.x; - Output->ny = norm.y; - Output->nz = norm.z; - Output->u = ShapePoints[ j ].z / Texturescale; - Output->v = tv2; - } + Output->nx = norm.x; + Output->ny = norm.y; + Output->nz = norm.z; + Output->u = ShapePoints[ j ].z / Texturescale; + Output->v = tv2; ++Output; } ++vertexcount; @@ -534,9 +512,7 @@ int TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int } pos1 = pos2; parallel1 = parallel2; - if( false == Onlypositions ) { - tv1 = tv2; - } + tv1 = tv2; } return vertexcount; diff --git a/Segment.h b/Segment.h index 1c4c84ab..25a9875f 100644 --- a/Segment.h +++ b/Segment.h @@ -113,7 +113,7 @@ class TSegment r1 = fRoll1; r2 = fRoll2; } - int RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, bool Onlypositions = false, vector3 **p = nullptr, bool bRender = true); + int RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, vector6 const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, vector3 **p = nullptr, bool bRender = true); void Render(); inline double GetLength() { diff --git a/Track.cpp b/Track.cpp index b0920ad9..ddb669cc 100644 --- a/Track.cpp +++ b/Track.cpp @@ -1090,6 +1090,9 @@ void TTrack::Compile(GLuint tex) hypot2 = hypot1; normal2 = normal1; } + + auto const origin = pMyNode->m_rootposition; + double roll1, roll2; switch (iCategoryFlag & 15) { @@ -1216,15 +1219,15 @@ void TTrack::Compile(GLuint tex) } if (!tex) GfxRenderer.Bind( TextureID2 ); - Segment->RenderLoft( immediate, bpts1, iTrapezoid ? -4 : 4, fTexLength); + Segment->RenderLoft( immediate, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength); } if (TextureID1) if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) { // szyny if (!tex) GfxRenderer.Bind( TextureID1 ); - Segment->RenderLoft( immediate, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); - Segment->RenderLoft( immediate, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RenderLoft( immediate, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RenderLoft( immediate, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); } break; case tt_Switch: // dla zwrotnicy dwa razy szyny @@ -1252,31 +1255,31 @@ void TTrack::Compile(GLuint tex) { // zwrotnica prawa if( TextureID1 ) { GfxRenderer.Bind( TextureID1 ); - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); // prawa iglica - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts1, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts2, nnumPts, fTexLength ); // lewa szyna normalnie cała + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); // prawa iglica + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength ); // lewa szyna normalnie cała } if( TextureID2 ) { GfxRenderer.Bind( TextureID2 ); - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts1, nnumPts, fTexLength ); // prawa szyna normalna cała - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); // lewa iglica - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts2, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength ); // prawa szyna normalna cała + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); // lewa iglica + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą } } else { // lewa kiedyś działała lepiej niż prawa if( TextureID1 ) { GfxRenderer.Bind( TextureID1 ); - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts1, nnumPts, fTexLength ); // prawa szyna normalna cała - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // lewa iglica - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts2, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength ); // prawa szyna normalna cała + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // lewa iglica + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą } if( TextureID2 ) { // nie wiadomo, czy OpenGL to optymalizuje GfxRenderer.Bind( TextureID2 ); - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // prawa iglica - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts1, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts2, nnumPts, fTexLength ); // lewa szyna normalnie cała + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // prawa iglica + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength ); // lewa szyna normalnie cała } } } @@ -1315,7 +1318,7 @@ void TTrack::Compile(GLuint tex) { // tworzenie trójkątów nawierzchni szosy if (!tex) GfxRenderer.Bind( TextureID1 ); - Segment->RenderLoft( immediate, bpts1, iTrapezoid ? -2 : 2, fTexLength); + Segment->RenderLoft( immediate, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); } if (TextureID2) if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex) @@ -1399,16 +1402,16 @@ void TTrack::Compile(GLuint tex) { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony // odcinka if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0)) - Segment->RenderLoft( immediate, rpts1, -3, fTexLength); // tylko jeśli jest z prawej + Segment->RenderLoft( immediate, origin, rpts1, -3, fTexLength); // tylko jeśli jest z prawej if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) - Segment->RenderLoft( immediate, rpts2, -3, fTexLength); // tylko jeśli jest z lewej + Segment->RenderLoft( immediate, origin, rpts2, -3, fTexLength); // tylko jeśli jest z lewej } else { // pobocza zwykłe, brak przechyłki if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0)) - Segment->RenderLoft( immediate, rpts1, 3, fTexLength); + Segment->RenderLoft( immediate, origin, rpts1, 3, fTexLength); if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) - Segment->RenderLoft( immediate, rpts2, 3, fTexLength); + Segment->RenderLoft( immediate, origin, rpts2, 3, fTexLength); } } break; @@ -1551,19 +1554,19 @@ void TTrack::Compile(GLuint tex) if (SwitchExtension->iRoads == 4) { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - SwitchExtension->Segments[ 3 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - SwitchExtension->Segments[ 4 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - SwitchExtension->Segments[ 5 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 3 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 4 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 5 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); } } else // to będzie ewentualnie dla prostego na skrzyżowaniu trzech dróg { // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P2 do P4 - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P4 do P3=P1 (odwrócony) - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P1 do P2 + SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4 + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony) + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2 } } } @@ -1628,7 +1631,7 @@ void TTrack::Compile(GLuint tex) { if (!tex) GfxRenderer.Bind( TextureID1 ); - Segment->RenderLoft( immediate, bpts1, numPts, fTexLength); + Segment->RenderLoft( immediate, origin, bpts1, numPts, fTexLength); } if (TextureID2) if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex) @@ -1640,8 +1643,8 @@ void TTrack::Compile(GLuint tex) vector6(-rozp, -fTexHeight1, 0.0)}; // Ra: po kiego 0.1? if (!tex) GfxRenderer.Bind( TextureID2 ); // brzeg rzeki - Segment->RenderLoft( immediate, rpts1, 3, fTexLength); - Segment->RenderLoft( immediate, rpts2, 3, fTexLength); + Segment->RenderLoft( immediate, origin, rpts1, 3, fTexLength ); + Segment->RenderLoft( immediate, origin, rpts2, 3, fTexLength ); } break; } @@ -1858,6 +1861,9 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons hypot2 = hypot1; normal2 = normal1; } + + auto const origin = pMyNode->m_rootposition; + double roll1, roll2; switch (iCategoryFlag & 15) { @@ -1959,12 +1965,12 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos } } - Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -4 : 4, fTexLength); + Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength); } if (TextureID1) { // szyny - generujemy dwie, najwyżej rysować się będzie jedną - Segment->RenderLoft(Vert, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); - Segment->RenderLoft(Vert, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RenderLoft(Vert, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RenderLoft(Vert, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); } break; case tt_Switch: // dla zwrotnicy dwa razy szyny @@ -1989,32 +1995,32 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa if( TextureID1 ) { - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, nnumPts, fTexLength ); - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2 ); + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength ); + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); } if( TextureID2 ) { SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts1, nnumPts, fTexLength ); + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength ); } } else { // lewa działa lepiej niż prawa if( TextureID1 ) { - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // prawa iglica + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // prawa iglica } if( TextureID2 ) { SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // lewa iglica - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // lewa iglica + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała } } } @@ -2049,7 +2055,7 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons } if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy - Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); + Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); } if (TextureID2) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) @@ -2130,18 +2136,18 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony // odcinka if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { - Segment->RenderLoft( Vert, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej + Segment->RenderLoft( Vert, origin, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej } if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - Segment->RenderLoft( Vert, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej + Segment->RenderLoft( Vert, origin, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej } } else { // pobocza zwykłe, brak przechyłki if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { - Segment->RenderLoft( Vert, rpts1, 3, fTexLength ); + Segment->RenderLoft( Vert, origin, rpts1, 3, fTexLength ); } if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - Segment->RenderLoft( Vert, rpts2, 3, fTexLength ); + Segment->RenderLoft( Vert, origin, rpts2, 3, fTexLength ); } } } @@ -2266,18 +2272,18 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons if (SwitchExtension->iRoads == 4) { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); - SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); } } else { // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P2 do P4 - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P4 do P3=P1 (odwrócony) - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P1 do P2 + SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4 + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony) + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2 } } } @@ -2297,17 +2303,17 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons Vert->nz = 0.0; Vert->u = 0.5; Vert->v = 0.5; - Vert->x = oxz.x; - Vert->y = oxz.y; - Vert->z = oxz.z; + Vert->x = oxz.x - origin.x; + Vert->y = oxz.y - origin.y; + Vert->z = oxz.z - origin.z; ++Vert; // ...and add one extra vertex to close the fan... Vert->nx = 0.0; Vert->ny = 1.0; Vert->nz = 0.0; // mapowanie we współrzędnych scenerii - u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x ) / fTexLength; - v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z ) / ( fTexRatio1 * fTexLength ); + u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + origin.x ) / fTexLength; + v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength ); Vert->u = cosa0 * u + sina0 * v + 0.5; Vert->v = -sina0 * u + cosa0 * v + 0.5; Vert->x = SwitchExtension->vPoints[ 0 ].x; @@ -2321,8 +2327,8 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons Vert->ny = 1.0; Vert->nz = 0.0; // mapowanie we współrzędnych scenerii - u = (SwitchExtension->vPoints[i].x - oxz.x) / fTexLength; - v = (SwitchExtension->vPoints[i].z - oxz.z) / (fTexRatio1 * fTexLength); + u = (SwitchExtension->vPoints[i].x - oxz.x + origin.x ) / fTexLength; + v = (SwitchExtension->vPoints[i].z - oxz.z + origin.z ) / (fTexRatio1 * fTexLength); Vert->u = cosa0 * u + sina0 * v + 0.5; Vert->v = -sina0 * u + cosa0 * v + 0.5; Vert->x = SwitchExtension->vPoints[ i ].x; @@ -2368,7 +2374,7 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons } if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy - Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); + Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); } if (TextureID2) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w @@ -2390,13 +2396,13 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza - Segment->RenderLoft(Vert, rpts1, -3, fTexLength); - Segment->RenderLoft(Vert, rpts2, -3, fTexLength); + Segment->RenderLoft(Vert, origin, rpts1, -3, fTexLength); + Segment->RenderLoft(Vert, origin, rpts2, -3, fTexLength); } else { // pobocza zwykłe, brak przechyłki - Segment->RenderLoft(Vert, rpts1, 3, fTexLength); - Segment->RenderLoft(Vert, rpts2, 3, fTexLength); + Segment->RenderLoft(Vert, origin, rpts1, 3, fTexLength); + Segment->RenderLoft(Vert, origin, rpts2, 3, fTexLength); } } } @@ -2884,13 +2890,14 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer) bladesbuffer.data() ); */ auto bladevertices = bladesbuffer.data(); + auto const origin = pMyNode->m_rootposition; if( SwitchExtension->RightSwitch ) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa - SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 /*, true*/ ); - SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 /*, true*/ ); + SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 /*, true*/ ); + SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 /*, true*/ ); } else { - SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 /*, true*/ ); // prawa iglica - SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 /*, true*/ ); // lewa iglica + SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 /*, true*/ ); // prawa iglica + SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 /*, true*/ ); // lewa iglica } // push back updated geometry ::glBufferSubData( diff --git a/Traction.cpp b/Traction.cpp index 8324854a..6cf2842a 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -324,7 +324,7 @@ int TTraction::RaArrayPrepare() return iLines; }; -int TTraction::RaArrayFill(CVertNormTex *Vert) +int TTraction::RaArrayFill(CVertNormTex *Vert, Math3D::vector3 const &Origin) { // wypełnianie tablic VBO int debugvertexcount{ 0 }; @@ -332,14 +332,14 @@ int TTraction::RaArrayFill(CVertNormTex *Vert) if (Wires == 2) WireOffset = 0; // jezdny - Vert->x = pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; - Vert->y = pPoint1.y; - Vert->z = pPoint1.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; + Vert->x = pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x; + Vert->y = pPoint1.y - Origin.y; + Vert->z = pPoint1.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z; ++Vert; ++debugvertexcount; - Vert->x = pPoint2.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; - Vert->y = pPoint2.y; - Vert->z = pPoint2.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; + Vert->x = pPoint2.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x; + Vert->y = pPoint2.y - Origin.y; + Vert->z = pPoint2.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z; ++Vert; ++debugvertexcount; // Nie wiem co 'Marcin @@ -355,9 +355,9 @@ int TTraction::RaArrayFill(CVertNormTex *Vert) // Przewod nosny 'Marcin if (Wires > 1) { // lina nośna w kawałkach - Vert->x = pPoint3.x; - Vert->y = pPoint3.y; - Vert->z = pPoint3.z; + Vert->x = pPoint3.x - Origin.x; + Vert->y = pPoint3.y - Origin.y; + Vert->z = pPoint3.z - Origin.z; ++Vert; ++debugvertexcount; for (int i = 0; i < iNumSections - 1; ++i) @@ -367,31 +367,31 @@ int TTraction::RaArrayFill(CVertNormTex *Vert) if( ( Wires < 4 ) || ( ( i != 0 ) && ( i != iNumSections - 2 ) ) ) { - Vert->x = pt3.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference; - Vert->z = pt3.z; + Vert->x = pt3.x - Origin.x; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - Origin.y; + Vert->z = pt3.z - Origin.z; ++Vert; ++debugvertexcount; } f += step; } - Vert->x = pPoint4.x; - Vert->y = pPoint4.y; - Vert->z = pPoint4.z; + Vert->x = pPoint4.x - Origin.x; + Vert->y = pPoint4.y - Origin.y; + Vert->z = pPoint4.z - Origin.z; ++Vert; ++debugvertexcount; } // Drugi przewod jezdny 'Winger if (Wires > 2) { - Vert->x = pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; - Vert->y = pPoint1.y; - Vert->z = pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; + Vert->x = pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x; + Vert->y = pPoint1.y - Origin.y; + Vert->z = pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z; ++Vert; ++debugvertexcount; - Vert->x = pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; - Vert->y = pPoint2.y; - Vert->z = pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; + Vert->x = pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x; + Vert->y = pPoint2.y - Origin.y; + Vert->z = pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z; ++Vert; ++debugvertexcount; } @@ -399,28 +399,29 @@ int TTraction::RaArrayFill(CVertNormTex *Vert) f = step; if( Wires == 4 ) { - Vert->x = pPoint3.x; - Vert->y = pPoint3.y - 0.65f * fHeightDifference; - Vert->z = pPoint3.z; + Vert->x = pPoint3.x - Origin.x; + Vert->y = pPoint3.y - 0.65f * fHeightDifference - Origin.y; + Vert->z = pPoint3.z - Origin.z; ++Vert; ++debugvertexcount; for( int i = 0; i < iNumSections - 1; ++i ) { pt3 = pPoint3 + v1 * f; t = ( 1 - std::fabs( f - mid ) * 2 ); - Vert->x = pt3.x; + Vert->x = pt3.x - Origin.x; Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( ( i == 0 ) || ( i == iNumSections - 2 ) ) ? 0.25f * fHeightDifference : - 0.05 ); - Vert->z = pt3.z; + 0.05 ) + - Origin.y; + Vert->z = pt3.z - Origin.z; ++Vert; ++debugvertexcount; f += step; } - Vert->x = pPoint4.x; - Vert->y = pPoint4.y - 0.65f * fHeightDifference; - Vert->z = pPoint4.z; + Vert->x = pPoint4.x - Origin.x; + Vert->y = pPoint4.y - 0.65f * fHeightDifference - Origin.y; + Vert->z = pPoint4.z - Origin.z; ++Vert; ++debugvertexcount; } @@ -439,40 +440,40 @@ int TTraction::RaArrayFill(CVertNormTex *Vert) t = (1 - std::fabs(f - mid) * 2); if( ( i % 2 ) == 0 ) { - Vert->x = pt3.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ); - Vert->z = pt3.z; + Vert->x = pt3.x - Origin.x; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - Origin.y; + Vert->z = pt3.z - Origin.z; ++Vert; ++debugvertexcount; - Vert->x = pt4.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; - Vert->y = pt4.y; - Vert->z = pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; + Vert->x = pt4.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x; + Vert->y = pt4.y - Origin.y; + Vert->z = pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z; ++Vert; ++debugvertexcount; } else { - Vert->x = pt3.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ); - Vert->z = pt3.z; + Vert->x = pt3.x - Origin.x; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - Origin.y; + Vert->z = pt3.z - Origin.z; ++Vert; ++debugvertexcount; - Vert->x = pt4.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; - Vert->y = pt4.y; - Vert->z = pt4.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; + Vert->x = pt4.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x; + Vert->y = pt4.y - Origin.y; + Vert->z = pt4.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z; ++Vert; ++debugvertexcount; } if( ( ( Wires == 4 ) && ( ( i == 1 ) || ( i == iNumSections - 3 ) ) ) ) { - Vert->x = pt3.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - 0.05; - Vert->z = pt3.z; + Vert->x = pt3.x - Origin.x; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - 0.05 - Origin.y; + Vert->z = pt3.z - Origin.z; ++Vert; ++debugvertexcount; - Vert->x = pt3.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference; - Vert->z = pt3.z; + Vert->x = pt3.x - Origin.x; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - Origin.y; + Vert->z = pt3.z - Origin.z; ++Vert; ++debugvertexcount; } diff --git a/Traction.h b/Traction.h index e276bf59..5a68c359 100644 --- a/Traction.h +++ b/Traction.h @@ -68,7 +68,7 @@ class TTraction // virtual void SelectedRender(); void RenderDL(float mgn); int RaArrayPrepare(); - int RaArrayFill(CVertNormTex *Vert); + int RaArrayFill( CVertNormTex *Vert, Math3D::vector3 const &Origin ); void RenderVBO(float mgn, int iPtr); int TestPoint(Math3D::vector3 *Point); void Connect(int my, TTraction *with, int to); diff --git a/World.cpp b/World.cpp index d7fa9bae..dc3c4968 100644 --- a/World.cpp +++ b/World.cpp @@ -1276,6 +1276,8 @@ TWorld::Render_Cab() { return; } + ::glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit +/* glPushMatrix(); vector3 pos = dynamic->GetPosition(); // wszpółrzędne pojazdu z kabiną // glTranslatef(pos.x,pos.y,pos.z); //przesunięcie o wektor (tak było i trzęsło) @@ -1284,7 +1286,11 @@ TWorld::Render_Cab() { glLoadIdentity(); // zacząć od macierzy jedynkowej Camera.SetCabMatrix( pos ); // widok z kamery po przesunięciu glMultMatrixd( dynamic->mMatrix.getArray() ); // ta macierz nie ma przesunięcia - glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit +*/ + ::glPushMatrix(); + auto const originoffset = dynamic->GetPosition() - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + ::glMultMatrixd( dynamic->mMatrix.getArray() ); if( dynamic->mdKabina ) // bo mogła zniknąć przy przechodzeniu do innego pojazdu { diff --git a/frustum.h b/frustum.h index 19febbe3..360f8a5a 100644 --- a/frustum.h +++ b/frustum.h @@ -27,6 +27,9 @@ public: calculate(glm::mat4 const &Projection, glm::mat4 const &Modelview); // returns true if specified point is inside of the frustum inline + bool + point_inside( glm::vec3 const &Point ) const { return point_inside( Point.x, Point.y, Point.z ); } + inline bool point_inside( float3 const &Point ) const { return point_inside( Point.x, Point.y, Point.z ); } inline @@ -36,6 +39,9 @@ public: point_inside( float const X, float const Y, float const Z ) const; // tests if the sphere is in frustum, returns the distance between origin and sphere centre inline + float + sphere_inside( glm::vec3 const &Center, float const Radius ) const { return sphere_inside( Center.x, Center.y, Center.z, Radius ); } + inline float sphere_inside( float3 const &Center, float const Radius ) const { return sphere_inside( Center.x, Center.y, Center.z, Radius ); } inline @@ -45,6 +51,9 @@ public: sphere_inside( float const X, float const Y, float const Z, float const Radius ) const; // returns true if specified cube is inside of the frustum. Size = half of the length inline + bool + cube_inside( glm::vec3 const &Center, float const Size ) const { return cube_inside( Center.x, Center.y, Center.z, Size ); } + inline bool cube_inside( float3 const &Center, float const Size ) const { return cube_inside( Center.x, Center.y, Center.z, Size ); } inline diff --git a/renderer.cpp b/renderer.cpp index 2fe2ede1..0403e303 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -142,9 +142,16 @@ opengl_renderer::Render() { ::glLoadIdentity(); if( World.InitPerformed() ) { - +/* World.Camera.SetMatrix(); m_camera.update_frustum(); +*/ + glm::dmat4 worldcamera; + World.Camera.SetMatrix( worldcamera ); + m_camera.update_frustum( OpenGLMatrices.data( GL_PROJECTION ), worldcamera ); + // frustum tests are performed in 'world space' but after we set up frustum + // we no longer need camera translation, only rotation + ::glMultMatrixd( glm::value_ptr( glm::dmat4( glm::dmat3( worldcamera )))); Render( &World.Environment ); Render( &World.Ground ); @@ -178,11 +185,12 @@ opengl_renderer::Render( world_environment *Environment ) { /* ::glTranslatef( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z ); */ +/* glm::mat4 worldcamera; World.Camera.SetMatrix( worldcamera ); glLoadIdentity(); glMultMatrixf( glm::value_ptr( glm::mat4( glm::mat3( worldcamera ) ) ) ); - +*/ // setup fog if( Global::fFogEnd > 0 ) { // fog setup @@ -294,12 +302,16 @@ opengl_renderer::Render( world_environment *Environment ) { bool opengl_renderer::Render( TGround *Ground ) { -/* - glDisable( GL_BLEND ); - glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - glEnable( GL_LIGHTING ); - glColor3f( 1.0f, 1.0f, 1.0f ); + ::glEnable( GL_LIGHTING ); + ::glDisable( GL_BLEND ); + ::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + ::glColor3f( 1.0f, 1.0f, 1.0f ); + + ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji) + + Update_Lights( Ground->m_lights ); +/* glm::vec3 const cameraposition( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z ); int const camerax = static_cast( std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2 ); int const cameraz = static_cast( std::floor( cameraposition.z / 1000.0f ) + iNumRects / 2 ); @@ -317,15 +329,6 @@ opengl_renderer::Render( TGround *Ground ) { } } */ - ::glEnable( GL_LIGHTING ); - ::glDisable( GL_BLEND ); - ::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - ::glColor3f( 1.0f, 1.0f, 1.0f ); - - ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji) - - Update_Lights( Ground->m_lights ); - Ground->CameraDirection.x = std::sin( Global::pCameraRotation ); // wektor kierunkowy Ground->CameraDirection.z = std::cos( Global::pCameraRotation ); TGroundNode *node; @@ -354,6 +357,16 @@ opengl_renderer::Render( TGround *Ground ) { } } // renderowanie progresywne - zależne od FPS oraz kierunku patrzenia + // pre-calculate camera view span + double const fieldofviewcosine = + std::cos( + std::max( + // vertical... + Global::FieldOfView / Global::ZoomFactor, + // ...or horizontal, whichever is bigger + Global::FieldOfView / Global::ZoomFactor + * std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ) ) ); + Ground->iRendered = 0; // ilość renderowanych sektorów Math3D::vector3 direction; for( k = 0; k < Global::iSegmentsRendered; ++k ) // sektory w kolejności odległości @@ -369,10 +382,16 @@ opengl_renderer::Render( TGround *Ground ) { if( Math3D::LengthSquared3( direction ) > 5 ) // te blisko są zawsze wyświetlane { direction = Math3D::SafeNormalize( direction ); // normalizacja - if( Ground->CameraDirection.x * direction.x + Ground->CameraDirection.z * direction.z < 0.55 ) + if( Ground->CameraDirection.x * direction.x + Ground->CameraDirection.z * direction.z < 0.5 ) continue; // pomijanie sektorów poza kątem patrzenia } // kwadrat kilometrowy nie zawsze, bo szkoda FPS + // TODO: unify all math objects + ::glPushMatrix(); + auto const &cellorigin = Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].m_area.center; + auto const originoffset = Math3D::vector3( cellorigin.x, cellorigin.y, cellorigin.z ) - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + if( Global::bUseVBO ) { // vbo render path Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].RenderVBO(); @@ -381,6 +400,8 @@ opengl_renderer::Render( TGround *Ground ) { // display list render path Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].RenderDL(); } + ::glPopMatrix(); + if( ( tmp = Ground->FastGetSubRect( i + c, j + r ) ) != nullptr ) { if( tmp->iNodeCount ) { // o ile są jakieś obiekty, bo po co puste sektory przelatywać @@ -389,16 +410,15 @@ opengl_renderer::Render( TGround *Ground ) { } } while( ( i < 0 ) || ( j < 0 ) ); // są 4 przypadki, oprócz i=j=0 } - // dodać renderowanie terenu z E3D - jedno VBO jest używane dla całego modelu, chyba że jest ich więcej if( Global::bUseVBO ) { if( Global::pTerrainCompact ) { Global::pTerrainCompact->TerrainRenderVBO( TGroundRect::iFrameNumber ); } } - // renderowanie nieprzezroczystych for( i = 0; i < Ground->iRendered; ++i ) { + if( Global::bUseVBO ) { // vbo render path Ground->pRendered[ i ]->RenderVBO(); @@ -408,10 +428,8 @@ opengl_renderer::Render( TGround *Ground ) { Ground->pRendered[ i ]->RenderDL(); } } - // regular render takes care of all solid geometry present in the scene, thus we can launch alpha parts render here return Render_Alpha( Ground ); - } bool @@ -436,22 +454,30 @@ opengl_renderer::Render( TGroundNode *Node ) { switch (Node->iType) { case TP_TRACK: { + + if( Global::bUseVBO && ( Node->iNumVerts <= 0 ) ) { + return false; + } + // setup + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + // TODO: unify the render code after generic buffers are in place if( Global::bUseVBO ) { - if( Node->iNumVerts ) { - Node->pTrack->RaRenderVBO( Node->iVboPtr ); - } - else { - return false; - } + // vbo render path + Node->pTrack->RaRenderVBO( Node->iVboPtr ); } else { + // display list render path Node->pTrack->Render(); } + // post-render cleanup + ::glPopMatrix(); return true; } case TP_MODEL: { - Node->Model->Render( &Node->pCenter ); + Node->Model->Render( Node->pCenter - Global::pCameraPosition ); return true; } case TP_MEMCELL: { @@ -480,6 +506,9 @@ opengl_renderer::Render( TGroundNode *Node ) { // wszelkie linie są rysowane na samym końcu if( Node->iNumPts ) { // setup + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); // w zaleznosci od koloru swiatla ::glColor4ub( static_cast( std::floor( Node->Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ) ), @@ -497,6 +526,9 @@ opengl_renderer::Render( TGroundNode *Node ) { else { ::glCallList( Node->DisplayListID ); } + + // post-render cleanup + ::glPopMatrix(); return true; } else { @@ -505,7 +537,17 @@ opengl_renderer::Render( TGroundNode *Node ) { } else { // GL_TRIANGLE etc + if( ( Global::bUseVBO ? + Node->iVboPtr < 0 : + Node->DisplayListID == 0 ) ) { + return false; + } + // setup + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + ::glColor3ub( static_cast( Node->Diffuse[ 0 ] ), static_cast( Node->Diffuse[ 1 ] ), @@ -517,22 +559,16 @@ opengl_renderer::Render( TGroundNode *Node ) { // TODO: unify the render code after generic buffers are in place if( Global::bUseVBO ) { // vbo render path - if( Node->iVboPtr >= 0 ) { - ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts ); - } - else { - return false; - } + ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts ); } else { // display list render path - if( Node->DisplayListID != 0 ) { - ::glCallList( Node->DisplayListID ); - } - else { - return false; - } + ::glCallList( Node->DisplayListID ); } + + // post-render cleanup + ::glPopMatrix(); + return true; } } @@ -550,11 +586,11 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { // setup TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji - double squaredistance = SquareMagnitude( ( Global::pCameraPosition - Dynamic->vPosition ) / Global::ZoomFactor ); + auto const originoffset = Dynamic->vPosition - Global::pCameraPosition; + double const squaredistance = SquareMagnitude( originoffset / Global::ZoomFactor ); Dynamic->ABuLittleUpdate( squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu - ::glPushMatrix(); - +/* if( Dynamic == Global::pUserDynamic ) { //specjalne ustawienie, aby nie trzęsło //tu trzeba by ustawić animacje na modelu zewnętrznym @@ -563,7 +599,8 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { } else ::glTranslated( Dynamic->vPosition.x, Dynamic->vPosition.y, Dynamic->vPosition.z ); // standardowe przesunięcie względem początku scenerii - +*/ + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glMultMatrixd( Dynamic->mMatrix.getArray() ); if( Dynamic->fShade > 0.0f ) { @@ -666,7 +703,7 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, Math3D: if( Angle.z != 0.0 ) ::glRotated( Angle.z, 0.0, 0.0, 1.0 ); - auto const result = Render( Model, Material, SquareMagnitude( Position - Global::GetCameraPosition() ) ); + auto const result = Render( Model, Material, SquareMagnitude( Position / Global::ZoomFactor ) ); // position is effectively camera offset ::glPopMatrix(); @@ -932,12 +969,19 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { case TP_TRACTION: { // TODO: unify the render code after generic buffers are in place if( Node->bVisible ) { + // setup + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + // render if( Global::bUseVBO ) { Node->hvTraction->RenderVBO( distancesquared, Node->iVboPtr ); } else { Node->hvTraction->RenderDL( distancesquared ); } + // post-render cleanup + ::glPopMatrix(); return true; } else { @@ -945,7 +989,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { } } case TP_MODEL: { - Node->Model->RenderAlpha( &Node->pCenter ); + Node->Model->RenderAlpha( Node->pCenter - Global::pCameraPosition ); return true; } } @@ -980,6 +1024,9 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { // wszelkie linie są rysowane na samym końcu if( Node->iNumPts ) { // setup + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); // w zaleznosci od koloru swiatla ::glColor4ub( static_cast( std::floor( Node->Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ) ), @@ -997,12 +1044,18 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { else { ::glCallList( Node->DisplayListID ); } + // post-render cleanup + ::glPopMatrix(); result = true; } } else { // GL_TRIANGLE etc // setup + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + ::glColor3ub( static_cast( Node->Diffuse[ 0 ] ), static_cast( Node->Diffuse[ 1 ] ), @@ -1024,8 +1077,10 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { ::glCallList( Node->DisplayListID ); result = true; } + // post-render cleanup + ::glPopMatrix(); } - // post-render cleanup + #ifdef _PROBLEND if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 { @@ -1049,17 +1104,19 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { // setup TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji - double squaredistance = SquareMagnitude( ( Global::pCameraPosition - Dynamic->vPosition ) / Global::ZoomFactor ); + auto const originoffset = Dynamic->vPosition - Global::pCameraPosition; + double const squaredistance = SquareMagnitude( originoffset / Global::ZoomFactor ); Dynamic->ABuLittleUpdate( squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu - ::glPushMatrix(); +/* if( Dynamic == Global::pUserDynamic ) { // specjalne ustawienie, aby nie trzęsło ::glLoadIdentity(); // zacząć od macierzy jedynkowej Global::pCamera->SetCabMatrix( Dynamic->vPosition ); // specjalne ustawienie kamery } else ::glTranslated( Dynamic->vPosition.x, Dynamic->vPosition.y, Dynamic->vPosition.z ); // standardowe przesunięcie względem początku scenerii - +*/ + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glMultMatrixd( Dynamic->mMatrix.getArray() ); if( Dynamic->fShade > 0.0f ) { @@ -1161,7 +1218,7 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, M if( Angle.z != 0.0 ) ::glRotated( Angle.z, 0.0, 0.0, 1.0 ); - auto const result = Render_Alpha( Model, Material, SquareMagnitude( Position - Global::GetCameraPosition() ) ); + auto const result = Render_Alpha( Model, Material, SquareMagnitude( Position / Global::ZoomFactor ) ); // position is effectively camera offset ::glPopMatrix(); @@ -1400,7 +1457,7 @@ opengl_renderer::Update_Lights( light_array const &Lights ) { continue; } // if the light passed tests so far, it's good enough - renderlight->set_position( scenelight.position ); + renderlight->set_position( scenelight.position - Global::pCameraPosition ); renderlight->direction = scenelight.direction; auto luminance = Global::fLuminance; // TODO: adjust this based on location, e.g. for tunnels diff --git a/renderer.h b/renderer.h index 65531612..1b478d3c 100644 --- a/renderer.h +++ b/renderer.h @@ -94,7 +94,7 @@ public: update_frustum() { m_frustum.calculate(); } inline void - update_frustum(glm::mat4 &Projection, glm::mat4 &Modelview) { m_frustum.calculate(Projection, Modelview); } + update_frustum(glm::mat4 const &Projection, glm::mat4 const &Modelview) { m_frustum.calculate(Projection, Modelview); } bool visible( bounding_area const &Area ) const; bool From 3068cc669eb2c066d627f452d6b8ab1a854e3867 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 26 May 2017 21:22:13 +0200 Subject: [PATCH 09/12] fixes for display list path camera-centric rendering, basic support for binary terrain object type, fix for assignment of 3d objects to terrain cells --- Ground.cpp | 41 +++++++++++++++------- Ground.h | 11 +++--- Model3d.cpp | 2 ++ Track.cpp | 64 +++++++++++++++++---------------- Traction.cpp | 99 ++++++++++++++++++++++++++++++---------------------- Traction.h | 4 +-- renderer.cpp | 39 +++++++++++---------- version.h | 2 +- 8 files changed, 150 insertions(+), 112 deletions(-) diff --git a/Ground.cpp b/Ground.cpp index fff7c1ed..cad91fec 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -255,9 +255,9 @@ void TGroundNode::RaRenderVBO() glDrawArrays(iType, iVboPtr, iNumVerts); // Narysuj naraz wszystkie trójkąty } -void TGroundNode::Compile(bool many) +void TGroundNode::Compile( Math3D::vector3 const &Origin, bool const Multiple ) { // tworzenie skompilowanej listy w wyświetlaniu DL - if (!many) + if (false == Multiple) { // obsługa pojedynczej listy if (DisplayListID) Release(); @@ -273,9 +273,9 @@ void TGroundNode::Compile(bool many) glBegin(iType); for (int i = 0; i < iNumPts; ++i) glVertex3d( - Points[i].x - m_rootposition.x, - Points[i].y - m_rootposition.y, - Points[i].z - m_rootposition.z ); + Points[i].x - Origin.x, + Points[i].y - Origin.y, + Points[i].z - Origin.z ); glEnd(); } else if (iType == GL_TRIANGLE_STRIP || iType == GL_TRIANGLE_FAN || iType == GL_TRIANGLES) @@ -293,9 +293,9 @@ void TGroundNode::Compile(bool many) Vertices[i].tu, Vertices[i].tv); glVertex3d( - Points[i].x - m_rootposition.x, - Points[i].y - m_rootposition.y, - Points[i].z - m_rootposition.z ); + Vertices[i].Point.x - Origin.x, + Vertices[i].Point.y - Origin.y, + Vertices[i].Point.z - Origin.z ); } glEnd(); } @@ -318,7 +318,7 @@ void TGroundNode::Compile(bool many) n = n->nNext3; // następny z listy } } - if (!many) + if (false == Multiple) if (Global::bManageNodes) glEndList(); }; @@ -392,6 +392,7 @@ void TSubRect::NodeAdd(TGroundNode *Node) case TP_TRACK: // TODO: tory z cieniem (tunel, canyon) też dać bez łączenia? ++iTracks; // jeden tor więcej Node->pTrack->RaOwnerSet(this); // do którego sektora ma zgłaszać animację +/* if( ( true == Global::bUseVBO ) || ( false == Node->pTrack->IsGroupable() ) ) { // tory ruchome nie są grupowane przy Display Lists (wymagają odświeżania DL) @@ -427,6 +428,11 @@ void TSubRect::NodeAdd(TGroundNode *Node) nMeshed = Node; } // do podzielenia potem } +*/ + // NOTE: track merge code temporarily disabled to simplify implementation of camera-centric rendering + // TODO: re-implement merge for both render paths down the road + RaNodeAdd( Node ); + break; case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: @@ -940,8 +946,10 @@ TGroundRect::Init() { - glm::vec3( 500.0f, 0.0f, 500.0f ) // 'upper left' corner of rectangle + glm::vec3( subrectsize * 0.5f, 0.0f, subrectsize * 0.5f ) // center of sub-rectangle + glm::vec3( subrectsize * column, 0.0f, subrectsize * row ); +/* // NOTE: the actual coordinates get swapped, as they're swapped in rest of the code :x area.center = glm::vec3( area.center.z, area.center.y, area.center.x ); +*/ area.radius = subrectsize * M_SQRT2; } } @@ -962,16 +970,23 @@ void TGroundRect::RenderDL() nRender->DisplayListID = glGenLists(1); glNewList(nRender->DisplayListID, GL_COMPILE); nRender->iVersion = Global::iReCompile; // aktualna wersja siatek + auto const origin = Math3D::vector3( m_area.center.x, m_area.center.y, m_area.center.z ); for (TGroundNode *node = nRender; node; node = node->nNext3) // następny tej grupy - node->Compile(true); + node->Compile(origin, true); glEndList(); } GfxRenderer.Render( nRender ); // nieprzezroczyste trójkąty kwadratu kilometrowego } - if( nRootMesh ) + // submodels geometry is world-centric, so at least for the time being we need to pop the stack early + ::glPopMatrix(); + if( nRootMesh ) { GfxRenderer.Render( nRootMesh ); + } iLastDisplay = iFrameNumber; // drugi raz nie potrzeba } + else { + ::glPopMatrix(); + } #else if( iLastDisplay != iFrameNumber ) { // tylko jezeli dany kwadrat nie był jeszcze renderowany LoadNodes(); // ewentualne tworzenie siatek @@ -1898,7 +1913,7 @@ TSubRect * TGround::FastGetSubRect(int iCol, int iRow) sc = iCol - bc * iNumSubRects; if ((br < 0) || (bc < 0) || (br >= iNumRects) || (bc >= iNumRects)) return NULL; - return (Rects[br][bc].FastGetRect(sc, sr)); + return (Rects[bc][br].FastGetRect(sc, sr)); } TSubRect * TGround::GetSubRect(int iCol, int iRow) @@ -1910,7 +1925,7 @@ TSubRect * TGround::GetSubRect(int iCol, int iRow) sc = iCol - bc * iNumSubRects; if ((br < 0) || (bc < 0) || (br >= iNumRects) || (bc >= iNumRects)) return NULL; // jeśli poza mapą - return (Rects[br][bc].SafeGetRect(sc, sr)); // pobranie małego kwadratu + return (Rects[bc][br].SafeGetRect(sc, sr)); // pobranie małego kwadratu } TEvent * TGround::FindEvent(const std::string &asEventName) diff --git a/Ground.h b/Ground.h index ca2aced2..4ee33f16 100644 --- a/Ground.h +++ b/Ground.h @@ -166,7 +166,7 @@ public: return NULL; }; - void Compile(bool many = false); + void Compile(Math3D::vector3 const &Origin, bool const Multiple = false); void Release(); void RenderHidden(); // obsługa dźwięków i wyzwalaczy zdarzeń @@ -341,16 +341,15 @@ class TGround { return &Rects[GetColFromX(x) / iNumSubRects][GetRowFromZ(z) / iNumSubRects]; }; + TSubRect * GetSubRect( int iCol, int iRow ); TSubRect * GetSubRect(double x, double z) { return GetSubRect(GetColFromX(x), GetRowFromZ(z)); }; - TSubRect * FastGetSubRect(double x, double z) - { - return FastGetSubRect(GetColFromX(x), GetRowFromZ(z)); + TSubRect * FastGetSubRect( int iCol, int iRow ); + TSubRect * FastGetSubRect( double x, double z ) { + return FastGetSubRect( GetColFromX( x ), GetRowFromZ( z ) ); }; - TSubRect * GetSubRect(int iCol, int iRow); - TSubRect * FastGetSubRect(int iCol, int iRow); int GetRowFromZ(double z) { return (int)(z / fSubRectSize + fHalfTotalNumSubRects); diff --git a/Model3d.cpp b/Model3d.cpp index a6e0845f..7eb1493f 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1828,6 +1828,8 @@ TSubModel *TModel3d::TerrainSquare(int n) void TModel3d::TerrainRenderVBO(int n) { // renderowanie terenu z VBO glPushMatrix(); + ::glTranslated( -Global::pCameraPosition.x, -Global::pCameraPosition.y, -Global::pCameraPosition.z ); + // glTranslated(vPosition->x,vPosition->y,vPosition->z); // if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0); // if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0); diff --git a/Track.cpp b/Track.cpp index ddb669cc..d42a3c91 100644 --- a/Track.cpp +++ b/Track.cpp @@ -1447,19 +1447,19 @@ void TTrack::Compile(GLuint tex) if( SwitchExtension->iRoads == 3 ) { // mogą być tylko 3 drogi zamiast 4 SwitchExtension->iPoints = - 5 + SwitchExtension->Segments[ 0 ]->RaSegCount() + - SwitchExtension->Segments[ 1 ]->RaSegCount() + - SwitchExtension->Segments[ 2 ]->RaSegCount(); + SwitchExtension->Segments[ 0 ]->RaSegCount() + + SwitchExtension->Segments[ 1 ]->RaSegCount() + + SwitchExtension->Segments[ 2 ]->RaSegCount(); } else { SwitchExtension->iPoints = - 5 + SwitchExtension->Segments[ 2 ]->RaSegCount() + - SwitchExtension->Segments[ 3 ]->RaSegCount() + - SwitchExtension->Segments[ 4 ]->RaSegCount() + - SwitchExtension->Segments[ 5 ]->RaSegCount(); // mogą być tylko 3 drogi + SwitchExtension->Segments[ 2 ]->RaSegCount() + + SwitchExtension->Segments[ 3 ]->RaSegCount() + + SwitchExtension->Segments[ 4 ]->RaSegCount() + + SwitchExtension->Segments[ 5 ]->RaSegCount(); } // tablica utworzona z zapasem, ale nie wypełniona współrzędnymi - SwitchExtension->vPoints = new vector3[SwitchExtension->iPoints]; + SwitchExtension->vPoints = new vector3[ SwitchExtension->iPoints + SwitchExtension->iRoads ]; } vector3 *b = SwitchExtension->bPoints ? @@ -1573,39 +1573,43 @@ void TTrack::Compile(GLuint tex) // renderowanie nawierzchni na końcu double sina0 = sin(a[0]), cosa0 = cos(a[0]); double u, v; - if (!SwitchExtension->bPoints) // jeśli tablica nie wypełniona - if (b) // ale jest wskaźnik do tablicy - może nie być? - { // coś się gubi w obliczeniach na wskaźnikach - // ustalenie liczby punktów, bo mogło wyjść inaczej niż - i = (int)(((size_t)(b)) - ((size_t)(SwitchExtension->vPoints))) / sizeof(vector3); - // policzone z góry - if (i > 0) - { // jeśli zostało to właśnie utworzone - if (SwitchExtension->iPoints > i) // jeśli wyszło mniej niż było miejsca - SwitchExtension->iPoints = i; // domknięcie wachlarza - else { - // jak tutaj wejdzie, to błąd jest - zrobić miejsce na powtórzenie pierwszego punktu na końcu - --SwitchExtension->iPoints; - } - SwitchExtension->vPoints[SwitchExtension->iPoints++] = SwitchExtension->vPoints[0]; - SwitchExtension->bPoints = true; // tablica punktów została wypełniona - } - } + if( ( false == SwitchExtension->bPoints ) // jeśli tablica nie wypełniona + && ( b != nullptr ) ) { + SwitchExtension->bPoints = true; // tablica punktów została wypełniona + } + if (TextureID1) // jeśli podana tekstura nawierzchni if ( (tex == TextureID1) || (tex == 0) ) // jeśli pasuje do grupy (tex) { if (!tex) GfxRenderer.Bind( TextureID1 ); glBegin(GL_TRIANGLE_FAN); // takie kółeczko będzie + // we start with a vertex in the middle... glNormal3f(0, 1, 0); glTexCoord2f(0.5, 0.5); //środek tekstury na środku skrzyżowania - glVertex3f(oxz.x, oxz.y, oxz.z); - for (i = SwitchExtension->iPoints - 1; i >= 0; --i) + glVertex3f( + oxz.x - origin.x, + oxz.y - origin.y, + oxz.z - origin.z ); + // ...and add one extra vertex to close the fan... + glNormal3f( 0, 1, 0 ); + // mapowanie we współrzędnych scenerii + u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + origin.x ) / fTexLength; + v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength ); + glTexCoord2f( + cosa0 * u + sina0 * v + 0.5, + -sina0 * u + cosa0 * v + 0.5 ); + glVertex3f( + SwitchExtension->vPoints[ 0 ].x, + SwitchExtension->vPoints[ 0 ].y, + SwitchExtension->vPoints[ 0 ].z ); + + for ( i = SwitchExtension->iPoints + SwitchExtension->iRoads - 1; i >= 0; --i ) { glNormal3f(0, 1, 0); // mapowanie we współrzędnych scenerii - u = (SwitchExtension->vPoints[i].x - oxz.x) / fTexLength; - v = (SwitchExtension->vPoints[i].z - oxz.z) / (fTexRatio1 * fTexLength); + u = (SwitchExtension->vPoints[i].x - oxz.x + origin.x) / fTexLength; + v = (SwitchExtension->vPoints[i].z - oxz.z + origin.z) / (fTexRatio1 * fTexLength); glTexCoord2f( cosa0 * u + sina0 * v + 0.5, -sina0 * u + cosa0 * v + 0.5); diff --git a/Traction.cpp b/Traction.cpp index 6cf2842a..c7add93a 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -109,7 +109,7 @@ TTraction::~TTraction() glDeleteLists(uiDisplayList, 1); } -void TTraction::Optimize() +void TTraction::Optimize( Math3D::vector3 const &Origin ) { if (Global::bUseVBO) return; @@ -125,13 +125,13 @@ void TTraction::Optimize() // Przewoz jezdny 1 'Marcin glBegin(GL_LINE_STRIP); glVertex3f( - pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, - pPoint1.y, - pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, + pPoint1.y - Origin.y, + pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z); glVertex3f( - pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, - pPoint2.y, - pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, + pPoint2.y - Origin.y, + pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z ); glEnd(); // Nie wiem co 'Marcin Math3D::vector3 pt1, pt2, pt3, pt4, v1, v2; @@ -147,29 +147,39 @@ void TTraction::Optimize() if (Wires > 1) { glBegin(GL_LINE_STRIP); - glVertex3f(pPoint3.x, pPoint3.y, pPoint3.z); + glVertex3f( + pPoint3.x - Origin.x, + pPoint3.y - Origin.y, + pPoint3.z - Origin.z ); for (int i = 0; i < iNumSections - 1; ++i) { pt3 = pPoint3 + v1 * f; t = (1 - std::fabs(f - mid) * 2); if ((Wires < 4) || ((i != 0) && (i != iNumSections - 2))) glVertex3f( - pt3.x, - pt3.y - std::sqrt(t) * fHeightDifference, - pt3.z); + pt3.x - Origin.x, + pt3.y - std::sqrt(t) * fHeightDifference - Origin.y, + pt3.z - Origin.z ); f += step; } - glVertex3f(pPoint4.x, pPoint4.y, pPoint4.z); + glVertex3f( + pPoint4.x - Origin.x, + pPoint4.y - Origin.y, + pPoint4.z - Origin.z ); glEnd(); } // Drugi przewod jezdny 'Winger if (Wires > 2) { glBegin(GL_LINE_STRIP); - glVertex3f(pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint1.y, - pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); - glVertex3f(pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint2.y, - pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + glVertex3f( + pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, + pPoint1.y - Origin.y, + pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z ); + glVertex3f( + pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, + pPoint2.y - Origin.y, + pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z ); glEnd(); } @@ -178,22 +188,29 @@ void TTraction::Optimize() if (Wires == 4) { glBegin(GL_LINE_STRIP); - glVertex3f(pPoint3.x, pPoint3.y - 0.65f * fHeightDifference, pPoint3.z); + glVertex3f( + pPoint3.x - Origin.x, + pPoint3.y - 0.65f * fHeightDifference - Origin.y, + pPoint3.z - Origin.z ); for (int i = 0; i < iNumSections - 1; ++i) { pt3 = pPoint3 + v1 * f; t = (1 - std::fabs(f - mid) * 2); glVertex3f( - pt3.x, + pt3.x - Origin.x, pt3.y - std::sqrt( t ) * fHeightDifference - ( ( ( i == 0 ) || ( i == iNumSections - 2 ) ) ? 0.25f * fHeightDifference : - 0.05 ), - pt3.z); + 0.05 ) + - Origin.y, + pt3.z - Origin.z ); f += step; } - glVertex3f(pPoint4.x, pPoint4.y - 0.65f * fHeightDifference, pPoint4.z); + glVertex3f( + pPoint4.x - Origin.x, + pPoint4.y - 0.65f * fHeightDifference - Origin.y, + pPoint4.z - Origin.z ); glEnd(); } @@ -214,35 +231,35 @@ void TTraction::Optimize() if ((i % 2) == 0) { glVertex3f( - pt3.x, - pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1), - pt3.z); + pt3.x - Origin.x, + pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1) - Origin.y, + pt3.z - Origin.z ); glVertex3f( - pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, - pt4.y, - pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, + pt4.y - Origin.y, + pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z ); } else { glVertex3f( - pt3.x, - pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1), - pt3.z); + pt3.x - Origin.x, + pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1) - Origin.y, + pt3.z - Origin.z ); glVertex3f( - pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, - pt4.y, - pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, + pt4.y - Origin.y, + pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z ); } if ((Wires == 4) && ((i == 1) || (i == iNumSections - 3))) { glVertex3f( - pt3.x, - pt3.y - std::sqrt(t) * fHeightDifference - 0.05, - pt3.z); + pt3.x - Origin.x, + pt3.y - std::sqrt(t) * fHeightDifference - 0.05 - Origin.y, + pt3.z - Origin.z ); glVertex3f( - pt3.x, - pt3.y - std::sqrt(t) * fHeightDifference, - pt3.z); + pt3.x - Origin.x, + pt3.y - std::sqrt(t) * fHeightDifference - Origin.y, + pt3.z - Origin.z ); } f += step; } @@ -258,7 +275,7 @@ void TTraction::InitCenter(vector3 Angles, vector3 pOrigin) fSquaredRadius= SquareMagnitude((pPoint2-pPoint1)*0.5f); } */ -void TTraction::RenderDL(float mgn) // McZapkie: mgn to odleglosc od obserwatora +void TTraction::RenderDL(float mgn, Math3D::vector3 const &Origin ) // McZapkie: mgn to odleglosc od obserwatora { // McZapkie: ustalanie przezroczystosci i koloru linii: if( Wires != 0 && !TestFlag( DamageFlag, 128 ) ) // rysuj jesli sa druty i nie zerwana @@ -281,7 +298,7 @@ void TTraction::RenderDL(float mgn) // McZapkie: mgn to odleglosc od obserwatora ::glColor4f( red, green, blue, linealpha ); // draw code if (!uiDisplayList) - Optimize(); // generowanie DL w miarę potrzeby + Optimize( Origin ); // generowanie DL w miarę potrzeby ::glCallList(uiDisplayList); // cleanup ::glLineWidth(1.0); diff --git a/Traction.h b/Traction.h index 5a68c359..62a635cb 100644 --- a/Traction.h +++ b/Traction.h @@ -56,7 +56,7 @@ class TTraction int iTries = 0; int PowerState{ 0 }; // type of incoming power, if any - void Optimize(); + void Optimize( Math3D::vector3 const &Origin ); TTraction(); ~TTraction(); @@ -66,7 +66,7 @@ class TTraction // { return TNode::Hit(x,z,hitPoint,hitDirection); }; // virtual bool Move(double dx, double dy, double dz) { return false; }; // virtual void SelectedRender(); - void RenderDL(float mgn); + void RenderDL(float mgn, Math3D::vector3 const &Origin ); int RaArrayPrepare(); int RaArrayFill( CVertNormTex *Vert, Math3D::vector3 const &Origin ); void RenderVBO(float mgn, int iPtr); diff --git a/renderer.cpp b/renderer.cpp index 0403e303..19ae8014 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -395,12 +395,12 @@ opengl_renderer::Render( TGround *Ground ) { if( Global::bUseVBO ) { // vbo render path Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].RenderVBO(); + ::glPopMatrix(); } else { // display list render path Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].RenderDL(); } - ::glPopMatrix(); if( ( tmp = Ground->FastGetSubRect( i + c, j + r ) ) != nullptr ) { if( tmp->iNodeCount ) { @@ -440,8 +440,12 @@ opengl_renderer::Render( TGroundNode *Node ) { switch (Node->iType) { // obiekty renderowane niezależnie od odległości case TP_SUBMODEL: + ::glPushMatrix(); + auto const originoffset = Node->pCenter - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); TSubModel::fSquareDist = 0; Render( Node->smTerrain ); + ::glPopMatrix(); return true; } @@ -494,7 +498,7 @@ opengl_renderer::Render( TGroundNode *Node ) { // additional setup for display lists if( ( Node->DisplayListID == 0 ) || ( Node->iVersion != Global::iReCompile ) ) { // Ra: wymuszenie rekompilacji - Node->Compile(); + Node->Compile(Node->m_rootposition); if( Global::bManageNodes ) ResourceManager::Register( Node ); }; @@ -506,9 +510,6 @@ opengl_renderer::Render( TGroundNode *Node ) { // wszelkie linie są rysowane na samym końcu if( Node->iNumPts ) { // setup - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - Global::pCameraPosition; - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); // w zaleznosci od koloru swiatla ::glColor4ub( static_cast( std::floor( Node->Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ) ), @@ -521,14 +522,16 @@ opengl_renderer::Render( TGroundNode *Node ) { // render // TODO: unify the render code after generic buffers are in place if( Global::bUseVBO ) { + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumPts ); + ::glPopMatrix(); } else { ::glCallList( Node->DisplayListID ); } - // post-render cleanup - ::glPopMatrix(); return true; } else { @@ -542,12 +545,7 @@ opengl_renderer::Render( TGroundNode *Node ) { Node->DisplayListID == 0 ) ) { return false; } - // setup - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - Global::pCameraPosition; - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - ::glColor3ub( static_cast( Node->Diffuse[ 0 ] ), static_cast( Node->Diffuse[ 1 ] ), @@ -559,16 +557,17 @@ opengl_renderer::Render( TGroundNode *Node ) { // TODO: unify the render code after generic buffers are in place if( Global::bUseVBO ) { // vbo render path + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts ); + ::glPopMatrix(); } else { // display list render path ::glCallList( Node->DisplayListID ); } - // post-render cleanup - ::glPopMatrix(); - return true; } } @@ -703,7 +702,8 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, Math3D: if( Angle.z != 0.0 ) ::glRotated( Angle.z, 0.0, 0.0, 1.0 ); - auto const result = Render( Model, Material, SquareMagnitude( Position / Global::ZoomFactor ) ); // position is effectively camera offset +// auto const result = Render( Model, Material, SquareMagnitude( Position / Global::ZoomFactor ) ); // position is effectively camera offset + auto const result = Render( Model, Material, SquareMagnitude( Position ) ); // position is effectively camera offset ::glPopMatrix(); @@ -978,7 +978,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { Node->hvTraction->RenderVBO( distancesquared, Node->iVboPtr ); } else { - Node->hvTraction->RenderDL( distancesquared ); + Node->hvTraction->RenderDL( distancesquared, Node->m_rootposition ); } // post-render cleanup ::glPopMatrix(); @@ -1010,7 +1010,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { // additional setup for display lists if( ( Node->DisplayListID == 0 ) || ( Node->iVersion != Global::iReCompile ) ) { // Ra: wymuszenie rekompilacji - Node->Compile(); + Node->Compile(Node->m_rootposition); if( Global::bManageNodes ) ResourceManager::Register( Node ); }; @@ -1218,7 +1218,8 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, M if( Angle.z != 0.0 ) ::glRotated( Angle.z, 0.0, 0.0, 1.0 ); - auto const result = Render_Alpha( Model, Material, SquareMagnitude( Position / Global::ZoomFactor ) ); // position is effectively camera offset +// auto const result = Render_Alpha( Model, Material, SquareMagnitude( Position / Global::ZoomFactor ) ); // position is effectively camera offset + auto const result = Render_Alpha( Model, Material, SquareMagnitude( Position ) ); // position is effectively camera offset ::glPopMatrix(); diff --git a/version.h b/version.h index 12dfa00e..7667fb27 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 524 +#define VERSION_MINOR 525 #define VERSION_REVISION 0 From d2a9f7080e683cfb44a6f7d4ce86a27664458a1a Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 29 May 2017 00:41:09 +0200 Subject: [PATCH 10/12] ground cells render code moved to renderer and partially unified; fix for slipping wheels calculation logic --- Ground.cpp | 147 ---------------------------------- Ground.h | 13 +--- McZapkie/Mover.cpp | 3 +- openglmatrixstack.h | 6 +- renderer.cpp | 186 +++++++++++++++++++++++++++++++++++--------- renderer.h | 6 ++ 6 files changed, 166 insertions(+), 195 deletions(-) diff --git a/Ground.cpp b/Ground.cpp index cad91fec..4dfbaa9f 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -840,84 +840,6 @@ void TSubRect::Release() CMesh::Clear(); // usuwanie buforów }; -void TSubRect::RenderDL() -{ // renderowanie nieprzezroczystych (DL) - TGroundNode *node; - RaAnimate(); // przeliczenia animacji torów w sektorze -/* - LoadNodes(); // czemu tutaj? -*/ - for( node = nRenderRect; node; node = node->nNext3 ) { - GfxRenderer.Render( node ); // nieprzezroczyste obiekty terenu - } - for( node = nRender; node; node = node->nNext3 ) - GfxRenderer.Render( node ); // nieprzezroczyste obiekty (oprócz pojazdów) - for (node = nRenderMixed; node; node = node->nNext3) - GfxRenderer.Render( node ); // nieprzezroczyste z mieszanych modeli - for (int j = 0; j < iTracks; ++j) - tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach -#ifdef EU07_SCENERY_EDITOR - // memcells - if( DebugModeFlag ) { - for( auto const memcell : m_memcells ) { - memcell->RenderDL(); - } - } -#endif -}; - -void TSubRect::RenderAlphaDL() -{ // renderowanie przezroczystych modeli oraz pojazdów (DL) - TGroundNode *node; - for( node = nRenderMixed; node; node = node->nNext3 ) - GfxRenderer.Render_Alpha( node ); // przezroczyste z mieszanych modeli - for( node = nRenderAlpha; node; node = node->nNext3 ) - GfxRenderer.Render_Alpha( node ); // przezroczyste modele - for (int j = 0; j < iTracks; ++j) - tTracks[j]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach -}; - -void TSubRect::RenderVBO() -{ // renderowanie nieprzezroczystych (VBO) - TGroundNode *node; - RaAnimate(); // przeliczenia animacji torów w sektorze -/* - LoadNodes(); // czemu tutaj? -*/ - if (StartVBO()) - { - for( node = nRenderRect; node; node = node->nNext3 ) - if( node->iVboPtr >= 0 ) - GfxRenderer.Render( node ); // nieprzezroczyste obiekty terenu - EndVBO(); - } - for( node = nRender; node; node = node->nNext3 ) - GfxRenderer.Render( node ); // nieprzezroczyste obiekty (oprócz pojazdów) - for (node = nRenderMixed; node; node = node->nNext3) - GfxRenderer.Render( node ); // nieprzezroczyste z mieszanych modeli - for (int j = 0; j < iTracks; ++j) - tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach -#ifdef EU07_SCENERY_EDITOR - // memcells - if( DebugModeFlag ) { - for( auto const memcell : m_memcells ) { - memcell->RenderVBO(); - } - } -#endif -}; - -void TSubRect::RenderAlphaVBO() -{ // renderowanie przezroczystych modeli oraz pojazdów (VBO) - TGroundNode *node; - for( node = nRenderMixed; node; node = node->nNext3 ) - GfxRenderer.Render_Alpha( node ); // przezroczyste z mieszanych modeli - for( node = nRenderAlpha; node; node = node->nNext3 ) - GfxRenderer.Render_Alpha( node ); // przezroczyste modele - for (int j = 0; j < iTracks; ++j) - tTracks[j]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach -}; - void TSubRect::RenderSounds() { // aktualizacja dźwięków w pojazdach sektora (sektor może nie być wyświetlany) for (int j = 0; j < iTracks; ++j) @@ -955,75 +877,6 @@ TGroundRect::Init() { } }; -void TGroundRect::RenderDL() -{ // renderowanie kwadratu kilometrowego (DL), jeśli jeszcze nie zrobione -#ifdef EU07_USE_OLD_RENDERCODE - if (iLastDisplay != iFrameNumber) - { // tylko jezeli dany kwadrat nie był jeszcze renderowany - // for (TGroundNode* node=pRender;node;node=node->pNext3) - // node->Render(); //nieprzezroczyste trójkąty kwadratu kilometrowego - if (nRender) - { //łączenie trójkątów w jedną listę - trochę wioska - if (!nRender->DisplayListID || (nRender->iVersion != Global::iReCompile)) - { // jeżeli nie skompilowany, kompilujemy wszystkie trójkąty w jeden - nRender->fSquareRadius = 5000.0 * 5000.0; // aby agregat nigdy nie znikał - nRender->DisplayListID = glGenLists(1); - glNewList(nRender->DisplayListID, GL_COMPILE); - nRender->iVersion = Global::iReCompile; // aktualna wersja siatek - auto const origin = Math3D::vector3( m_area.center.x, m_area.center.y, m_area.center.z ); - for (TGroundNode *node = nRender; node; node = node->nNext3) // następny tej grupy - node->Compile(origin, true); - glEndList(); - } - GfxRenderer.Render( nRender ); // nieprzezroczyste trójkąty kwadratu kilometrowego - } - // submodels geometry is world-centric, so at least for the time being we need to pop the stack early - ::glPopMatrix(); - if( nRootMesh ) { - GfxRenderer.Render( nRootMesh ); - } - iLastDisplay = iFrameNumber; // drugi raz nie potrzeba - } - else { - ::glPopMatrix(); - } -#else - if( iLastDisplay != iFrameNumber ) { // tylko jezeli dany kwadrat nie był jeszcze renderowany - LoadNodes(); // ewentualne tworzenie siatek - if( nRenderRect ) { - for( TGroundNode *node = nRenderRect; node; node = node->nNext3 ) // następny tej grupy - GfxRenderer.Render( node ); // nieprzezroczyste trójkąty kwadratu kilometrowego - } - if( nRootMesh ) - GfxRenderer.Render( nRootMesh ); - iLastDisplay = iFrameNumber; - } -#endif -}; - -void TGroundRect::RenderVBO() -{ // renderowanie kwadratu kilometrowego (VBO), jeśli jeszcze nie zrobione - if (iLastDisplay != iFrameNumber) - { // tylko jezeli dany kwadrat nie był jeszcze renderowany - LoadNodes(); // ewentualne tworzenie siatek - if ( nRenderRect && StartVBO()) - { - for (TGroundNode *node = nRenderRect; node; node = node->nNext3) // następny tej grupy -#ifdef EU07_USE_OLD_RENDERCODE - node->RaRenderVBO(); // nieprzezroczyste trójkąty kwadratu kilometrowego -#else - GfxRenderer.Render( node ); // nieprzezroczyste trójkąty kwadratu kilometrowego -#endif - EndVBO(); - iLastDisplay = iFrameNumber; - } - if (nTerrain) - nTerrain->smTerrain->iVisible = iFrameNumber; // ma się wyświetlić w tej ramce - } -}; - -//--------------------------------------------------------------------------- -//--------------------------------------------------------------------------- //--------------------------------------------------------------------------- std::vector TempVerts; diff --git a/Ground.h b/Ground.h index 4ee33f16..dd408880 100644 --- a/Ground.h +++ b/Ground.h @@ -192,8 +192,8 @@ class TSubRect : public Resource, public CMesh TGroundNode *nRootMesh = nullptr; // obiekty renderujące wg tekstury (wtórne, lista po nNext2) TGroundNode *nMeshed = nullptr; // lista obiektów dla których istnieją obiekty renderujące grupowo public: - TGroundNode * nRootNode = nullptr; // wszystkie obiekty w sektorze, z wyjątkiem renderujących i pojazdów (nNext2) - TGroundNode * nRenderHidden = nullptr; // lista obiektów niewidocznych, "renderowanych" również z tyłu (nNext3) + TGroundNode *nRootNode = nullptr; // wszystkie obiekty w sektorze, z wyjątkiem renderujących i pojazdów (nNext2) + TGroundNode *nRenderHidden = nullptr; // lista obiektów niewidocznych, "renderowanych" również z tyłu (nNext3) TGroundNode *nRenderRect = nullptr; // z poziomu sektora - nieprzezroczyste (nNext3) TGroundNode *nRenderRectAlpha = nullptr; // z poziomu sektora - przezroczyste (nNext3) TGroundNode *nRenderWires = nullptr; // z poziomu sektora - druty i inne linie (nNext3) @@ -217,11 +217,6 @@ class TSubRect : public Resource, public CMesh bool StartVBO(); // ustwienie VBO sektora dla (nRenderRect), (nRenderRectAlpha) i (nRenderWires) bool RaTrackAnimAdd(TTrack *t); // zgłoszenie toru do animacji void RaAnimate(); // przeliczenie animacji torów - void RenderDL(); // renderowanie nieprzezroczystych w Display Lists - void RenderAlphaDL(); // renderowanie przezroczystych w Display Lists - // (McZapkie-131202) - void RenderVBO(); // renderowanie nieprzezroczystych z własnego VBO - void RenderAlphaVBO(); // renderowanie przezroczystych z (własnego) VBO void RenderSounds(); // dźwięki pojazdów z niewidocznych sektorów }; @@ -238,6 +233,8 @@ class TGroundRect : public TSubRect { // kwadrat kilometrowy // obiekty o niewielkiej ilości wierzchołków będą renderowane stąd // Ra: 2012-02 doszły submodele terenu + friend class opengl_renderer; + private: int iLastDisplay; // numer klatki w której był ostatnio wyświetlany TSubRect *pSubRects{ nullptr }; @@ -264,8 +261,6 @@ class TGroundRect : public TSubRect for (int i = iNumSubRects * iNumSubRects - 1; i >= 0; --i) pSubRects[i].Sort(); // optymalizacja obiektów w sektorach }; - void RenderDL(); - void RenderVBO(); }; class TGround diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 74a80001..b707b944 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -3685,7 +3685,8 @@ void TMoverParameters::ComputeTotalForce(double dt, double dt1, bool FullVer) else FTrain = 0; Fb = BrakeForce(RunningTrack); - if( std::max( std::abs( FTrain ), Fb ) > TotalMassxg * Adhesive( RunningTrack.friction ) ) // poslizg + if( ( Vel > 0.001 ) // crude trap, to prevent braked stationary vehicles from passing fb > mass * adhesive test + && ( std::max( std::abs( FTrain ), Fb ) > TotalMassxg * Adhesive( RunningTrack.friction ) ) ) // poslizg { SlippingWheels = true; } diff --git a/openglmatrixstack.h b/openglmatrixstack.h index 890843d3..85561d0f 100644 --- a/openglmatrixstack.h +++ b/openglmatrixstack.h @@ -82,9 +82,9 @@ typedef std::vector openglstack_array; public: // constructors: opengl_matrices() { - m_stacks.emplace_back(); // projection - m_stacks.emplace_back(); // modelview - } + m_stacks.emplace_back(); // projection + m_stacks.emplace_back(); // modelview + } // methods: void diff --git a/renderer.cpp b/renderer.cpp index 19ae8014..93789019 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -322,9 +322,9 @@ opengl_renderer::Render( TGround *Ground ) { for( int column = originx; column <= originx + segmentcount; ++column ) { for( int row = originz; row <= originz + segmentcount; ++row ) { - auto &rectangle = Ground->Rects[ column ][ row ]; - if( m_camera.visible( rectangle.m_area ) ) { - rectangle.RenderDL(); + auto *rectangle = &Ground->Rects[ column ][ row ]; + if( m_camera.visible( rectangle->m_area ) ) { + Render( rectangle ); } } } @@ -386,21 +386,7 @@ opengl_renderer::Render( TGround *Ground ) { continue; // pomijanie sektorów poza kątem patrzenia } // kwadrat kilometrowy nie zawsze, bo szkoda FPS - // TODO: unify all math objects - ::glPushMatrix(); - auto const &cellorigin = Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].m_area.center; - auto const originoffset = Math3D::vector3( cellorigin.x, cellorigin.y, cellorigin.z ) - Global::pCameraPosition; - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - - if( Global::bUseVBO ) { - // vbo render path - Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].RenderVBO(); - ::glPopMatrix(); - } - else { - // display list render path - Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].RenderDL(); - } + Render( &Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ] ); if( ( tmp = Ground->FastGetSubRect( i + c, j + r ) ) != nullptr ) { if( tmp->iNodeCount ) { @@ -418,20 +404,143 @@ opengl_renderer::Render( TGround *Ground ) { } // renderowanie nieprzezroczystych for( i = 0; i < Ground->iRendered; ++i ) { - - if( Global::bUseVBO ) { - // vbo render path - Ground->pRendered[ i ]->RenderVBO(); - } - else { - // display list render path - Ground->pRendered[ i ]->RenderDL(); - } + Render( Ground->pRendered[ i ] ); } // regular render takes care of all solid geometry present in the scene, thus we can launch alpha parts render here return Render_Alpha( Ground ); } +// TODO: unify ground render code, until then old version is in place +#define EU07_USE_OLD_RENDERCODE +bool +opengl_renderer::Render( TGroundRect *Groundcell ) { + + ::glPushMatrix(); + auto const &cellorigin = Groundcell->m_area.center; + // TODO: unify all math objects + auto const originoffset = Math3D::vector3( cellorigin.x, cellorigin.y, cellorigin.z ) - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + + bool result{ false }; // will be true if we do any rendering + + // TODO: unify render paths + if( Global::bUseVBO ) { + + if ( Groundcell->iLastDisplay != Groundcell->iFrameNumber) + { // tylko jezeli dany kwadrat nie był jeszcze renderowany + Groundcell->LoadNodes(); // ewentualne tworzenie siatek + if ( Groundcell->nRenderRect && Groundcell->StartVBO()) + { + for (TGroundNode *node = Groundcell->nRenderRect; node; node = node->nNext3) // następny tej grupy +#ifdef EU07_USE_OLD_RENDERCODE + node->RaRenderVBO(); // nieprzezroczyste trójkąty kwadratu kilometrowego +#else + Render( node ); // nieprzezroczyste trójkąty kwadratu kilometrowego +#endif + Groundcell->EndVBO(); + Groundcell->iLastDisplay = Groundcell->iFrameNumber; + result = true; + } + if ( Groundcell->nTerrain) + Groundcell->nTerrain->smTerrain->iVisible = Groundcell->iFrameNumber; // ma się wyświetlić w tej ramce + } + ::glPopMatrix(); + } + else { +#ifdef EU07_USE_OLD_RENDERCODE + if (Groundcell->iLastDisplay != Groundcell->iFrameNumber) + { // tylko jezeli dany kwadrat nie był jeszcze renderowany + // for (TGroundNode* node=pRender;node;node=node->pNext3) + // node->Render(); //nieprzezroczyste trójkąty kwadratu kilometrowego + if ( Groundcell->nRender) + { //łączenie trójkątów w jedną listę - trochę wioska + if (!Groundcell->nRender->DisplayListID || ( Groundcell->nRender->iVersion != Global::iReCompile)) + { // jeżeli nie skompilowany, kompilujemy wszystkie trójkąty w jeden + Groundcell->nRender->fSquareRadius = 5000.0 * 5000.0; // aby agregat nigdy nie znikał + Groundcell->nRender->DisplayListID = glGenLists(1); + glNewList( Groundcell->nRender->DisplayListID, GL_COMPILE); + Groundcell->nRender->iVersion = Global::iReCompile; // aktualna wersja siatek + auto const origin = Math3D::vector3( Groundcell->m_area.center.x, Groundcell->m_area.center.y, Groundcell->m_area.center.z ); + for (TGroundNode *node = Groundcell->nRender; node; node = node->nNext3) // następny tej grupy + node->Compile(origin, true); + glEndList(); + } + Render( Groundcell->nRender ); // nieprzezroczyste trójkąty kwadratu kilometrowego + } + // submodels geometry is world-centric, so at least for the time being we need to pop the stack early + ::glPopMatrix(); + + if( Groundcell->nRootMesh ) { + Render( Groundcell->nRootMesh ); + } + Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba + result = true; + } + else { + ::glPopMatrix(); + } +#else + if( iLastDisplay != iFrameNumber ) { // tylko jezeli dany kwadrat nie był jeszcze renderowany + LoadNodes(); // ewentualne tworzenie siatek + if( nRenderRect ) { + for( TGroundNode *node = nRenderRect; node; node = node->nNext3 ) // następny tej grupy + Render( node ); // nieprzezroczyste trójkąty kwadratu kilometrowego + } + if( nRootMesh ) + Render( nRootMesh ); + iLastDisplay = iFrameNumber; + } +#endif + } + + return result; +} +#undef EU07_USE_OLD_RENDERCODE + +bool +opengl_renderer::Render( TSubRect *Groundsubcell ) { + + Groundsubcell->RaAnimate(); // przeliczenia animacji torów w sektorze + + TGroundNode *node; + // nieprzezroczyste obiekty terenu + if( Global::bUseVBO ) { + // vbo render path + if( Groundsubcell->StartVBO() ) { + for( node = Groundsubcell->nRenderRect; node; node = node->nNext3 ) { + if( node->iVboPtr >= 0 ) { + Render( node ); + } + } + Groundsubcell->EndVBO(); + } + } + else { + // display list render path + for( node = Groundsubcell->nRenderRect; node; node = node->nNext3 ) { + Render( node ); // nieprzezroczyste obiekty terenu + } + } + // nieprzezroczyste obiekty (oprócz pojazdów) + for( node = Groundsubcell->nRender; node; node = node->nNext3 ) + Render( node ); + // nieprzezroczyste z mieszanych modeli + for( node = Groundsubcell->nRenderMixed; node; node = node->nNext3 ) + Render( node ); + // nieprzezroczyste fragmenty pojazdów na torach + for( int j = 0; j < Groundsubcell->iTracks; ++j ) + Groundsubcell->tTracks[ j ]->RenderDyn(); +#ifdef EU07_SCENERY_EDITOR + // memcells + if( DebugModeFlag ) { + for( auto const memcell : m_memcells ) { + memcell->RenderDL(); + } + } +#endif + return true; +} + bool opengl_renderer::Render( TGroundNode *Node ) { @@ -901,14 +1010,7 @@ opengl_renderer::Render_Alpha( TGround *Ground ) { } for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych { // renderowanie przezroczystych modeli oraz pojazdów - if( Global::bUseVBO ) { - // vbo render path - Ground->pRendered[ i ]->RenderAlphaVBO(); - } - else { - // display list render path - Ground->pRendered[ i ]->RenderAlphaDL(); - } + Render_Alpha( Ground->pRendered[ i ] ); } ::glDisable( GL_LIGHTING ); // linie nie powinny świecić @@ -936,6 +1038,20 @@ opengl_renderer::Render_Alpha( TGround *Ground ) { return true; } +bool +opengl_renderer::Render_Alpha( TSubRect *Groundsubcell ) { + + TGroundNode *node; + for( node = Groundsubcell->nRenderMixed; node; node = node->nNext3 ) + Render_Alpha( node ); // przezroczyste z mieszanych modeli + for( node = Groundsubcell->nRenderAlpha; node; node = node->nNext3 ) + Render_Alpha( node ); // przezroczyste modele + for( int j = 0; j < Groundsubcell->iTracks; ++j ) + Groundsubcell->tTracks[ j ]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach + + return true; +} + // NOTE: legacy render system switch #define _PROBLEND diff --git a/renderer.h b/renderer.h index 1b478d3c..3cce3b05 100644 --- a/renderer.h +++ b/renderer.h @@ -124,6 +124,10 @@ public: Render( world_environment *Environment ); bool Render( TGround *Ground ); + bool + Render( TGroundRect *Groundcell ); + bool + Render( TSubRect *Groundsubcell ); bool Render( TGroundNode *Node ); bool @@ -138,6 +142,8 @@ public: Render( TMemCell *Memcell ); bool Render_Alpha( TGround *Ground ); + bool + Render_Alpha( TSubRect *Groundsubcell ); bool Render_Alpha( TGroundNode *Node ); bool From a28b3d5af9242184ec9cef6072681fc96903ede2 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 1 Jun 2017 16:21:17 +0200 Subject: [PATCH 11/12] build 170531. fix for pantograph pressure switch activation, partial fix for event sorting --- Driver.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++----------- Driver.h | 4 +-- DynObj.cpp | 42 ++++++++++++++++++------------ Event.cpp | 6 +++-- Ground.cpp | 37 +++++++++++++------------- version.h | 2 +- 6 files changed, 113 insertions(+), 54 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index dbb4b171..35daf905 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -469,6 +469,16 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) } else { if( iTableDirection == 0 ) { return; } + // NOTE: provisory fix for BUG: sempahor indices no longer matching table size + // TODO: find and really fix the reason it happens + if( ( SemNextIndex != -1 ) + && ( SemNextIndex >= sSpeedTable.size() ) ) { + SemNextIndex = -1; + } + if( ( SemNextStopIndex != -1 ) + && ( SemNextStopIndex >= sSpeedTable.size() ) ) { + SemNextStopIndex = -1; + } // kontynuacja skanowania od ostatnio sprawdzonego toru (w ostatniej pozycji zawsze jest tor) if( ( SemNextStopIndex != -1 ) && ( sSpeedTable[SemNextStopIndex].fVelNext < 1.0 ) ) { @@ -1335,7 +1345,6 @@ void TController::TablePurger() // we can only update pointers safely after new table is finalized, so record their indices until then for( std::size_t idx = 0; idx < sSpeedTable.size() - 1; ++idx ) { // cache placement of semaphors in the new table, if we encounter them - // NOTE: we rely on the semaphor actually getting added in the next step rather than skipped, but it's a pretty safe bet if( idx == SemNextIndex ) { SemNextIndex = trimmedtable.size(); } @@ -1346,6 +1355,13 @@ void TController::TablePurger() if( ( 0 == ( speedpoint.iFlags & spEnabled ) ) || ( ( speedpoint.iFlags & ( spElapsed | spTrack | spCurve | spSwitch ) == ( spElapsed | spTrack | spCurve ) ) && ( speedpoint.fVelNext < 0.0 ) ) ) { + // if the trimmed point happens to be currently active semaphor we need to invalidate their placements + if( idx == SemNextIndex ) { + SemNextIndex = -1; + } + if( idx == SemNextStopIndex ) { + SemNextStopIndex = -1; + } continue; } // we're left with useful speed point record we should copy @@ -3365,8 +3381,8 @@ bool TController::UpdateSituation(double dt) } ElapsedTime += dt; WaitingTime += dt; - fBrakeTime -= - dt; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca + // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca + fBrakeTime -= dt; fStopTime += dt; // zliczanie czasu postoju, nie ruszy dopóki ujemne fActionTime += dt; // czas używany przy regulacji prędkości i zamykaniu drzwi if (WriteLogFlag) @@ -3384,7 +3400,7 @@ bool TController::UpdateSituation(double dt) LastUpdatedTime = LastUpdatedTime + dt; } // Ra: skanowanie również dla prowadzonego ręcznie, aby podpowiedzieć prędkość - if ((LastReactionTime > Min0R(ReactionTime, 2.0))) + if ((LastReactionTime > std::min(ReactionTime, 2.0))) { // Ra: nie wiem czemu ReactionTime potrafi dostać 12 sekund, to jest przegięcie, bo przeżyna // STÓJ @@ -3429,18 +3445,48 @@ bool TController::UpdateSituation(double dt) if (AIControllFlag) { // tu bedzie logika sterowania if (mvOccupied->CommandIn.Command != "") - if (!mvOccupied->RunInternalCommand()) // rozpoznaj komende bo lokomotywa jej nie - // rozpoznaje + if( !mvOccupied->RunInternalCommand() ) { + // rozpoznaj komende bo lokomotywa jej nie rozpoznaje RecognizeCommand(); // samo czyta komendę wstawioną do pojazdu? - if (mvOccupied->SecuritySystem.Status > 1) // jak zadziałało CA/SHP - if (!mvOccupied->SecuritySystemReset()) // to skasuj - // if - // ((TestFlag(mvOccupied->SecuritySystem.Status,s_ebrake))&&(mvOccupied->BrakeCtrlPos==0)&&(AccDesired>0.0)) - if ((TestFlag(mvOccupied->SecuritySystem.Status, s_SHPebrake) || - TestFlag(mvOccupied->SecuritySystem.Status, s_CAebrake)) && - (mvOccupied->BrakeCtrlPos == 0) && (AccDesired > 0.0)) - mvOccupied->BrakeLevelSet( - 0); //!!! hm, może po prostu normalnie sterować hamulcem? + } + if( mvOccupied->SecuritySystem.Status > 1 ) { + // jak zadziałało CA/SHP + if( !mvOccupied->SecuritySystemReset() ) { // to skasuj + if( ( mvOccupied->BrakeCtrlPos == 0 ) + && ( AccDesired > 0.0 ) + && ( ( TestFlag( mvOccupied->SecuritySystem.Status, s_SHPebrake ) ) + || ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAebrake ) ) ) ) { + //!!! hm, może po prostu normalnie sterować hamulcem? + mvOccupied->BrakeLevelSet( 0 ); + } + } + } + // basic emergency stop handling, while at it + if( ( true == mvOccupied->EmergencyBrakeFlag ) // radio-stop + && ( mvOccupied->Vel < 0.01 ) // and actual stop + && ( true == mvOccupied->Radio ) ) { // and we didn't touch the radio yet + // turning off the radio should reset the flag, during security system check + if( m_radiocontroltime > 2.5 ) { + // arbitrary 2.5 sec delay between stop and disabling the radio + mvOccupied->Radio = false; + m_radiocontroltime = 0.0; + } + else { + m_radiocontroltime += LastReactionTime; + } + } + if( ( false == mvOccupied->Radio ) + && ( false == mvOccupied->EmergencyBrakeFlag ) ) { + // otherwise if it's safe to do so, turn the radio back on + if( m_radiocontroltime > 5.0 ) { + // arbitrary 5 sec delay before switching radio back on + mvOccupied->Radio = true; + m_radiocontroltime = 0.0; + } + else { + m_radiocontroltime += LastReactionTime; + } + } } switch (OrderList[OrderPos]) { // ustalenie prędkości przy doczepianiu i odczepianiu, dystansów w pozostałych przypadkach diff --git a/Driver.h b/Driver.h index ea961098..512e1d23 100644 --- a/Driver.h +++ b/Driver.h @@ -201,8 +201,7 @@ class TController public: double fLastStopExpDist = -1.0; // odległość wygasania ostateniego przystanku double ReactionTime = 0.0; // czas reakcji Ra: czego i na co? świadomości AI - double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę - // hamulca + double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca private: double fReady = 0.0; // poziom odhamowania wagonów bool Ready = false; // ABu: stan gotowosci do odjazdu - sprawdzenie odhamowania wagonow @@ -211,6 +210,7 @@ class TController double deltalog = 0.05; // przyrost czasu double LastReactionTime = 0.0; double fActionTime = 0.0; // czas używany przy regulacji prędkości i zamykaniu drzwi + double m_radiocontroltime{ 0.0 }; // timer used to control speed of radio operations TAction eAction = actSleep; // aktualny stan bool HelpMeFlag = false; // wystawiane True jesli cos niedobrego sie dzieje public: diff --git a/DynObj.cpp b/DynObj.cpp index 16229e1d..d13a2b7e 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2472,10 +2472,15 @@ bool TDynamicObject::Update(double dt, double dt1) } else { if( MoverParameters->PantPress >= 4.6 ) { - // prime the pressure switch - MoverParameters->PantPressSwitchActive = true; - // turn off the subsystems lock - MoverParameters->PantPressLockActive = false; + // NOTE: we require active low power source to prime the pressure switch + // this is a work-around for potential isssues caused by the switch activating on otherwise idle vehicles, but should check whether it's accurate + if( ( true == MoverParameters->Battery ) + || ( true == MoverParameters->ConverterFlag ) ) { + // prime the pressure switch + MoverParameters->PantPressSwitchActive = true; + // turn off the subsystems lock + MoverParameters->PantPressLockActive = false; + } if( MoverParameters->PantPress >= 4.8 ) { // Winger - automatyczne wylaczanie malej sprezarki @@ -5233,22 +5238,27 @@ TDynamicObject * TDynamicObject::ControlledFind() // jeździć dobrze // również hamowanie wykonuje się zaworem w członie, a nie w silnikowym... TDynamicObject *d = this; // zaczynamy od aktualnego - if (d->MoverParameters->TrainType & dt_EZT) // na razie dotyczy to EZT - if (d->NextConnected ? d->MoverParameters->Couplers[1].AllowedFlag & ctrain_depot : false) - { // gdy jest człon od sprzęgu 1, a sprzęg łączony - // warsztatowo (powiedzmy) - if ((d->MoverParameters->Power < 1.0) && (d->NextConnected->MoverParameters->Power > - 1.0)) // my nie mamy mocy, ale ten drugi ma + if( d->MoverParameters->TrainType & dt_EZT ) { + // na razie dotyczy to EZT + if( ( d->NextConnected != nullptr ) + && ( true == TestFlag( d->MoverParameters->Couplers[ 1 ].AllowedFlag, coupling::permanent ) ) ) { + // gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy) + if( ( d->MoverParameters->Power < 1.0 ) + && ( d->NextConnected->MoverParameters->Power > 1.0 ) ) { + // my nie mamy mocy, ale ten drugi ma d = d->NextConnected; // będziemy sterować tym z mocą + } } - else if (d->PrevConnected ? d->MoverParameters->Couplers[0].AllowedFlag & ctrain_depot : - false) - { // gdy jest człon od sprzęgu 0, a sprzęg łączony - // warsztatowo (powiedzmy) - if ((d->MoverParameters->Power < 1.0) && (d->PrevConnected->MoverParameters->Power > - 1.0)) // my nie mamy mocy, ale ten drugi ma + else if( ( d->PrevConnected != nullptr ) + && ( true == TestFlag( d->MoverParameters->Couplers[ 0 ].AllowedFlag, coupling::permanent ) ) ) { + // gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy) + if( ( d->MoverParameters->Power < 1.0 ) + && ( d->PrevConnected->MoverParameters->Power > 1.0 ) ) { + // my nie mamy mocy, ale ten drugi ma d = d->PrevConnected; // będziemy sterować tym z mocą + } } + } return d; }; //--------------------------------------------------------------------------- diff --git a/Event.cpp b/Event.cpp index c27f9a4a..bcca997f 100644 --- a/Event.cpp +++ b/Event.cpp @@ -612,8 +612,10 @@ void TEvent::Load(cParser *parser, vector3 *org) void TEvent::AddToQuery(TEvent *e) { // dodanie eventu do kolejki - if (evNext ? (e->fStartTime >= evNext->fStartTime) : false) - evNext->AddToQuery(e); // sortowanie wg czasu + if( ( evNext != nullptr ) + && ( e->fStartTime > evNext->fStartTime ) ) { + evNext->AddToQuery( e ); // sortowanie wg czasu + } else { // dodanie z przodu e->evNext = evNext; diff --git a/Ground.cpp b/Ground.cpp index 4dfbaa9f..91ee13e3 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -3178,9 +3178,9 @@ bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) if (!Event->iQueued) // jeśli nie dodany jeszcze do kolejki { // kolejka eventów jest posortowana względem (fStartTime) Event->Activator = Node; - if (Event->Type == tp_AddValues ? (Event->fDelay == 0.0) : false) - { // eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić - // jakieś dodawanie + if( ( Event->Type == tp_AddValues ) + && ( Event->fDelay == 0.0 ) ) { + // eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieś dodawanie // Ra: kopiowanie wykonania tu jest bez sensu, lepiej by było wydzielić funkcję // wykonującą eventy i ją wywołać if (EventConditon(Event)) @@ -3208,11 +3208,10 @@ bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) std::to_string(Event->Params[1].asdouble) + " " + std::to_string(Event->Params[2].asdouble)); } - Event = - Event - ->evJoined; // jeśli jest kolejny o takiej samej nazwie, to idzie do kolejki + // jeśli jest kolejny o takiej samej nazwie, to idzie do kolejki (and if there's no joint event it'll be set to null and processing will end here) + Event = Event->evJoined; } - if (Event) + if( Event != nullptr ) { // standardowe dodanie do kolejki WriteLog("EVENT ADDED TO QUEUE: " + Event->asName + (Node ? (" by " + Node->asName) : "")); Event->fStartTime = @@ -3221,10 +3220,13 @@ bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) Event->fStartTime += Event->fRandomDelay * Random(10000) * 0.0001; // doliczenie losowego czasu opóźnienia ++Event->iQueued; // zabezpieczenie przed podwójnym dodaniem do kolejki - if (QueryRootEvent ? Event->fStartTime >= QueryRootEvent->fStartTime : false) - QueryRootEvent->AddToQuery(Event); // dodanie gdzieś w środku - else - { // dodanie z przodu: albo nic nie ma, albo ma być wykonany szybciej niż pierwszy + if( ( QueryRootEvent != nullptr ) + && ( Event->fStartTime > QueryRootEvent->fStartTime ) ) { + // dodanie gdzieś w środku + QueryRootEvent->AddToQuery( Event ); + } + else { + // dodanie z przodu: albo nic nie ma, albo ma być wykonany szybciej niż pierwszy Event->evNext = QueryRootEvent; QueryRootEvent = Event; } @@ -3355,11 +3357,9 @@ bool TGround::CheckQuery() { // to teraz on będzie następny do wykonania QueryRootEvent = QueryRootEvent->evJoined; // następny będzie ten doczepiony QueryRootEvent->evNext = tmpEvent->evNext; // pamiętając o następnym z kolejki - QueryRootEvent->fStartTime = - tmpEvent->fStartTime; // czas musi być ten sam, bo nie jest aktualizowany + QueryRootEvent->fStartTime = tmpEvent->fStartTime; // czas musi być ten sam, bo nie jest aktualizowany QueryRootEvent->Activator = tmpEvent->Activator; // pojazd aktywujący - // w sumie można by go dodać normalnie do kolejki, ale trzeba te połączone posortować wg - // czasu wykonania + // w sumie można by go dodać normalnie do kolejki, ale trzeba te połączone posortować wg czasu wykonania } else // a jak nazwa jest unikalna, to kolejka idzie dalej QueryRootEvent = QueryRootEvent->evNext; // NULL w skrajnym przypadku @@ -3880,9 +3880,10 @@ bool TGround::GetTraction(TDynamicObject *model) node->hvTraction ->vParametric; // współczynniki równania parametrycznego fRaParam = -DotProduct(pant0, vFront); - fRaParam = -(DotProduct(node->hvTraction->pPoint1, vFront) + - fRaParam) / - DotProduct(vParam, vFront); + auto const paramfrontdot = DotProduct( vParam, vFront ); + fRaParam = + -( DotProduct( node->hvTraction->pPoint1, vFront ) + fRaParam ) + / ( paramfrontdot != 0.0 ? paramfrontdot : 0.001 ); // div0 trap if ((fRaParam >= -0.001) ? (fRaParam <= 1.001) : false) { // jeśli tylko jest w przedziale, wyznaczyć odległość wzdłuż // wektorów vUp i vLeft diff --git a/version.h b/version.h index 7667fb27..cbf2eb2e 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 525 +#define VERSION_MINOR 531 #define VERSION_REVISION 0 From 5f0069bf609f2ab9bfd87a1a18faca8a02100957 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 2 Jun 2017 16:35:36 +0200 Subject: [PATCH 12/12] build 170602. completed fix for infinite event loop, modified horn controls to work independent of each other --- Event.cpp | 34 +++++++--- Event.h | 2 +- Ground.cpp | 189 ++++++++++++++++------------------------------------- Ground.h | 4 +- Train.cpp | 10 +++ version.h | 2 +- 6 files changed, 96 insertions(+), 145 deletions(-) diff --git a/Event.cpp b/Event.cpp index bcca997f..ee34478a 100644 --- a/Event.cpp +++ b/Event.cpp @@ -610,16 +610,32 @@ void TEvent::Load(cParser *parser, vector3 *org) } }; -void TEvent::AddToQuery(TEvent *e) -{ // dodanie eventu do kolejki - if( ( evNext != nullptr ) - && ( e->fStartTime > evNext->fStartTime ) ) { - evNext->AddToQuery( e ); // sortowanie wg czasu +void TEvent::AddToQuery( TEvent *Event, TEvent *&Start ) { + + TEvent *target( Start ); + TEvent *previous( nullptr ); + while( ( Event->fStartTime >= target->fStartTime ) + && ( target->evNext != nullptr ) ) { + previous = target; + target = target->evNext; } - else - { // dodanie z przodu - e->evNext = evNext; - evNext = e; + // the new event will be either before or after the one we located + if( Event->fStartTime >= target->fStartTime ) { + assert( target->evNext == nullptr ); + target->evNext = Event; + // if we have resurrected event land at the end of list, the link from previous run could potentially "add" unwanted events to the queue + Event->evNext = nullptr; + } + else { + if( previous != nullptr ) { + previous->evNext = Event; + Event->evNext = target; + } + else { + // special case, we're inserting our event before the provided start point + Event->evNext = Start; + Start = Event; + } } } diff --git a/Event.h b/Event.h index 110e3abc..7d020046 100644 --- a/Event.h +++ b/Event.h @@ -105,7 +105,7 @@ class TEvent // zmienne: ev* ~TEvent(); void Init(); void Load(cParser *parser, vector3 *org); - void AddToQuery(TEvent *e); + static void AddToQuery( TEvent *Event, TEvent *&Start ); std::string CommandGet(); TCommandType Command(); double ValueGet(int n); diff --git a/Ground.cpp b/Ground.cpp index 91ee13e3..54662956 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -3065,17 +3065,6 @@ TTrack * TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclud if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL) return tmp; } -#if 0 - //wyszukiwanie czołgowe (po wszystkich jak leci) - nie ma chyba sensu - for (Current=nRootOfType[TP_TRACK];Current;Current=Current->Next) - { - if ((Current->iType==TP_TRACK) && (Current!=Exclude)) - { - iConnection=Current->pTrack->TestPoint(&Point); - if (iConnection>=0) return Current->pTrack; - } - } -#endif return NULL; } @@ -3174,22 +3163,21 @@ TTraction * TGround::TractionNearestFind(vector3 &p, int dir, TGroundNode *n) bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) { - if (Event->bEnabled) // jeśli może być dodany do kolejki (nie używany w skanowaniu) - if (!Event->iQueued) // jeśli nie dodany jeszcze do kolejki + if( Event->bEnabled ) { + // jeśli może być dodany do kolejki (nie używany w skanowaniu) + if( !Event->iQueued ) // jeśli nie dodany jeszcze do kolejki { // kolejka eventów jest posortowana względem (fStartTime) Event->Activator = Node; if( ( Event->Type == tp_AddValues ) - && ( Event->fDelay == 0.0 ) ) { - // eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieś dodawanie - // Ra: kopiowanie wykonania tu jest bez sensu, lepiej by było wydzielić funkcję - // wykonującą eventy i ją wywołać - if (EventConditon(Event)) - { // teraz mogą być warunki do tych eventów - Event->Params[5].asMemCell->UpdateValues( - Event->Params[0].asText, Event->Params[1].asdouble, - Event->Params[2].asdouble, Event->iFlags); - if (Event->Params[6].asTrack) - { // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla + && ( Event->fDelay == 0.0 ) ) { + // eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieś dodawanie + // Ra: kopiowanie wykonania tu jest bez sensu, lepiej by było wydzielić funkcję + // wykonującą eventy i ją wywołać + if( EventConditon( Event ) ) { // teraz mogą być warunki do tych eventów + Event->Params[ 5 ].asMemCell->UpdateValues( + Event->Params[ 0 ].asText, Event->Params[ 1 ].asdouble, + Event->Params[ 2 ].asdouble, Event->iFlags ); + if( Event->Params[ 6 ].asTrack ) { // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla // wszystkich 'dynamic' na danym torze for( auto dynamic : Event->Params[ 6 ].asTrack->Dynamics ) { Event->Params[ 5 ].asMemCell->PutCommand( @@ -3197,41 +3185,47 @@ bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) &Event->Params[ 4 ].nGroundNode->pCenter ); } //if (DebugModeFlag) - WriteLog("EVENT EXECUTED: AddValues & Track command - " + - std::string(Event->Params[0].asText) + " " + - std::to_string(Event->Params[1].asdouble) + " " + - std::to_string(Event->Params[2].asdouble)); + WriteLog( + "EVENT EXECUTED" + ( Node ? ( " by " + Node->asName ) : "" ) + ": AddValues & Track command ( " + + std::string( Event->Params[ 0 ].asText ) + " " + + std::to_string( Event->Params[ 1 ].asdouble ) + " " + + std::to_string( Event->Params[ 2 ].asdouble ) + " )" ); } //else if (DebugModeFlag) - WriteLog("EVENT EXECUTED: AddValues - " + - std::string(Event->Params[0].asText) + " " + - std::to_string(Event->Params[1].asdouble) + " " + - std::to_string(Event->Params[2].asdouble)); + WriteLog( + "EVENT EXECUTED" + ( Node ? ( " by " + Node->asName ) : "" ) + ": AddValues ( " + + std::string( Event->Params[ 0 ].asText ) + " " + + std::to_string( Event->Params[ 1 ].asdouble ) + " " + + std::to_string( Event->Params[ 2 ].asdouble ) + " )" ); } // jeśli jest kolejny o takiej samej nazwie, to idzie do kolejki (and if there's no joint event it'll be set to null and processing will end here) - Event = Event->evJoined; + do { + Event = Event->evJoined; + // NOTE: we could've received a new event from joint event above, so we need to check conditions just in case and discard the bad events + // TODO: refactor this arrangement, it's hardly optimal + } while( ( Event != nullptr ) + && ( ( false == Event->bEnabled ) + || ( Event->iQueued > 0 ) ) ); } - if( Event != nullptr ) - { // standardowe dodanie do kolejki - WriteLog("EVENT ADDED TO QUEUE: " + Event->asName + (Node ? (" by " + Node->asName) : "")); - Event->fStartTime = - fabs(Event->fDelay) + Timer::GetTime(); // czas od uruchomienia scenerii - if (Event->fRandomDelay > 0.0) - Event->fStartTime += Event->fRandomDelay * Random(10000) * - 0.0001; // doliczenie losowego czasu opóźnienia + if( Event != nullptr ) { + // standardowe dodanie do kolejki ++Event->iQueued; // zabezpieczenie przed podwójnym dodaniem do kolejki - if( ( QueryRootEvent != nullptr ) - && ( Event->fStartTime > QueryRootEvent->fStartTime ) ) { - // dodanie gdzieś w środku - QueryRootEvent->AddToQuery( Event ); + WriteLog( "EVENT ADDED TO QUEUE" + ( Node ? ( " by " + Node->asName ) : "" ) + ": " + Event->asName ); + Event->fStartTime = std::abs( Event->fDelay ) + Timer::GetTime(); // czas od uruchomienia scenerii + if( Event->fRandomDelay > 0.0 ) { + // doliczenie losowego czasu opóźnienia + Event->fStartTime += Event->fRandomDelay * Random( 10000 ) * 0.0001; + } + if( QueryRootEvent != nullptr ) { + TEvent::AddToQuery( Event, QueryRootEvent ); } else { - // dodanie z przodu: albo nic nie ma, albo ma być wykonany szybciej niż pierwszy - Event->evNext = QueryRootEvent; QueryRootEvent = Event; + QueryRootEvent->evNext = nullptr; } } } + } return true; } @@ -3308,49 +3302,8 @@ bool TGround::CheckQuery() { // sprawdzenie kolejki eventów oraz wykonanie tych, którym czas minął TLocation loc; int i; - /* //Ra: to w ogóle jakiś chory kod jest; wygląda jak wyszukanie eventu z najlepszym czasem - Double evtime,evlowesttime; //Ra: co to za typ? - //evlowesttime=1000000; - if (QueryRootEvent) - { - OldQRE=QueryRootEvent; - tmpEvent=QueryRootEvent; - } - if (QueryRootEvent) - { - for (i=0;i<90;++i) - { - evtime=((tmpEvent->fStartTime)-(Timer::GetTime())); //pobranie wartości zmiennej - if (evtimeNext) - tmpEvent=tmpEvent->Next; - else - i=100; - } - if (OldQRE!=tmp2Event) - { - QueryRootEvent->AddToQuery(QueryRootEvent); - QueryRootEvent=tmp2Event; - } - } - */ - /* - if (QueryRootEvent) - {//wypisanie kolejki - tmpEvent=QueryRootEvent; - WriteLog("--> Event queue:"); - while (tmpEvent) - { - WriteLog(tmpEvent->asName+" "+AnsiString(tmpEvent->fStartTime)); - tmpEvent=tmpEvent->Next; - } - } - */ - while (QueryRootEvent ? QueryRootEvent->fStartTime < Timer::GetTime() : false) + while( ( QueryRootEvent != nullptr ) + && ( QueryRootEvent->fStartTime < Timer::GetTime() ) ) { // eventy są posortowana wg czasu wykonania tmpEvent = QueryRootEvent; // wyjęcie eventu z kolejki if (QueryRootEvent->evJoined) // jeśli jest kolejny o takiej samej nazwie @@ -3359,16 +3312,15 @@ bool TGround::CheckQuery() QueryRootEvent->evNext = tmpEvent->evNext; // pamiętając o następnym z kolejki QueryRootEvent->fStartTime = tmpEvent->fStartTime; // czas musi być ten sam, bo nie jest aktualizowany QueryRootEvent->Activator = tmpEvent->Activator; // pojazd aktywujący + QueryRootEvent->iQueued = 1; // w sumie można by go dodać normalnie do kolejki, ale trzeba te połączone posortować wg czasu wykonania } else // a jak nazwa jest unikalna, to kolejka idzie dalej QueryRootEvent = QueryRootEvent->evNext; // NULL w skrajnym przypadku if (tmpEvent->bEnabled) { // w zasadzie te wyłączone są skanowane i nie powinny się nigdy w kolejce znaleźć - WriteLog("EVENT LAUNCHED: " + tmpEvent->asName + - (tmpEvent->Activator ? - std::string(" by " + tmpEvent->Activator->asName) : - "" )); + --tmpEvent->iQueued; // teraz moze być ponownie dodany do kolejki + WriteLog( "EVENT LAUNCHED" + ( tmpEvent->Activator ? ( " by " + tmpEvent->Activator->asName ) : "" ) + ": " + tmpEvent->asName ); switch (tmpEvent->Type) { case tp_CopyValues: // skopiowanie wartości z innej komórki @@ -3530,29 +3482,20 @@ bool TGround::CheckQuery() conditional_anyelse)) // warunek spelniony albo było użyte else { WriteLog("Multiple passed"); - for (i = 0; i < 8; ++i) - { // dodawane do kolejki w kolejności zapisania - if (tmpEvent->Params[i].asEvent) - if (bCondition != (((tmpEvent->iFlags & (conditional_else << i)) != 0))) - { - if (tmpEvent->Params[i].asEvent != tmpEvent) - AddToQuery(tmpEvent->Params[i].asEvent, - tmpEvent->Activator); // normalnie dodać - else // jeśli ma być rekurencja - if (tmpEvent->fDelay >= - 5.0) // to musi mieć sensowny okres powtarzania - if (tmpEvent->iQueued < 2) - { // trzeba zrobić wyjątek, aby event mógł się sam dodać do - // kolejki, raz już jest, ale będzie usunięty - // pętla eventowa może być uruchomiona wiele razy, ale tylko - // pierwsze uruchomienie zadziała - tmpEvent->iQueued = - 0; // tymczasowo, aby był ponownie dodany do kolejki - AddToQuery(tmpEvent, tmpEvent->Activator); - tmpEvent->iQueued = - 2; // kolejny raz już absolutnie nie dodawać + for (i = 0; i < 8; ++i) { + // dodawane do kolejki w kolejności zapisania + if( tmpEvent->Params[ i ].asEvent ) { + if( bCondition != ( ( ( tmpEvent->iFlags & ( conditional_else << i ) ) != 0 ) ) ) { + if( tmpEvent->Params[ i ].asEvent != tmpEvent ) + AddToQuery( tmpEvent->Params[ i ].asEvent, tmpEvent->Activator ); // normalnie dodać + else { + // jeśli ma być rekurencja to musi mieć sensowny okres powtarzania + if( tmpEvent->fDelay >= 5.0 ) { + AddToQuery( tmpEvent, tmpEvent->Activator ); } + } } + } } if (Global::iMultiplayer) // dajemy znać do serwera o wykonaniu if ((tmpEvent->iFlags & conditional_anyelse) == @@ -3635,22 +3578,6 @@ bool TGround::CheckQuery() break; } // switch (tmpEvent->Type) } // if (tmpEvent->bEnabled) - --tmpEvent->iQueued; // teraz moze być ponownie dodany do kolejki - /* - if (QueryRootEvent->eJoined) //jeśli jest kolejny o takiej samej nazwie - {//to teraz jego dajemy do wykonania - QueryRootEvent->eJoined->Next=QueryRootEvent->Next; //pamiętając o następnym z kolejki - QueryRootEvent->eJoined->fStartTime=QueryRootEvent->fStartTime; //czas musi być ten sam, - bo nie jest aktualizowany - //QueryRootEvent->fStartTime=0; - QueryRootEvent=QueryRootEvent->eJoined; //a wykonać ten doczepiony - } - else - {//a jak nazwa jest unikalna, to kolejka idzie dalej - //QueryRootEvent->fStartTime=0; - QueryRootEvent=QueryRootEvent->Next; //NULL w skrajnym przypadku - } - */ } // while return true; } diff --git a/Ground.h b/Ground.h index dd408880..d8d62ac5 100644 --- a/Ground.h +++ b/Ground.h @@ -274,9 +274,7 @@ class TGround TGroundRect Rects[iNumRects][iNumRects]; // mapa kwadratów kilometrowych TEvent *RootEvent = nullptr; // lista zdarzeń TEvent *QueryRootEvent = nullptr, - *tmpEvent = nullptr, - *tmp2Event = nullptr, - *OldQRE = nullptr; + *tmpEvent = nullptr; TSubRect *pRendered[1500]; // lista renderowanych sektorów int iNumNodes = 0; vector3 pOrigin; diff --git a/Train.cpp b/Train.cpp index 75bd2f53..61bc9138 100644 --- a/Train.cpp +++ b/Train.cpp @@ -2881,10 +2881,12 @@ void TTrain::OnCommand_hornlowactivate( TTrain *Train, command_data const &Comma if( false == TestFlag( Train->mvOccupied->WarningSignal, 1 ) ) { // turn on Train->mvOccupied->WarningSignal |= 1; +/* if( true == TestFlag( Train->mvOccupied->WarningSignal, 2 ) ) { // low and high horn are treated as mutually exclusive Train->mvControlled->WarningSignal &= ~2; } +*/ // audio feedback if( ( Train->ggHornButton.GetValue() > -0.5 ) || ( Train->ggHornLowButton.GetValue() < 0.5 ) ) { @@ -2897,8 +2899,11 @@ void TTrain::OnCommand_hornlowactivate( TTrain *Train, command_data const &Comma } else if( Command.action == GLFW_RELEASE ) { // turn off +/* // NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); +*/ + Train->mvOccupied->WarningSignal &= ~1; // audio feedback if( ( Train->ggHornButton.GetValue() < -0.5 ) || ( Train->ggHornLowButton.GetValue() > 0.5 ) ) { @@ -2925,10 +2930,12 @@ void TTrain::OnCommand_hornhighactivate( TTrain *Train, command_data const &Comm if( false == TestFlag( Train->mvOccupied->WarningSignal, 2 ) ) { // turn on Train->mvOccupied->WarningSignal |= 2; +/* if( true == TestFlag( Train->mvOccupied->WarningSignal, 1 ) ) { // low and high horn are treated as mutually exclusive Train->mvControlled->WarningSignal &= ~1; } +*/ // audio feedback if( Train->ggHornButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); @@ -2940,8 +2947,11 @@ void TTrain::OnCommand_hornhighactivate( TTrain *Train, command_data const &Comm } else if( Command.action == GLFW_RELEASE ) { // turn off +/* // NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); +*/ + Train->mvOccupied->WarningSignal &= ~2; // audio feedback if( Train->ggHornButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); diff --git a/version.h b/version.h index cbf2eb2e..005e6949 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 531 +#define VERSION_MINOR 602 #define VERSION_REVISION 0