diff --git a/AdvSound.cpp b/AdvSound.cpp index 63149449..7aefa52f 100644 --- a/AdvSound.cpp +++ b/AdvSound.cpp @@ -128,6 +128,10 @@ void TAdvancedSound::Update(bool ListenerInside, vector3 NewPosition) void TAdvancedSound::UpdateAF(double A, double F, bool ListenerInside, vector3 NewPosition) { // update, ale z amplituda i czestotliwoscia + if( State == ss_Off ) { + return; + } + if ((State == ss_Commencing) && (SoundCommencing.AM > 0)) { SoundShut.Stop(); // hunter-311211 diff --git a/AnimModel.cpp b/AnimModel.cpp index e5828761..6408a443 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -411,11 +411,13 @@ TAnimModel::TAnimModel() pModel = NULL; iNumLights = 0; fBlinkTimer = 0; - ReplacableSkinId[0] = 0; - ReplacableSkinId[1] = 0; - ReplacableSkinId[2] = 0; - ReplacableSkinId[3] = 0; - ReplacableSkinId[4] = 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 @@ -441,7 +443,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) == @@ -462,6 +464,28 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable // przezroczystych return (Init(TModelsManager::GetModel(asName))); } +#else +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") + m_materialdata.replacable_skins[1] = + GfxRenderer.GetTextureId( asReplacableTexture, "" ); + if( ( m_materialdata.replacable_skins[ 1 ] != 0 ) + && ( GfxRenderer.Texture( m_materialdata.replacable_skins[ 1 ] ).has_alpha ) ) { + // tekstura z kanałem alfa - nie renderować w cyklu nieprzezroczystych + m_materialdata.textures_alpha = 0x31310031; + } + else{ + // tekstura nieprzezroczysta - nie renderować w cyklu + m_materialdata.textures_alpha = 0x30300030; + } + // przezroczystych + return (Init(TModelsManager::GetModel(asName))); +} +#endif bool TAnimModel::Load(cParser *parser, bool ter) { // rozpoznanie wpisu modelu i ustawienie świateł @@ -629,6 +653,7 @@ void TAnimModel::RenderAlphaDL(vector3 pPosition, double fAngle) 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 @@ -642,6 +667,21 @@ int TAnimModel::Flags() // 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 @@ -651,29 +691,39 @@ void TAnimModel::RenderDL(vector3 *vPosition) { RaAnimate(); // jednorazowe przeliczenie animacji RaPrepare(); - if (pModel) // renderowanie rekurencyjne submodeli + if( pModel ) // renderowanie rekurencyjne submodeli +#ifdef EU07_USE_OLD_RENDERCODE pModel->Render(vPosition, &vAngle, ReplacableSkinId, iTexAlpha); +#else + GfxRenderer.Render( pModel, Material(), *vPosition, vAngle ); +#endif }; void TAnimModel::RenderAlphaDL(vector3 *vPosition) { RaPrepare(); if (pModel) // renderowanie rekurencyjne submodeli +#ifdef EU07_USE_OLD_RENDERCODE pModel->RenderAlpha(vPosition, &vAngle, ReplacableSkinId, iTexAlpha); +#else + GfxRenderer.Render_Alpha( pModel, Material(), *vPosition, vAngle ); +#endif }; + void TAnimModel::RenderVBO(vector3 *vPosition) { RaAnimate(); // jednorazowe przeliczenie animacji RaPrepare(); if (pModel) // renderowanie rekurencyjne submodeli - pModel->RaRender(vPosition, &vAngle, ReplacableSkinId, iTexAlpha); + 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, ReplacableSkinId, iTexAlpha); + pModel->RaRenderAlpha(vPosition, &vAngle, Material()->replacable_skins, Material()->textures_alpha); }; + //--------------------------------------------------------------------------- bool TAnimModel::TerrainLoaded() { // zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy diff --git a/AnimModel.h b/AnimModel.h index 5c2899b2..5c8693f2 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/. #include "Model3d.h" #include "Texture.h" +#include "DynObj.h" const int iMaxNumLights = 8; @@ -138,7 +139,12 @@ 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; void Advanced(); @@ -149,9 +155,15 @@ 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 - static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane - // również bez wyświetlania +#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(); bool Init(TModel3d *pNewModel); diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f39b19a..e8e9ef6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ set(SOURCES "Spring.cpp" "shader.cpp" "frustum.cpp" +"uilayer.cpp" ) if (WIN32) diff --git a/Camera.cpp b/Camera.cpp index e92180ee..f1c0db7e 100644 --- a/Camera.cpp +++ b/Camera.cpp @@ -111,41 +111,52 @@ vector3 TCamera::GetDirection() return (Normalize(Vec)); } - -// bool TCamera::GetMatrix(matrix4x4 &Matrix) +/* bool TCamera::SetMatrix() { - glRotated(-Roll * 180.0f / M_PI, 0, 0, 1); // po wyłączeniu tego kręci się pojazd, a sceneria - // nie - glRotated(-Pitch * 180.0f / M_PI, 1, 0, 0); - glRotated(-Yaw * 180.0f / M_PI, 0, 1, 0); // w zewnętrznym widoku: kierunek patrzenia + glRotated( -Roll * 180.0f / M_PI, 0, 0, 1 ); // po wyłączeniu tego kręci się pojazd, a sceneria nie + glRotated( -Pitch * 180.0f / M_PI, 1, 0, 0 ); + glRotated( -Yaw * 180.0f / M_PI, 0, 1, 0 ); // w zewnętrznym widoku: kierunek patrzenia - if (Type == tp_Follow) + if( Type == tp_Follow ) { - // gluLookAt(Pos.x+pOffset.x,Pos.y+pOffset.y,Pos.z+pOffset.z, - // LookAt.x+pOffset.x,LookAt.y+pOffset.y,LookAt.z+pOffset.z,vUp.x,vUp.y,vUp.z); - // gluLookAt(Pos.x+pOffset.x,Pos.y+pOffset.y,Pos.z+pOffset.z, - // LookAt.x+pOffset.x,LookAt.y+pOffset.y,LookAt.z+pOffset.z,vUp.x,vUp.y,vUp.z); - gluLookAt(Pos.x, Pos.y, Pos.z, LookAt.x, LookAt.y, LookAt.z, vUp.x, vUp.y, - vUp.z); // Ra: pOffset is zero - // gluLookAt(Pos.x,Pos.y,Pos.z,Pos.x+Velocity.x,Pos.y+Velocity.y,Pos.z+Velocity.z,0,1,0); - // return true; + gluLookAt( + Pos.x, Pos.y, Pos.z, + LookAt.x, LookAt.y, LookAt.z, + vUp.x, vUp.y, vUp.z); // Ra: pOffset is zero } - - if (Type == tp_Satelite) - Pitch = M_PI * 0.5; - - if (Type != tp_Follow) - { - glTranslated(-Pos.x, -Pos.y, -Pos.z); // nie zmienia kierunku patrzenia + else { + glTranslated( -Pos.x, -Pos.y, -Pos.z ); // nie zmienia kierunku patrzenia } Global::SetCameraPosition(Pos); // było +pOffset return true; } +*/ +bool TCamera::SetMatrix( glm::mat4 &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 + + 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 ) ); + } + else { + Matrix = glm::translate( Matrix, glm::vec3( -Pos.x, -Pos.y, -Pos.z ) ); // nie zmienia kierunku patrzenia + } + + Global::SetCameraPosition( Pos ); // było +pOffset + return true; +} void TCamera::SetCabMatrix(vector3 &p) { // ustawienie widoku z kamery bez przesunięcia robionego przez OpenGL - nie powinno tak trząść + glRotated(-Roll * 180.0f / M_PI, 0, 0, 1); glRotated(-Pitch * 180.0f / M_PI, 1, 0, 0); glRotated(-Yaw * 180.0f / M_PI, 0, 1, 0); // w zewnętrznym widoku: kierunek patrzenia @@ -170,16 +181,3 @@ void TCamera::Stop() Velocity = vector3(0, 0, 0); }; -// returns true if specified object is within camera frustum, false otherwise -bool -TCamera::IsVisible( TDynamicObject const *Dynamic ) const { - - // sphere test is faster than AABB, so we'll use it here - float3 diagonal( - Dynamic->MoverParameters->Dim.L, - Dynamic->MoverParameters->Dim.H, - Dynamic->MoverParameters->Dim.W ); - float const radius = static_cast(diagonal.Length()) * 0.5f; - - return ( m_frustum.sphere_inside( Dynamic->GetPosition(), radius ) > 0.0f ); -} diff --git a/Camera.h b/Camera.h index 2ec975da..9a04bb96 100644 --- a/Camera.h +++ b/Camera.h @@ -7,11 +7,9 @@ obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef CameraH -#define CameraH +#pragma once #include "dumb3d.h" -#include "frustum.h" #include "dynobj.h" using namespace Math3D; @@ -28,7 +26,6 @@ class TCamera { private: vector3 pOffset; // nie używane (zerowe) - cFrustum m_frustum; public: // McZapkie: potrzebuje do kiwania na boki double Pitch; @@ -51,17 +48,13 @@ class TCamera void Update(); vector3 GetDirection(); // vector3 inline GetCrossPos() { return Pos+GetDirection()*CrossDist+CrossPos; }; - +/* bool SetMatrix(); - void SetCabMatrix(vector3 &p); +*/ + bool SetMatrix(glm::mat4 &Matrix); + void SetCabMatrix( vector3 &p ); void RaLook(); void Stop(); - inline - void - SetFrustum() { m_frustum.calculate(); } - bool - IsVisible( TDynamicObject const *Dynamic ) const; // bool GetMatrix(matrix4x4 &Matrix); vector3 PtNext, PtPrev; }; -#endif diff --git a/Console.cpp b/Console.cpp index a61a4484..efaadc5c 100644 --- a/Console.cpp +++ b/Console.cpp @@ -480,22 +480,11 @@ float Console::AnalogCalibrateGet(int x) if (iMode == 4 && PoKeys55[0]) { float b = PoKeys55[0]->fAnalog[x]; - /*return (((((Global::fCalibrateIn[x][5] * b) + Global::fCalibrateIn[x][4]) * b + - Global::fCalibrateIn[x][3]) * - b + - Global::fCalibrateIn[x][2]) * - b + - Global::fCalibrateIn[x][1]) * - b + - Global::fCalibrateIn[x][0];*/ - b = (((((Global::fCalibrateIn[x][5] * b) + Global::fCalibrateIn[x][4]) * b + - Global::fCalibrateIn[x][3]) * - b + - Global::fCalibrateIn[x][2]) * - b + - Global::fCalibrateIn[x][1]) * - b + - Global::fCalibrateIn[x][0]; + b = (((((Global::fCalibrateIn[x][5] * b) + Global::fCalibrateIn[x][4]) * b + + Global::fCalibrateIn[x][3]) * b + + Global::fCalibrateIn[x][2]) * b + + Global::fCalibrateIn[x][1]) * b + + Global::fCalibrateIn[x][0]; if (x == 0) return (b + 2) / 8; if (x == 1) return b/10; else return b; diff --git a/Console/MWD.cpp b/Console/MWD.cpp index 8d075280..67b63bdd 100644 --- a/Console/MWD.cpp +++ b/Console/MWD.cpp @@ -223,78 +223,84 @@ bool TMWDComm::Run() // wywoływanie obsługi MWD + generacja większego opóźn void TMWDComm::CheckData() // sprawdzanie wejść cyfrowych i odpowiednie sterowanie maszyną { - int i = 0; - while (i < 6) - { - maskData[i] = ReadDataBuff[i] ^ lastStateData[i]; - lastStateData[i] = ReadDataBuff[i]; - i++; - } - /* - Rozpiska portów! - Port0: 0 NC odblok. przek. sprężarki i wentyl. oporów - 1 M wyłącznik wył. szybkiego - 2 Shift+M impuls załączający wył. szybki - 3 N odblok. przekaźników nadmiarowych - i różnicowego obwodu głównego - 4 NC rezerwa - 5 Ctrl+N odblok. przek. nadmiarowych - przetwornicy, ogrzewania pociągu i różnicowych obw. pomocniczych - 6 L wył. styczników liniowych - 7 SPACE kasowanie czuwaka + int i = 0; + while (i < 6) + { + maskData[i] = ReadDataBuff[i] ^ lastStateData[i]; + lastStateData[i] = ReadDataBuff[i]; + i++; + } + /* + Rozpiska portów! + Port0: 0 NC odblok. przek. sprężarki i wentyl. oporów + 1 M wyłącznik wył. szybkiego + 2 Shift+M impuls załączający wył. szybki + 3 N odblok. przekaźników nadmiarowych + i różnicowego obwodu głównegoMMm + 4 NC rezerwa + 5 Ctrl+N odblok. przek. nadmiarowych + przetwornicy, ogrzewania pociągu i różnicowych obw. pomocniczych + 6 L wył. styczników liniowych + 7 SPACE kasowanie czuwaka - Port1: 0 NC - 1 (Shift) X przetwornica - 2 (Shift) C sprężarka - 3 S piasecznice - 4 (Shift) H ogrzewanie składu - 5 przel. hamowania Shift+B - pspbpwy Ctrl+B pospieszny B towarowy - 6 przel. hamowania - 7 (Shift) F rozruch w/n + Port1: 0 NC + 1 (Shift) X przetwornica + 2 (Shift) C sprężarka + 3 S piasecznice + 4 (Shift) H ogrzewanie składu + 5 przel. hamowania Shift+B + pspbpwy Ctrl+B pospieszny B towarowy + 6 przel. hamowania + 7 (Shift) F rozruch w/n - Port2: 0 (Shift) P pantograf przedni - 1 (Shift) O pantograf tylni - 2 ENTER przyhamowanie przy poślizgu - 3 () przyciemnienie świateł - 4 () przyciemnienie świateł - 5 NUM6 odluźniacz - 6 a syrena lok W - 7 A syrena lok N + Port2: 0 (Shift) P pantograf przedni + 1 (Shift) O pantograf tylni + 2 ENTER przyhamowanie przy poślizgu + 3 () przyciemnienie świateł + 4 () przyciemnienie świateł + 5 NUM6 odluźniacz + 6 a syrena lok W + 7 A syrena lok N - Port3: 0 Shift+J bateria - 1 - 2 - 3 - 4 - 5 - 6 - 7 - */ + Port3: 0 Shift+J bateria + 1 + 2 + 3 + 4 + 5 + 6 + 7 + */ - /* po przełączeniu bistabilnego najpierw wciskamy klawisz i przy następnym - wejściu w pętlę MWD puszczamy bo inaczej nie działa - */ + /* po przełączeniu bistabilnego najpierw wciskamy klawisz i przy następnym + wejściu w pętlę MWD puszczamy bo inaczej nie działa + */ - // wciskanie przycisków klawiatury - /*PORT0*/ - if (maskData[0] & 0x02) if (lastStateData[0] & 0x02) KeyBoard('M', 1); // wyłączenie wyłącznika szybkiego - else KeyBoard('M', 0); // monostabilny - if (maskData[0] & 0x04) if (lastStateData[0] & 0x04) { // impuls załączający wyłącznik szybki + // wciskanie przycisków klawiatury + /*PORT0*/ + if (maskData[0] & 0x02) if (lastStateData[0] & 0x02) + KeyBoard('M', 1); // wyłączenie wyłącznika szybkiego + else KeyBoard('M', 0); // monostabilny + if (maskData[0] & 0x04) if (lastStateData[0] & 0x04) // impuls załączający wyłącznik szybki + { KeyBoard(0x10, 1); // monostabilny KeyBoard('M', 1); } - else { + else + { KeyBoard('M', 0); KeyBoard(0x10, 0); } - if (maskData[0] & 0x08) if (lastStateData[0] & 0x08) KeyBoard('N', 1); // odblok nadmiarowego silników trakcyjnych - else KeyBoard('N', 0); // monostabilny - if (maskData[0] & 0x20) if (lastStateData[0] & 0x20) { // odblok nadmiarowego przetwornicy, ogrzewania poc. - KeyBoard(0x11, 1); // różnicowego obwodów pomocniczych - KeyBoard('N', 1); // monostabilny + if (maskData[0] & 0x08) if (lastStateData[0] & 0x08) + KeyBoard('N', 1); // odblok nadmiarowego silników trakcyjnych + else KeyBoard('N', 0); // monostabilny + if (maskData[0] & 0x20) if (lastStateData[0] & 0x20) + { // odblok nadmiarowego przetwornicy, ogrzewania poc. + KeyBoard(0x11, 1); // różnicowego obwodów pomocniczych + KeyBoard('N', 1); // monostabilny } - else { + else + { KeyBoard('N', 0); KeyBoard(0x11, 0); } @@ -303,16 +309,18 @@ void TMWDComm::CheckData() // sprawdzanie wejść cyfrowych i odpowiednie sterow if (maskData[0] & 0x80) if (lastStateData[0] & 0x80) KeyBoard(0x20, 1); // kasowanie czuwaka/SHP else KeyBoard(0x20, 0); // kasowanie czuwaka/SHP - /*PORT1*/ + /*PORT1*/ - // puszczanie przycisku bistabilnego klawiatury - if (maskSwitch[1] & 0x02) { - if (bitSwitch[1] & 0x02) { + // puszczanie przycisku bistabilnego klawiatury + if (maskSwitch[1] & 0x02) + { + if (bitSwitch[1] & 0x02) + { KeyBoard('X', 0); KeyBoard(0x10, 0); } else KeyBoard('X', 0); - maskSwitch[1] &= ~0x02; + maskSwitch[1] &= ~0x02; } if (maskSwitch[1] & 0x04) { if (bitSwitch[1] & 0x04) { @@ -345,61 +353,78 @@ void TMWDComm::CheckData() // sprawdzanie wejść cyfrowych i odpowiednie sterow maskSwitch[1] &= ~0x80; } - - if (maskData[1] & 0x02) if (lastStateData[1] & 0x02) { // przetwornica + // przetwornica + if (maskData[1] & 0x02) if (lastStateData[1] & 0x02) + { KeyBoard(0x10, 1); // bistabilny KeyBoard('X', 1); maskSwitch[1] |= 0x02; bitSwitch[1] |= 0x02; } - else { + else + { maskSwitch[1] |= 0x02; bitSwitch[1] &= ~0x02; KeyBoard('X', 1); } - if (maskData[1] & 0x04) if (lastStateData[1] & 0x04) { // sprężarka + // sprężarka + if (maskData[1] & 0x04) if (lastStateData[1] & 0x04) + { KeyBoard(0x10, 1); // bistabilny KeyBoard('C', 1); maskSwitch[1] |= 0x04; bitSwitch[1] |= 0x04; } - else { + else + { maskSwitch[1] |= 0x04; bitSwitch[1] &= ~0x04; KeyBoard('C', 1); } - if (maskData[1] & 0x08) if (lastStateData[1] & 0x08) KeyBoard('S', 1); // piasecznica - else KeyBoard('S', 0); // monostabilny - if (maskData[1] & 0x10) if (lastStateData[1] & 0x10) { // ogrzewanie składu + // piasecznica + if (maskData[1] & 0x08) if (lastStateData[1] & 0x08) + KeyBoard('S', 1); + else + KeyBoard('S', 0); // monostabilny + // ogrzewanie składu + if (maskData[1] & 0x10) if (lastStateData[1] & 0x10) + { KeyBoard(0x11, 1); // bistabilny KeyBoard('H', 1); maskSwitch[1] |= 0x10; bitSwitch[1] |= 0x10; } - else { + else + { maskSwitch[1] |= 0x10; bitSwitch[1] &= ~0x10; KeyBoard('H', 1); } - if (maskData[1] & 0x20 || maskData[1] & 0x40) { // przełącznik hamowania - if (lastStateData[1] & 0x20) { // Shift+B + // przełącznik hamowania + if (maskData[1] & 0x20 || maskData[1] & 0x40) + { + if (lastStateData[1] & 0x20) + { // Shift+B KeyBoard(0x10, 1); maskSwitch[1] |= 0x20; } - else if (lastStateData[1] & 0x40) { // Ctrl+B + else if (lastStateData[1] & 0x40) + { // Ctrl+B KeyBoard(0x11, 1); maskSwitch[1] |= 0x40; } KeyBoard('B', 1); } - - if (maskData[1] & 0x80) if (lastStateData[1] & 0x80) { // rozruch wysoki/niski + // rozruch wysoki/niski + if (maskData[1] & 0x80) if (lastStateData[1] & 0x80) + { KeyBoard(0x10, 1); // bistabilny KeyBoard('F', 1); maskSwitch[1] |= 0x80; bitSwitch[1] |= 0x80; } - else { + else + { maskSwitch[1] |= 0x80; bitSwitch[1] &= ~0x80; KeyBoard('F', 1); @@ -407,16 +432,20 @@ void TMWDComm::CheckData() // sprawdzanie wejść cyfrowych i odpowiednie sterow //PORT2 - if (maskSwitch[2] & 0x01) { - if (bitSwitch[2] & 0x01) { + if (maskSwitch[2] & 0x01) + { + if (bitSwitch[2] & 0x01) + { KeyBoard('P', 0); KeyBoard(0x10, 0); } else KeyBoard('P', 0); maskSwitch[2] &= ~0x01; } - if (maskSwitch[2] & 0x02) { - if (bitSwitch[2] & 0x02) { + if (maskSwitch[2] & 0x02) + { + if (bitSwitch[2] & 0x02) + { KeyBoard('O', 0); KeyBoard(0x10, 0); } @@ -424,35 +453,41 @@ void TMWDComm::CheckData() // sprawdzanie wejść cyfrowych i odpowiednie sterow maskSwitch[2] &= ~0x02; } - - if (maskData[2] & 0x01) if (lastStateData[2] & 0x01) { // pantograf przedni + // pantograf przedni + if (maskData[2] & 0x01) if (lastStateData[2] & 0x01) + { KeyBoard(0x10, 1); // bistabilny KeyBoard('P', 1); maskSwitch[2] |= 0x01; bitSwitch[2] |= 0x01; } - else { + else + { maskSwitch[2] |= 0x01; bitSwitch[2] &= ~0x01; KeyBoard('P', 1); } - if (maskData[2] & 0x02) if (lastStateData[2] & 0x02) { // pantograf tylni + // pantograf tylni + if (maskData[2] & 0x02) if (lastStateData[2] & 0x02) + { KeyBoard(0x10, 1); // bistabilny KeyBoard('O', 1); maskSwitch[2] |= 0x02; bitSwitch[2] |= 0x02; } - else { + else + { maskSwitch[2] |= 0x02; bitSwitch[2] &= ~0x02; KeyBoard('O', 1); } - if (maskData[2] & 0x04) if (lastStateData[2] & 0x04) { // przyhamowanie przy poślizgu + // przyhamowanie przy poślizgu + if (maskData[2] & 0x04) if (lastStateData[2] & 0x04) { KeyBoard(0x10, 1); // monostabilny KeyBoard(0x0D, 1); } - else { - + else + { KeyBoard(0x0D, 0); KeyBoard(0x10, 0); } @@ -474,178 +509,129 @@ void TMWDComm::CheckData() // sprawdzanie wejść cyfrowych i odpowiednie sterow KeyBoard(0x11,0); KeyBoard(' ',1); }*/ - if (maskData[2] & 0x20) if (lastStateData[2] & 0x20) KeyBoard(0x66, 1); // odluźniacz - else KeyBoard(0x66, 0); // monostabilny - if (maskData[2] & 0x40) if (lastStateData[2] & 0x40) { // syrena wysoka + // odluźniacz + if (maskData[2] & 0x20) if (lastStateData[2] & 0x20) + KeyBoard(0x66, 1); + else + KeyBoard(0x66, 0); // monostabilny + // syrena wysoka + if (maskData[2] & 0x40) if (lastStateData[2] & 0x40) + { KeyBoard(0x10, 1); // monostabilny KeyBoard('A', 1); } - else { + else + { KeyBoard('A', 0); KeyBoard(0x10, 0); } - if (maskData[2] & 0x80) if (lastStateData[2] & 0x80) KeyBoard('A', 1); // syrena niska - else KeyBoard('A', 0); // monostabilny + if (maskData[2] & 0x80) if (lastStateData[2] & 0x80) + KeyBoard('A', 1); // syrena niska + else + KeyBoard('A', 0); // monostabilny - //PORT3 + //PORT3 - if (maskSwitch[3] & 0x01) { - if (bitSwitch[3] & 0x01) { + if (maskSwitch[3] & 0x01) + { + if (bitSwitch[3] & 0x01) + { KeyBoard('J', 0); KeyBoard(0x10, 0); } else KeyBoard('J', 0); maskSwitch[3] &= ~0x01; } + if (maskSwitch[3] & 0x02) + { + if (bitSwitch[3] & 0x02) + { + KeyBoard('Y', 0); + KeyBoard(0x10, 0); + } + else KeyBoard('Y', 0); + maskSwitch[3] &= ~0x02; + } + if (maskSwitch[3] & 0x04) + { + if (bitSwitch[3] & 0x04) + { + KeyBoard('U', 0); + KeyBoard(0x10, 0); + } + else KeyBoard('U', 0); + maskSwitch[3] &= ~0x04; + } + if (maskSwitch[3] & 0x08) + { + if (bitSwitch[3] & 0x08) + { + KeyBoard('I', 0); + KeyBoard(0x10, 0); + } + else KeyBoard('I', 0); + maskSwitch[3] &= ~0x08; + } - if (maskData[3] & 0x01) if (lastStateData[3] & 0x01) { // bateria + + // bateria + if (maskData[3] & 0x01) if (lastStateData[3] & 0x01) + { KeyBoard(0x10, 1); // bistabilny KeyBoard('J', 1); maskSwitch[3] |= 0x01; bitSwitch[3] |= 0x01; } - else { + else + { maskSwitch[3] |= 0x01; bitSwitch[3] &= ~0x01; KeyBoard('J', 1); } - - /* - if(maskData[3] & 0x04 && lastStateData[1] & 0x04) { KeyBoard(0x10,1); - KeyBoard('C',1); // - KeyBoard('C',0); - KeyBoard(0x10,0); - }else{ KeyBoard('C',1); // - KeyBoard('C',0); - } - if(maskData[3] & 0x08 && lastStateData[1] & 0x08) KeyBoard('S',1); // - else KeyBoard('S',0); + //Światło lewe + if (maskData[3] & 0x02) if (lastStateData[3] & 0x02) + { + KeyBoard(0x10, 1); // bistabilny + KeyBoard('Y', 1); + maskSwitch[3] |= 0x02; + bitSwitch[3] |= 0x02; + }else + { + maskSwitch[3] |= 0x02; + bitSwitch[3] &= ~0x02; + KeyBoard('Y', 1); + } + //światło górne + if (maskData[3] & 0x04) if (lastStateData[3] & 0x04) + { + KeyBoard(0x10, 1); // bistabilny + KeyBoard('U', 1); + maskSwitch[3] |= 0x04; + bitSwitch[3] |= 0x04; + } + else + { + maskSwitch[3] |= 0x04; + bitSwitch[3] &= ~0x04; + KeyBoard('U', 1); + } + //światło prawe + if (maskData[3] & 0x08) if (lastStateData[3] & 0x08) + { + KeyBoard(0x10, 1); // bistabilny + KeyBoard('I', 1); + maskSwitch[3] |= 0x08; + bitSwitch[3] |= 0x08; + } + else + { + maskSwitch[3] |= 0x08; + bitSwitch[3] &= ~0x08; + KeyBoard('I', 1); + } - if(maskData[3] & 0x10 && lastStateData[1] & 0x10) { - KeyBoard(0x11,1); - KeyBoard('H',1); - }else{ KeyBoard('H',0); - KeyBoard(0x11,0); - } - if(maskData[3] & 0x20 && lastStateData[1] & 0x20) { - KeyBoard(0x11,1); - KeyBoard(' ',1); - }else{ KeyBoard(' ',0); - KeyBoard(0x11,0); - } - if(maskData[3] & 0x40 && lastStateData[1] & 0x40) { - KeyBoard(0x10,1); - KeyBoard(' ',1); - }else{ KeyBoard(' ',0); - KeyBoard(0x10,0); - } - if(maskData[3] & 0x80 && lastStateData[1] & 0x80) { - KeyBoard(0x10,1); - KeyBoard('F',1); - }else{ KeyBoard('F',0); - KeyBoard(0x10,0); - } - - /*PORT4*/ /* - if(maskData[4] & 0x02 && lastStateData[1] & 0x02) { - KeyBoard(0x10,1); - KeyBoard('X',1); // - KeyBoard('X',0); - KeyBoard(0x10,0); - }else{ KeyBoard('X',1); // - KeyBoard('X',0); - } - if(maskData[4] & 0x04 && lastStateData[1] & 0x04) { - KeyBoard(0x10,1); - KeyBoard('C',1); // - KeyBoard('C',0); - KeyBoard(0x10,0); - }else{ KeyBoard('C',1); // - KeyBoard('C',0); - } - if(maskData[4] & 0x08 && lastStateData[1] & 0x08) KeyBoard('S',1); // - else KeyBoard('S',0); - - - if(maskData[4] & 0x10 && lastStateData[1] & 0x10) { - KeyBoard(0x11,1); - KeyBoard('H',1); - }else{ KeyBoard('H',0); - KeyBoard(0x11,0); - } - if(maskData[4] & 0x20 && lastStateData[1] & 0x20) { - KeyBoard(0x11,1); - KeyBoard(' ',1); - }else{ KeyBoard(' ',0); - KeyBoard(0x11,0); - } - if(maskData[4] & 0x40 && lastStateData[1] & 0x40) { - KeyBoard(0x10,1); - KeyBoard(' ',1); - }else{ KeyBoard(' ',0); - KeyBoard(0x10,0); - } - if(maskData[4] & 0x80 && lastStateData[1] & 0x80) { - KeyBoard(0x10,1); - KeyBoard('F',1); - }else{ KeyBoard('F',0); - KeyBoard(0x10,0); - } - - /*PORT5*/ /* - if(maskData[5] & 0x02 && lastStateData[1] & 0x02) { - KeyBoard(0x10,1); - KeyBoard('X',1); // - KeyBoard('X',0); - KeyBoard(0x10,0); - }else{ - KeyBoard('X',1); // - KeyBoard('X',0); - } - if(maskData[5] & 0x04 && lastStateData[1] & 0x04) { - KeyBoard(0x10,1); - KeyBoard('C',1); // - KeyBoard('C',0); - KeyBoard(0x10,0); - }else{ - KeyBoard('C',1); // - KeyBoard('C',0); - } - if(maskData[5] & 0x08 && lastStateData[1] & 0x08) KeyBoard('S',1); // - else - KeyBoard('S',0); - - - if(maskData[5] & 0x10 && lastStateData[1] & 0x10) { - KeyBoard(0x11,1); - KeyBoard('H',1); - }else{ - KeyBoard('H',0); - KeyBoard(0x11,0); - } - if(maskData[5] & 0x20 && lastStateData[1] & 0x20) { - KeyBoard(0x11,1); - KeyBoard(' ',1); - }else{ - KeyBoard(' ',0); - KeyBoard(0x11,0); - } - if(maskData[5] & 0x40 && lastStateData[1] & 0x40) { - KeyBoard(0x10,1); - KeyBoard(' ',1); - }else{ - KeyBoard(' ',0); - KeyBoard(0x10,0); - } - if(maskData[5] & 0x80 && lastStateData[1] & 0x80) { - KeyBoard(0x10,1); - KeyBoard('F',1); - }else{ - KeyBoard('F',0); - KeyBoard(0x10,0); - }//*/ /* NASTAWNIK, BOCZNIK i KIERUNEK */ diff --git a/Driver.h b/Driver.h index 4f27d920..eeddc1a1 100644 --- a/Driver.h +++ b/Driver.h @@ -399,4 +399,5 @@ class TController int CrossRoute(TTrack *tr); void RouteSwitch(int d); std::string OwnerName(); + TMoverParameters const *Controlling() const { return mvControlling; } }; diff --git a/DynObj.cpp b/DynObj.cpp index 1a3a2dc3..3a59e335 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -523,7 +523,7 @@ void TDynamicObject::UpdateLeverEnum(TAnim *pAnim) }; // ABu 29.01.05 przeklejone z render i renderalpha: ********************* -void __inline TDynamicObject::ABuLittleUpdate(double ObjSqrDist) +void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) { // ABu290105: pozbierane i uporzadkowane powtarzajace // sie rzeczy z Render i RenderAlpha // dodatkowy warunek, if (ObjSqrDist<...) zeby niepotrzebnie nie zmianiec w @@ -557,8 +557,6 @@ void __inline TDynamicObject::ABuLittleUpdate(double ObjSqrDist) mdLoad->GetSMRoot()->SetTranslate(modelShake + vFloor); if (mdLowPolyInt) mdLowPolyInt->GetSMRoot()->SetTranslate(modelShake); - if (mdPrzedsionek) - mdPrzedsionek->GetSMRoot()->SetTranslate(modelShake); // ABu: koniec rzucania // ABu011104: liczenie obrotow wozkow ABuBogies(); @@ -1694,12 +1692,14 @@ TDynamicObject::TDynamicObject() //} mdModel = NULL; mdKabina = NULL; - ReplacableSkinID[0] = 0; - ReplacableSkinID[1] = 0; - ReplacableSkinID[2] = 0; - ReplacableSkinID[3] = 0; - ReplacableSkinID[4] = 0; +#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; @@ -1707,7 +1707,6 @@ TDynamicObject::TDynamicObject() smLoadMode = NULL; mdLoad = NULL; mdLowPolyInt = NULL; - mdPrzedsionek = NULL; //smMechanik0 = smMechanik1 = NULL; smBuforLewy[0] = smBuforLewy[1] = NULL; smBuforPrawy[0] = smBuforPrawy[1] = NULL; @@ -2341,8 +2340,7 @@ void TDynamicObject::Move(double fDistance) { // przeliczenie cienia TTrack *t0 = Axle0.GetTrack(); // już po przesunięciu TTrack *t1 = Axle1.GetTrack(); - if ((t0->eEnvironment == e_flat) && (t1->eEnvironment == e_flat)) // może być - // e_bridge... + if ((t0->eEnvironment == e_flat) && (t1->eEnvironment == e_flat)) // może być e_bridge... fShade = 0.0; // standardowe oświetlenie else { // jeżeli te tory mają niestandardowy stopień zacienienia @@ -2365,6 +2363,21 @@ void TDynamicObject::Move(double fDistance) if (Axle0.GetDirection() < 0) d = t0->fTrackLength - d; // od drugiej strony liczona długość d /= fAxleDist; // rozsataw osi procentowe znajdowanie się na torze + + float shadefrom = 1.0f, shadeto = 1.0f; + // NOTE, TODO: calculating brightness level is used enough times to warrant encapsulation into a function + switch( t0->eEnvironment ) { + case e_canyon: { shadeto = 0.65f; break; } + case e_tunnel: { shadeto = 0.2f; break; } + default: {break; } + } + switch( t1->eEnvironment ) { + case e_canyon: { shadefrom = 0.65f; break; } + case e_tunnel: { shadefrom = 0.2f; break; } + default: {break; } + } + fShade = interpolate( shadefrom, shadeto, static_cast( d ) ); +/* switch (t0->eEnvironment) { // typ zmiany oświetlenia - zakładam, że // drugi tor ma e_flat @@ -2385,6 +2398,7 @@ void TDynamicObject::Move(double fDistance) fShade = d + (1.0 - d) * 0.20; break; // zacienienie w tunelu } +*/ } } } @@ -3699,39 +3713,12 @@ 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 -/* - double modelrotate; - vector3 tempangle; - // zmienne - renderme = false; - // przeklejka - double ObjSqrDist = SquareMagnitude(Global::pCameraPosition - vPosition) / Global::ZoomFactor; - // koniec przeklejki - if (ObjSqrDist < 500) // jak jest blisko - do 70m - modelrotate = 0.01; // mały kąt, żeby nie znikało - else - { // Global::pCameraRotation to kąt bewzględny w świecie (zero - na północ) - tempangle = (vPosition - Global::pCameraPosition); // wektor od kamery - modelrotate = ABuAcos(tempangle); // określenie kąta - // if (modelrotate>M_PI) modelrotate-=(2*M_PI); - modelrotate += Global::pCameraRotation; - } - if (modelrotate > M_PI) - modelrotate -= (2 * M_PI); - if (modelrotate < -M_PI) - modelrotate += (2 * M_PI); - ModCamRot = modelrotate; - modelrotate = abs(modelrotate); - - if (modelrotate < maxrot) - renderme = true; -*/ - if (Global::pCamera->IsVisible(this)) + if (GfxRenderer.Visible(this)) { TSubModel::iInstance = (size_t)this; //żeby nie robić cudzych animacji // AnsiString asLoadName=""; @@ -3776,7 +3763,6 @@ void TDynamicObject::Render() 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}; @@ -3793,6 +3779,11 @@ void TDynamicObject::Render() 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 @@ -3802,8 +3793,6 @@ void TDynamicObject::Render() mdModel->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha); if (mdLoad) // renderowanie nieprzezroczystego ładunku mdLoad->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha); - if (mdPrzedsionek) - mdPrzedsionek->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha); } else { // wersja Display Lists @@ -3830,8 +3819,6 @@ void TDynamicObject::Render() mdModel->Render(ObjSqrDist, ReplacableSkinID, iAlpha); if (mdLoad) // renderowanie nieprzezroczystego ładunku mdLoad->Render(ObjSqrDist, ReplacableSkinID, iAlpha); - if (mdPrzedsionek) - mdPrzedsionek->Render(ObjSqrDist, ReplacableSkinID, iAlpha); } // Ra: czy ta kabina tu ma sens? @@ -3898,6 +3885,11 @@ void TDynamicObject::Render() 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) @@ -3905,10 +3897,83 @@ void TDynamicObject::Render() } // 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 +{ // przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem +// if( Global::iPause > 0 ) { return; } + // McZapkie-010302: ulepszony dzwiek silnika double freq; double vol = 0; @@ -3919,11 +3984,10 @@ void TDynamicObject::RenderSounds() if (MoverParameters->Power > 0) { - if ((rsSilnik.AM != 0) && ((MoverParameters->Mains) || (MoverParameters->EngineType == - DieselEngine))) // McZapkie-280503: - // zeby dla dumb - // dzialal silnik na - // jalowych obrotach + if ((rsSilnik.AM != 0) + && ((MoverParameters->Mains) + // McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach + || (MoverParameters->EngineType == DieselEngine))) { if ((fabs(MoverParameters->enrot) > 0.01) || (MoverParameters->EngineType == Dumb)) //&& (MoverParameters->EnginePower>0.1)) @@ -4128,9 +4192,8 @@ void TDynamicObject::RenderSounds() sSmallCompressor.Update(MechInside, GetPosition()); // youBy - przenioslem, bo diesel tez moze miec turbo - if ((MoverParameters->MainCtrlPos) >= - (MoverParameters->TurboTest)) // hunter-250312: dlaczego zakomentowane? - // Ra: bo nie działało dobrze + if( (MoverParameters->TurboTest > 0) + && (MoverParameters->MainCtrlPos >= MoverParameters->TurboTest)) { // udawanie turbo: (6.66*(eng_vol-0.85)) if (eng_turbo > 6.66 * (enginevolume - 0.8) + 0.2 * dt) @@ -4274,85 +4337,6 @@ void TDynamicObject::RenderSounds() */ }; -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 - if (Global::bSmudge) - { // jak smuga, to rysować po smudze - 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); - // if (mdPrzedsionek) //Ra: przedsionków tu wcześniej nie było - włączyć? - // mdPrzedsionek->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); - // if (mdPrzedsionek) //Ra: przedsionków tu wcześniej nie było - włączyć? - // mdPrzedsionek->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 - // McZapkie-250202 // wczytywanie pliku z danymi multimedialnymi (dzwieki) void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, @@ -4378,6 +4362,7 @@ 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; @@ -4388,10 +4373,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, } 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? + { // 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) @@ -4399,78 +4381,37 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, 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; + if( asModel[asModel.size() - 1] == '#' ) // Ra 2015-01: nie podoba mi siê to + { // model wymaga wielu tekstur wymiennych + m_materialdata.multi_textures = 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()) + 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 ((i = ReplacableSkin.Pos("|")) > 0) // replacable dzielone - { - iMultiTex = -1; - ReplacableSkinID[-iMultiTex] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin.SubString(1, i - 1).c_str(), - Global::iDynamicFiltering); - ReplacableSkin.Delete(1, i); // usunięcie razem z pionową kreską - ReplacableSkin = Global::asCurrentTexturePath + - ReplacableSkin; // odtworzenie początku ścieżki - // sprawdzić, ile jest i ustawić iMultiTex na liczbę podanych tekstur - if (!ReplacableSkin.IsEmpty()) - { // próba wycięcia drugiej nazwy - iMultiTex = -2; // skoro zostało coś po kresce, to są co najmniej dwie - if ((i = ReplacableSkin.Pos("|")) == 0) // gdy nie ma już kreski - ReplacableSkinID[-iMultiTex] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin.SubString(1, i - 1).c_str(), - Global::iDynamicFiltering); - else - { // jak jest kreska, to wczytać drugą i próbować trzecią - ReplacableSkinID[-iMultiTex] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin.SubString(1, i - 1).c_str(), - Global::iDynamicFiltering); - ReplacableSkin.Delete(1, i); // usunięcie razem z pionową kreską - ReplacableSkin = Global::asCurrentTexturePath + - ReplacableSkin; // odtworzenie początku ścieżki - if (!ReplacableSkin.IsEmpty()) - { // próba wycięcia trzeciej nazwy - iMultiTex = - -3; // skoro zostało coś po kresce, to są co najmniej trzy - if ((i = ReplacableSkin.Pos("|")) == 0) // gdy nie ma już kreski - ReplacableSkinID[-iMultiTex] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin.SubString(1, i - 1).c_str(), - Global::iDynamicFiltering); - else - { // jak jest kreska, to wczytać trzecią i próbować czwartą - ReplacableSkinID[-iMultiTex] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin.SubString(1, i - 1).c_str(), - Global::iDynamicFiltering); - ReplacableSkin.Delete(1, i); // usunięcie razem z pionową kreską - ReplacableSkin = Global::asCurrentTexturePath + - ReplacableSkin; // odtworzenie początku ścieżki - if (!ReplacableSkin.IsEmpty()) - { // próba wycięcia trzeciej nazwy - iMultiTex = -4; // skoro zostało coś po kresce, to są co - // najmniej cztery - ReplacableSkinID[-iMultiTex] = - TTexturesManager::GetTextureID( - NULL, NULL, - ReplacableSkin.SubString(1, i - 1).c_str(), - Global::iDynamicFiltering); - // więcej na razie nie zadziała, a u tak trzeba to do modeli - // przenieść - } - } - } - } - } - } - */ + 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( @@ -4490,8 +4431,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, ReplacableSkinID[4] = GfxRenderer.GetTextureId( ReplacableSkin + ",4", "", Global::iDynamicFiltering); if (ReplacableSkinID[4]) - iMultiTex = 4; // jak są cztery, to blokujemy podmianę tekstury - // rozkładem + iMultiTex = 4; // jak są cztery, to blokujemy podmianę tekstury rozkładem } } } @@ -4506,37 +4446,75 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, 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 + iAlpha = 0x31310031; // tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych else - iAlpha = 0x30300030; // wszystkie tekstury nieprzezroczyste - nie - // renderować w - // cyklu przezroczystych + 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 + 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 + 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 + iAlpha |= 0x08080008; // tekstura -4 z kanałem alfa - nie renderować w cyklu nieprzezroczystych } -/* - // Winger 040304 - ladowanie przedsionkow dla EZT - if (MoverParameters->TrainType == dt_EZT) - { - asModel = "przedsionki.t3d"; - asModel = BaseDir + asModel; - mdPrzedsionek = TModelsManager::GetModel(asModel, true); +#else + { // 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()) + m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + "nowhere", "", 9 ); + + if (m_materialdata.multi_textures > 0) + { // jeśli model ma 4 tekstury + m_materialdata.replacable_skins[ 1 ] = GfxRenderer.GetTextureId( + ReplacableSkin + ",1", "", Global::iDynamicFiltering); + if( m_materialdata.replacable_skins[ 1 ] ) + { // pierwsza z zestawu znaleziona + m_materialdata.replacable_skins[ 2 ] = GfxRenderer.GetTextureId( + ReplacableSkin + ",2", "", Global::iDynamicFiltering); + if( m_materialdata.replacable_skins[ 2 ] ) + { + m_materialdata.multi_textures = 2; // już są dwie + m_materialdata.replacable_skins[ 3 ] = GfxRenderer.GetTextureId( + ReplacableSkin + ",3", "", Global::iDynamicFiltering); + if( m_materialdata.replacable_skins[ 3 ] ) + { + m_materialdata.multi_textures = 3; // a teraz nawet trzy + m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( + ReplacableSkin + ",4", "", Global::iDynamicFiltering); + if( m_materialdata.replacable_skins[ 4 ] ) + m_materialdata.multi_textures = 4; // jak są cztery, to blokujemy podmianę tekstury + // rozkładem + } + } + } + else + { // zestaw nie zadziałał, próbujemy normanie + m_materialdata.multi_textures = 0; + m_materialdata.replacable_skins[ 1 ] = GfxRenderer.GetTextureId( + ReplacableSkin, "", Global::iDynamicFiltering); + } + } + else + m_materialdata.replacable_skins[ 1 ] = GfxRenderer.GetTextureId( + ReplacableSkin, "", Global::iDynamicFiltering); + if( GfxRenderer.Texture( m_materialdata.replacable_skins[ 1 ] ).has_alpha ) + m_materialdata.textures_alpha = 0x31310031; // tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych + else + m_materialdata.textures_alpha = 0x30300030; // wszystkie tekstury nieprzezroczyste - nie renderować w cyklu przezroczystych + if( m_materialdata.replacable_skins[ 2 ] ) + if( GfxRenderer.Texture( m_materialdata.replacable_skins[ 2 ] ).has_alpha ) + m_materialdata.textures_alpha |= 0x02020002; // tekstura -2 z kanałem alfa - nie renderować w cyklu nieprzezroczystych + if( m_materialdata.replacable_skins[ 3 ] ) + if( GfxRenderer.Texture( m_materialdata.replacable_skins[ 3 ] ).has_alpha ) + m_materialdata.textures_alpha |= 0x04040004; // tekstura -3 z kanałem alfa - nie renderować w cyklu nieprzezroczystych + if( m_materialdata.replacable_skins[ 4 ] ) + 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")) @@ -5449,8 +5427,6 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, // binarnego if (mdLoad) mdLoad->Init(); - if (mdPrzedsionek) - mdPrzedsionek->Init(); if (mdLowPolyInt) mdLowPolyInt->Init(); // sHorn2.CopyIfEmpty(sHorn1); ///żeby jednak trąbił też drugim @@ -5820,6 +5796,7 @@ 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 @@ -5866,6 +5843,51 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer) // 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 + 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()) + { + m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( x, "", 9 ); // rozmywania 0,1,4,5 nie nadają się + return; + } + x = TextureTest(asBaseDir + numer ); + if (!x.empty()) + { + m_materialdata.replacable_skins[ 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()) + { + m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( x, "", 9 ); // rozmywania 0,1,4,5 nie nadają się + return; + } + x = TextureTest(asBaseDir + to); // na razie prymitywnie + if (!x.empty()) + m_materialdata.replacable_skins[ 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()) + 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 +}; +#endif void TDynamicObject::OverheadTrack(float o) { // ewentualne wymuszanie jazdy diff --git a/DynObj.h b/DynObj.h index b3a48742..b0efde63 100644 --- a/DynObj.h +++ b/DynObj.h @@ -18,6 +18,7 @@ http://mozilla.org/MPL/2.0/. #include "AdvSound.h" #include "Button.h" #include "AirCoupler.h" +#include "texture.h" //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- @@ -140,7 +141,24 @@ class TAnim //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- +#ifndef EU07_USE_OLD_RENDERCODE +// parameters for the material object, as currently used by various simulator models +struct material_data { + + int textures_alpha{ 0x30300030 }; // maska przezroczystości tekstur. default: tekstury wymienne nie mają przezroczystości + texture_manager::size_type replacable_skins[ 5 ]; // McZapkie:zmienialne nadwozie + int multi_textures{ 0 }; //<0 tekstury wskazane wpisem, >0 tekstury z przecinkami, =0 jedna + + material_data() { + ::SecureZeroMemory( replacable_skins, sizeof( replacable_skins ) ); + } +}; +#endif + class TDynamicObject { // klasa pojazdu + + friend class opengl_renderer; + private: // położenie pojazdu w świecie oraz parametry ruchu vector3 vPosition; // Ra: pozycja pojazdu liczona zaraz po przesunięciu vector3 vCoulpler[ 2 ]; // współrzędne sprzęgów do liczenia zderzeń czołowych @@ -172,12 +190,9 @@ public: // parametry położenia pojazdu dostępne publicznie TPowerSource ConnectedEnginePowerSource( TDynamicObject const *Caller ) const; -private: - // returns type of the nearest functional power source present in the trainset public: // modele składowe pojazdu TModel3d *mdModel; // model pudła TModel3d *mdLoad; // model zmiennego ładunku - TModel3d *mdPrzedsionek; // model przedsionków dla EZT - może użyć mdLoad zamiast? TModel3d *mdKabina; // model kabiny dla użytkownika; McZapkie-030303: to z train.h TModel3d *mdLowPolyInt; // ABu 010305: wnetrze lowpoly float3 InteriorLight{ 0.9f * 255.0f / 255.0f, 0.9f * 216.0f / 255.0f, 0.9f * 176.0f / 255.0f }; // tungsten light. TODO: allow definition of light type? @@ -185,8 +200,17 @@ 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 - public: // 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 +#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 + // 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: int iAnimations; // liczba obiektów animujących /* @@ -343,6 +367,7 @@ public: // modele składowe pojazdu public: int *iLights; // wskaźnik na bity zapalonych świateł (własne albo innego członu) + bool DimHeadlights{ false }; // status of the headlight dimming toggle. NOTE: single toggle for all lights is a simplification. TODO: separate per-light switches double fTrackBlock; // odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym // pojazdem) TDynamicObject * PrevAny(); @@ -396,9 +421,11 @@ 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; @@ -417,8 +444,10 @@ 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 3d1cc35b..45e234db 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -28,6 +28,9 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #include "World.h" #include "Mover.h" #include "usefull.h" +#include "timer.h" +#include "resource.h" +#include "uilayer.h" #pragma comment (lib, "glu32.lib") #pragma comment (lib, "dsound.lib") @@ -78,8 +81,10 @@ void make_screenshot() void window_resize_callback(GLFWwindow *window, int w, int h) { - Global::ScreenWidth = w; - Global::ScreenHeight = h; + // NOTE: we have two variables which basically do the same thing as we don't have dynamic fullscreen toggle + // TBD, TODO: merge them? + Global::ScreenWidth = Global::iWindowWidth = w; + Global::ScreenHeight = Global::iWindowHeight = h; Global::fDistanceFactor = std::max( 0.5f, h / 768.0f ); // not sure if this is really something we want to use glViewport(0, 0, w, h); } @@ -115,21 +120,33 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo make_screenshot(); break; case GLFW_KEY_ESCAPE: { - //[Esc] pauzuje tylko bez Debugmode - if( DebugModeFlag ) +/* + if( ( DebugModeFlag ) //[Esc] pauzuje tylko bez Debugmode + && ( Global::iPause == 0 ) ) { // but unpausing should work always + break; - + } +*/ if( Global::iPause & 1 ) // jeśli pauza startowa Global::iPause &= ~1; // odpauzowanie, gdy po wczytaniu miało nie startować else if( !( Global::iMultiplayer & 2 ) ) // w multiplayerze pauza nie ma sensu if( !Global::ctrlState ) // z [Ctrl] to radiostop jest Global::iPause ^= 2; // zmiana stanu zapauzowania - if( Global::iPause ) // jak pauza + if( Global::iPause ) {// jak pauza Global::iTextMode = GLFW_KEY_F1; // to wyświetlić zegar i informację + } break; } case GLFW_KEY_F7: - if( DebugModeFlag ) { // siatki wyświetlane tyko w trybie testowym + if( DebugModeFlag ) { + + if( Global::ctrlState ) { + // ctrl + f7 toggles static daylight + World.ToggleDaylight(); + break; + } + // f7: wireframe toggle + // siatki wyświetlane tyko w trybie testowym Global::bWireFrame = !Global::bWireFrame; if( true == Global::bWireFrame ) { glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); @@ -158,6 +175,14 @@ void focus_callback( GLFWwindow *window, int focus ) Global::iPause |= 4; // włączenie pauzy, gdy nieaktywy } +void scroll_callback( GLFWwindow* window, double xoffset, double yoffset ) { + + if( Global::ctrlState ) { + // ctrl + scroll wheel adjusts fov in debug mode + Global::FieldOfView = clamp( static_cast(Global::FieldOfView - yoffset * 20.0 / Global::fFpsAverage), 15.0f, 75.0f ); + } +} + #ifdef _WINDOWS extern "C" { @@ -230,9 +255,11 @@ int main(int argc, char *argv[]) glfwWindowHint(GLFW_REFRESH_RATE, vmode->refreshRate); glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE); - glfwWindowHint(GLFW_SAMPLES, 1 << Global::iMultisampling); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + if( Global::iMultisampling > 0 ) { + glfwWindowHint( GLFW_SAMPLES, 1 << Global::iMultisampling ); + } if (Global::bFullScreen) { @@ -243,7 +270,7 @@ int main(int argc, char *argv[]) GLFWwindow *window = glfwCreateWindow( Global::iWindowWidth, Global::iWindowHeight, - "EU07++NG", Global::bFullScreen ? monitor : nullptr, nullptr ); + Global::AppName.c_str(), Global::bFullScreen ? monitor : nullptr, nullptr ); if (!window) { @@ -257,6 +284,7 @@ int main(int argc, char *argv[]) glfwSetFramebufferSizeCallback(window, window_resize_callback); glfwSetCursorPosCallback(window, cursor_pos_callback); glfwSetKeyCallback(window, key_callback); + glfwSetScrollCallback( window, scroll_callback ); glfwSetWindowFocusCallback(window, focus_callback); { int width, height; @@ -276,9 +304,23 @@ int main(int argc, char *argv[]) BaseWindowProc = (WNDPROC)::SetWindowLongPtr( Hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc ); // switch off the topmost flag ::SetWindowPos( Hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE ); + + const HANDLE icon = ::LoadImage( + ::GetModuleHandle( 0 ), + MAKEINTRESOURCE( IDI_ICON1 ), + IMAGE_ICON, + ::GetSystemMetrics( SM_CXSMICON ), + ::GetSystemMetrics( SM_CYSMICON ), + 0 ); + if( icon ) + ::SendMessage( Hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast( icon ) ); #endif - GfxRenderer.Init(); + if( ( false == GfxRenderer.Init( window ) ) + || ( false == UILayer.init( window ) ) ) { + + return -1; + } Global::pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów try @@ -311,9 +353,10 @@ 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()) + while (!glfwWindowShouldClose(window) + && World.Update() + && GfxRenderer.Render()) { - glfwSwapBuffers(window); glfwPollEvents(); } Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej) diff --git a/Float3d.h b/Float3d.h index d6011163..0acc89cd 100644 --- a/Float3d.h +++ b/Float3d.h @@ -23,7 +23,8 @@ class float3 y = b; z = c; }; - double inline Length() const; + float Length() const; + float LengthSquared() const; }; inline bool operator==(const float3 &v1, const float3 &v2) @@ -49,10 +50,13 @@ inline float3 operator+(const float3 &v1, const float3 &v2) { return float3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); }; -double inline float3::Length() const +inline float float3::Length() const { - return sqrt(x * x + y * y + z * z); + return std::sqrt(LengthSquared()); }; +inline float float3::LengthSquared() const { + return ( x * x + y * y + z * z ); +} inline float3 operator*( float3 const &v, float const k ) { return float3( v.x * k, v.y * k, v.z * k ); }; @@ -212,7 +216,7 @@ public: { return &e[i << 2]; } - const float * readArray(void) + const float * readArray(void) const { return e; } diff --git a/Globals.cpp b/Globals.cpp index 55e8c117..5d787f3d 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -28,24 +28,15 @@ http://mozilla.org/MPL/2.0/. // parametry do użytku wewnętrznego // double Global::tSinceStart=0; TGround *Global::pGround = NULL; -// char Global::CreatorName1[30]="2001-2004 Maciej Czapkiewicz "; -// char Global::CreatorName2[30]="2001-2003 Marcin Woźniak "; -// char Global::CreatorName3[20]="2004-2005 Adam Bugiel "; -// char Global::CreatorName4[30]="2004 Arkadiusz Ślusarczyk "; -// char Global::CreatorName5[30]="2003-2009 Łukasz Kirchner "; +std::string Global::AppName{ "EU07" }; std::string Global::asCurrentSceneryPath = "scenery/"; std::string Global::asCurrentTexturePath = std::string(szTexturePath); std::string Global::asCurrentDynamicPath = ""; int Global::iSlowMotion = 0; // info o malym FPS: 0-OK, 1-wyłączyć multisampling, 3-promień 1.5km, 7-1km TDynamicObject *Global::changeDynObj = NULL; // info o zmianie pojazdu -bool Global::detonatoryOK; // info o nowych detonatorach double Global::ABuDebug = 0; std::string Global::asSky = "1"; -double Global::fOpenGL = 0.0; // wersja OpenGL - do sprawdzania obecności rozszerzeń -/* -bool Global::bOpenGL_1_5 = false; // czy są dostępne funkcje OpenGL 1.5 -*/ double Global::fLuminance = 1.0; // jasność światła do automatycznego zapalania float Global::SunAngle = 0.0f; int Global::iReCompile = 0; // zwiększany, gdy trzeba odświeżyć siatki @@ -59,18 +50,15 @@ bool Global::ctrlState; int Global::iCameraLast = -1; std::string Global::asRelease = "NG"; std::string Global::asVersion = "EU07++NG"; -int Global::iViewMode = 0; // co aktualnie widać: 0-kabina, 1-latanie, 2-sprzęgi, 3-dokumenty int Global::iTextMode = 0; // tryb pracy wyświetlacza tekstowego -int Global::iScreenMode[12] = {0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0}; // numer ekranu wyświetlacza tekstowego +int Global::iScreenMode[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // numer ekranu wyświetlacza tekstowego double Global::fSunDeclination = 0.0; // deklinacja Słońca double Global::fTimeAngleDeg = 0.0; // godzina w postaci kąta float Global::fClockAngleDeg[6]; // kąty obrotu cylindrów dla zegara cyfrowego std::string Global::szTexturesTGA = ".tga"; // lista tekstur od TGA std::string Global::szTexturesDDS = ".dds"; // lista tekstur od DDS int Global::iKeyLast = 0; // ostatnio naciśnięty klawisz w celu logowania -GLuint Global::iTextureId = 0; // ostatnio użyta tekstura 2D -int Global::iPause = 0x10; // globalna pauza ruchu +int Global::iPause = 0; // 0x10; // globalna pauza ruchu int Global::iErorrCounter = 0; // licznik sprawdzań do śledzenia błędów OpenGL int Global::iTextures = 0; // licznik użytych tekstur TWorld *Global::pWorld = NULL; @@ -78,11 +66,11 @@ cParser *Global::pParser = NULL; int Global::iSegmentsRendered = 90; // ilość segmentów do regulacji wydajności TCamera *Global::pCamera = NULL; // parametry kamery TDynamicObject *Global::pUserDynamic = NULL; // pojazd użytkownika, renderowany bez trzęsienia -bool Global::bSmudge = false; // czy wyświetlać smugę, a pojazd użytkownika na końcu /* std::string Global::asTranscript[5]; // napisy na ekranie (widoczne) */ TTranscripts Global::tranTexts; // obiekt obsługujący stenogramy dźwięków na ekranie +float4 Global::UITextColor = float4( 225.0f / 255.0f, 225.0f / 255.0f, 225.0f / 255.0f, 1.0f ); // parametry scenerii vector3 Global::pCameraPosition; @@ -122,7 +110,7 @@ int Global::iFeedbackMode = 1; // tryb pracy informacji zwrotnej int Global::iFeedbackPort = 0; // dodatkowy adres dla informacji zwrotnych bool Global::bFreeFly = false; bool Global::bFullScreen = false; -bool Global::VSync{ true }; +bool Global::VSync{ false }; bool Global::bInactivePause = true; // automatyczna pauza, gdy okno nieaktywne float Global::fMouseXScale = 1.5f; float Global::fMouseYScale = 0.2f; @@ -130,6 +118,7 @@ std::string Global::SceneryFile = "td.scn"; std::string Global::asHumanCtrlVehicle = "EU07-424"; int Global::iMultiplayer = 0; // blokada działania niektórych funkcji na rzecz komunikacji double Global::fMoveLight = -1; // ruchome światło +bool Global::FakeLight{ false }; // toggle between fixed and dynamic daylight double Global::fLatitudeDeg = 52.0; // szerokość geograficzna float Global::fFriction = 1.0; // mnożnik tarcia - KURS90 double Global::fBrakeStep = 1.0; // krok zmiany hamulca dla klawiszy [Num3] i [Num9] @@ -146,10 +135,12 @@ int Global::iBallastFiltering = 9; // domyślne rozmywanie tekstur podsypki int Global::iRailProFiltering = 5; // domyślne rozmywanie tekstur szyn int Global::iDynamicFiltering = 5; // domyślne rozmywanie tekstur pojazdów bool Global::bUseVBO = true; // czy jest VBO w karcie graficznej (czy użyć) -GLint Global::iMaxTextureSize = 16384; // maksymalny rozmiar tekstury +std::string Global::LastGLError; +GLint Global::iMaxTextureSize = 4096; // maksymalny rozmiar tekstury bool Global::bSmoothTraction = false; // wygładzanie drutów starym sposobem std::string Global::szDefaultExt = Global::szTexturesDDS; // domyślnie od DDS int Global::iMultisampling = 2; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px +bool Global::DLFont{ false }; // switch indicating presence of basic font bool Global::bGlutFont = false; // czy tekst generowany przez GLUT32.DLL //int Global::iConvertModels = 7; // tworzenie plików binarnych, +2-optymalizacja transformów int Global::iConvertModels{ 0 }; // temporary override, to prevent generation of .e3d not compatible with old exe @@ -160,8 +151,8 @@ TAnimModel *Global::pTerrainCompact = NULL; // do zapisania terenu w pliku std::string Global::asTerrainModel = ""; // nazwa obiektu terenu do zapisania w pliku double Global::fFpsAverage = 20.0; // oczekiwana wartosć FPS double Global::fFpsDeviation = 5.0; // odchylenie standardowe FPS -double Global::fFpsMin = 0.0; // dolna granica FPS, przy której promień scenerii będzie zmniejszany -double Global::fFpsMax = 0.0; // górna granica FPS, przy której promień scenerii będzie zwiększany +double Global::fFpsMin = 30.0; // dolna granica FPS, przy której promień scenerii będzie zmniejszany +double Global::fFpsMax = 65.0; // górna granica FPS, przy której promień scenerii będzie zwiększany double Global::fFpsRadiusMax = 3000.0; // maksymalny promień renderowania int Global::iFpsRadiusMax = 225; // maksymalny promień renderowania double Global::fRadiusFactor = 1.1; // współczynnik jednorazowej zmiany promienia scenerii @@ -281,8 +272,7 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens( 1, false ); Parser >> Global::FieldOfView; // guard against incorrect values - Global::FieldOfView = std::min( 75.0f, Global::FieldOfView ); - Global::FieldOfView = std::max( 15.0f, Global::FieldOfView ); + Global::FieldOfView = clamp( Global::FieldOfView, 15.0f, 75.0f ); } else if (token == "width") { @@ -521,42 +511,15 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens(1, false); int size; Parser >> size; - if (size <= 64) - { - Global::iMaxTextureSize = 64; - } - else if (size <= 128) - { - Global::iMaxTextureSize = 128; - } - else if (size <= 256) - { - Global::iMaxTextureSize = 256; - } - else if (size <= 512) - { - Global::iMaxTextureSize = 512; - } - else if (size <= 1024) - { - Global::iMaxTextureSize = 1024; - } - else if (size <= 2048) - { - Global::iMaxTextureSize = 2048; - } - else if (size <= 4096) - { - Global::iMaxTextureSize = 4096; - } - else if (size <= 8192) - { - Global::iMaxTextureSize = 8192; - } - else - { - Global::iMaxTextureSize = 16384; - } + if (size <= 64) { Global::iMaxTextureSize = 64; } + else if (size <= 128) { Global::iMaxTextureSize = 128; } + else if (size <= 256) { Global::iMaxTextureSize = 256; } + else if (size <= 512) { Global::iMaxTextureSize = 512; } + else if (size <= 1024) { Global::iMaxTextureSize = 1024; } + else if (size <= 2048) { Global::iMaxTextureSize = 2048; } + else if (size <= 4096) { Global::iMaxTextureSize = 4096; } + else if (size <= 8192) { Global::iMaxTextureSize = 8192; } + else { Global::iMaxTextureSize = 16384; } } else if (token == "doubleambient") { @@ -581,8 +544,8 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens( 1, false ); Parser >> Global::DynamicLightCount; // clamp the light number - Global::DynamicLightCount = std::min( 7, Global::DynamicLightCount ); // max 8 lights per opengl specs, and one used for sun - Global::DynamicLightCount = std::max( 1, Global::DynamicLightCount ); // at least one light for controlled vehicle + // max 8 lights per opengl specs, minus one used for sun. at least one light for controlled vehicle + Global::DynamicLightCount = clamp( Global::DynamicLightCount, 1, 7 ); } else if (token == "smoothtraction") { @@ -690,7 +653,8 @@ void Global::ConfigParse(cParser &Parser) in = 5; // na ostatni, bo i tak trzeba pominąć wartości } Parser.getTokens(4, false); - Parser >> Global::fCalibrateIn[in][0] // wyraz wolny + Parser + >> Global::fCalibrateIn[in][0] // wyraz wolny >> Global::fCalibrateIn[in][1] // mnożnik >> Global::fCalibrateIn[in][2] // mnożnik dla kwadratu >> Global::fCalibrateIn[in][3]; // mnożnik dla sześcianu @@ -805,11 +769,18 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens(1, false); Parser >> Global::asLang; } - else if (token == "opengl") - { - // deklarowana wersja OpenGL, żeby powstrzymać błędy - Parser.getTokens(1, false); - Parser >> Global::fOpenGL; + else if( token == "uitextcolor" ) { + // color of the ui text. NOTE: will be obsolete once the real ui is in place + Parser.getTokens( 3, false ); + Parser + >> Global::UITextColor.x + >> Global::UITextColor.y + >> Global::UITextColor.z; + Global::UITextColor.x = clamp( Global::UITextColor.x, 0.0f, 255.0f ); + Global::UITextColor.y = clamp( Global::UITextColor.y, 0.0f, 255.0f ); + Global::UITextColor.z = clamp( Global::UITextColor.z, 0.0f, 255.0f ); + Global::UITextColor = Global::UITextColor / 255.0f; + Global::UITextColor.w = 1.0f; } else if (token == "pyscreenrendererpriority") { @@ -929,8 +900,6 @@ void Global::ConfigParse(cParser &Parser) bEnableTraction = false; // false = pantograf się nie połamie bLiveTraction = false; // false = pantografy zawsze zbierają 95% MaxVoltage } - // if (fMoveLight>0) bDoubleAmbient=false; //wtedy tylko jedno światło ruchome - // if (fOpenGL<1.3) iMultisampling=0; //można by z góry wyłączyć, ale nie mamy jeszcze fOpenGL if (iMultisampling) { // antyaliasing całoekranowy wyłącza rozmywanie drutów bSmoothTraction = false; @@ -941,10 +910,12 @@ void Global::ConfigParse(cParser &Parser) // pauzowanie jest zablokowane dla (iMultiplayer&2)>0, więc iMultiplayer=1 da się zapauzować // (tryb instruktora) } +/* fFpsMin = fFpsAverage - fFpsDeviation; // dolna granica FPS, przy której promień scenerii będzie zmniejszany fFpsMax = fFpsAverage + fFpsDeviation; // górna granica FPS, przy której promień scenerii będzie zwiększany +*/ if (iPause) iTextMode = GLFW_KEY_F1; // jak pauza, to pokazać zegar /* this won't execute anymore with the old parser removed @@ -1043,9 +1014,12 @@ void Global::InitKeys() Keys[k_PantRearDown] = 'O'; // Winger 020304 - ogrzewanie Keys[k_Heating] = 'H'; + // headlights Keys[k_LeftSign] = 'Y'; Keys[k_UpperSign] = 'U'; Keys[k_RightSign] = 'I'; + Keys[k_DimHeadlights] = 'L'; + // tail lights Keys[k_EndSign] = 'T'; Keys[k_SmallCompressor] = 'V'; @@ -1078,14 +1052,6 @@ void Global::SetCameraRotation(double Yaw) pCameraRotationDeg = pCameraRotation * 180.0 / M_PI; } -void Global::BindTexture(GLuint t) -{ // ustawienie aktualnej tekstury, tylko gdy się zmienia - if (t != iTextureId) - { - iTextureId = t; - } -}; - void Global::TrainDelete(TDynamicObject *d) { // usunięcie pojazdu prowadzonego przez użytkownika if (pWorld) diff --git a/Globals.h b/Globals.h index 2599c83b..ec5a59d9 100644 --- a/Globals.h +++ b/Globals.h @@ -110,7 +110,8 @@ const int k_Active = 71; // Winger 020304 const int k_Battery = 72; const int k_WalkMode = 73; -const int MaxKeys = 74; +int const k_DimHeadlights = 74; +const int MaxKeys = 75; // klasy dla wskaźników globalnych class TGround; @@ -162,7 +163,6 @@ private: class Global { private: - static GLuint iTextureId; // ostatnio użyta tekstura 2D public: // double Global::tSinceStart; static int Keys[MaxKeys]; @@ -199,11 +199,7 @@ class Global static TGround *pGround; static std::string szDefaultExt; static std::string SceneryFile; - static char CreatorName1[20]; - static char CreatorName2[20]; - static char CreatorName3[20]; - static char CreatorName4[30]; - static char CreatorName5[30]; + static std::string AppName; static std::string asCurrentSceneryPath; static std::string asCurrentTexturePath; static std::string asCurrentDynamicPath; @@ -243,7 +239,6 @@ class Global static int iSlowMotion; static TDynamicObject *changeDynObj; static double ABuDebug; - static bool detonatoryOK; static std::string asSky; static bool bnewAirCouplers; // Ra: nowe zmienne globalne @@ -254,12 +249,9 @@ class Global static int iDynamicFiltering; // domyślne rozmywanie tekstur pojazdów static int iReCompile; // zwiększany, gdy trzeba odświeżyć siatki static bool bUseVBO; // czy jest VBO w karcie graficznej + static std::string LastGLError; static int iFeedbackMode; // tryb pracy informacji zwrotnej static int iFeedbackPort; // dodatkowy adres dla informacji zwrotnych - static double fOpenGL; // wersja OpenGL - przyda się -/* - static bool bOpenGL_1_5; // czy są dostępne funkcje OpenGL 1.5 -*/ 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 @@ -273,13 +265,12 @@ class Global static int iCameraLast; static std::string asRelease; // numer static std::string asVersion; // z opisem - static int - iViewMode; // co aktualnie widać: 0-kabina, 1-latanie, 2-sprzęgi, 3-dokumenty, 4-obwody static GLint iMaxTextureSize; // maksymalny rozmiar tekstury static int iTextMode; // tryb pracy wyświetlacza tekstowego static int iScreenMode[12]; // numer ekranu wyświetlacza tekstowego static bool bDoubleAmbient; // podwójna jasność ambient static double fMoveLight; // numer dnia w roku albo -1 + static bool FakeLight; // toggle between fixed and dynamic daylight static bool bSmoothTraction; // wygładzanie drutów static double fSunDeclination; // deklinacja Słońca static double fTimeSpeed; // przyspieszenie czasu, zmienna do testów @@ -289,6 +280,7 @@ class Global static std::string szTexturesTGA; // lista tekstur od TGA static std::string szTexturesDDS; // lista tekstur od DDS static int iMultisampling; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px + static bool DLFont; // switch indicating presence of basic font static bool bGlutFont; // tekst generowany przez GLUT 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 @@ -324,11 +316,11 @@ class Global // informacje podczas kalibracji static double fBrakeStep; // krok zmiany hamulca dla klawiszy [Num3] i [Num9] static bool bJoinEvents; // czy grupować eventy o tych samych nazwach - static bool bSmudge; // czy wyświetlać smugę, a pojazd użytkownika na końcu /* static std::string asTranscript[5]; // napisy na ekranie (widoczne) */ static TTranscripts tranTexts; // obiekt obsługujący stenogramy dźwięków na ekranie + static float4 UITextColor; // base color of UI text static std::string asLang; // domyślny język - http://tools.ietf.org/html/bcp47 static int iHiddenEvents; // czy łączyć eventy z torami poprzez nazwę toru static TTextSound *tsRadioBusy[10]; // zajętość kanałów radiowych (wskaźnik na odgrywany dźwięk) @@ -372,6 +364,7 @@ class Global float3 direction; float3 color; float3 ambient; + float intensity; }; static daylight_s daylight; diff --git a/Ground.cpp b/Ground.cpp index 9c0e48f5..63825be1 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -36,6 +36,7 @@ http://mozilla.org/MPL/2.0/. #include "Driver.h" #include "Console.h" #include "Names.h" +#include "uilayer.h" #define _PROBLEND 1 //--------------------------------------------------------------------------- @@ -702,8 +703,7 @@ void TGroundNode::RenderAlphaDL() if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 { glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER, 0.04f); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glAlphaFunc(GL_GREATER, 0.02f); }; #endif } @@ -1168,6 +1168,45 @@ void TSubRect::RenderDL() node->RenderDL(); // nieprzezroczyste z mieszanych modeli for (int j = 0; j < iTracks; ++j) tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach + +/* + float width = 100.0f; + float height = 25.0f; + float3 vTopLeftFront( m_area.center.x - width, m_area.center.y + height, m_area.center.z + width ); + float3 vTopLeftBack( m_area.center.x - width, m_area.center.y + height, m_area.center.z - width ); + float3 vTopRightBack( m_area.center.x + width, m_area.center.y + height, m_area.center.z - width ); + float3 vTopRightFront( m_area.center.x + width, m_area.center.y + height, m_area.center.z + width ); + + float3 vBottom_LeftFront( m_area.center.x - width, m_area.center.y - height, m_area.center.z + width ); + float3 vBottom_LeftBack( m_area.center.x - width, m_area.center.y - height, m_area.center.z - width ); + float3 vBottomRightBack( m_area.center.x + width, m_area.center.y - height, m_area.center.z - width ); + float3 vBottomRightFront( m_area.center.x + width, m_area.center.y - height, m_area.center.z + width ); + + glDisable( GL_LIGHTING ); + glDisable( GL_TEXTURE_2D ); + glColor3ub( 255, 255, (iTracks ? 0 : 255) ); + glBegin( GL_LINE_LOOP ); + glVertex3fv( &vTopLeftFront.x ); + glVertex3fv( &vTopLeftBack.x ); + glVertex3fv( &vTopRightBack.x ); + glVertex3fv( &vTopRightFront.x ); + glEnd(); + glBegin( GL_LINE_LOOP ); + glVertex3fv( &vBottom_LeftFront.x ); + glVertex3fv( &vBottom_LeftBack.x ); + glVertex3fv( &vBottomRightBack.x ); + glVertex3fv( &vBottomRightFront.x ); + glEnd(); + glBegin( GL_LINES ); + glVertex3fv( &vTopLeftFront.x ); glVertex3fv( &vBottom_LeftFront.x ); + glVertex3fv( &vTopLeftBack.x ); glVertex3fv( &vBottom_LeftBack.x ); + glVertex3fv( &vTopRightBack.x ); glVertex3fv( &vBottomRightBack.x ); + glVertex3fv( &vTopRightFront.x ); glVertex3fv( &vBottomRightFront.x ); + glEnd(); + glColor3ub( 255, 255, 255 ); + glEnable( GL_TEXTURE_2D ); + glEnable( GL_LIGHTING ); +*/ }; void TSubRect::RenderAlphaDL() @@ -1228,17 +1267,31 @@ void TSubRect::RenderSounds() //--------------------------------------------------------------------------- int TGroundRect::iFrameNumber = 0; // licznik wyświetlanych klatek -TGroundRect::TGroundRect() -{ - pSubRects = NULL; - nTerrain = NULL; -}; +//TGroundRect::TGroundRect( float3 const &Position, float const Radius = 1000.0f * M_SQRT2 ) : TGroundRect::~TGroundRect() { SafeDeleteArray(pSubRects); }; +void +TGroundRect::Init() { + + pSubRects = new TSubRect[ iNumSubRects * iNumSubRects ]; + 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; + 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 ); + area.radius = subrectsize * (float)M_SQRT2; + } + } +}; + void TGroundRect::RenderDL() { // renderowanie kwadratu kilometrowego (DL), jeśli jeszcze nie zrobione if (iLastDisplay != iFrameNumber) @@ -1263,6 +1316,44 @@ void TGroundRect::RenderDL() nRootMesh->RenderDL(); iLastDisplay = iFrameNumber; // drugi raz nie potrzeba } +/* + float width = 500.0f; + float height = 50.0f; + float3 vTopLeftFront( m_area.center.x - width, m_area.center.y + height, m_area.center.z + width ); + float3 vTopLeftBack( m_area.center.x - width, m_area.center.y + height, m_area.center.z - width ); + float3 vTopRightBack( m_area.center.x + width, m_area.center.y + height, m_area.center.z - width ); + float3 vTopRightFront( m_area.center.x + width, m_area.center.y + height, m_area.center.z + width ); + + float3 vBottom_LeftFront( m_area.center.x - width, m_area.center.y - height, m_area.center.z + width ); + float3 vBottom_LeftBack( m_area.center.x - width, m_area.center.y - height, m_area.center.z - width ); + float3 vBottomRightBack( m_area.center.x + width, m_area.center.y - height, m_area.center.z - width ); + float3 vBottomRightFront( m_area.center.x + width, m_area.center.y - height, m_area.center.z + width ); + + glDisable( GL_LIGHTING ); + glDisable( GL_TEXTURE_2D ); + glColor3ub( 0, 255, 255 ); + glBegin( GL_LINE_LOOP ); + glVertex3fv( &vTopLeftFront.x ); + glVertex3fv( &vTopLeftBack.x ); + glVertex3fv( &vTopRightBack.x ); + glVertex3fv( &vTopRightFront.x ); + glEnd(); + glBegin( GL_LINE_LOOP ); + glVertex3fv( &vBottom_LeftFront.x ); + glVertex3fv( &vBottom_LeftBack.x ); + glVertex3fv( &vBottomRightBack.x ); + glVertex3fv( &vBottomRightFront.x ); + glEnd(); + glBegin( GL_LINES ); + glVertex3fv( &vTopLeftFront.x ); glVertex3fv( &vBottom_LeftFront.x ); + glVertex3fv( &vTopLeftBack.x ); glVertex3fv( &vBottom_LeftBack.x ); + glVertex3fv( &vTopRightBack.x ); glVertex3fv( &vBottomRightBack.x ); + glVertex3fv( &vTopRightFront.x ); glVertex3fv( &vBottomRightFront.x ); + glEnd(); + glColor3ub( 255, 255, 255 ); + glEnable( GL_TEXTURE_2D ); + glEnable( GL_LIGHTING ); +*/ }; void TGroundRect::RenderVBO() @@ -1340,6 +1431,22 @@ TGround::TGround() #endif ::SecureZeroMemory( TempConnectionType, sizeof( TempConnectionType ) ); ::SecureZeroMemory( pRendered, sizeof( pRendered ) ); + + // set bounding area information for ground rectangles + float const rectsize = 1000.0f; + float3 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 * (float)M_SQRT2; + 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 ); + } + } } TGround::~TGround() @@ -1978,9 +2085,12 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) // if the vehicle has defined light source, it can (potentially) emit light, so add it to the light array */ if( ( tmp != nullptr ) - && ( tmp->DynamicObject->MoverParameters->SecuritySystem.SystemType != 0 ) ) { - // we check for presence of security system, as a way to determine whether the vehicle is a controllable engine - // NOTE: this isn't 100% precise, e.g. middle EZT module comes with security system, while it has no lights + && ( tmp->DynamicObject->MoverParameters->CategoryFlag == 1 ) // trains only + && ( ( tmp->DynamicObject->MoverParameters->SecuritySystem.SystemType != 0 ) + || ( tmp->DynamicObject->MoverParameters->SandCapacity > 0.0 ) ) ) { + // we check for presence of security system or sand load, as a way to determine whether the vehicle is a controllable engine + // NOTE: this isn't 100% precise, e.g. middle EZT module comes with security system, while it has no lights, and some engines + // don't have security systems fitted m_lights.insert( tmp->DynamicObject ); } @@ -2446,66 +2556,17 @@ void TGround::FirstInit() for (j = 0; j < iNumRects; ++j) Rects[i][j].Optimize(); // optymalizacja obiektów w sektorach WriteLog("InitNormals OK"); - WriteLog("InitTracks"); InitTracks(); //łączenie odcinków ze sobą i przyklejanie eventów WriteLog("InitTracks OK"); - WriteLog("InitTraction"); InitTraction(); //łączenie drutów ze sobą WriteLog("InitTraction OK"); - WriteLog("InitEvents"); InitEvents(); WriteLog("InitEvents OK"); - WriteLog("InitLaunchers"); InitLaunchers(); WriteLog("InitLaunchers OK"); - WriteLog("InitGlobalTime"); // ABu 160205: juz nie TODO :) Mtable::GlobalTime = std::make_shared( hh, mm, srh, srm, ssh, ssm ); // McZapkie-300302: inicjacja czasu rozkladowego - TODO: czytac z trasy! WriteLog("InitGlobalTime OK"); - // jeszcze ustawienie pogody, gdyby nie było w scenerii wpisów - glClearColor(Global::AtmoColor[0], Global::AtmoColor[1], Global::AtmoColor[2], - 0.0); // Background Color - if (Global::fFogEnd > 0) - { - glFogi(GL_FOG_MODE, GL_LINEAR); - glFogfv(GL_FOG_COLOR, Global::FogColor); // set fog color - glFogf(GL_FOG_START, Global::fFogStart); // fog start depth - glFogf(GL_FOG_END, Global::fFogEnd); // fog end depth - glEnable(GL_FOG); - } - else - glDisable(GL_FOG); - glDisable(GL_LIGHTING); -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // TODO, TBD: re-implement this - glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos); // daylight position - glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); // kolor wszechobceny - glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); // kolor padający - glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); // kolor odbity - // musi być tutaj, bo wcześniej nie mieliśmy wartości światła -#endif -/* - if (Global::fMoveLight >= 0.0) // albo tak, albo niech ustala minimum ciemności w nocy - { -*/ -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // TODO, TBD: re-implement this - Global::fLuminance = // obliczenie luminacji "światła w ciemności" - +0.150 * Global::ambientDayLight[0] // R - + 0.295 * Global::ambientDayLight[1] // G - + 0.055 * Global::ambientDayLight[2]; // B - if (Global::fLuminance > 0.1) // jeśli miało by być za jasno - for (int i = 0; i < 3; i++) - Global::ambientDayLight[i] *= - 0.1 / Global::fLuminance; // ograniczenie jasności w nocy - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Global::ambientDayLight); -#endif -/* - } - else if (Global::bDoubleAmbient) // Ra: wcześniej było ambient dawane na obydwa światła - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Global::ambientDayLight); -*/ - glEnable(GL_LIGHTING); WriteLog("FirstInit is done"); }; @@ -2556,17 +2617,17 @@ bool TGround::Init(std::string File) token = ""; parser.getTokens(); parser >> token; - int refresh = 0; + std::size_t processed = 0; while (token != "") //(!Parser->EndOfFile) { - if (refresh == 50) - { // SwapBuffers(hDC); //Ra: bez ogranicznika za bardzo spowalnia :( a u niektórych miga - refresh = 0; - Global::DoEvents(); + ++processed; + if( processed % 1000 == 0 ) + { + UILayer.set_progress( parser.getProgress(), parser.getFullProgress() ); + GfxRenderer.Render(); + glfwPollEvents(); } - else - ++refresh; str = token; if (str == "node") { @@ -4835,13 +4896,13 @@ TGround::Render( Math3D::vector3 const &Camera ) { if( !RenderAlphaVBO( Camera ) ) return false; } - else { // renderowanie przez Display List + else { + // renderowanie przez Display List if( !RenderDL( Camera ) ) return false; if( !RenderAlphaDL( Camera ) ) return false; } - return true; } @@ -4893,6 +4954,7 @@ bool TGround::RenderDL(vector3 pPosition) if (CameraDirection.x * direction.x + CameraDirection.z * direction.z < 0.55) continue; // pomijanie sektorów poza kątem patrzenia } + // NOTE: terrain data is disabled, as it's moved to the renderer Rects[(i + c) / iNumSubRects][(j + r) / iNumSubRects] .RenderDL(); // kwadrat kilometrowy nie zawsze, bo szkoda FPS if ((tmp = FastGetSubRect(i + c, j + r)) != NULL) @@ -4908,7 +4970,7 @@ bool TGround::RenderDL(vector3 pPosition) bool TGround::RenderAlphaDL(vector3 pPosition) { // renderowanie scenerii z Display List - faza przezroczystych glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER, 0.04f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + glAlphaFunc(GL_GREATER, 0.02f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f TGroundNode *node; glColor4f(1.0f, 1.0f, 1.0f, 1.0f); TSubRect *tmp; diff --git a/Ground.h b/Ground.h index 63bb3ae9..f86b52a5 100644 --- a/Ground.h +++ b/Ground.h @@ -181,11 +181,19 @@ class TGroundNode : public Resource void RaRenderVBO(); // renderowanie (nieprzezroczystych) ze wspólnego VBO void RenderVBO(); // renderowanie nieprzezroczystych z własnego VBO void RenderAlphaVBO(); // renderowanie przezroczystych z (własnego) VBO + +}; + +struct bounding_area { + + float3 center; // mid point of the rectangle + float radius{ 0.0f }; // radius of the bounding sphere }; class TSubRect : public Resource, public CMesh { // sektor składowy kwadratu kilometrowego public: + bounding_area m_area; int iTracks = 0; // ilość torów w (tTracks) TTrack **tTracks = nullptr; // tory do renderowania pojazdów protected: @@ -207,7 +215,6 @@ class TSubRect : public Resource, public CMesh public: void LoadNodes(); // utworzenie VBO sektora public: -// TSubRect() = default; virtual ~TSubRect(); virtual void Release(); // zwalnianie VBO sektora void NodeAdd(TGroundNode *Node); // dodanie obiektu do sektora na etapie rozdzielania na sektory @@ -242,16 +249,12 @@ class TGroundRect : public TSubRect // Ra: 2012-02 doszły submodele terenu private: int iLastDisplay; // numer klatki w której był ostatnio wyświetlany - TSubRect *pSubRects; - void Init() - { - pSubRects = new TSubRect[iNumSubRects * iNumSubRects]; - }; + TSubRect *pSubRects{ nullptr }; + void Init(); public: static int iFrameNumber; // numer kolejny wyświetlanej klatki - TGroundNode *nTerrain; // model terenu z E3D - użyć nRootMesh? - TGroundRect(); + TGroundNode *nTerrain{ nullptr }; // model terenu z E3D - użyć nRootMesh? virtual ~TGroundRect(); TSubRect * SafeGetRect(int iCol, int iRow) @@ -276,6 +279,8 @@ class TGroundRect : public TSubRect class TGround { + friend class opengl_renderer; + vector3 CameraDirection; // zmienna robocza przy renderowaniu int const *iRange = nullptr; // tabela widoczności // TGroundNode *nRootNode; //lista wszystkich węzłów diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index ee072da9..aa11d20b 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1127,6 +1127,7 @@ private: void LoadFIZ_Circuit( std::string const &Input ); void LoadFIZ_RList( std::string const &Input ); void LoadFIZ_DList( std::string const &Input ); + void LoadFIZ_FFList( std::string const &Input ); void LoadFIZ_LightsList( std::string const &Input ); void LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparameters, std::string const Prefix, std::string const &Input ); TPowerType LoadFIZ_PowerDecode( std::string const &Power ); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index eb65d3c8..eed06456 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -428,45 +428,47 @@ double TMoverParameters::Distance(const vector3 &s1, const vector3 &s2, const ve */ double TMoverParameters::CouplerDist(int Coupler) { // obliczenie odległości pomiędzy sprzęgami (kula!) - return Couplers[Coupler].CoupleDist = - Distance(Loc, Couplers[Coupler].Connected->Loc, Dim, - Couplers[Coupler].Connected->Dim); // odległość pomiędzy sprzęgami (kula!) + Couplers[Coupler].CoupleDist = + Distance( + Loc, Couplers[Coupler].Connected->Loc, + Dim, Couplers[Coupler].Connected->Dim); // odległość pomiędzy sprzęgami (kula!) + + return Couplers[ Coupler ].CoupleDist; }; -bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, - int CouplingType, bool Forced) +bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced) { //łączenie do swojego sprzęgu (ConnectNo) pojazdu (ConnectTo) stroną (ConnectToNr) // Ra: zwykle wykonywane dwukrotnie, dla każdego pojazdu oddzielnie // Ra: trzeba by odróżnić wymóg dociśnięcia od uszkodzenia sprzęgu przy podczepianiu AI do // składu if (ConnectTo) // jeśli nie pusty { + auto &coupler = Couplers[ ConnectNo ]; if (ConnectToNr != 2) - Couplers[ConnectNo].ConnectedNr = ConnectToNr; // 2=nic nie podłączone - TCouplerType ct = ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr] - .CouplerType; // typ sprzęgu podłączanego pojazdu - Couplers[ConnectNo].Connected = - ConnectTo; // tak podpiąć (do siebie) zawsze można, najwyżej będzie wirtualny - CouplerDist(ConnectNo); // przeliczenie odległości pomiędzy sprzęgami + coupler.ConnectedNr = ConnectToNr; // 2=nic nie podłączone + coupler.Connected = ConnectTo; // tak podpiąć (do siebie) zawsze można, najwyżej będzie wirtualny + CouplerDist( ConnectNo ); // przeliczenie odległości pomiędzy sprzęgami + if (CouplingType == ctrain_virtual) return false; // wirtualny więcej nic nie robi - if (Forced ? true : ((Couplers[ConnectNo].CoupleDist <= dEpsilon) && - (Couplers[ConnectNo].CouplerType != NoCoupler) && - (Couplers[ConnectNo].CouplerType == ct))) + + auto &othercoupler = ConnectTo->Couplers[ coupler.ConnectedNr ]; + if( ( Forced ) + || ( ( coupler.CoupleDist <= dEpsilon ) + && ( coupler.CouplerType != NoCoupler ) + && ( coupler.CouplerType == othercoupler.CouplerType ) ) ) { // stykaja sie zderzaki i kompatybilne typy sprzegow, chyba że łączenie na starcie - if (Couplers[ConnectNo].CouplingFlag == - ctrain_virtual) // jeśli wcześniej nie było połączone - { // ustalenie z której strony rysować sprzęg - Couplers[ConnectNo].Render = true; // tego rysować - ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].Render = false; // a tego nie + if( coupler.CouplingFlag == ctrain_virtual ) { + // jeśli wcześniej nie było połączone, ustalenie z której strony rysować sprzęg + coupler.Render = true; // tego rysować + othercoupler.Render = false; // a tego nie }; - Couplers[ConnectNo].CouplingFlag = CouplingType; // ustawienie typu sprzęgu + coupler.CouplingFlag = CouplingType; // ustawienie typu sprzęgu // if (CouplingType!=ctrain_virtual) //Ra: wirtualnego nie łączymy zwrotnie! //{//jeśli łączenie sprzęgiem niewirtualnym, ustawiamy połączenie zwrotne - ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag = CouplingType; - ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].Connected = this; - ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].CoupleDist = - Couplers[ConnectNo].CoupleDist; + othercoupler.CouplingFlag = CouplingType; + othercoupler.Connected = this; + othercoupler.CoupleDist = coupler.CoupleDist; return true; //} // podłączenie nie udało się - jest wirtualne @@ -2421,7 +2423,7 @@ bool TMoverParameters::DecBrakeLevelOld(void) bool TMoverParameters::IncLocalBrakeLevel(int CtrlSpeed) { bool IBL; - if ((LocalBrakePos < LocalBrakePosNo) /*and (BrakeCtrlPos<1)*/) + if ((LocalBrakePos < LocalBrakePosNo) /*and (BrakeCtrlPos<1)*/) { while ((LocalBrakePos < LocalBrakePosNo) && (CtrlSpeed > 0)) { @@ -6139,7 +6141,8 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) if( issection( "ffList:", inputline ) ) { startBPT = false; startFFLIST = true; LISTLINE = 0; - continue; + LoadFIZ_FFList( inputline ); + continue; } if( issection( "WWList:", inputline ) ) @@ -6324,7 +6327,8 @@ void TMoverParameters::LoadFIZ_Wheels( std::string const &line ) { void TMoverParameters::LoadFIZ_Brake( std::string const &line ) { - BrakeValveDecode( extract_value( "BrakeValve", line ) ); + extract_value( BrakeValveParams, "BrakeValve", line, "" ); + BrakeValveDecode( BrakeValveParams ); BrakeSubsystemDecode(); extract_value( NBpA, "NBpA", line, "" ); @@ -6951,6 +6955,11 @@ void TMoverParameters::LoadFIZ_DList( std::string const &Input ) { extract_value( dizel_Mstand, "Mstand", Input, "" ); } +void TMoverParameters::LoadFIZ_FFList( std::string const &Input ) { + + extract_value( RlistSize, "Size", Input, "" ); +} + void TMoverParameters::LoadFIZ_LightsList( std::string const &Input ) { extract_value( LightsPosNo, "Size", Input, "" ); diff --git a/McZapkie/Oerlikon_ESt.cpp b/McZapkie/Oerlikon_ESt.cpp index eded5cf6..ef433d64 100644 --- a/McZapkie/Oerlikon_ESt.cpp +++ b/McZapkie/Oerlikon_ESt.cpp @@ -63,10 +63,12 @@ void TPrzekladnik::Update(double dt) if ( BCP > P() ) dV = -PFVd(BCP, 0, d2A(10), P()) * dt; - else if ( BCP < P() ) - dV = PFVa(BVP, BCP, d2A(10), P()) * dt; - else - dV = 0; + else { + if( BCP < P() ) + dV = PFVa( BVP, BCP, d2A( 10 ), P() ) * dt; + else + dV = 0; + } Next->Flow(dV); if (dV > 0) @@ -86,8 +88,8 @@ void TRapid::SetRapidParams(double mult, double size) } else { - DN = d2A(5); - DL = d2A(5); + DN = d2A(5.0); + DL = d2A(5.0); } } @@ -117,10 +119,10 @@ void TRapid::Update(double dt) else if ((BCP * RapidMult) < (P() * ActMult)) dV = PFVa(BVP, BCP, DN, P() * ActMult / RapidMult) * dt; else - dV = 0; + dV = 0.0; Next->Flow(dV); - if (dV > 0) + if (dV > 0.0) BrakeRes->Flow(-dV); } @@ -128,7 +130,7 @@ void TRapid::Update(double dt) void TPrzekCiagly::SetMult(double m) { - mult = m; + Mult = m; } void TPrzekCiagly::Update(double dt) @@ -137,15 +139,15 @@ void TPrzekCiagly::Update(double dt) double const BCP{ Next->P() }; double dV; - if ( BCP > (P() * mult)) - dV = -PFVd(BCP, 0, d2A(8), P() * mult) * dt; - else if (BCP < (P() * mult)) - dV = PFVa(BVP, BCP, d2A(8), P() * mult) * dt; + if ( BCP > (P() * Mult)) + dV = -PFVd(BCP, 0, d2A(8.0), P() * Mult) * dt; + else if (BCP < (P() * Mult)) + dV = PFVa(BVP, BCP, d2A(8.0), P() * Mult) * dt; else - dV = 0; + dV = 0.0; Next->Flow(dV); - if (dV > 0) + if (dV > 0.0) BrakeRes->Flow(-dV); } @@ -165,14 +167,14 @@ void TPrzek_PZZ::Update(double dt) double dV; if (BCP > Pgr) - dV = -PFVd(BCP, 0, d2A(8), Pgr) * dt; + dV = -PFVd(BCP, 0, d2A(8.0), Pgr) * dt; else if (BCP < Pgr) - dV = PFVa(BVP, BCP, d2A(8), Pgr) * dt; + dV = PFVa(BVP, BCP, d2A(8.0), Pgr) * dt; else - dV = 0; + dV = 0.0; Next->Flow(dV); - if (dV > 0) + if (dV > 0.0) BrakeRes->Flow(-dV); } @@ -188,11 +190,11 @@ void TPrzekED::Update(double dt) if (Next->P() > MaxP) { BrakeRes->Flow(dVol); - Next->Flow(PFVd(Next->P(), 0, d2A(10) * dt, MaxP)); + Next->Flow(PFVd(Next->P(), 0, d2A(10.0) * dt, MaxP)); } else Next->Flow(dVol); - dVol = 0; + dVol = 0.0; } // ------ OERLIKON EST NA BOGATO ------ @@ -216,15 +218,17 @@ double TNESt3::GetPF( double const PP, double const dt, double const Vel ) // pr // luzowanie if ((BrakeStatus & b_hld) == b_off) - dV = PF(0, BCP, Nozzles[dTO] * nastG + (1.0 - nastG) * Nozzles[dOO]) * dt * - (0.1 + 4.9 * std::min(0.2, BCP - ((CVP - 0.05 - VVP) * BVM + 0.1))); + dV = + PF(0.0, BCP, Nozzles[dTO] * nastG + (1.0 - nastG) * Nozzles[dOO]) + * dt * (0.1 + 4.9 * std::min(0.2, BCP - ((CVP - 0.05 - VVP) * BVM + 0.1))); else - dV = 0; + dV = 0.0; // BrakeCyl.Flow(-dV); Przekladniki[1]->Flow(-dV); if ( ((BrakeStatus & b_on) == b_on) && (Przekladniki[1]->P() * HBG300 < MaxBP) ) - dV = PF( BVP, BCP, Nozzles[dTN] * (nastG + 2.0 * (BCP < Podskok ? 1.0 : 0.0)) + Nozzles[dON] * (1 - nastG) ) - * dt * (0.1 + 4.9 * std::min( 0.2, (CVP - 0.05 - VVP) * BVM - BCP ) ); + dV = + PF( BVP, BCP, Nozzles[dTN] * (nastG + 2.0 * (BCP < Podskok ? 1.0 : 0.0)) + Nozzles[dON] * (1.0 - nastG) ) + * dt * (0.1 + 4.9 * std::min( 0.2, (CVP - 0.05 - VVP) * BVM - BCP ) ); else dV = 0; // BrakeCyl.Flow(-dV); @@ -236,30 +240,32 @@ double TNESt3::GetPF( double const PP, double const dt, double const Vel ) // pr Przekladniki[i]->Update(dt); if (typeid(*Przekladniki[i]) == typeid(TRapid)) { - RapidStatus = - (((BrakeDelayFlag & bdelay_R) == bdelay_R) && - ((abs(Vel) > 70) || ((RapidStatus) && (abs(Vel) > 50)) || (RapidStaly))); + RapidStatus = ( ( ( BrakeDelayFlag & bdelay_R ) == bdelay_R ) + && ( ( std::abs( Vel ) > 70.0 ) + || ( ( std::abs( Vel ) > 50.0 ) && ( RapidStatus ) ) + || ( RapidStaly ) ) ); Przekladniki[i]->SetRapidStatus(RapidStatus); } - else if (typeid(*Przekladniki[i]) == typeid(TPrzeciwposlizg)) + else if( typeid( *Przekladniki[i] ) == typeid( TPrzeciwposlizg ) ) Przekladniki[i]->SetPoslizg((BrakeStatus & b_asb) == b_asb); - else if (typeid(*Przekladniki[i]) == typeid(TPrzekED)) - if (Vel < -15) - Przekladniki[i]->SetP(0); + else if( typeid( *Przekladniki[ i ] ) == typeid( TPrzekED ) ) { + if( Vel < -15.0 ) + Przekladniki[ i ]->SetP( 0.0 ); else - Przekladniki[i]->SetP(MaxBP * 3); - else if (typeid(*Przekladniki[i]) == typeid(TPrzekCiagly)) + Przekladniki[ i ]->SetP( MaxBP * 3.0 ); + } + else if( typeid( *Przekladniki[i] ) == typeid( TPrzekCiagly ) ) Przekladniki[i]->SetMult(LoadC); - else if (typeid(*Przekladniki[i]) == typeid(TPrzek_PZZ)) + else if( typeid( *Przekladniki[i] ) == typeid( TPrzek_PZZ ) ) Przekladniki[i]->SetLBP(LBP); } // przeplyw testowy miedzypojemnosci dV = PF(MPP, VVP, BVs(BCP)) + PF(MPP, CVP, CVs(BCP)); - if ((MPP - 0.05 > BVP)) + if ((MPP - 0.05) > BVP) dV += PF(MPP - 0.05, BVP, Nozzles[dPT] * nastG + (1.0 - nastG) * Nozzles[dPO]); if (MPP > VVP) - dV += PF(MPP, VVP, d2A(5)); + dV += PF(MPP, VVP, d2A(5.0)); Miedzypoj->Flow(dV * dt * 0.15); // przeplyw ZS <-> PG @@ -270,10 +276,10 @@ double TNESt3::GetPF( double const PP, double const dt, double const Vel ) // pr dV1 += 0.98 * dV; // przeplyw ZP <-> MPJ - if (MPP - 0.05 > BVP) + if ((MPP - 0.05) > BVP) dV = PF(BVP, MPP - 0.05, Nozzles[dPT] * nastG + (1.0 - nastG) * Nozzles[dPO]) * dt; else - dV = 0; + dV = 0.0; BrakeRes->Flow(dV); dV1 += dV * 0.98; ValveRes->Flow(-0.02 * dV); @@ -303,21 +309,23 @@ void TNESt3::Init( double const PP, double const HPP, double const LPP, double c BrakeCyl->CreatePress(BP); BrakeRes->CreatePress(PP); CntrlRes = std::make_shared(); - CntrlRes->CreateCap(15); + CntrlRes->CreateCap(15.0); CntrlRes->CreatePress(HPP); - BrakeStatus = static_cast(BP > 1.0); + BrakeStatus = (BP > 1.0 ? 1 : 0); Miedzypoj = std::make_shared(); - Miedzypoj->CreateCap(5); + Miedzypoj->CreateCap(5.0); Miedzypoj->CreatePress(PP); BVM = 1.0 / (HPP - 0.05 - LPP) * MaxBP; BrakeDelayFlag = BDF; - if (!(typeid(*FM) == typeid(TDisk1) || typeid(*FM) == typeid(TDisk2))) // jesli zeliwo to schodz - RapidStaly = false; - else + Zamykajacy = false; + + if ( (typeid(*FM) == typeid(TDisk1)) || (typeid(*FM) == typeid(TDisk2)) ) // jesli zeliwo to schodz RapidStaly = true; + else + RapidStaly = false; } double TNESt3::GetCRP() @@ -339,19 +347,19 @@ void TNESt3::CheckState(double const BCP, double &dV1) // glowny przyrzad rozrza // sprawdzanie stanu // if ((BrakeStatus and 1)=1)and(BCP>0.25)then - if ((VVP + 0.01 + BCP / BVM < CVP - 0.05) && (Przys_blok)) + if (((VVP + 0.01 + BCP / BVM) < (CVP - 0.05)) && (Przys_blok)) BrakeStatus |= ( b_on | b_hld ); // hamowanie stopniowe; - else if (VVP - 0.01 + (BCP - 0.1) / BVM > CVP - 0.05) + else if ((VVP - 0.01 + (BCP - 0.1) / BVM) > (CVP - 0.05)) BrakeStatus &= ~( b_on | b_hld ); // luzowanie; - else if (VVP + BCP / BVM > CVP - 0.05) + else if ((VVP + BCP / BVM) > (CVP - 0.05)) BrakeStatus &= ~b_on; // zatrzymanie napelaniania; - else if ((VVP + (BCP - 0.1) / BVM < CVP - 0.05) && (BCP > 0.25)) // zatrzymanie luzowania + else if (((VVP + (BCP - 0.1) / BVM) < (CVP - 0.05)) && (BCP > 0.25)) // zatrzymanie luzowania BrakeStatus |= b_hld; if( ( BrakeStatus & b_hld ) == 0 ) SoundFlag |= sf_CylU; - if ((VVP + 0.10 < CVP) && (BCP < 0.25)) // poczatek hamowania + if (((VVP + 0.10) < CVP) && (BCP < 0.25)) // poczatek hamowania if (false == Przys_blok) { ValveRes->CreatePress(0.1 * VVP); @@ -362,7 +370,7 @@ void TNESt3::CheckState(double const BCP, double &dV1) // glowny przyrzad rozrza if (BCP > 0.5) Zamykajacy = true; - else if (VVP - 0.6 < MPP) + else if ((VVP - 0.6) < MPP) Zamykajacy = false; } @@ -375,7 +383,7 @@ void TNESt3::CheckReleaser(double const dt) // odluzniacz if ((BrakeStatus & b_rls) == b_rls) { CntrlRes->Flow(PF(CVP, 0, 0.02) * dt); - if ((CVP < VVP + 0.3) || (false == autom)) + if ((CVP < (VVP + 0.3)) || (false == autom)) BrakeStatus &= ~b_rls; } } @@ -386,9 +394,9 @@ double TNESt3::CVs(double const BP) // napelniacz sterujacego double const MPP{ Miedzypoj->P() }; // przeplyw ZS <-> PG - if (MPP < CVP - 0.17) - return 0; - else if (MPP > CVP - 0.08) + if (MPP < (CVP - 0.17)) + return 0.0; + else if (MPP > (CVP - 0.08)) return Nozzles[dSd]; else return Nozzles[dSm]; @@ -400,15 +408,16 @@ double TNESt3::BVs(double const BCP) // napelniacz pomocniczego double const MPP{ Miedzypoj->P() }; // przeplyw ZP <-> rozdzielacz - if (MPP < CVP - 0.3) + if (MPP < (CVP - 0.3)) return Nozzles[dP]; - else if (BCP < 0.5) - if ( true == Zamykajacy) - return Nozzles[dPm]; // 1.25 + else if( BCP < 0.5 ) { + if( true == Zamykajacy ) + return Nozzles[ dPm ]; // 1.25 else - return Nozzles[dPd]; + return Nozzles[ dPd ]; + } else - return 0; + return 0.0; } void TNESt3::PLC(double const mass) @@ -461,7 +470,7 @@ void TNESt3::SetSize( int const size, std::string const ¶ms ) // ustawianie } else { - Podskok = -1; + Podskok = -1.0; Przekladniki[1] = std::make_shared(); if (params.find("-s216") != std::string::npos) Przekladniki[1]->SetRapidParams(2, 16); @@ -489,9 +498,9 @@ void TNESt3::SetSize( int const size, std::string const ¶ms ) // ustawianie else autom = true; if ((params.find("HBG300") != std::string::npos)) - HBG300 = 1; + HBG300 = 1.0; else - HBG300 = 0; + HBG300 = 0.0; switch (size) { diff --git a/McZapkie/Oerlikon_ESt.h b/McZapkie/Oerlikon_ESt.h index 88b07d27..62a64cee 100644 --- a/McZapkie/Oerlikon_ESt.h +++ b/McZapkie/Oerlikon_ESt.h @@ -133,7 +133,7 @@ class TRapid : public TPrzekladnik { class TPrzekCiagly : public TPrzekladnik { private: - double mult = 0.0; + double Mult = 0.0; public: void SetMult(double m); diff --git a/McZapkie/hamulce.cpp b/McZapkie/hamulce.cpp index ef93c067..daab0a22 100644 --- a/McZapkie/hamulce.cpp +++ b/McZapkie/hamulce.cpp @@ -193,7 +193,7 @@ double TBrakeCyl::P() static double const cD = 1; static double const pD = VD - cD; - double VtoC = ( Cap > 0.0 ) ? Vol / Cap : 0.0; // stosunek cisnienia do objetosci. + double VtoC = ( Cap > 0.0 ? Vol / Cap : 0.0 ); // stosunek cisnienia do objetosci. // Added div/0 trap for vehicles with incomplete definitions (cars etc) // P:=VtoC; if (VtoC < VS) diff --git a/McZapkie/hamulce.h b/McZapkie/hamulce.h index 962b6a87..d9cb56da 100644 --- a/McZapkie/hamulce.h +++ b/McZapkie/hamulce.h @@ -137,10 +137,10 @@ static int const i_bcpno = 6; //klasa obejmujaca pojedyncze zbiorniki class TReservoir { - protected: - double Cap = 1.0; - double Vol = 0.0; - double dVol = 0.0; +protected: + double Cap{ 1.0 }; + double Vol{ 0.0 }; + double dVol{ 0.0 }; public: void CreateCap(double Capacity); @@ -500,7 +500,7 @@ class TDriverHandle { public: bool Time = false; bool TimeEP = false; - double Sounds[ 5 ]; //wielkosci przeplywow dla dzwiekow + double Sounds[ 5 ]; //wielkosci przeplywow dla dzwiekow virtual double GetPF(double i_bcp, double PP, double HP, double dt, double ep); virtual void Init(double Press); @@ -509,6 +509,8 @@ class TDriverHandle { virtual double GetSound(int i); virtual double GetPos(int i); virtual double GetEP(double pos); + + inline TDriverHandle() { ::SecureZeroMemory( Sounds, sizeof( Sounds ) ); } }; class TFV4a : public TDriverHandle { diff --git a/Model3d.cpp b/Model3d.cpp index 05b08007..f08534ee 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -33,7 +33,7 @@ using namespace Mtable; double TSubModel::fSquareDist = 0; size_t TSubModel::iInstance; // numer renderowanego egzemplarza obiektu -texture_manager::size_type *TSubModel::ReplacableSkinId = NULL; +texture_manager::size_type const *TSubModel::ReplacableSkinId = NULL; int TSubModel::iAlpha = 0x30300030; // maska do testowania flag tekstur wymiennych TModel3d *TSubModel::pRoot; // Ra: tymczasowo wskaźnik na model widoczny z submodelu std::string *TSubModel::pasText; @@ -48,7 +48,7 @@ std::string *TSubModel::pasText; TSubModel::TSubModel() { - ZeroMemory(this, sizeof(TSubModel)); // istotne przy zapisywaniu wersji binarnej + ::SecureZeroMemory(this, sizeof(TSubModel)); // istotne przy zapisywaniu wersji binarnej FirstInit(); }; @@ -1054,6 +1054,7 @@ void TSubModel::RaAnimation(glm::mat4 &m, TAnimType a) void TSubModel::RenderDL() { // główna procedura renderowania przez DL + return; if( ( iVisible ) && ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) ) && ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) ) @@ -1153,6 +1154,7 @@ void TSubModel::RenderDL() void TSubModel::RenderAlphaDL() { // renderowanie przezroczystych przez DL + return; if( ( iVisible ) && ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) ) && ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) ) @@ -2099,39 +2101,7 @@ void TModel3d::BreakHierarhy() Error("Not implemented yet :("); }; -/* -void TModel3d::Render(vector3 pPosition,double fAngle,GLuint -ReplacableSkinId,int iAlpha) -{ -// glColor3f(1.0f,1.0f,1.0f); -// glColor3f(0.0f,0.0f,0.0f); -glPushMatrix(); - -glTranslated(pPosition.x,pPosition.y,pPosition.z); -if (fAngle!=0) -glRotatef(fAngle,0,1,0); -/* -matrix4x4 Identity; -Identity.Identity(); - -matrix4x4 CurrentMatrix; -glGetdoublev(GL_MODELVIEW_MATRIX,CurrentMatrix.getArray()); -vector3 pos=vector3(0,0,0); -pos=CurrentMatrix*pos; -fSquareDist=SquareMagnitude(pos); -* / -fSquareDist=SquareMagnitude(pPosition-Global::GetCameraPosition()); - -#ifdef _DEBUG -if (Root) -Root->Render(ReplacableSkinId,iAlpha); -#else -Root->Render(ReplacableSkinId,iAlpha); -#endif -glPopMatrix(); -}; -*/ - +#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 @@ -2152,42 +2122,8 @@ void TModel3d::RenderAlpha(double fSquareDistance, texture_manager::size_type *R Root->RenderAlphaDL(); } }; - -/* -void TModel3d::RaRender(vector3 pPosition,double fAngle,GLuint -*ReplacableSkinId,int -iAlpha) -{ -// glColor3f(1.0f,1.0f,1.0f); -// glColor3f(0.0f,0.0f,0.0f); -glPushMatrix(); //zapamiętanie matrycy przekształcenia -glTranslated(pPosition.x,pPosition.y,pPosition.z); -if (fAngle!=0) -glRotatef(fAngle,0,1,0); -/* -matrix4x4 Identity; -Identity.Identity(); - -matrix4x4 CurrentMatrix; -glGetdoublev(GL_MODELVIEW_MATRIX,CurrentMatrix.getArray()); -vector3 pos=vector3(0,0,0); -pos=CurrentMatrix*pos; -fSquareDist=SquareMagnitude(pos); -*/ -/* -fSquareDist=SquareMagnitude(pPosition-Global::GetCameraPosition()); //zmienna -globalna! -if (StartVBO()) -{//odwrócenie flag, aby wyłapać nieprzezroczyste -Root->ReplacableSet(ReplacableSkinId,iAlpha^0x0F0F000F); -Root->RaRender(); -EndVBO(); -} -glPopMatrix(); //przywrócenie ustawień przekształcenia -}; -*/ - -void TModel3d::RaRender(double fSquareDistance, texture_manager::size_type *ReplacableSkinId, int iAlpha) +#endif +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? @@ -2210,7 +2146,7 @@ void TModel3d::RaRender(double fSquareDistance, texture_manager::size_type *Repl } }; -void TModel3d::RaRenderAlpha(double fSquareDistance, texture_manager::size_type *ReplacableSkinId, int iAlpha) +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? { @@ -2231,30 +2167,10 @@ void TModel3d::RaRenderAlpha(double fSquareDistance, texture_manager::size_type } }; -/* -void TModel3d::RaRenderAlpha(vector3 pPosition,double fAngle,GLuint -*ReplacableSkinId,int -iAlpha) -{ -glPushMatrix(); -glTranslatef(pPosition.x,pPosition.y,pPosition.z); -if (fAngle!=0) -glRotatef(fAngle,0,1,0); -fSquareDist=SquareMagnitude(pPosition-Global::GetCameraPosition()); //zmienna -globalna! -if (StartVBO()) -{Root->ReplacableSet(ReplacableSkinId,iAlpha); -Root->RaRenderAlpha(); -EndVBO(); -} -glPopMatrix(); -}; -*/ - //----------------------------------------------------------------------------- // 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(); @@ -2289,7 +2205,8 @@ void TModel3d::RenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager: Root->RenderAlphaDL(); glPopMatrix(); }; -void TModel3d::RaRender(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId, int iAlpha) +#endif +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); @@ -2316,7 +2233,7 @@ void TModel3d::RaRender(vector3 *vPosition, vector3 *vAngle, texture_manager::si } glPopMatrix(); }; -void TModel3d::RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId, +void TModel3d::RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type const *ReplacableSkinId, int iAlpha) { // przezroczyste, VBO glPushMatrix(); @@ -2345,6 +2262,7 @@ void TModel3d::RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manage glPopMatrix(); }; + //----------------------------------------------------------------------------- // 2012-02 funkcje do tworzenia terenu z E3D //----------------------------------------------------------------------------- diff --git a/Model3d.h b/Model3d.h index d20a71e9..d0f52786 100644 --- a/Model3d.h +++ b/Model3d.h @@ -131,7 +131,10 @@ class TModel3d; class TSubModel { // klasa submodelu - pojedyncza siatka, punkt świetlny albo grupa punktów - //m7todo: zrobić normalną serializację + //m7todo: zrobić normalną serializację + + friend class opengl_renderer; + private: int iNext; int iChild; @@ -222,7 +225,7 @@ private: public: static size_t iInstance; // identyfikator egzemplarza, który aktualnie renderuje model - static texture_manager::size_type *ReplacableSkinId; + static texture_manager::size_type const *ReplacableSkinId; static int iAlpha; // maska bitowa dla danego przebiegu static double fSquareDist; static TModel3d *pRoot; @@ -279,7 +282,7 @@ public: void DisplayLists(); void BinInit(TSubModel *s, float4x4 *m, float8 *v, std::vector *t, std::vector *n, bool dynamic); - void ReplacableSet(texture_manager::size_type *r, int a) + void ReplacableSet(texture_manager::size_type const *r, int a) { ReplacableSkinId = r; iAlpha = a; @@ -322,6 +325,8 @@ public: class TModel3d : public CMesh { + friend class opengl_renderer; + private: // TMaterial *Materials; // int MaterialsCount; //Ra: nie używane @@ -355,32 +360,21 @@ public: 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); - void RaRender(double fSquareDistance, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RaRenderAlpha(double fSquareDistance, texture_manager::size_type *ReplacableSkinId = NULL, - int iAlpha = 0x30300030); - // jeden kąt obrotu - void Render(vector3 pPosition, double fAngle = 0, texture_manager::size_type *ReplacableSkinId = NULL, - int iAlpha = 0x30300030); - void RenderAlpha(vector3 pPosition, double fAngle = 0, texture_manager::size_type *ReplacableSkinId = NULL, - int iAlpha = 0x30300030); - void RaRender(vector3 pPosition, double fAngle = 0, texture_manager::size_type *ReplacableSkinId = NULL, - int iAlpha = 0x30300030); - void RaRenderAlpha(vector3 pPosition, double fAngle = 0, 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 - 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); - void RaRender(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId = NULL, - int iAlpha = 0x30300030); - void RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId = NULL, - int iAlpha = 0x30300030); +#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() + int Flags() const { return iFlags; }; diff --git a/Texture.cpp b/Texture.cpp index 4cbc4ee1..a9be7800 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -53,6 +53,13 @@ opengl_texture::load() { // data state will be set by called loader, so we're all done here if( data_state == resource_state::good ) { + has_alpha = ( + data_components == GL_RGBA ? + true : + false ); + + size = data.size() / 1024; + return; } @@ -473,6 +480,16 @@ opengl_texture::load_TGA() { return; } + downsize( GL_BGRA ); + if( ( data_width > Global::iMaxTextureSize ) || ( data_height > Global::iMaxTextureSize ) ) { + // for non-square textures there's currently possibility the scaling routine will have to abort + // before it gets all work done + data_state = resource_state::failed; + return; + } + + // TODO: add horizontal/vertical data flip, based on the descriptor (18th) header byte + // fill remaining data info data_mapcount = 1; data_format = GL_BGRA; @@ -485,82 +502,101 @@ opengl_texture::load_TGA() { return; } -void +resource_state +opengl_texture::bind() { + + if( false == is_ready ) { + + create(); + if( data_state != resource_state::good ) { + return data_state; + } + } + ::glBindTexture( GL_TEXTURE_2D, id ); + return data_state; +} + +resource_state opengl_texture::create() { if( data_state != resource_state::good ) { // don't bother until we have useful texture data - return; + return data_state; } - ::glGenTextures( 1, &id ); - ::glBindTexture( GL_TEXTURE_2D, id ); + // TODO: consider creating and storing low-res version of the texture if it's ever unloaded from the gfx card, + // as a placeholder until it can be loaded again + if( id == -1 ) { - // analyze specified texture traits - bool wraps{ true }; - bool wrapt{ true }; - for( auto const &trait : traits ) { + ::glGenTextures( 1, &id ); + ::glBindTexture( GL_TEXTURE_2D, id ); - switch( trait ) { + // analyze specified texture traits + bool wraps{ true }; + bool wrapt{ true }; + for( auto const &trait : traits ) { - case 's': { wraps = false; break; } - case 't': { wrapt = false; break; } + switch( trait ) { + + case 's': { wraps = false; break; } + case 't': { wrapt = false; break; } + } } - } - ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( wraps == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) ); - ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( wrapt == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( wraps == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( wrapt == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) ); - set_filtering(); + set_filtering(); - if( data_mapcount == 1 ) { - // fill missing mipmaps if needed - ::glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); - } - // upload texture data - int dataoffset = 0, - datasize = 0, - datawidth = data_width, - dataheight = data_height; - for( int maplevel = 0; maplevel < data_mapcount; ++maplevel ) { + if( data_mapcount == 1 ) { + // fill missing mipmaps if needed + ::glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); + } + // upload texture data + int dataoffset = 0, + datasize = 0, + datawidth = data_width, + dataheight = data_height; + for( int maplevel = 0; maplevel < data_mapcount; ++maplevel ) { - if( ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) - || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) - || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ) { - // compressed dds formats - int const datablocksize = - ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? + if( ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) + || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) + || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ) { + // compressed dds formats + int const datablocksize = + ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16 ); - datasize = ( ( std::max(datawidth, 4) + 3 ) / 4 ) * ( ( std::max(dataheight, 4) + 3 ) / 4 ) * datablocksize; + datasize = ( ( std::max( datawidth, 4 ) + 3 ) / 4 ) * ( ( std::max( dataheight, 4 ) + 3 ) / 4 ) * datablocksize; - ::glCompressedTexImage2D( - GL_TEXTURE_2D, maplevel, data_format, - datawidth, dataheight, 0, - datasize, (GLubyte *)&data[dataoffset] ); + ::glCompressedTexImage2D( + GL_TEXTURE_2D, maplevel, data_format, + datawidth, dataheight, 0, + datasize, (GLubyte *)&data[ dataoffset ] ); - dataoffset += datasize; - datawidth = std::max( datawidth / 2, 1 ); - dataheight = std::max( dataheight / 2, 1 ); - } - else{ - // uncompressed texture data - ::glTexImage2D( - GL_TEXTURE_2D, 0, GL_RGBA8, - data_width, data_height, 0, - data_format, GL_UNSIGNED_BYTE, (GLubyte *)&data[0] ); + dataoffset += datasize; + datawidth = std::max( datawidth / 2, 1 ); + dataheight = std::max( dataheight / 2, 1 ); + } + else { + // uncompressed texture data + ::glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA8, + data_width, data_height, 0, + data_format, GL_UNSIGNED_BYTE, (GLubyte *)&data[ 0 ] ); + } } + + data.resize( 0 ); // TBD, TODO: keep the texture data if we start doing some gpu data cleaning down the road +/* + data_state = resource_state::none; +*/ + data_state = resource_state::good; + is_ready = true; } - is_ready = true; - has_alpha = ( - data_components == GL_RGBA ? - true : - false ); - - data.resize( 0 ); // TBD, TODO: keep the texture data if we start doing some gpu data cleaning down the road - data_state = resource_state::none; + return data_state; } void @@ -628,6 +664,31 @@ opengl_texture::set_filtering() { } } +void +opengl_texture::downsize( GLuint const Format ) { + + while( ( data_width > Global::iMaxTextureSize ) || ( data_height > Global::iMaxTextureSize ) ) { + // scale down the base texture, if it's larger than allowed maximum + // NOTE: scaling is uniform along both axes, meaning non-square textures can drop below the maximum + // TODO: replace with proper scaling function once we have image middleware in place + if( ( data_width < 2 ) || ( data_height < 2 ) ) { + // can't go any smaller + break; + } + + switch( Format ) { + + case GL_RGB: { downsample< glm::tvec3 >( data_width, data_height, data.data() ); break; } + case GL_BGRA: + case GL_RGBA: { downsample< glm::tvec4 >( data_width, data_height, data.data() ); break; } + default: { break; } + } + data_width /= 2; + data_height /= 2; + data.resize( data.size() / 4 ); // not strictly needed, but, eh + }; +} + void texture_manager::Init() { } @@ -733,7 +794,9 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int if( true == Loadnow ) { Texture( textureindex ).load(); +#ifndef EU07_DEFERRED_TEXTURE_UPLOAD Texture( textureindex ).create(); +#endif } return textureindex; @@ -753,20 +816,77 @@ texture_manager::Bind( texture_manager::size_type const Id ) { // TODO: do binding in texture object, add support for other types if( Id != 0 ) { - - auto const &texture = Texture( Id ); - if( true == texture.is_ready ) { - ::glBindTexture( GL_TEXTURE_2D, texture.id ); +#ifndef EU07_DEFERRED_TEXTURE_UPLOAD + ::glBindTexture( GL_TEXTURE_2D, Id ); + m_activetexture = 0; +#else + if( Texture( Id ).bind() == resource_state::good ) { m_activetexture = Id; - return; } + else { + // TODO: bind a special 'error' texture on failure + } +#endif } + else { - ::glBindTexture( GL_TEXTURE_2D, 0 ); - m_activetexture = 0; - + ::glBindTexture( GL_TEXTURE_2D, 0 ); + m_activetexture = 0; + } + // all done return; } + +void +texture_manager::Free() { + for( auto const &texture : m_textures ) { + // usunięcie wszyskich tekstur (bez usuwania struktury) + if( ( texture.id > 0 ) + && ( texture.id != -1 ) ) { + ::glDeleteTextures( 1, &texture.id ); + } + } +} + +// debug performance string +std::string +texture_manager::Info() const { + + // TODO: cache this data and update only during resource sweep + std::size_t totaltexturecount{ m_textures.size() - 1 }; + std::size_t totaltexturesize{ 0 }; +#ifdef EU07_DEFERRED_TEXTURE_UPLOAD + std::size_t readytexturecount{ 0 }; + std::size_t readytexturesize{ 0 }; +#endif + + for( auto const& texture : m_textures ) { + + totaltexturesize += texture.size; +#ifdef EU07_DEFERRED_TEXTURE_UPLOAD + + if( texture.is_ready ) { + + ++readytexturecount; + readytexturesize += texture.size; + } +#endif + } + + return + "Textures: " +#ifdef EU07_DEFERRED_TEXTURE_UPLOAD + + std::to_string( readytexturecount ) + + " (" + + to_string( readytexturesize / 1024.0f, 2 ) + " mb)" + + " in vram, "; +#endif + + std::to_string( totaltexturecount ) + + " (" + + to_string( totaltexturesize / 1024.0f, 2 ) + " mb)" + + " total"; +} + // checks whether specified texture is in the texture bank. returns texture id, or npos. texture_manager::size_type texture_manager::find_in_databank( std::string const &Texturename ) { @@ -806,12 +926,3 @@ texture_manager::find_on_disk( std::string const &Texturename ) { // no results either way, report failure return ""; } - -void -texture_manager::Free() -{ - for( auto const &texture : m_textures ) { - // usunięcie wszyskich tekstur (bez usuwania struktury) - ::glDeleteTextures( 1, &texture.id ); - } -} diff --git a/Texture.h b/Texture.h index 4c122e05..bfdd73c5 100644 --- a/Texture.h +++ b/Texture.h @@ -29,13 +29,15 @@ struct opengl_texture { // methods void load(); - void create(); + resource_state bind(); + resource_state create(); // members GLuint id{ (GLuint)-1 }; // associated GL resource bool has_alpha{ false }; // indicates the texture has alpha channel bool is_ready{ false }; // indicates the texture was processed and is ready for use std::string traits; // requested texture attributes: wrapping modes etc std::string name; // name of the texture source file + std::size_t size{ 0 }; // size of the texture data, in kb private: // methods @@ -44,6 +46,7 @@ private: void load_TEX(); void load_TGA(); void set_filtering(); + void downsize( GLuint const Format ); // members std::vector data; // texture data @@ -71,11 +74,19 @@ public: texture_manager(); ~texture_manager() { Free(); } - size_type GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ); - void Bind( size_type const Id ); - opengl_texture &Texture( size_type const Id ) { return m_textures.at( Id ); } - void Init(); - void Free(); + size_type + GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ); + void + Bind( size_type const Id ); + opengl_texture & + Texture( size_type const Id ) { return m_textures[ Id ]; } + void + Init(); + void + Free(); + // debug performance string + std::string + Info() const; private: typedef std::unordered_map index_map; @@ -103,3 +114,60 @@ private: index_map m_texturemappings; size_type m_activetexture{ 0 }; // last i.e. currently bound texture }; + +// reduces provided data image to half of original size, using basic 2x2 average +template +void +downsample( std::size_t const Width, std::size_t const Height, char *Imagedata ) { + + _Colortype *destination = reinterpret_cast<_Colortype*>( Imagedata ); + _Colortype *sampler = reinterpret_cast<_Colortype*>( Imagedata ); + + _Colortype accumulator, color; +/* + _Colortype color; + float component; +*/ + for( size_t row = 0; row < Height; row += 2, sampler += Width ) { // column movement advances us down another row + for( size_t column = 0; column < Width; column += 2, sampler += 2 ) { +/* + // straightforward, but won't work with byte data + auto color = ( + *sampler + + *( sampler + 1 ) + + *( sampler + Width ) + + *( sampler + Width + 1 ) ); + color /= 4; +*/ + // manual version of the above, but drops colour resolution to 6 bits + accumulator = *sampler; + accumulator /= 4; + color = accumulator; + accumulator = *(sampler + 1); + accumulator /= 4; + color += accumulator; + accumulator = *(sampler + Width); + accumulator /= 4; + color += accumulator; + accumulator = *(sampler + Width + 1); + accumulator /= 4; + color += accumulator; + + *destination++ = color; +/* + // "full" 8bit resolution + color = _Colortype(); component = 0; + for( int idx = 0; idx < sizeof( _Colortype ); ++idx ) { + + component = ( + (*sampler)[idx] + + ( *( sampler + 1 ) )[idx] + + ( *( sampler + Width ) )[idx] + + (*( sampler + Width + 1 ))[idx] ); + color[ idx ] = component /= 4; + } + *destination++ = color; +*/ + } + } +} diff --git a/Track.cpp b/Track.cpp index 0c563e58..bcda0a10 100644 --- a/Track.cpp +++ b/Track.cpp @@ -2595,6 +2595,20 @@ void TTrack::EnvironmentSet() break; } } +#else + switch( eEnvironment ) { + case e_canyon: { + Global::daylight.intensity = 0.5f; + break; + } + case e_tunnel: { + Global::daylight.intensity = 0.2f; + break; + } + default: { + break; + } + } #endif }; @@ -2610,6 +2624,17 @@ void TTrack::EnvironmentReset() glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); } +#else + switch( eEnvironment ) { + case e_canyon: + case e_tunnel: { + Global::daylight.intensity = 1.0f; + break; + } + default: { + break; + } + } #endif }; @@ -2625,7 +2650,11 @@ void TTrack::RenderDyn() #else for( auto dynamic : Dynamics ) { // sam sprawdza, czy VBO; zmienia kontekst VBO! +#ifdef EU07_USE_OLD_RENDERCODE dynamic->Render(); +#else + GfxRenderer.Render( dynamic ); +#endif } #endif }; @@ -2642,7 +2671,11 @@ void TTrack::RenderDynAlpha() #else for( auto dynamic : Dynamics ) { // sam sprawdza, czy VBO; zmienia kontekst VBO! +#ifdef EU07_USE_OLD_RENDERCODE dynamic->RenderAlpha(); +#else + GfxRenderer.Render_Alpha( dynamic ); +#endif } #endif }; diff --git a/Train.cpp b/Train.cpp index 1efc968a..ff111fba 100644 --- a/Train.cpp +++ b/Train.cpp @@ -295,35 +295,58 @@ PyObject *TTrain::GetTrainState() { return NULL; } - PyDict_SetItemString( dict, "direction", PyGetInt( DynamicObject->MoverParameters->ActiveDir ) ); - PyDict_SetItemString( dict, "cab", PyGetInt( DynamicObject->MoverParameters->ActiveCab ) ); - PyDict_SetItemString( dict, "slipping_wheels", - PyGetBool( DynamicObject->MoverParameters->SlippingWheels ) ); - PyDict_SetItemString( dict, "converter", - PyGetBool( DynamicObject->MoverParameters->ConverterFlag ) ); - PyDict_SetItemString( dict, "main_ctrl_actual_pos", - PyGetInt( DynamicObject->MoverParameters->MainCtrlActualPos ) ); - PyDict_SetItemString( dict, "scnd_ctrl_actual_pos", - PyGetInt( DynamicObject->MoverParameters->ScndCtrlActualPos ) ); - PyDict_SetItemString( dict, "fuse", PyGetBool( DynamicObject->MoverParameters->FuseFlag ) ); - PyDict_SetItemString( dict, "converter_overload", - PyGetBool( DynamicObject->MoverParameters->ConvOvldFlag ) ); - PyDict_SetItemString( dict, "voltage", PyGetFloat( DynamicObject->MoverParameters->Voltage ) ); - PyDict_SetItemString( dict, "velocity", PyGetFloat( DynamicObject->MoverParameters->Vel ) ); - PyDict_SetItemString( dict, "im", PyGetFloat( DynamicObject->MoverParameters->Im ) ); - PyDict_SetItemString( dict, "compress", - PyGetBool( DynamicObject->MoverParameters->CompressorFlag ) ); - PyDict_SetItemString( dict, "hours", PyGetInt( GlobalTime->hh ) ); - PyDict_SetItemString( dict, "minutes", PyGetInt( GlobalTime->mm ) ); - PyDict_SetItemString( dict, "seconds", PyGetInt( GlobalTime->mr ) ); - PyDict_SetItemString( dict, "velocity_desired", PyGetFloat( DynamicObject->Mechanik->VelDesired ) ); + auto const &mover = DynamicObject->MoverParameters; + + PyDict_SetItemString( dict, "cab", PyGetInt( mover->ActiveCab ) ); + // basic systems state data + PyDict_SetItemString( dict, "battery", PyGetBool( mvControlled->Battery ) ); + PyDict_SetItemString( dict, "linebreaker", PyGetBool( mvControlled->Mains ) ); + PyDict_SetItemString( dict, "converter", PyGetBool( mover->ConverterFlag ) ); + PyDict_SetItemString( dict, "converter_overload", PyGetBool( mover->ConvOvldFlag ) ); + PyDict_SetItemString( dict, "compress", PyGetBool( mover->CompressorFlag ) ); + // reverser + PyDict_SetItemString( dict, "direction", PyGetInt( mover->ActiveDir ) ); + // throttle + PyDict_SetItemString( dict, "mainctrl_pos", PyGetInt( mover->MainCtrlPos ) ); + PyDict_SetItemString( dict, "main_ctrl_actual_pos", PyGetInt( mover->MainCtrlActualPos ) ); + PyDict_SetItemString( dict, "scndctrl_pos", PyGetInt( mover->ScndCtrlPos ) ); + PyDict_SetItemString( dict, "scnd_ctrl_actual_pos", PyGetInt( mover->ScndCtrlActualPos ) ); + // brakes + PyDict_SetItemString( dict, "manual_brake", PyGetBool( mvOccupied->ManualBrakePos > 0 ) ); + bool const bEP = ( mvControlled->LocHandle->GetCP()>0.2 ) || ( fEIMParams[ 0 ][ 2 ]>0.01 ); + PyDict_SetItemString( dict, "dir_brake", PyGetBool( bEP ) ); + bool bPN; + if( ( typeid( *mvControlled->Hamulec ) == typeid( TLSt ) ) + || ( typeid( *mvControlled->Hamulec ) == typeid( TEStED ) ) ) { + + TBrake* temp_ham = mvControlled->Hamulec.get(); + bPN = ( static_cast( temp_ham )->GetEDBCP()>0.2 ); + } + else + bPN = false; + PyDict_SetItemString( dict, "indir_brake", PyGetBool( bPN ) ); + // other controls + PyDict_SetItemString( dict, "ca", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) ); + PyDict_SetItemString( dict, "shp", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ) ); + PyDict_SetItemString( dict, "pantpress", PyGetFloat( mvControlled->PantPress ) ); + PyDict_SetItemString( dict, "universal3", PyGetBool( LampkaUniversal3_st ) ); + // movement data + PyDict_SetItemString( dict, "velocity", PyGetFloat( mover->Vel ) ); + PyDict_SetItemString( dict, "tractionforce", PyGetFloat( mover->Ft ) ); + PyDict_SetItemString( dict, "slipping_wheels", PyGetBool( mover->SlippingWheels ) ); + // electric current data + PyDict_SetItemString( dict, "traction_voltage", PyGetFloat( mover->RunningTraction.TractionVoltage ) ); + PyDict_SetItemString( dict, "voltage", PyGetFloat( mover->Voltage ) ); + PyDict_SetItemString( dict, "im", PyGetFloat( mover->Im ) ); + PyDict_SetItemString( dict, "fuse", PyGetBool( mover->FuseFlag ) ); + // induction motor state data char* TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" }; char* TXTC[ 10 ] = { "fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv" }; char* TXTP[ 3 ] = { "bc", "bp", "sp" }; - for( int j = 0; j<10; j++ ) + for( int j = 0; j < 10; ++j ) PyDict_SetItemString( dict, ( std::string( "eimp_t_" ) + std::string( TXTT[ j ] ) ).c_str(), PyGetFloatS( fEIMParams[ 0 ][ j ] ) ); - for( int i = 0; i<8; i++ ) { - for( int j = 0; j<10; j++ ) + for( int i = 0; i < 8; ++i ) { + for( int j = 0; j < 10; ++j ) PyDict_SetItemString( dict, ( std::string( "eimp_c" ) + std::to_string( i + 1 ) + std::string( "_" ) + std::string( TXTC[ j ] ) ).c_str(), PyGetFloatS( fEIMParams[ i + 1 ][ j ] ) ); PyDict_SetItemString( dict, ( std::string( "eimp_c" ) + std::to_string( i + 1 ) + std::string( "_ms" ) ).c_str(), PyGetBool( bMains[ i ] ) ); PyDict_SetItemString( dict, ( std::string( "eimp_c" ) + std::to_string( i + 1 ) + std::string( "_cv" ) ).c_str(), PyGetFloatS( fCntVol[ i ] ) ); @@ -337,25 +360,17 @@ PyObject *TTrain::GetTrainState() { PyDict_SetItemString( dict, ( std::string( "eimp_c" ) + std::to_string( i + 1 ) + std::string( "_heat" ) ).c_str(), PyGetBool( bHeat[ i ] ) ); } - for( int i = 0; i<20; i++ ) { - for( int j = 0; j<3; j++ ) + for( int i = 0; i < 20; ++i ) { + for( int j = 0; j < 3; ++j ) PyDict_SetItemString( dict, ( std::string( "eimp_pn" ) + std::to_string( i + 1 ) + std::string( "_" ) + std::string( TXTP[ j ] ) ).c_str(), PyGetFloatS( fPress[ i ][ j ] ) ); } - bool bEP, bPN; - bEP = ( mvControlled->LocHandle->GetCP()>0.2 ) || ( fEIMParams[ 0 ][ 2 ]>0.01 ); - PyDict_SetItemString( dict, "dir_brake", PyGetBool( bEP ) ); - if( ( typeid( *mvControlled->Hamulec ) == typeid( TLSt ) ) - || ( typeid( *mvControlled->Hamulec ) == typeid( TEStED ) ) ) { + // multi-unit state data + PyDict_SetItemString( dict, "car_no", PyGetInt( iCarNo ) ); + PyDict_SetItemString( dict, "power_no", PyGetInt( iPowerNo ) ); + PyDict_SetItemString( dict, "unit_no", PyGetInt( iUnitNo ) ); - TBrake* temp_ham = mvControlled->Hamulec.get(); - // TLSt* temp_ham2 = temp_ham; - bPN = ( static_cast( temp_ham )->GetEDBCP()>0.2 ); - } - else - bPN = false; - PyDict_SetItemString( dict, "indir_brake", PyGetBool( bPN ) ); - for( int i = 0; i<20; i++ ) { + for( int i = 0; i < 20; i++ ) { PyDict_SetItemString( dict, ( std::string( "doors_" ) + std::to_string( i + 1 ) ).c_str(), PyGetFloatS( bDoors[ i ][ 0 ] ) ); PyDict_SetItemString( dict, ( std::string( "doors_r_" ) + std::to_string( i + 1 ) ).c_str(), PyGetFloatS( bDoors[ i ][ 1 ] ) ); PyDict_SetItemString( dict, ( std::string( "doors_l_" ) + std::to_string( i + 1 ) ).c_str(), PyGetFloatS( bDoors[ i ][ 2 ] ) ); @@ -364,23 +379,21 @@ PyObject *TTrain::GetTrainState() { cCode[ i ] ).c_str() ) ); PyDict_SetItemString( dict, ( std::string( "car_name" ) + std::to_string( i + 1 ) ).c_str(), PyGetString( asCarName[ i ].c_str() ) ); } - PyDict_SetItemString( dict, "car_no", PyGetInt( iCarNo ) ); - PyDict_SetItemString( dict, "power_no", PyGetInt( iPowerNo ) ); - PyDict_SetItemString( dict, "unit_no", PyGetInt( iUnitNo ) ); - PyDict_SetItemString( dict, "universal3", PyGetBool( LampkaUniversal3_st ) ); - PyDict_SetItemString( dict, "ca", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) ); - PyDict_SetItemString( dict, "shp", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ) ); - PyDict_SetItemString( dict, "manual_brake", PyGetBool( mvOccupied->ManualBrakePos > 0 ) ); - PyDict_SetItemString( dict, "pantpress", PyGetFloat( mvControlled->PantPress ) ); - PyDict_SetItemString( dict, "trainnumber", PyGetString( DynamicObject->Mechanik->TrainName().c_str() ) ); - PyDict_SetItemString( dict, "velnext", PyGetFloat( DynamicObject->Mechanik->VelNext ) ); - PyDict_SetItemString( dict, "actualproximitydist", PyGetFloat( DynamicObject->Mechanik->ActualProximityDist ) ); - PyDict_SetItemString( dict, "velsignallast", PyGetFloat( DynamicObject->Mechanik->VelSignalLast ) ); - PyDict_SetItemString( dict, "vellimitlast", PyGetFloat( DynamicObject->Mechanik->VelLimitLast ) ); - PyDict_SetItemString( dict, "velroad", PyGetFloat( DynamicObject->Mechanik->VelRoad ) ); - PyDict_SetItemString( dict, "velsignalnext", PyGetFloat( DynamicObject->Mechanik->VelSignalNext ) ); - PyDict_SetItemString( dict, "battery", PyGetBool( mvControlled->Battery ) ); - PyDict_SetItemString( dict, "tractionforce", PyGetFloat( DynamicObject->MoverParameters->Ft ) ); + // ai state data + auto const &driver = DynamicObject->Mechanik; + + PyDict_SetItemString( dict, "velocity_desired", PyGetFloat( driver->VelDesired ) ); + PyDict_SetItemString( dict, "velroad", PyGetFloat( driver->VelRoad ) ); + PyDict_SetItemString( dict, "vellimitlast", PyGetFloat( driver->VelLimitLast ) ); + PyDict_SetItemString( dict, "velsignallast", PyGetFloat( driver->VelSignalLast ) ); + PyDict_SetItemString( dict, "velsignalnext", PyGetFloat( driver->VelSignalNext ) ); + PyDict_SetItemString( dict, "velnext", PyGetFloat( driver->VelNext ) ); + PyDict_SetItemString( dict, "actualproximitydist", PyGetFloat( driver->ActualProximityDist ) ); + PyDict_SetItemString( dict, "trainnumber", PyGetString( driver->TrainName().c_str() ) ); + // world state data + PyDict_SetItemString( dict, "hours", PyGetInt( GlobalTime->hh ) ); + PyDict_SetItemString( dict, "minutes", PyGetInt( GlobalTime->mm ) ); + PyDict_SetItemString( dict, "seconds", PyGetInt( GlobalTime->mr ) ); return dict; } @@ -508,7 +521,7 @@ void TTrain::OnKeyDown(int cKey) } } } - else if (cKey == Global::Keys[k_StLinOff]) + else if ((cKey == Global::Keys[k_StLinOff]) && (!Global::shiftState) && (!Global::ctrlState)) // shift&ctrl are used for light dimming { if (mvControlled->TrainType == dt_EZT) { @@ -1792,21 +1805,18 @@ if { // tryb freefly int CouplNr = -1; // normalnie żaden ze sprzęgów TDynamicObject *tmp; - tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, - CouplNr); - if (tmp == NULL) - tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, - 1500, CouplNr); - if (tmp && (CouplNr != -1)) + tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, CouplNr); + if (tmp == nullptr) + tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, 1500, CouplNr); + if( ( CouplNr != -1 ) + && ( tmp != nullptr ) + && ( tmp->MoverParameters->Couplers[ CouplNr ].Connected != nullptr ) ) { - if (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag == - 0) // najpierw hak + if (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag == 0) // najpierw hak { - if ((tmp->MoverParameters->Couplers[CouplNr] - .Connected->Couplers[CouplNr] - .AllowedFlag & - tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & - ctrain_coupler) == ctrain_coupler) + if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag + & tmp->MoverParameters->Couplers[CouplNr].AllowedFlag + & ctrain_coupler) == ctrain_coupler) if (tmp->MoverParameters->Attach( CouplNr, 2, tmp->MoverParameters->Couplers[CouplNr].Connected, @@ -1815,46 +1825,37 @@ if // tmp->MoverParameters->Couplers[CouplNr].Render=true; // //podłączony sprzęg będzie widoczny if (DynamicObject->Mechanik) // na wszelki wypadek - DynamicObject->Mechanik->CheckVehicles( - Connect); // aktualizacja flag kierunku w składzie + DynamicObject->Mechanik->CheckVehicles(Connect); // aktualizacja flag kierunku w składzie dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); dsbCouplerAttach->Play(0, 0, 0); } else WriteLog("Mechanical coupling failed."); } - else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, - ctrain_pneumatic)) // pneumatyka + else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_pneumatic)) // pneumatyka { - if ((tmp->MoverParameters->Couplers[CouplNr] - .Connected->Couplers[CouplNr] - .AllowedFlag & - tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & - ctrain_pneumatic) == ctrain_pneumatic) + if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag + & tmp->MoverParameters->Couplers[CouplNr].AllowedFlag + & ctrain_pneumatic) == ctrain_pneumatic) if (tmp->MoverParameters->Attach( CouplNr, 2, tmp->MoverParameters->Couplers[CouplNr].Connected, - tmp->MoverParameters->Couplers[CouplNr].CouplingFlag + - ctrain_pneumatic)) + (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_pneumatic))) { rsHiss.Play(1, DSBPLAY_LOOPING, true, tmp->GetPosition()); DynamicObject->SetPneumatic(CouplNr != 0, true); // Ra: to mi się nie podoba !!!! tmp->SetPneumatic(CouplNr != 0, true); } } - else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, - ctrain_scndpneumatic)) // zasilajacy + else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_scndpneumatic)) // zasilajacy { - if ((tmp->MoverParameters->Couplers[CouplNr] - .Connected->Couplers[CouplNr] - .AllowedFlag & - tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & - ctrain_scndpneumatic) == ctrain_scndpneumatic) + if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag + & tmp->MoverParameters->Couplers[CouplNr].AllowedFlag + & ctrain_scndpneumatic) == ctrain_scndpneumatic) if (tmp->MoverParameters->Attach( CouplNr, 2, tmp->MoverParameters->Couplers[CouplNr].Connected, - tmp->MoverParameters->Couplers[CouplNr].CouplingFlag + - ctrain_scndpneumatic)) + (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_scndpneumatic))) { // rsHiss.Play(1,DSBPLAY_LOOPING,true,tmp->GetPosition()); dsbCouplerDetach->SetVolume(DSBVOLUME_MAX); @@ -1863,8 +1864,7 @@ if tmp->SetPneumatic(CouplNr != 0, false); } } - else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, - ctrain_controll)) // ukrotnionko + else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_controll)) // ukrotnionko { if ((tmp->MoverParameters->Couplers[CouplNr] .Connected->Couplers[CouplNr] @@ -1874,15 +1874,13 @@ if if (tmp->MoverParameters->Attach( CouplNr, 2, tmp->MoverParameters->Couplers[CouplNr].Connected, - tmp->MoverParameters->Couplers[CouplNr].CouplingFlag + - ctrain_controll)) + (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_controll))) { dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); dsbCouplerAttach->Play(0, 0, 0); } } - else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, - ctrain_passenger)) // mostek + else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_passenger)) // mostek { if ((tmp->MoverParameters->Couplers[CouplNr] .Connected->Couplers[CouplNr] @@ -1892,8 +1890,7 @@ if if (tmp->MoverParameters->Attach( CouplNr, 2, tmp->MoverParameters->Couplers[CouplNr].Connected, - tmp->MoverParameters->Couplers[CouplNr].CouplingFlag + - ctrain_passenger)) + (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_passenger))) { // rsHiss.Play(1,DSBPLAY_LOOPING,true,tmp->GetPosition()); dsbCouplerDetach->SetVolume(DSBVOLUME_MAX); @@ -1912,8 +1909,7 @@ if // odlegle wagony if (iCabn > 0) { - if (!FreeFlyModeFlag) // tryb 'kabinowy' (pozwala również rozłączyć - // sprzęgi zablokowane) + if (!FreeFlyModeFlag) // tryb 'kabinowy' (pozwala również rozłączyć sprzęgi zablokowane) { if (DynamicObject->DettachStatus(iCabn - 1) < 0) // jeśli jest co odczepić if (DynamicObject->Dettach(iCabn - 1)) // iCab==1:przód,iCab==2:tył @@ -1926,15 +1922,12 @@ if { // tryb freefly int CouplNr = -1; TDynamicObject *tmp; - tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, - CouplNr); + tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, CouplNr); if (tmp == NULL) - tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, - 1500, CouplNr); + tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, 1500, CouplNr); if (tmp && (CouplNr != -1)) { - if ((tmp->MoverParameters->Couplers[CouplNr].CouplingFlag & ctrain_depot) == - 0) // jeżeli sprzęg niezablokowany + if ((tmp->MoverParameters->Couplers[CouplNr].CouplingFlag & ctrain_depot) == 0) // jeżeli sprzęg niezablokowany if (tmp->DettachStatus(CouplNr) < 0) // jeśli jest co odczepić i się da if (!tmp->Dettach(CouplNr)) { // dźwięk odczepiania @@ -2352,7 +2345,7 @@ if } } } - else if (cKey == Global::Keys[k_StLinOff]) // Winger 110904: wylacznik st. + else if ((cKey == Global::Keys[k_StLinOff]) && (!Global::shiftState) && (!Global::ctrlState)) // Winger 110904: wylacznik st. // liniowych { if ((mvControlled->TrainType != dt_EZT) && (mvControlled->TrainType != dt_EP05) && @@ -2481,6 +2474,29 @@ if ++iRadioChannel; // 0=wyłączony } } + + // TODO: break the mess above into individual command-based routines. + // TODO: test for modifiers inside the routines, instead of grouping by the modifier + // TODO: do away with the modifier tests, each command should be separate and issued by input processor(s) up the chain + if( cKey == Global::Keys[ k_DimHeadlights ] ) { + // headlight strength toggle + if( !Global::ctrlState ) { + // switch uses either ctrl, or ctrl+shift, so we can bail early here + return; + } + if( DynamicObject->DimHeadlights && (!Global::shiftState)) { + DynamicObject->DimHeadlights = false; + // switch sound + dsbSwitch->SetVolume( DSBVOLUME_MAX ); + dsbSwitch->Play( 0, 0, 0 ); + } + else if( (!DynamicObject->DimHeadlights) && (Global::shiftState)) { + DynamicObject->DimHeadlights = true; + // switch sound + dsbSwitch->SetVolume( DSBVOLUME_MAX ); + dsbSwitch->Play( 0, 0, 0 ); + } + } } void TTrain::OnKeyUp(int cKey) @@ -2490,7 +2506,7 @@ void TTrain::OnKeyUp(int cKey) } else { - if (cKey == Global::Keys[k_StLinOff]) // Winger 110904: wylacznik st. liniowych + if ((cKey == Global::Keys[k_StLinOff]) && (!Global::shiftState) && (!Global::ctrlState)) // Winger 110904: wylacznik st. liniowych { // zwolnienie klawisza daje powrót przycisku do zwykłego stanu if ((mvControlled->TrainType != dt_EZT) && (mvControlled->TrainType != dt_EP05) && (mvControlled->TrainType != dt_ET40)) @@ -2686,10 +2702,9 @@ bool TTrain::Update( double const Deltatime ) iSekunda=floor(GlobalTime->mr); } */ - // Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są - // ewentualnie na - // PoKeys - if ((mvControlled->EngineType != DieselElectric) && (mvControlled->EngineType != ElectricInductionMotor)) // Ra 2014-09: czy taki rozdzia? ma sens? + // Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są ewentualnie na PoKeys + if ((mvControlled->EngineType != DieselElectric) + && (mvControlled->EngineType != ElectricInductionMotor)) // Ra 2014-09: czy taki rozdzia? ma sens? fHVoltage = mvControlled->RunningTraction.TractionVoltage; // Winger czy to nie jest zle? // *mvControlled->Mains); else @@ -3901,41 +3916,6 @@ bool TTrain::Update( double const Deltatime ) ggLeftEndLightButton.PutValue(0); } - //--------- - // hunter-101211: poprawka na zle obracajace sie przelaczniki - /* - if (((DynamicObject->iLights[0]&1)==1) - ||((DynamicObject->iLights[1]&1)==1)) - ggLeftLightButton.PutValue(1); - if (((DynamicObject->iLights[0]&16)==16) - ||((DynamicObject->iLights[1]&16)==16)) - ggRightLightButton.PutValue(1); - if (((DynamicObject->iLights[0]&4)==4) - ||((DynamicObject->iLights[1]&4)==4)) - ggUpperLightButton.PutValue(1); - - if (((DynamicObject->iLights[0]&2)==2) - ||((DynamicObject->iLights[1]&2)==2)) - if (ggLeftEndLightButton.SubModel) - { - ggLeftEndLightButton.PutValue(1); - ggLeftLightButton.PutValue(0); - } - else - ggLeftLightButton.PutValue(-1); - - if (((DynamicObject->iLights[0]&32)==32) - ||((DynamicObject->iLights[1]&32)==32)) - if (ggRightEndLightButton.SubModel) - { - ggRightEndLightButton.PutValue(1); - ggRightLightButton.PutValue(0); - } - else - ggRightLightButton.PutValue(-1); - */ - - //-------------- // hunter-230112 // REFLEKTOR LEWY @@ -4073,6 +4053,11 @@ bool TTrain::Update( double const Deltatime ) ggLightsButton.PutValue(mvOccupied->LightsPos - 1); ggLightsButton.Update(); } + if( ggDimHeadlightsButton.SubModel ) { + + ggDimHeadlightsButton.PutValue( DynamicObject->DimHeadlights ? 1.0 : 0.0 ); + ggDimHeadlightsButton.Update(); + } //--------- // Winger 010304 - pantografy @@ -5879,6 +5864,7 @@ void TTrain::clear_cab_controls() ggLeftLightButton.Clear(); ggRightLightButton.Clear(); ggUpperLightButton.Clear(); + ggDimHeadlightsButton.Clear(); ggLeftEndLightButton.Clear(); ggRightEndLightButton.Clear(); ggLightsButton.Clear(); @@ -6283,7 +6269,11 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con // swiatlo ggRightLightButton.Load(Parser, DynamicObject->mdKabina); } - else if (Label == "leftend_sw:") + else if( Label == "dimheadlights_sw:" ) { + // swiatlo + ggDimHeadlightsButton.Load( Parser, DynamicObject->mdKabina ); + } + else if( Label == "leftend_sw:" ) { // swiatlo ggLeftEndLightButton.Load(Parser, DynamicObject->mdKabina); diff --git a/Train.h b/Train.h index 560a75e9..173d1489 100644 --- a/Train.h +++ b/Train.h @@ -177,6 +177,7 @@ class TTrain TGauge ggLeftEndLightButton; TGauge ggRightEndLightButton; TGauge ggLightsButton; // przelacznik reflektorow (wszystkich) + TGauge ggDimHeadlightsButton; // headlights dimming switch // hunter-230112: przelacznik swiatel tylnich TGauge ggRearUpperLightButton; @@ -251,8 +252,7 @@ class TTrain TButton btLampkaOpory; TButton btLampkaWysRozr; TButton btLampkaUniversal3; - int LampkaUniversal3_typ; // ABu 030405 - swiecenie uzaleznione od: 0-nic, - // 1-obw.gl, 2-przetw. + int LampkaUniversal3_typ; // ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw. bool LampkaUniversal3_st; TButton btLampkaWentZaluzje; // ET22 TButton btLampkaOgrzewanieSkladu; diff --git a/World.cpp b/World.cpp index 32ad1d17..8880ff94 100644 --- a/World.cpp +++ b/World.cpp @@ -33,12 +33,15 @@ http://mozilla.org/MPL/2.0/. #include "Driver.h" #include "Console.h" #include "color.h" +#include "uilayer.h" //--------------------------------------------------------------------------- TDynamicObject *Controlled = NULL; // pojazd, który prowadzimy -const double fTimeMax = 1.00; //[s] maksymalny czas aktualizacji w jednek klatce +std::shared_ptr UIHeader = std::make_shared( 20, 20 ); // header ui panel +std::shared_ptr UITable = std::make_shared( 20, 100 ); // schedule or scan table +std::shared_ptr UITranscripts = std::make_shared( 85, 600 ); // voice transcripts extern "C" { @@ -58,7 +61,6 @@ TWorld::TWorld() OutText1 = ""; // teksty wyświetlane na ekranie OutText2 = ""; OutText3 = ""; - iCheckFPS = 0; // kiedy znów sprawdzić FPS, żeby wyłączać optymalizacji od razu do zera pDynamicNearest = NULL; fTimeBuffer = 0.0; // bufor czasu aktualizacji dla stałego kroku fizyki fMaxDt = 0.01; //[s] początkowy krok czasowy fizyki @@ -72,7 +74,6 @@ TWorld::~TWorld() // Ground.Free(); //Ra: usunięcie obiektów przed usunięciem dźwięków - sypie się TSoundsManager::Free(); TModelsManager::Free(); - glDeleteLists(base, 96); } void TWorld::TrainDelete(TDynamicObject *d) @@ -88,26 +89,6 @@ void TWorld::TrainDelete(TDynamicObject *d) Global::pUserDynamic = NULL; // tego też nie ma }; -GLvoid TWorld::glPrint( std::string const &Text ) // custom GL "Print" routine -{ // wypisywanie tekstu 2D na ekranie - if (Text.empty()) - return; - - if (Global::bGlutFont) - { // tekst generowany przez GLUT - for (size_t i = 0; i < Text.size(); i++) - glutBitmapCharacter(GLUT_BITMAP_8_BY_13, Text[i]); - } - else - - { // generowanie przez Display Lists - glPushAttrib(GL_LIST_BIT); // pushes the display list bits - glListBase(base - 32); // sets the base character to 32 - glCallLists((GLsizei)Text.size(), GL_UNSIGNED_BYTE, Text.c_str()); // draws the display list text - glPopAttrib(); // pops the display list bits - } -} - /* Ra: do opracowania: wybor karty graficznej ~Intel gdy są dwie... BOOL GetDisplayMonitorInfo(int nDeviceIndex, LPSTR lpszMonitorInfo) { @@ -163,334 +144,51 @@ BOOL GetDisplayMonitorInfo(int nDeviceIndex, LPSTR lpszMonitorInfo) } */ -bool TWorld::Init(GLFWwindow *w) -{ - auto timestart = std::chrono::system_clock::now(); - - window = w; - Global::window = w; // do WM_COPYDATA +bool TWorld::Init( GLFWwindow *Window ) { + + auto timestart = std::chrono::system_clock::now(); + + window = Window; + Global::window = Window; // do WM_COPYDATA Global::pCamera = &Camera; // Ra: wskaźnik potrzebny do likwidacji drgań - Global::detonatoryOK = true; - WriteLog("Starting MaSzyna rail vehicle simulator."); + + WriteLog("\nStarting MaSzyna rail vehicle simulator."); WriteLog(Global::asVersion); WriteLog("Online documentation and additional files on http://eu07.pl"); WriteLog("Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, " - "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others"); - WriteLog("Renderer:"); - WriteLog((char *)glGetString(GL_RENDERER)); - WriteLog("Vendor:"); - // Winger030405: sprawdzanie sterownikow - WriteLog((char *)glGetString(GL_VENDOR)); - std::string glver = ((char *)glGetString(GL_VERSION)); - WriteLog("OpenGL Version:"); - WriteLog(glver); - if (!GLEW_VERSION_1_4) - { - std::cout << "required opengl >=3.2" << std::endl; - return false; - } - - // Ra: umieszczone w EU07.cpp jakoś nie chce działać - while( glver.rfind( '.' ) > glver.find( '.' ) ) { - glver = glver.substr( 0, glver.rfind( '.' ) - 1 ); // obcięcie od drugiej kropki - } - double ogl; - try - { - ogl = std::stod( glver ); - } - catch (...) - { - ogl = 0.0; - } - if (Global::fOpenGL > 0.0) // jeśli była wpisane maksymalna wersja w EU07.INI - { - if (ogl > 0.0) // zakładając, że się odczytało dobrze - if (ogl < Global::fOpenGL) // a karta oferuje niższą wersję niż wpisana - Global::fOpenGL = ogl; // to przyjąc to z karty - } - else if (false == GLEW_VERSION_1_3) // sprzętowa deompresja DDS zwykle wymaga 1.3 - Error("Missed OpenGL 1.3+ drivers!"); // błąd np. gdy wersja 1.1, a nie ma wpisu w EU07.INI -/* - Global::bOpenGL_1_5 = (Global::fOpenGL >= 1.5); // są fragmentaryczne animacje VBO -*/ - WriteLog("Supported extensions:"); - WriteLog((char *)glGetString(GL_EXTENSIONS)); - if (GLEW_ARB_vertex_buffer_object) // czy jest VBO w karcie graficznej - { - if (Global::bUseVBO) - WriteLog("Ra: The VBO is found and will be used."); - else - WriteLog("Ra: The VBO is found, but Display Lists are selected."); - } - else - { - WriteLog("Ra: No VBO found - Display Lists used. Graphics card too old?"); - Global::bUseVBO = false; // może być włączone parametrem w INI - } - if (Global::bDecompressDDS) // jeśli sprzętowa (domyślnie jest false) - WriteLog("DDS textures support at OpenGL level is disabled in INI file."); - else - { - Global::bDecompressDDS = - !(GLEW_EXT_texture_compression_s3tc); // czy obsługiwane? - if (Global::bDecompressDDS) // czy jest obsługa DDS w karcie graficznej - WriteLog("DDS textures are not supported."); - else // brak obsługi DDS - trzeba włączyć programową dekompresję - WriteLog("DDS textures are supported."); - } - if (Global::iMultisampling) - WriteLog("Used multisampling of " + std::to_string(Global::iMultisampling) + " samples."); - { // ograniczenie maksymalnego rozmiaru tekstur - parametr dla skalowania tekstur - GLint i; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &i); - if (i < Global::iMaxTextureSize) - Global::iMaxTextureSize = i; - WriteLog("Max texture size: " + std::to_string(Global::iMaxTextureSize)); - } - /*-----------------------Render Initialization----------------------*/ + "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n"); - shader = gl_program_light({gl_shader("lighting.vert"), gl_shader("blinnphong.frag")}); + UILayer.set_background( "logo" ); - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - glClearDepth( 1.0f ); // ZBuffer Value - glClearColor( 51.0f / 255.0f, 102.0f / 255.0f, 85.0f / 255.0f, 1.0f ); // Background Color - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Clear screen and depth buffer - - glEnable(GL_TEXTURE_2D); // Enable Texture Mapping - glShadeModel(GL_SMOOTH); // Enable Smooth Shading - glEnable(GL_DEPTH_TEST); - - // McZapkie:261102-uruchomienie polprzezroczystosci (na razie linie) pod kierunkiem Marcina - // if (Global::bRenderAlpha) //Ra: wywalam tę flagę - { - glEnable(GL_BLEND); - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.04f); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthFunc(GL_LEQUAL); - } - - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations - glPolygonMode(GL_FRONT, GL_FILL); - glFrontFace(GL_CCW); // Counter clock-wise polygons face out - glEnable(GL_CULL_FACE); // Cull back-facing triangles - glLineWidth(1.0f); - glPointSize(3.0f); - glEnable( GL_POINT_SMOOTH ); -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // ----------- LIGHTING SETUP ----------- - // Light values and coordinates - - vector3 lp = Normalize(vector3(-500, 500, 200)); - - Global::lightPos[0] = lp.x; - Global::lightPos[1] = lp.y; - Global::lightPos[2] = lp.z; - Global::lightPos[3] = 0.0f; - - // Ra: światła by sensowniej było ustawiać po wczytaniu scenerii - // TODO: re-implement this - // Ra: szczątkowe światło rozproszone - żeby było cokolwiek widać w ciemności - WriteLog("glLightModelfv(GL_LIGHT_MODEL_AMBIENT,darkLight);"); - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Global::darkLight); - - // Ra: światło 0 - główne światło zewnętrzne (Słońce, Księżyc) - WriteLog("glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);"); - glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); - WriteLog("glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);"); - glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); - WriteLog("glLightfv(GL_LIGHT0,GL_SPECULAR,specularLight);"); - glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); - WriteLog("glLightfv(GL_LIGHT0,GL_POSITION,lightPos);"); - glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos); - WriteLog("glEnable(GL_LIGHT0);"); - glEnable(GL_LIGHT0); -#endif - // glColor() ma zmieniać kolor wybrany w glColorMaterial() - glEnable(GL_COLOR_MATERIAL); - - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); - glColor4fv(Global::whiteLight); - - glEnable(GL_LIGHTING); - - glFogi(GL_FOG_MODE, GL_LINEAR); // Fog Mode - GLfloat FogColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - glFogfv(GL_FOG_COLOR, FogColor); // Set Fog Color - glFogf(GL_FOG_START, 10.0f); // Fog Start Depth - glFogf(GL_FOG_END, 200.0f); // Fog End Depth - glEnable(GL_FOG); // Enables GL_FOG - - // Ra: ustawienia testowe - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); - - /*--------------------Render Initialization End---------------------*/ - - //m7todo - - WriteLog("Font init"); // początek inicjacji fontów 2D - if (Global::bGlutFont) - { - int zi = 0; - char zc = 0; - char *zcp = &zc; - glutInit(&zi, &zcp); - WriteLog("Used font from GLUT."); - } - if (!Global::bGlutFont) - { // jeśli bezGLUTowy font - HFONT font; // Windows Font ID - base = glGenLists(96); // storage for 96 characters - font = CreateFont(-15, // height of font - 0, // width of font - 0, // angle of escapement - 0, // orientation angle - FW_BOLD, // font weight - FALSE, // italic - FALSE, // underline - FALSE, // strikeout - ANSI_CHARSET, // character set identifier - OUT_TT_PRECIS, // output precision - CLIP_DEFAULT_PRECIS, // clipping precision - ANTIALIASED_QUALITY, // output quality - FF_DONTCARE | DEFAULT_PITCH, // family and pitch - "Courier New"); // font name - HDC hDC = GetDC(glfwGetWin32Window(window)); - SelectObject(hDC, font); // selects the font we want - wglUseFontBitmapsA(hDC, 32, 96, base); // builds 96 characters starting at character 32 - WriteLog("Display Lists font used."); //+AnsiString(glGetError()) - } - WriteLog("Font init OK"); //+AnsiString(glGetError()) - - Timer::ResetTimers(); - - glColor4f(1.0f, 3.0f, 3.0f, 0.0f); - // SwapBuffers(hDC); // Swap Buffers (Double Buffering) - // glClear(GL_COLOR_BUFFER_BIT); - // glFlush(); - - WriteLog("Sound Init"); - - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - glDisable( GL_DEPTH_TEST ); // Disables depth testing -#ifndef EU07_USE_OLD_LIGHTING_MODEL - glEnable( GL_LIGHTING ); - glEnable( GL_LIGHT0 ); -#endif - - glLoadIdentity(); - // glColor4f(0.3f,0.0f,0.0f,0.0f); -// glTranslatef(0.0f, 0.0f, -0.50f); - // glRasterPos2f(-0.25f, -0.10f); -#ifdef EU07_USE_OLD_LIGHTING_MODEL - glColor3f( 3.0f, 3.0f, 3.0f ); -#else - glColor3f( 1.0f, 1.0f, 1.0f ); -#endif - - auto logo = GfxRenderer.GetTextureId( "logo", szTexturePath, 6 ); - GfxRenderer.Bind(logo); // Select our texture - - float const widthratio = ( 4.0f / 3.0f ) / ( (float)Global::iWindowWidth / Global::iWindowHeight ); - - glBegin(GL_QUADS); // Drawing using triangles - glTexCoord2f(0.0f, 0.0f); - glVertex2f( -widthratio, -1.0f ); // bottom left of the texture and quad - glTexCoord2f(1.0f, 0.0f); - glVertex2f(widthratio, -1.0f); // bottom right of the texture and quad - glTexCoord2f(1.0f, 1.0f); - glVertex2f(widthratio, 1.0f); // top right of the texture and quad - glTexCoord2f(0.0f, 1.0f); - glVertex2f( -widthratio, 1.0f ); // top left of the texture and quad - glEnd(); - - glColor3f(0.0f, 0.0f, 0.0f); - glRasterPos2f(-0.85f * widthratio, -0.25f); - glPrint("Uruchamianie / Initializing..."); - glfwSwapBuffers( window ); - - /*-----------------------Sound Initialization-----------------------*/ - glRasterPos2f( -0.85f * widthratio, -0.30f ); - glPrint( "Dzwiek / Sound..." ); + std::shared_ptr initpanel = std::make_shared(85, 600); TSoundsManager::Init( glfwGetWin32Window( window ) ); WriteLog("Sound Init OK"); - glRasterPos2f(-0.25f * widthratio, -0.30f); - glPrint("OK."); - glfwSwapBuffers( window ); - /*---------------------Sound Initialization End---------------------*/ - - WriteLog("Textures init"); - glRasterPos2f(-0.85f * widthratio, -0.35f); - glPrint("Tekstury / Textures..."); - glfwSwapBuffers( window ); - WriteLog("Textures init OK"); - glRasterPos2f( -0.25f * widthratio, -0.35f ); - glPrint("OK."); - glfwSwapBuffers( window ); - - WriteLog("Models init"); - glRasterPos2f( -0.85f * widthratio, -0.40f ); - glPrint("Modele / Models..."); - glfwSwapBuffers( window ); TModelsManager::Init(); WriteLog("Models init OK"); - glRasterPos2f( -0.25f * widthratio, -0.40f ); - glPrint("OK."); - glfwSwapBuffers( window ); - WriteLog("Ground init"); - glRasterPos2f( -0.85f * widthratio, -0.45f ); - glPrint("Sceneria / Scenery (please wait)..."); - glfwSwapBuffers( window ); + initpanel->text_lines.emplace_back( "Loading scenery / Wczytywanie scenerii:", float4( 0.0f, 0.0f, 0.0f, 1.0f ) ); + initpanel->text_lines.emplace_back( Global::SceneryFile.substr(0, 40), float4( 0.0f, 0.0f, 0.0f, 1.0f ) ); + UILayer.push_back( initpanel ); + UILayer.set_progress(0.01f); -#ifndef EU07_USE_OLD_LIGHTING_MODEL - // setup lighting -// GLfloat ambient[] = { 0.65f, 0.65f, 0.65f, 0.5f }; - GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); - - // directional light - // TODO, TBD: test omni-directional variant - - // rgb value for 5780 kelvin - Global::daylight.color.x = 255.0f / 255.0f; - Global::daylight.color.y = 242.0f / 255.0f; - Global::daylight.color.z = 231.0f / 255.0f; -#endif + GfxRenderer.Render(); + WriteLog( "Ground init" ); Ground.Init(Global::SceneryFile); - // Global::tSinceStart= 0; + WriteLog( "Ground init OK" ); + + glfwSetWindowTitle( window, ( Global::AppName + " (" + Global::SceneryFile + ")" ).c_str() ); // nazwa scenerii + Environment.init(); - WriteLog("Ground init OK"); - glRasterPos2f( -0.25f * widthratio, -0.45f ); - glColor3f( 0.0f, 0.0f, 0.0f ); - glPrint( "OK." ); - glfwSwapBuffers( window ); - - // TTrack *Track=Ground.FindGroundNode("train_start",TP_TRACK)->pTrack; - - // Camera.Init(vector3(2700,10,6500),0,M_PI,0); - // Camera.Init(vector3(00,40,000),0,M_PI,0); - // Camera.Init(vector3(1500,5,-4000),0,M_PI,0); - // McZapkie-130302 - coby nie przekompilowywac: - // Camera.Init(Global::pFreeCameraInit,0,M_PI,0); Camera.Init(Global::FreeCameraInit[0], Global::FreeCameraInitAngle[0]); - char buff[255] = "Player train init: "; - glRasterPos2f( -0.85f * widthratio, -0.50f ); - glColor3f( 0.0f, 0.0f, 0.0f ); - glPrint( "Przygotowanie kabiny do sterowania..." ); - glfwSwapBuffers( window ); + initpanel->text_lines.clear(); + initpanel->text_lines.emplace_back( "Preparing train / Przygotowanie kabiny:", float4( 0.0f, 0.0f, 0.0f, 1.0f ) ); + GfxRenderer.Render(); + + WriteLog( "Player train init: " + Global::asHumanCtrlVehicle ); - strcat(buff, Global::asHumanCtrlVehicle.c_str()); - WriteLog(buff); TGroundNode *nPlayerTrain = NULL; if (Global::asHumanCtrlVehicle != "ghostview") nPlayerTrain = Ground.DynamicFind(Global::asHumanCtrlVehicle); // szukanie w tych z obsadą @@ -503,20 +201,15 @@ bool TWorld::Init(GLFWwindow *w) mvControlled = Controlled->ControlledFind()->MoverParameters; Global::pUserDynamic = Controlled; // renerowanie pojazdu względem kabiny WriteLog("Player train init OK"); - glRasterPos2f( -0.25f * widthratio, -0.50f ); - glColor3f( 0.0f, 0.0f, 0.0f ); - glPrint( "OK." ); + + glfwSetWindowTitle( window, ( Global::AppName + " (" + Controlled->MoverParameters->Name + " @ " + Global::SceneryFile + ")" ).c_str() ); + FollowView(); - glfwSwapBuffers(window); } else { Error("Player train init failed!"); FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie - glRasterPos2f( -0.85f * widthratio, -0.50f ); - glColor3f( 0.0f, 0.0f, 0.0f ); - glPrint( "Blad inicjalizacji sterowanego pojazdu!" ); - glfwSwapBuffers( window ); Controlled = NULL; mvControlled = NULL; Camera.Type = tp_Free; @@ -526,10 +219,7 @@ bool TWorld::Init(GLFWwindow *w) { if (Global::asHumanCtrlVehicle != "ghostview") { - Error("Player train not exist!"); - glRasterPos2f( -0.85f * widthratio, -0.55f ); - glColor3f( 0.0f, 0.0f, 0.0f ); - glPrint( "Wybrany pojazd nie istnieje w scenerii!" ); + Error("Player train doesn't exist!"); } FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie glfwSwapBuffers(window); @@ -537,8 +227,7 @@ bool TWorld::Init(GLFWwindow *w) mvControlled = NULL; Camera.Type = tp_Free; } - glEnable(GL_DEPTH_TEST); - // Ground.pTrain=Train; + // if (!Global::bMultiplayer) //na razie włączone { // eventy aktywowane z klawiatury tylko dla jednego użytkownika KeyEvents[0] = Ground.FindEvent("keyctrl00"); @@ -552,21 +241,31 @@ bool TWorld::Init(GLFWwindow *w) KeyEvents[8] = Ground.FindEvent("keyctrl08"); KeyEvents[9] = Ground.FindEvent("keyctrl09"); } - // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //{Texture blends with object - // background} - if (Global::bOldSmudge == true) - light = GfxRenderer.GetTextureId( "smuga.tga", szTexturePath ); - else - light = GfxRenderer.GetTextureId( "smuga2.tga", szTexturePath ); - // Camera.Reset(); - Timer::ResetTimers(); - WriteLog( "Load time: " + + + 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(); + + Timer::ResetTimers(); + + // make 4 empty lines for the ui header, to cut down on work down the road + UIHeader->text_lines.emplace_back( "", Global::UITextColor ); + UIHeader->text_lines.emplace_back( "", Global::UITextColor ); + UIHeader->text_lines.emplace_back( "", Global::UITextColor ); + UIHeader->text_lines.emplace_back( "", Global::UITextColor ); + // bind the panels with ui object. maybe not the best place for this but, eh + UILayer.push_back( UIHeader ); + UILayer.push_back( UITable ); + UILayer.push_back( UITranscripts ); + return true; }; @@ -641,33 +340,42 @@ void TWorld::OnKeyDown(int cKey) if( (!Global::ctrlState) && (!Global::shiftState) ) { // czas i relacja - if( Global::iTextMode == cKey ) { - // wyłączenie napisów, chyba że pauza - Global::iTextMode = - ( Global::iPause && ( cKey != GLFW_KEY_F1 ) ? - GLFW_KEY_F1 : - 0 ); + if( Global::iTextMode == cKey ) { ++Global::iScreenMode[ cKey - GLFW_KEY_F1 ]; } + if( Global::iScreenMode[ cKey - GLFW_KEY_F1 ] > 1 ) { + // wyłączenie napisów + Global::iTextMode = 0; + Global::iScreenMode[ cKey - GLFW_KEY_F1 ] = 0; } - else + else { Global::iTextMode = cKey; + } } break; } case GLFW_KEY_F2: { // parametry pojazdu - if( Global::iTextMode == cKey ) { - // jeśli kolejne naciśnięcie - ++Global::iScreenMode[ cKey - GLFW_KEY_F1 ]; // kolejny ekran + if( Global::iTextMode == cKey ) { ++Global::iScreenMode[ cKey - GLFW_KEY_F1 ]; } + if( Global::iScreenMode[ cKey - GLFW_KEY_F1 ] > 1 ) { + // wyłączenie napisów + Global::iTextMode = 0; + Global::iScreenMode[ cKey - GLFW_KEY_F1 ] = 0; } else { - // pierwsze naciśnięcie daje pierwszy (tzn. zerowy) ekran Global::iTextMode = cKey; - Global::iScreenMode[ cKey - GLFW_KEY_F1 ] = 0; } break; } case GLFW_KEY_F3: { - Global::iTextMode = cKey; + // timetable + if( Global::iTextMode == cKey ) { ++Global::iScreenMode[ cKey - GLFW_KEY_F1 ]; } + if( Global::iScreenMode[ cKey - GLFW_KEY_F1 ] > 1 ) { + // wyłączenie napisów + Global::iTextMode = 0; + Global::iScreenMode[ cKey - GLFW_KEY_F1 ] = 0; + } + else { + Global::iTextMode = cKey; + } break; } case GLFW_KEY_F4: { @@ -677,16 +385,50 @@ void TWorld::OnKeyDown(int cKey) } case GLFW_KEY_F5: { // przesiadka do innego pojazdu - Global::iTextMode = cKey; + if( false == FreeFlyModeFlag ) { + // only available in free fly mode + break; + } + + TDynamicObject *tmp = Ground.DynamicNearest( Camera.Pos, 50, true ); //łapiemy z obsadą + if( ( tmp != nullptr ) + && ( tmp != Controlled ) ) { + + if( Controlled ) // jeśli mielismy pojazd + if( Controlled->Mechanik ) // na skutek jakiegoś błędu może czasem zniknąć + Controlled->Mechanik->TakeControl( true ); // oddajemy dotychczasowy AI + + if( DebugModeFlag + || (tmp->MoverParameters->Vel <= 5.0) ) { + // works always in debug mode, or for stopped/slow moving vehicles otherwise + Controlled = tmp; // przejmujemy nowy + mvControlled = Controlled->ControlledFind()->MoverParameters; + if( Train ) + Train->Silence(); // wyciszenie dźwięków opuszczanego pojazdu + else + Train = new TTrain(); // jeśli niczym jeszcze nie jeździlismy + if( Train->Init( Controlled ) ) { // przejmujemy sterowanie + if( !DebugModeFlag ) // w DebugMode nadal prowadzi AI + Controlled->Mechanik->TakeControl( false ); + } + else + SafeDelete( Train ); // i nie ma czym sterować + // Global::pUserDynamic=Controlled; //renerowanie pojazdu względem kabiny + // Global::iTextMode=VK_F4; + if( Train ) + InOutKey(); // do kabiny + } + } +// Global::iTextMode = cKey; break; } case GLFW_KEY_F6: { - Global::iTextMode = cKey; +// Global::iTextMode = cKey; // przyspieszenie symulacji do testowania scenerii... uwaga na FPS! if( DebugModeFlag ) { if( Global::ctrlState ) { Global::fTimeSpeed = ( Global::shiftState ? 60.0 : 20.0 ); } - else { Global::fTimeSpeed = ( Global::shiftState ? 5.0 : 1.0 ); } + else { Global::fTimeSpeed = ( Global::shiftState ? 5.0 : 1.0 ); } } break; } @@ -917,6 +659,17 @@ void TWorld::InOutKey( bool const Near ) else FreeFlyModeFlag = true; // nadal poza kabiną } + // update window title to reflect the situation + glfwSetWindowTitle( + window, + ( Global::AppName + + " (" + + ( Controlled != nullptr ? + Controlled->MoverParameters->Name : + "" ) + + " @ " + + Global::SceneryFile + + ")" ).c_str() ); }; // places camera outside the controlled vehicle, or nearest if nothing is under control @@ -956,9 +709,6 @@ void TWorld::DistantView( bool const Near ) void TWorld::FollowView(bool wycisz) { // ustawienie śledzenia pojazdu - // ABu 180404 powrot mechanika na siedzenie albo w okolicę pojazdu - // if (Console::Pressed(GLFW_KEY_F4)) Global::iViewMode=GLFW_KEY_F4; - // Ra: na zewnątrz wychodzimy w Train.cpp Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na południe if (Controlled) // jest pojazd do prowadzenia? { @@ -1020,57 +770,6 @@ bool TWorld::Update() WriteLog("Scenery moved"); }; #endif - if (iCheckFPS) - --iCheckFPS; - else - { // jak doszło do zera, to sprawdzamy wydajność - if (Timer::GetFPS() < Global::fFpsMin) - { - Global::iSegmentsRendered -= - Random(10); // floor(0.5+Global::iSegmentsRendered/Global::fRadiusFactor); - if (Global::iSegmentsRendered < 10) // jeśli jest co zmniejszać - Global::iSegmentsRendered = 10; // 10=minimalny promień to 600m - } - else if (Timer::GetFPS() > Global::fFpsMax) // jeśli jest dużo FPS - if (Global::iSegmentsRendered < Global::iFpsRadiusMax) // jeśli jest co zwiększać - { - Global::iSegmentsRendered += - Random(5); // floor(0.5+Global::iSegmentsRendered*Global::fRadiusFactor); - if (Global::iSegmentsRendered > Global::iFpsRadiusMax) // 5.6km (22*22*M_PI) - Global::iSegmentsRendered = Global::iFpsRadiusMax; - } - if ((Timer::GetFPS() < 12) && (Global::iSlowMotion < 7)) - { - Global::iSlowMotion = (Global::iSlowMotion << 1) + 1; // zapalenie kolejnego bitu - if (Global::iSlowMotionMask & 1) - if (Global::iMultisampling) // a multisampling jest włączony - glDisable(GL_MULTISAMPLE); // wyłączenie multisamplingu powinno poprawić FPS - } - else if ((Timer::GetFPS() > 20) && Global::iSlowMotion) - { // FPS się zwiększył, można włączyć bajery - Global::iSlowMotion = (Global::iSlowMotion >> 1); // zgaszenie bitu - if (Global::iSlowMotion == 0) // jeśli jest pełna prędkość - if (Global::iMultisampling) // a multisampling jest włączony - glEnable(GL_MULTISAMPLE); - } - /* - if (!Global::bPause) - if (GetFPS()<=5) - {//zwiększenie kroku fizyki przy słabym FPS - if (fMaxDt<0.05) - {fMaxDt=0.05; //Ra: tak nie może być, bo są problemy na sprzęgach - WriteLog("Phisics step switched to 0.05s!"); - } - } - else if (GetFPS()>12) - if (fMaxDt>0.01) - {//powrót do podstawowego kroku fizyki - fMaxDt=0.01; - WriteLog("Phisics step switched to 0.01s!"); - } - */ - iCheckFPS = 0.25 * Timer::GetFPS(); // tak za 0.25 sekundy sprawdzić ponownie (jeszcze przycina?) - } Timer::UpdateTimers(Global::iPause != 0); if( (Global::iPause == false) || (m_init == false) ) @@ -1091,6 +790,7 @@ bool TWorld::Update() // poprzednie jakoś tam działało // fixed step, simulation time based updates + double dt = Timer::GetDeltaTime(); // 0.0 gdy pauza /* fTimeBuffer += dt; //[s] dodanie czasu od poprzedniej ramki @@ -1156,6 +856,7 @@ bool TWorld::Update() } */ // secondary fixed step simulation time routines + while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) { Global::tranTexts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie @@ -1167,12 +868,23 @@ bool TWorld::Update() iPause = Global::iPause; } - // TODO: add fixed step part of the camera update here + // fixed step part of the camera update + if( (Train != nullptr) + && (Camera.Type == tp_Follow )) { + // jeśli jazda w kabinie, przeliczyć trzeba parametry kamery + Train->UpdateMechPosition( m_secondaryupdaterate ); + } m_secondaryupdateaccumulator -= m_secondaryupdaterate; // these should be inexpensive enough we have no cap } // variable step simulation time routines + + if( Global::changeDynObj ) { + // ABu zmiana pojazdu - przejście do innego + ChangeDynamic(); + } + if( Train != nullptr ) { TSubModel::iInstance = reinterpret_cast( Train->Dynamic() ); Train->Update( dt ); @@ -1186,9 +898,11 @@ bool TWorld::Update() Ground.Update_Lights(); // render time routines follow: + dt = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu // fixed step render time routines + fTime50Hz += dt; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek if( fTime50Hz >= 0.2 ) { Console::Update(); // to i tak trzeba wywoływać @@ -1196,28 +910,17 @@ bool TWorld::Update() } // variable step render time routines - Update_Camera( dt ); // TODO: move the fixed step cab camera updates to fixed step secondary routines section - // przy 0.25 smuga gaśnie o 6:37 w Quarku, a mogłaby już 5:40 - // Ra 2014-12: przy 0.15 się skarżyli, że nie widać smug => zmieniłem na 0.25 - // changed light activation threshold to 0.5, paired with strength reduction in daylight - if( Train ) { - // jeśli nie usunięty - Global::bSmudge = - ( FreeFlyModeFlag ? - false : - ( Train->Dynamic()->fShade <= 0.0 ? - ( Global::fLuminance <= 0.5 ) : - ( Train->Dynamic()->fShade * Global::fLuminance <= 0.5 ) ) ); - } + Update_Camera( dt ); + + Update_UI(); // TBD, TODO: move the ui updates to secondary fixed step routines, to reduce workload? + + GfxRenderer.Update( dt ); + ResourceSweep(); m_init = true; - - // visualize state changes - if (!Render()) - return false; - - return (true); + + return true; }; void @@ -1264,12 +967,6 @@ TWorld::Update_Camera( double const Deltatime ) Global::ZoomFactor = std::max( 1.0f, Global::ZoomFactor - 15.0f * static_cast( Deltatime ) ); } -/* - else if( Global::iTextMode == -1 ) { // tu mozna dodac dopisywanie do logu przebiegu lokomotywy - WriteLog( "Number of textures used: " + std::to_string( Global::iTextures ) ); - return false; - } -*/ Camera.Update(); // uwzględnienie ruchu wywołanego klawiszami if( Camera.Type == tp_Follow ) { @@ -1452,36 +1149,9 @@ void TWorld::Update_Environment() { #endif } -bool TWorld::Render() +void TWorld::ResourceSweep() { - glColor3ub(255, 255, 255); - // glColor3b(255, 0, 255); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glDepthFunc( GL_LEQUAL ); - - glMatrixMode( GL_PROJECTION ); // select the Projection Matrix - glLoadIdentity(); // reset the Projection Matrix - // calculate the aspect ratio of the window - gluPerspective( Global::FieldOfView / Global::ZoomFactor, (GLdouble)Global::ScreenWidth / std::max((GLdouble)Global::ScreenHeight, 1.0), 0.1f * Global::ZoomFactor, 2500.0f * Global::ZoomFactor ); - - glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix - glLoadIdentity(); - Camera.SetMatrix(); // ustawienie macierzy kamery względem początku scenerii - Camera.SetFrustum(); // update camera frustum to match current data - - if( !Global::bWireFrame ) { - // bez nieba w trybie rysowania linii - Environment.render(); - } - - if( false == Ground.Render( Camera.Pos ) ) { return false; } - - Render_Cab(); - Render_UI(); - ResourceManager::Sweep( Timer::GetSimulationTime() ); - - return true; }; // rendering kabiny gdy jest oddzielnym modelem i ma byc wyswietlana @@ -1644,7 +1314,6 @@ TWorld::Render_Cab() { if( dynamic->mdKabina ) // bo mogła zniknąć przy przechodzeniu do innego pojazdu { #ifdef EU07_USE_OLD_LIGHTING_MODEL - // TODO: re-implement 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 }; @@ -1726,6 +1395,10 @@ TWorld::Render_Cab() { glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseCabLight ); glLightfv( GL_LIGHT0, GL_SPECULAR, specularCabLight ); #else + if( dynamic->fShade > 0.0f ) { + // change light level based on light level of the occupied track + Global::daylight.intensity = dynamic->fShade; + } if( dynamic->InteriorLightLevel > 0.0f ) { // crude way to light the cabin, until we have something more complete in place @@ -1733,21 +1406,32 @@ TWorld::Render_Cab() { ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &cablight.x ); } #endif - if( Global::bUseVBO ) { // renderowanie z użyciem VBO - dynamic->mdKabina->RaRender( 0.0, dynamic->ReplacableSkinID, dynamic->iAlpha ); - dynamic->mdKabina->RaRenderAlpha( 0.0, dynamic->ReplacableSkinID, dynamic->iAlpha ); + + 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 + else { + // renderowanie z Display List +#ifdef EU07_USE_OLD_RENDERCODE dynamic->mdKabina->Render( 0.0, dynamic->ReplacableSkinID, dynamic->iAlpha ); dynamic->mdKabina->RenderAlpha( 0.0, dynamic->ReplacableSkinID, dynamic->iAlpha ); +#else + GfxRenderer.Render( dynamic->mdKabina, dynamic->Material(), 0.0 ); + GfxRenderer.Render_Alpha( dynamic->mdKabina, dynamic->Material(), 0.0 ); +#endif } #ifdef EU07_USE_OLD_LIGHTING_MODEL - // TODO: re-implement this // 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 + if( dynamic->fShade > 0.0f ) { + // change light level based on light level of the occupied track + Global::daylight.intensity = 1.0f; + } if( dynamic->InteriorLightLevel > 0.0f ) { // reset the overall ambient GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; @@ -1759,229 +1443,158 @@ TWorld::Render_Cab() { } void -TWorld::Render_UI() { +TWorld::Update_UI() { - // set the UI mode projection. TODO: rework it all into somethinig more elegant... eventually - glMatrixMode( GL_PROJECTION ); // select the Projection Matrix - glLoadIdentity(); // reset the Projection Matrix - // calculate the aspect ratio of the window - gluPerspective( 45.0f, (GLdouble)Global::ScreenWidth / std::max((GLdouble)Global::ScreenHeight, 1.0), 0.2f, 2500.0f ); - glMatrixMode( GL_MODELVIEW ); // Select The Modelview Matrix - glLoadIdentity(); + OutText1 = OutText2 = OutText3 = OutText4 = ""; + UITable->text_lines.clear(); - if( DebugModeFlag && !Global::iTextMode ) { - OutText1 = "FPS: "; - OutText1 += to_string( Timer::GetFPS(), 2 ); - OutText1 += Global::iSlowMotion ? "(s)" : "(n)"; + switch( Global::iTextMode ) { - OutText1 += ( Timer::GetDeltaTime() >= 0.2 ) ? "!" : " "; - // if (GetDeltaTime()>=0.2) //Ra: to za bardzo miota tekstem! - // { - // OutText1+= " Slowing Down !!! "; - // } - } - /*if (Console::Pressed(GLFW_KEY_F5)) - {Global::slowmotion=true;}; - if (Console::Pressed(GLFW_KEY_F6)) - {Global::slowmotion=false;};*/ - - if( Global::iTextMode == GLFW_KEY_F8 ) { - Global::iViewMode = GLFW_KEY_F8; - OutText1 = "FPS: "; - OutText1 += to_string( Timer::GetFPS(), 2 ); - //OutText1 += sprintf(); - if( Global::iSlowMotion ) - OutText1 += " (slowmotion " + to_string( Global::iSlowMotion ) + ")"; - OutText1 += ", sectors: "; - OutText1 += to_string( Ground.iRendered ); - } - - // if (Console::Pressed(GLFW_KEY_F7)) - //{ - // OutText1=FloatToStrF(Controlled->MoverParameters->Couplers[0].CouplingFlag,ffFixed,2,0)+", - // "; - // OutText1+=FloatToStrF(Controlled->MoverParameters->Couplers[1].CouplingFlag,ffFixed,2,0); - //} - - /* - if (Console::Pressed(GLFW_KEY_F5)) - { - int line=2; - OutText1="Time: "+FloatToStrF(GlobalTime->hh,ffFixed,2,0)+":" - +FloatToStrF(GlobalTime->mm,ffFixed,2,0)+", "; - OutText1+="distance: "; - OutText1+="34.94"; - OutText2="Next station: "; - OutText2+=FloatToStrF(Controlled->TrainParams->TimeTable[line].km,ffFixed,2,2)+" km, "; - OutText2+=AnsiString(Controlled->TrainParams->TimeTable[line].StationName)+", "; - OutText2+=AnsiString(Controlled->TrainParams->TimeTable[line].StationWare); - OutText3="Arrival: "; - if(Controlled->TrainParams->TimeTable[line].Ah==-1) - { - OutText3+="--:--"; - } - else - { - OutText3+=FloatToStrF(Controlled->TrainParams->TimeTable[line].Ah,ffFixed,2,0)+":"; - OutText3+=FloatToStrF(Controlled->TrainParams->TimeTable[line].Am,ffFixed,2,0)+" "; - } - OutText3+=" Departure: "; - OutText3+=FloatToStrF(Controlled->TrainParams->TimeTable[line].Dh,ffFixed,2,0)+":"; - OutText3+=FloatToStrF(Controlled->TrainParams->TimeTable[line].Dm,ffFixed,2,0)+" "; - }; - // */ - /* - if (Console::Pressed(GLFW_KEY_F6)) - { - //GlobalTime->UpdateMTableTime(100); - //OutText1=FloatToStrF(SquareMagnitude(Global::pCameraPosition-Controlled->GetPosition()),ffFixed,10,0); - //OutText1=FloatToStrF(Global::TnijSzczegoly,ffFixed,7,0)+", "; - //OutText1+=FloatToStrF(dta,ffFixed,2,4)+", "; - OutText1+= FloatToStrF(GetFPS(),ffFixed,6,2); - OutText1+= FloatToStrF(Global::ABuDebug,ffFixed,6,15); - }; - */ - if( Global::changeDynObj ) { // ABu zmiana pojazdu - przejście do innego - // Ra: to nie może być tak robione, to zbytnia proteza jest - Train->Silence(); // wyłączenie dźwięków opuszczanej kabiny - if( Train->Dynamic()->Mechanik ) // AI może sobie samo pójść - if( !Train->Dynamic()->Mechanik->AIControllFlag ) // tylko jeśli ręcznie prowadzony - { // jeśli prowadzi AI, to mu nie robimy dywersji! - Train->Dynamic()->MoverParameters->CabDeactivisation(); - Train->Dynamic()->Controller = AIdriver; - // Train->Dynamic()->MoverParameters->SecuritySystem.Status=0; //rozwala CA w EZT - Train->Dynamic()->MoverParameters->ActiveCab = 0; - Train->Dynamic()->MoverParameters->BrakeLevelSet( - Train->Dynamic()->MoverParameters->Handle->GetPos( - bh_NP ) ); //rozwala sterowanie hamulcem GF 04-2016 - Train->Dynamic()->MechInside = false; + case( GLFW_KEY_F1 ) : { + // f1, default mode: current time and timetable excerpt + OutText1 = + "Time: " + + to_string( (int)GlobalTime->hh ) + ":" + + ( GlobalTime->mm < 10 ? "0" : "" ) + to_string( GlobalTime->mm ) + ":" + + ( GlobalTime->mr < 10 ? "0" : "" ) + to_string( std::floor( GlobalTime->mr ) ); + if( Global::iPause ) { + OutText1 += " (paused)"; } - // int CabNr; - TDynamicObject *temp = Global::changeDynObj; - // CabNr=temp->MoverParameters->ActiveCab; - /* - if (Train->Dynamic()->MoverParameters->ActiveCab==-1) - { - temp=Train->Dynamic()->NextConnected; //pojazd od strony sprzęgu 1 - CabNr=(Train->Dynamic()->NextConnectedNo==0)?1:-1; - } - else - { - temp=Train->Dynamic()->PrevConnected; //pojazd od strony sprzęgu 0 - CabNr=(Train->Dynamic()->PrevConnectedNo==0)?1:-1; - } - */ - Train->Dynamic()->bDisplayCab = false; - Train->Dynamic()->ABuSetModelShake( vector3( 0, 0, 0 ) ); - /// Train->Dynamic()->MoverParameters->LimPipePress=-1; - /// Train->Dynamic()->MoverParameters->ActFlowSpeed=0; - /// Train->Dynamic()->Mechanik->CloseLog(); - /// SafeDelete(Train->Dynamic()->Mechanik); - // Train->Dynamic()->mdKabina=NULL; - if( Train->Dynamic()->Mechanik ) // AI może sobie samo pójść - if( !Train->Dynamic()->Mechanik->AIControllFlag ) // tylko jeśli ręcznie prowadzony - Train->Dynamic()->Mechanik->MoveTo( temp ); // przsunięcie obiektu zarządzającego - // Train->DynamicObject=NULL; - Train->DynamicSet( temp ); - Controlled = temp; - mvControlled = Controlled->ControlledFind()->MoverParameters; - Global::asHumanCtrlVehicle = Train->Dynamic()->GetName(); - if( Train->Dynamic()->Mechanik ) // AI może sobie samo pójść - if( !Train->Dynamic()->Mechanik->AIControllFlag ) // tylko jeśli ręcznie prowadzony - { - Train->Dynamic()->MoverParameters->LimPipePress = - Controlled->MoverParameters->PipePress; - // Train->Dynamic()->MoverParameters->ActFlowSpeed=0; - // Train->Dynamic()->MoverParameters->SecuritySystem.Status=1; - // Train->Dynamic()->MoverParameters->ActiveCab=CabNr; - Train->Dynamic() - ->MoverParameters->CabActivisation(); // załączenie rozrządu (wirtualne kabiny) - Train->Dynamic()->Controller = Humandriver; - Train->Dynamic()->MechInside = true; - // Train->Dynamic()->Mechanik=new - // TController(l,r,Controlled->Controller,&Controlled->MoverParameters,&Controlled->TrainParams,Aggressive); - // Train->InitializeCab(CabNr,Train->Dynamic()->asBaseDir+Train->Dynamic()->MoverParameters->TypeName+".mmd"); - } - Train->InitializeCab( Train->Dynamic()->MoverParameters->CabNo, - Train->Dynamic()->asBaseDir + - Train->Dynamic()->MoverParameters->TypeName + ".mmd" ); - if( !FreeFlyModeFlag ) { - Global::pUserDynamic = Controlled; // renerowanie względem kamery - Train->Dynamic()->bDisplayCab = true; - Train->Dynamic()->ABuSetModelShake( - vector3( 0, 0, 0 ) ); // zerowanie przesunięcia przed powrotem? - Train->MechStop(); - FollowView(); // na pozycję mecha - } - Global::changeDynObj = NULL; - } + if( Controlled && ( Controlled->Mechanik != nullptr ) ) { - glDepthFunc( GL_ALWAYS ); - glDisable( GL_LIGHTING ); + auto const &mover = Controlled->MoverParameters; + auto const &driver = Controlled->Mechanik; - if (Controlled) - glfwSetWindowTitle(window, ("EU07++NG: " + Controlled->MoverParameters->Name).c_str()); - else - glfwSetWindowTitle(window, ("EU07++NG: " + Global::SceneryFile).c_str()); + OutText2 = "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) + "+" + std::to_string( driver->Controlling()->ScndCtrlPos ); + if( mover->ActiveDir > 0 ) { OutText2 += " D"; } + else if( mover->ActiveDir < 0 ) { OutText2 += " R"; } + else { OutText2 += " N"; } - GfxRenderer.Bind(0); - glColor4f( 1.0f, 0.0f, 0.0f, 1.0f ); - glLoadIdentity(); - glTranslatef( 0.0f, 0.0f, -0.50f ); + OutText3 = "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) + "+" + std::to_string( mover->LocalBrakePos ); - if( Global::iTextMode == GLFW_KEY_F1 ) { // tekst pokazywany po wciśnięciu [F1] - // Global::iViewMode=VK_F1; - glColor3f( 1.0f, 1.0f, 1.0f ); // a, damy białym - OutText1 = - "Time: " - + to_string( (int)GlobalTime->hh ) + ":" - + ( GlobalTime->mm < 10 ? "0" : "" ) + to_string( GlobalTime->mm ) + ":" - + ( GlobalTime->mr < 10 ? "0" : "" ) + to_string( std::floor( GlobalTime->mr ) ); - if( Global::iPause ) - OutText1 += " - paused"; - if( Controlled ) - if( Controlled->Mechanik ) { - OutText2 = Controlled->Mechanik->Relation(); - if( !OutText2.empty() ) // jeśli jest podana relacja, to dodajemy punkt następnego - // zatrzymania - OutText2 = - Global::Bezogonkow( OutText2 + ": -> " + Controlled->Mechanik->NextStop(), - true ); // dopisanie punktu zatrzymania - } - // double CtrlPos=mvControlled->MainCtrlPos; - // double CtrlPosNo=mvControlled->MainCtrlPosNo; - // OutText2="defrot="+FloatToStrF(1+0.4*(CtrlPos/CtrlPosNo),ffFixed,2,5); - OutText3 = ""; // Pomoc w sterowaniu - [F9]"; - // OutText3=AnsiString(Global::pCameraRotationDeg); //kąt kamery względem północy - } - else if( Global::iTextMode == GLFW_KEY_F12 ) { // opcje włączenia i wyłączenia logowania - OutText1 = "[0] Debugmode " + std::string( DebugModeFlag ? "(on)" : "(off)" ); - OutText2 = "[1] log.txt " + std::string( ( Global::iWriteLogEnabled & 1 ) ? "(on)" : "(off)" ); - OutText3 = "[2] Console " + std::string( ( Global::iWriteLogEnabled & 2 ) ? "(on)" : "(off)" ); - } - else if( Global::iTextMode == GLFW_KEY_F2 ) { // ABu: info dla najblizszego pojazdu! - TDynamicObject *tmp = FreeFlyModeFlag ? Ground.DynamicNearest( Camera.Pos ) : - Controlled; // w trybie latania lokalizujemy wg mapy - if( tmp ) { - if( Global::iScreenMode[ Global::iTextMode - GLFW_KEY_F1 ] == 0 ) { // jeśli domyślny ekran po pierwszym naciśnięciu - OutText3 = ""; - OutText1 = "Vehicle name: " + tmp->MoverParameters->Name; - // yB OutText1+="; d: "+FloatToStrF(tmp->ABuGetDirection(),ffFixed,2,0); - // OutText1=FloatToStrF(tmp->MoverParameters->Couplers[0].CouplingFlag,ffFixed,3,2)+", - // "; - // OutText1+=FloatToStrF(tmp->MoverParameters->Couplers[1].CouplingFlag,ffFixed,3,2); - if( tmp->Mechanik ) // jeśli jest prowadzący - { // ostatnia komenda dla AI - OutText1 += ", command: " + tmp->Mechanik->OrderCurrent(); + if( Global::iScreenMode[ Global::iTextMode - GLFW_KEY_F1 ] == 1 ) { + // detail mode on second key press + OutText2 += + " Speed: " + std::to_string( static_cast( std::floor( mover->Vel ) ) ) + " km/h" + + " (limit: " + std::to_string( static_cast( std::floor( driver->VelDesired ) ) ) + " km/h" + + ", next limit: " + std::to_string( static_cast( std::floor( Controlled->Mechanik->VelNext ) ) ) + " km/h" + + " in " + to_string( Controlled->Mechanik->ActualProximityDist * 0.001, 1 ) + " km)"; + OutText3 += + " Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa" + + " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)"; } - else if( tmp->ctOwner ) + } + + break; + } + + case( GLFW_KEY_F2 ) : { + // timetable + TDynamicObject *tmp = + ( FreeFlyModeFlag ? + Ground.DynamicNearest( Camera.Pos ) : + Controlled ); // w trybie latania lokalizujemy wg mapy + + if( tmp == nullptr ) { break; } + if( tmp->Mechanik == nullptr ) { break; } + + auto const table = tmp->Mechanik->Timetable(); + if( table == nullptr ) { break; } + + OutText1 = + "Time: " + + to_string( (int)GlobalTime->hh ) + ":" + + ( GlobalTime->mm < 10 ? "0" : "" ) + to_string( GlobalTime->mm ) + ":" + + ( GlobalTime->mr < 10 ? "0" : "" ) + to_string( std::floor( GlobalTime->mr ) ); + if( Global::iPause ) { + OutText1 += " (paused)"; + } + + if( Controlled + && Controlled->Mechanik ) { + OutText2 = Global::Bezogonkow( Controlled->Mechanik->Relation(), true ) + " (" + tmp->Mechanik->Timetable()->TrainName + ")"; + if( !OutText2.empty() ) { + // jeśli jest podana relacja, to dodajemy punkt następnego zatrzymania + OutText3 = " -> " + Global::Bezogonkow( Controlled->Mechanik->NextStop(), true ); + } + } + + if( Global::iScreenMode[ Global::iTextMode - GLFW_KEY_F1 ] == 1 ) { + + if( 0 == table->StationCount ) { + // only bother if there's stations to list + UITable->text_lines.emplace_back( "(no timetable)", Global::UITextColor ); + } + else { + // header + UITable->text_lines.emplace_back( "+----------------------------+-------+-------+-----+", Global::UITextColor ); + + TMTableLine *tableline; + for( int i = tmp->Mechanik->iStationStart; i <= std::min( tmp->Mechanik->iStationStart + 15, table->StationCount ); ++i ) { + // wyświetlenie pozycji z rozkładu + tableline = table->TimeTable + i; // linijka rozkładu + + std::string station = + ( tableline->StationName + " " ).substr( 0, 26 ); + std::string arrival = + ( tableline->Ah >= 0 ? + to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Am ) ).substr( 1, 2 ) : + " " ); + std::string departure = + ( tableline->Dh >= 0 ? + to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) : + " " ); + std::string vmax = + " " + + to_string( tableline->vmax, 0 ); + vmax = vmax.substr( vmax.length() - 3, 3 ); // z wyrównaniem do prawej + + UITable->text_lines.emplace_back( + Global::Bezogonkow( "| " + station + " | " + arrival + " | " + departure + " | " + vmax + " | " + tableline->StationWare, true ), + ( ( tmp->Mechanik->iStationStart < table->StationIndex ) && ( i < table->StationIndex ) ? + float4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minął i odjazd był, to nazwa stacji będzie na zielono + Global::UITextColor ) + ); + // divider/footer + UITable->text_lines.emplace_back( "+----------------------------+-------+-------+-----+", Global::UITextColor ); + } + } + } + + break; + } + + case( GLFW_KEY_F3 ) : { + + TDynamicObject *tmp = + ( FreeFlyModeFlag ? + Ground.DynamicNearest( Camera.Pos ) : + Controlled ); // w trybie latania lokalizujemy wg mapy + + if( tmp != nullptr ) { + // + // jeśli domyślny ekran po pierwszym naciśnięciu + OutText1 = "Vehicle name: " + tmp->MoverParameters->Name; + + if( ( tmp->Mechanik == nullptr ) && ( tmp->ctOwner ) ) { + // for cars other than leading unit indicate the leader OutText1 += ", owned by " + tmp->ctOwner->OwnerName(); - if( !tmp->MoverParameters->CommandLast.empty() ) - OutText1 += ", put: " + tmp->MoverParameters->CommandLast; - // OutText1+="; Cab="+AnsiString(tmp->MoverParameters->CabNo); - OutText2 = "Damage status: " + - tmp->MoverParameters->EngineDescription( 0 ); //+" Engine status: "; + } + // informacja o sprzęgach + OutText1 += + " C0:" + + ( tmp->PrevConnected ? + tmp->PrevConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 0 ].CouplingFlag ) : + "none" ); + OutText1 += + " C1:" + + ( tmp->NextConnected ? + tmp->NextConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 1 ].CouplingFlag ) : + "none" ); + + OutText2 = "Damage status: " + tmp->MoverParameters->EngineDescription( 0 ); + OutText2 += "; Brake delay: "; if( ( tmp->MoverParameters->BrakeDelayFlag & bdelay_G ) == bdelay_G ) OutText2 += "G"; @@ -1991,642 +1604,367 @@ TWorld::Render_UI() { OutText2 += "R"; if( ( tmp->MoverParameters->BrakeDelayFlag & bdelay_M ) == bdelay_M ) OutText2 += "+Mg"; - OutText2 += ", BTP:" + - to_string( tmp->MoverParameters->LoadFlag, 0 ); - // if ((tmp->MoverParameters->EnginePowerSource.SourceType==CurrentCollector) || - // (tmp->MoverParameters->TrainType==dt_EZT)) + + OutText2 += ", BTP:" + to_string( tmp->MoverParameters->LoadFlag, 0 ); { - OutText2 += "; pant. " + - to_string( tmp->MoverParameters->PantPress, 2 ); - OutText2 += ( tmp->MoverParameters->bPantKurek3 ? "MoverParameters->PantPress, 2 ) + + ( tmp->MoverParameters->bPantKurek3 ? "MoverParameters->u,ffFixed,3,3); - // OutText2+=AnsiString(", - // N:")+FloatToStrF(tmp->MoverParameters->Ntotal,ffFixed,4,0); - OutText2 += ", MED:" + - to_string( tmp->MoverParameters->LocalBrakePosA, 2 ); - OutText2 += "+" + - to_string( tmp->MoverParameters->AnPos, 2 ); - OutText2 += ", Ft:" + - to_string( tmp->MoverParameters->Ft * 0.001f, 0 ); - OutText2 += ", HV0:" + - to_string( tmp->MoverParameters->HVCouplers[ 0 ][ 1 ], 0 ); - OutText2 += "@" + - to_string( tmp->MoverParameters->HVCouplers[ 0 ][ 0 ], 0 ); - OutText2 += "+HV1:" + - to_string( tmp->MoverParameters->HVCouplers[ 1 ][ 1 ], 0 ); - OutText2 += "@" + - to_string( tmp->MoverParameters->HVCouplers[ 1 ][ 0 ], 0 ); - OutText2 += " TC:" + - to_string( tmp->MoverParameters->TotalCurrent, 0 ); - // OutText3= AnsiString("BP: - // ")+FloatToStrF(tmp->MoverParameters->BrakePress,ffFixed,5,2)+AnsiString(", - // "); - // OutText3+= AnsiString("PP: - // ")+FloatToStrF(tmp->MoverParameters->PipePress,ffFixed,5,2)+AnsiString(", - // "); - // OutText3+= AnsiString("BVP: - // ")+FloatToStrF(tmp->MoverParameters->Volume,ffFixed,5,3)+AnsiString(", - // "); - // OutText3+= - // FloatToStrF(tmp->MoverParameters->CntrlPipePress,ffFixed,5,3)+AnsiString(", - // "); - // OutText3+= - // FloatToStrF(tmp->MoverParameters->Hamulec->GetCRP(),ffFixed,5,3)+AnsiString(", - // "); - // OutText3+= - // FloatToStrF(tmp->MoverParameters->BrakeStatus,ffFixed,5,0)+AnsiString(", - // "); - // OutText3+= AnsiString("HP: - // ")+FloatToStrF(tmp->MoverParameters->ScndPipePress,ffFixed,5,2)+AnsiString(". - // "); - // OutText2+= - // FloatToStrF(tmp->MoverParameters->CompressorPower,ffFixed,5,0)+AnsiString(", - // "); - // yB if(tmp->MoverParameters->BrakeSubsystem==Knorr) OutText2+=" Knorr"; - // yB if(tmp->MoverParameters->BrakeSubsystem==Oerlikon) OutText2+=" Oerlikon"; - // yB if(tmp->MoverParameters->BrakeSubsystem==Hik) OutText2+=" Hik"; - // yB if(tmp->MoverParameters->BrakeSubsystem==WeLu) OutText2+=" Łestinghałs"; - // OutText2= " GetFirst: - // "+AnsiString(tmp->GetFirstDynamic(1)->MoverParameters->Name)+" Damage - // status="+tmp->MoverParameters->EngineDescription(0)+" Engine status: "; - // OutText2+= " GetLast: - // "+AnsiString(tmp->GetLastDynamic(1)->MoverParameters->Name)+" Damage - // status="+tmp->MoverParameters->EngineDescription(0)+" Engine status: "; - OutText3 = ( "BP: " ) + - to_string( tmp->MoverParameters->BrakePress, 2 ) + - ( ", " ); - OutText3 += to_string( tmp->MoverParameters->BrakeStatus, 0 ) + - ( ", " ); - OutText3 += ( "PP: " ) + - to_string( tmp->MoverParameters->PipePress, 2 ) + - ( "/" ); - OutText3 += to_string( tmp->MoverParameters->ScndPipePress, 2 ) + - ( "/" ); - OutText3 += to_string( tmp->MoverParameters->EqvtPipePress, 2 ) + - ( ", " ); - OutText3 += ( "BVP: " ) + - to_string( tmp->MoverParameters->Volume, 3 ) + - ( ", " ); - OutText3 += to_string( tmp->MoverParameters->CntrlPipePress, 3 ) + - ( ", " ); - OutText3 += to_string( tmp->MoverParameters->Hamulec->GetCRP(), 3 ) + - ( ", " ); - OutText3 += to_string( tmp->MoverParameters->BrakeStatus, 0 ) + - ( ", " ); - // OutText3+=AnsiString("BVP: - // ")+FloatToStrF(tmp->MoverParameters->BrakeVP(),ffFixed,5,2)+AnsiString(", - // "); + OutText2 += + ", MED:" + + to_string( tmp->MoverParameters->LocalBrakePosA, 2 ) + + "+" + + to_string( tmp->MoverParameters->AnPos, 2 ); - // OutText3+=FloatToStrF(tmp->MoverParameters->CntrlPipePress,ffFixed,5,2)+AnsiString(", - // "); - // OutText3+=FloatToStrF(tmp->MoverParameters->HighPipePress,ffFixed,5,2)+AnsiString(", - // "); - // OutText3+=FloatToStrF(tmp->MoverParameters->LowPipePress,ffFixed,5,2)+AnsiString(", - // "); + OutText2 += + ", Ft:" + + to_string( tmp->MoverParameters->Ft * 0.001f, 0 ); - if( tmp->MoverParameters->ManualBrakePos > 0 ) - OutText3 += ( "manual brake active. " ); - else if( tmp->MoverParameters->LocalBrakePos > 0 ) - OutText3 += ( "local brake active. " ); - else - OutText3 += ( "local brake inactive. " ); - /* - //OutText3+=AnsiString("LSwTim: - ")+FloatToStrF(tmp->MoverParameters->LastSwitchingTime,ffFixed,5,2); - //OutText3+=AnsiString(" Physic: - ")+FloatToStrF(tmp->MoverParameters->PhysicActivation,ffFixed,5,2); - //OutText3+=AnsiString(" ESF: - ")+FloatToStrF(tmp->MoverParameters->EndSignalsFlag,ffFixed,5,0); - OutText3+=AnsiString(" dPAngF: ")+FloatToStrF(tmp->dPantAngleF,ffFixed,5,0); - OutText3+=AnsiString(" dPAngFT: - ")+FloatToStrF(-(tmp->PantTraction1*28.9-136.938),ffFixed,5,0); - if (tmp->lastcabf==1) - { - OutText3+=AnsiString(" pcabc1: - ")+FloatToStrF(tmp->MoverParameters->PantFrontUp,ffFixed,5,0); - OutText3+=AnsiString(" pcabc2: - ")+FloatToStrF(tmp->MoverParameters->PantRearUp,ffFixed,5,0); + OutText2 += + "; TC:" + + to_string( tmp->MoverParameters->TotalCurrent, 0 ); + OutText2 += + ", HV0:" + + to_string( tmp->MoverParameters->HVCouplers[ 0 ][ 1 ], 0 ) + + "@" + + to_string( tmp->MoverParameters->HVCouplers[ 0 ][ 0 ], 0 ); + OutText2 += + ", HV1:" + + to_string( tmp->MoverParameters->HVCouplers[ 1 ][ 1 ], 0 ) + + "@" + + to_string( tmp->MoverParameters->HVCouplers[ 1 ][ 0 ], 0 ); + + OutText3 = + "BP: " + to_string( tmp->MoverParameters->BrakePress, 2 ) + + " (" + to_string( tmp->MoverParameters->BrakeStatus, 0 ) + + "), LBP: " + to_string( tmp->MoverParameters->LocBrakePress, 2 ) + + ", PP: " + to_string( tmp->MoverParameters->PipePress, 2 ) + + "/" + to_string( tmp->MoverParameters->ScndPipePress, 2 ) + + "/" + to_string( tmp->MoverParameters->EqvtPipePress, 2 ) + + ", BVP: " + to_string( tmp->MoverParameters->Volume, 3 ) + + ", " + to_string( tmp->MoverParameters->CntrlPipePress, 3 ) + + ", " + to_string( tmp->MoverParameters->Hamulec->GetCRP(), 3 ) + + ", " + to_string( tmp->MoverParameters->BrakeStatus, 0 ); + + if( tmp->MoverParameters->ManualBrakePos > 0 ) { + + OutText3 += ", manual brake on"; } - if (tmp->lastcabf==-1) - { - OutText3+=AnsiString(" pcabc1: - ")+FloatToStrF(tmp->MoverParameters->PantRearUp,ffFixed,5,0); - OutText3+=AnsiString(" pcabc2: - ")+FloatToStrF(tmp->MoverParameters->PantFrontUp,ffFixed,5,0); + + if( tmp->MoverParameters->LocalBrakePos > 0 ) { + + OutText3 += ", local brake on"; } - */ - OutText4 = ""; - if( tmp->Mechanik ) { // o ile jest ktoś w środku - // OutText4=tmp->Mechanik->StopReasonText(); - // if (!OutText4.IsEmpty()) OutText4+="; "; //aby ładniejszy odstęp był - // if (Controlled->Mechanik && (Controlled->Mechanik->AIControllFlag==AIdriver)) + else { + + OutText3 += ", local brake off"; + } + + if( tmp->Mechanik ) { + // o ile jest ktoś w środku std::string flags = "bwaccmlshhhoibsgvdp; "; // flagi AI (definicja w Driver.h) for( int i = 0, j = 1; i < 19; ++i, j <<= 1 ) if( tmp->Mechanik->DrivigFlags() & j ) // jak bit ustawiony flags[ i + 1 ] = std::toupper( flags[ i + 1 ] ); // ^= 0x20; // to zmiana na wielką literę + OutText4 = flags; + OutText4 += - ( "Driver: Vd=" ) + - to_string( tmp->Mechanik->VelDesired, 0 ) + ( " ad=" ) + - to_string( tmp->Mechanik->AccDesired, 2 ) + ( " Pd=" ) + - to_string( tmp->Mechanik->ActualProximityDist, 0 ) + - ( " Vn=" ) + to_string( tmp->Mechanik->VelNext, 0 ) + - ( " VSm=" ) + to_string( tmp->Mechanik->VelSignalLast, 0 ) + - ( " VLm=" ) + to_string( tmp->Mechanik->VelLimitLast, 0 ) + - ( " VRd=" ) + to_string( tmp->Mechanik->VelRoad, 0 ); - if( tmp->Mechanik->VelNext == 0.0 ) - if( tmp->Mechanik->eSignNext ) { // jeśli ma zapamiętany event semafora - // if (!OutText4.IsEmpty()) OutText4+=", "; //aby ładniejszy odstęp był - OutText4 += " (" + - Global::Bezogonkow( tmp->Mechanik->eSignNext->asName ) + - ")"; // nazwa eventu semafora - } - } - if( !OutText4.empty() ) - OutText4 += "; "; // aby ładniejszy odstęp był - // informacja o sprzęgach nawet bez mechanika - OutText4 += - "C0=" + ( tmp->PrevConnected ? - tmp->PrevConnected->GetName() + ":" + - to_string( tmp->MoverParameters->Couplers[ 0 ].CouplingFlag ) : - std::string( "NULL" ) ); - OutText4 += - " C1=" + ( tmp->NextConnected ? - tmp->NextConnected->GetName() + ":" + - to_string( tmp->MoverParameters->Couplers[ 1 ].CouplingFlag ) : - std::string( "NULL" ) ); - if( Console::Pressed( GLFW_KEY_F2 ) ) { - WriteLog( OutText1 ); - WriteLog( OutText2 ); - WriteLog( OutText3 ); - WriteLog( OutText4 ); - } - } // koniec treści podstawowego ekranu FK_V2 - else { // ekran drugi, czyli tabelka skanowania AI - if( tmp->Mechanik ) //żeby była tabelka, musi być AI - { // tabelka jest na użytek testujących scenerie, więc nie musi być "ładna" - glColor3f( 1.0f, 1.0f, 1.0f ); // a, damy zielony. GF: jednak biały - // glTranslatef(0.0f,0.0f,-0.50f); - glRasterPos2f( -0.25f, 0.20f ); - // OutText1="Scan distance: "+AnsiString(tmp->Mechanik->scanmax)+", back: - // "+AnsiString(tmp->Mechanik->scanback); - OutText1 = "Time: " + to_string( (int)GlobalTime->hh ) + ":"; - int i = GlobalTime->mm; // bo inaczej potrafi zrobić "hh:010" - if( i < 10 ) - OutText1 += "0"; - OutText1 += to_string( i ); // minuty - OutText1 += ":"; - i = floor( GlobalTime->mr ); // bo inaczej potrafi zrobić "hh:mm:010" - if( i < 10 ) - OutText1 += "0"; - OutText1 += to_string( i ); - OutText1 += - ( ". Vel: " ) + to_string( tmp->GetVelocity(), 1 ); - OutText1 += ". Scan table:"; - glPrint( Global::Bezogonkow( OutText1 ).c_str() ); - i = -1; - while( ( OutText1 = tmp->Mechanik->TableText( ++i ) ) != "" ) { // wyświetlenie pozycji z tabelki - glRasterPos2f( -0.25f, 0.19f - 0.01f * i ); - glPrint( Global::Bezogonkow( OutText1 ).c_str() ); + "Driver: Vd=" + to_string( tmp->Mechanik->VelDesired, 0 ) + + " ad=" + to_string( tmp->Mechanik->AccDesired, 2 ) + + " Pd=" + to_string( tmp->Mechanik->ActualProximityDist, 0 ) + + " Vn=" + to_string( tmp->Mechanik->VelNext, 0 ) + + " VSm=" + to_string( tmp->Mechanik->VelSignalLast, 0 ) + + " VLm=" + to_string( tmp->Mechanik->VelLimitLast, 0 ) + + " VRd=" + to_string( tmp->Mechanik->VelRoad, 0 ); + + if( ( tmp->Mechanik->VelNext == 0.0 ) + && ( tmp->Mechanik->eSignNext ) ) { + // jeśli ma zapamiętany event semafora, nazwa eventu semafora + OutText4 += + " (" + + Global::Bezogonkow( tmp->Mechanik->eSignNext->asName ) + + ")"; } - // podsumowanie sensu tabelki - OutText4 = - ( "Driver: Vd=" ) + - to_string( tmp->Mechanik->VelDesired, 0 ) + ( " ad=" ) + - to_string( tmp->Mechanik->AccDesired, 2 ) + ( " Pd=" ) + - to_string( tmp->Mechanik->ActualProximityDist, 0 ) + - ( " Vn=" ) + to_string( tmp->Mechanik->VelNext, 0 ) + - ( "\n VSm=" ) + to_string( tmp->Mechanik->VelSignalLast, 0 ) + - ( " VLm=" ) + to_string( tmp->Mechanik->VelLimitLast, 0 ) + - ( " VRd=" ) + to_string( tmp->Mechanik->VelRoad, 0 ) + - ( " VSig=" ) + to_string( tmp->Mechanik->VelSignal, 0 ); - if( tmp->Mechanik->VelNext == 0.0 ) - if( tmp->Mechanik->eSignNext ) { // jeśli ma zapamiętany event semafora - // if (!OutText4.IsEmpty()) OutText4+=", "; //aby ładniejszy odstęp był - OutText4 += " (" + - Global::Bezogonkow( tmp->Mechanik->eSignNext->asName ) + - ")"; // nazwa eventu semafora - } - glRasterPos2f( -0.25f, 0.19f - 0.01f * i ); - glPrint( Global::Bezogonkow( OutText4 ).c_str() ); + + // biezaca komenda dla AI + OutText4 += ", command: " + tmp->Mechanik->OrderCurrent(); } - } // koniec ekanu skanowania - } // koniec obsługi, gdy mamy wskaźnik do pojazdu - else { // wyświetlenie współrzędnych w scenerii oraz kąta kamery, gdy nie mamy wskaźnika - OutText1 = "Camera position: " + to_string( Camera.Pos.x, 2 ) + " " + - to_string( Camera.Pos.y, 2 ) + " " + - to_string( Camera.Pos.z, 2 ); - OutText1 += ", azimuth: " + - to_string( 180.0 - RadToDeg( Camera.Yaw ), 0 ); // ma być azymut, czyli 0 na północy i rośnie na wschód + + if( Global::iScreenMode[ Global::iTextMode - GLFW_KEY_F1 ] == 1 ) { + // f2 screen, track scan mode + if( tmp->Mechanik == nullptr ) { + //żeby była tabelka, musi być AI + break; + } + + int i = 0; + do { + std::string scanline = tmp->Mechanik->TableText( i ); + if( scanline.empty() ) { break; } + UITable->text_lines.emplace_back( Global::Bezogonkow( scanline ), Global::UITextColor ); + ++i; + } while( i < 16 ); // TController:iSpeedTableSize TODO: change when the table gets recoded + } + } + else { + // wyświetlenie współrzędnych w scenerii oraz kąta kamery, gdy nie mamy wskaźnika + OutText1 = + "Camera position: " + + to_string( Camera.Pos.x, 2 ) + " " + + to_string( Camera.Pos.y, 2 ) + " " + + to_string( Camera.Pos.z, 2 ) + + ", azimuth: " + + to_string( 180.0 - RadToDeg( Camera.Yaw ), 0 ) // ma być azymut, czyli 0 na północy i rośnie na wschód + + " " + + std::string( "S SEE NEN NWW SW" ) + .substr( 0 + 2 * floor( fmod( 8 + ( Camera.Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); + // current luminance level + OutText2 = "Light level: " + to_string( Global::fLuminance, 3 ); + if( Global::FakeLight ) { OutText2 += "(*)"; } + } + + break; + } + + case( GLFW_KEY_F8 ) : { + + OutText1 = + "Draw range x " + to_string( Global::fDistanceFactor, 1 ) + + "; FPS: " + to_string( Timer::GetFPS(), 2 ); + if( Global::iSlowMotion ) { + OutText1 += " (slowmotion " + to_string( Global::iSlowMotion ) + ")"; + } OutText1 += - " " + - std::string( "S SEE NEN NWW SW" ) - .substr( 0 + 2 * floor( fmod( 8 + ( Camera.Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); - // current luminance level - OutText2 = "Light level: " + to_string( Global::fLuminance, 3 ); + ", sectors: " + to_string( Ground.iRendered ) + + "/" + to_string( Global::iSegmentsRendered ) + + "; FoV: " + to_string( Global::FieldOfView / Global::ZoomFactor, 1 ); + + break; } - // OutText3= AnsiString(" Online documentation (PL, ENG, DE, soon CZ): - // http://www.eu07.pl"); - // OutText3="enrot="+FloatToStrF(Controlled->MoverParameters->enrot,ffFixed,6,2); - // OutText3="; n="+FloatToStrF(Controlled->MoverParameters->n,ffFixed,6,2); - } // koniec treści podstawowego ekranu FK_V2 - else if( Global::iTextMode == GLFW_KEY_F5 ) { // przesiadka do innego pojazdu - if( FreeFlyModeFlag ) // jeśli tryb latania - { - TDynamicObject *tmp = Ground.DynamicNearest( Camera.Pos, 50, true ); //łapiemy z obsadą - if( tmp ) - if( tmp != Controlled ) { - if( Controlled ) // jeśli mielismy pojazd - if( Controlled->Mechanik ) // na skutek jakiegoś błędu może czasem zniknąć - Controlled->Mechanik->TakeControl( true ); // oddajemy dotychczasowy AI - if( DebugModeFlag ? true : tmp->MoverParameters->Vel <= 5.0 ) { - Controlled = tmp; // przejmujemy nowy - mvControlled = Controlled->ControlledFind()->MoverParameters; - if( Train ) - Train->Silence(); // wyciszenie dźwięków opuszczanego pojazdu - else - Train = new TTrain(); // jeśli niczym jeszcze nie jeździlismy - if( Train->Init( Controlled ) ) { // przejmujemy sterowanie - if( !DebugModeFlag ) // w DebugMode nadal prowadzi AI - Controlled->Mechanik->TakeControl( false ); - } - else - SafeDelete( Train ); // i nie ma czym sterować - // Global::pUserDynamic=Controlled; //renerowanie pojazdu względem kabiny - // Global::iTextMode=GLFW_KEY_F4; - if( Train ) - InOutKey(); // do kabiny + + case( GLFW_KEY_F9 ) : { + // informacja o wersji, sposobie wyświetlania i błędach OpenGL + OutText1 = Global::asVersion; // informacja o wersji + if( Global::iMultiplayer ) { + OutText1 += " (multiplayer mode is active)"; + } + + OutText2 = + std::string("Rendering mode: ") + + ( Global::bUseVBO ? + "VBO" : + "Display Lists" ) + + ". " + + GfxRenderer.Info(); + + // dump last opengl error, if any + GLenum glerror = glGetError(); + if( glerror != GL_NO_ERROR ) { + Global::LastGLError = to_string( glerror ) + " (" + Global::Bezogonkow( (char *)gluErrorString( glerror ) ) + ")"; + } + if( false == Global::LastGLError.empty() ) { + OutText3 = + "Last openGL error: " + + Global::LastGLError; + } + + break; + } + + case( GLFW_KEY_F10 ) : { + + OutText1 = ( "Press [Y] key to quit / Aby zakonczyc program, przycisnij klawisz [Y]." ); + + break; + } + + case( GLFW_KEY_F12 ) : { + // opcje włączenia i wyłączenia logowania + OutText1 = "[0] Debugmode " + std::string( DebugModeFlag ? "(on)" : "(off)" ); + OutText2 = "[1] log.txt " + std::string( ( Global::iWriteLogEnabled & 1 ) ? "(on)" : "(off)" ); + OutText3 = "[2] Console " + std::string( ( Global::iWriteLogEnabled & 2 ) ? "(on)" : "(off)" ); + + break; + } + + default: { + // uncovered cases, nothing to do here... + // ... unless we're in debug mode + if( DebugModeFlag ) { + + TDynamicObject *tmp = + ( FreeFlyModeFlag ? + Ground.DynamicNearest( Camera.Pos ) : + Controlled ); // w trybie latania lokalizujemy wg mapy + if( tmp == nullptr ) { + break; + } + + OutText1 = + "vel: " + to_string(tmp->GetVelocity(), 2) + " km/h" + + "; dist: " + to_string(tmp->MoverParameters->DistCounter, 2) + " km" + + "; pos: (" + + to_string( tmp->GetPosition().x, 2 ) + ", " + + to_string( tmp->GetPosition().y, 2 ) + ", " + + to_string( tmp->GetPosition().z, 2 ) + + ")"; + + OutText2 = + "HamZ=" + to_string( tmp->MoverParameters->fBrakeCtrlPos, 1 ) + + "; HamP=" + std::to_string( tmp->MoverParameters->LocalBrakePos ) + "/" + to_string( tmp->MoverParameters->LocalBrakePosA, 2 ) + + "; NasJ=" + std::to_string( tmp->MoverParameters->MainCtrlPos ) + "(" + std::to_string( tmp->MoverParameters->MainCtrlActualPos ) + ")" + + "; NasB=" + std::to_string( tmp->MoverParameters->ScndCtrlPos ) + "(" + std::to_string( tmp->MoverParameters->ScndCtrlActualPos ) + ")" + + "; I=" + + ( tmp->MoverParameters->TrainType == dt_EZT ? + std::to_string( int( tmp->MoverParameters->ShowCurrent( 0 ) ) ) : + std::to_string( int( tmp->MoverParameters->Im ) ) ) + + "; U=" + to_string( int( tmp->MoverParameters->RunningTraction.TractionVoltage + 0.5 ) ) + + "; R=" + + ( tmp->MoverParameters->RunningShape.R > 100000.0 ? + "~0.0" : + to_string( tmp->MoverParameters->RunningShape.R, 1 ) ) + + " An=" + to_string( tmp->MoverParameters->AccN, 2 ); // przyspieszenie poprzeczne + + if( tprev != int( GlobalTime->mr ) ) { + tprev = GlobalTime->mr; + Acc = ( tmp->MoverParameters->Vel - VelPrev ) / 3.6; + VelPrev = tmp->MoverParameters->Vel; + } + OutText2 += ( "; As=" ) + to_string( Acc, 2 ); // przyspieszenie wzdłużne + + OutText3 = + "cyl.ham. " + to_string( tmp->MoverParameters->BrakePress, 2 ) + + "; prz.gl. " + to_string( tmp->MoverParameters->PipePress, 2 ) + + "; zb.gl. " + to_string( tmp->MoverParameters->CompressedVolume, 2 ) + // youBy - drugi wezyk + + "; p.zas. " + to_string( tmp->MoverParameters->ScndPipePress, 2 ); + + // McZapkie: warto wiedziec w jakim stanie sa przelaczniki + if( tmp->MoverParameters->ConvOvldFlag ) + OutText3 += " C! "; + else if( tmp->MoverParameters->FuseFlag ) + OutText3 += " F! "; + else if( !tmp->MoverParameters->Mains ) + OutText3 += " () "; + else { + switch( + tmp->MoverParameters->ActiveDir * + ( tmp->MoverParameters->Imin == tmp->MoverParameters->IminLo ? + 1 : + 2 ) ) { + case 2: { OutText3 += " >> "; break; } + case 1: { OutText3 += " -> "; break; } + case 0: { OutText3 += " -- "; break; } + case -1: { OutText3 += " <- "; break; } + case -2: { OutText3 += " << "; break; } } } - Global::iTextMode = 0; // tryb neutralny - } - /* + // McZapkie: predkosc szlakowa + if( tmp->MoverParameters->RunningTrack.Velmax == -1 ) { + OutText3 += " Vtrack=Vmax"; + } + else { + OutText3 += " Vtrack " + to_string( tmp->MoverParameters->RunningTrack.Velmax, 2 ); + } - OutText1=OutText2=OutText3=OutText4=""; - AnsiString flag[10]={"vmax", "tory", "smfr", "pjzd", "mnwr", "pstk", "brak", "brak", - "brak", "brak"}; - if(tmp) - if(tmp->Mechanik) - { - for(int i=0;i<15;i++) - { - int tmppar=floor(tmp->Mechanik->ProximityTable[i].Vel); - OutText2+=(tmppar<1000?(tmppar<100?((tmppar<10)&&(tmppar>=0)?" ":" "):" - "):"")+IntToStr(tmppar)+" "; - tmppar=floor(tmp->Mechanik->ProximityTable[i].Dist); - OutText3+=(tmppar<1000?(tmppar<100?((tmppar<10)&&(tmppar>=0)?" ":" "):" - "):"")+IntToStr(tmppar)+" "; - OutText1+=flag[tmp->Mechanik->ProximityTable[i].Flag]+" "; - } - for(int i=0;i<6;i++) - { - int tmppar=floor(tmp->Mechanik->ReducedTable[i]); - OutText4+=flag[i]+":"+(tmppar<1000?(tmppar<100?((tmppar<10)&&(tmppar>=0)?" ":" - "):" "):"")+IntToStr(tmppar)+" "; - } - } - */ - } - else if( Global::iTextMode == GLFW_KEY_F10 ) { // tu mozna dodac dopisywanie do logu przebiegu lokomotywy - // Global::iViewMode=VK_F10; - // return false; - OutText1 = ( "To quit press [Y] key." ); - OutText3 = ( "Aby zakonczyc program, przycisnij klawisz [Y]." ); - } - else if( Controlled && DebugModeFlag && !Global::iTextMode ) { - OutText1 += ( "; vel " ) + to_string( Controlled->GetVelocity(), 2 ); - OutText1 += ( "; pos " ) + to_string( Controlled->GetPosition().x, 2 ); - OutText1 += ( " ; " ) + to_string( Controlled->GetPosition().y, 2 ); - OutText1 += ( " ; " ) + to_string( Controlled->GetPosition().z, 2 ); - OutText1 += ( "; dist=" ) + to_string( Controlled->MoverParameters->DistCounter, 4 ); + if( ( tmp->MoverParameters->EnginePowerSource.SourceType == CurrentCollector ) + || ( tmp->MoverParameters->TrainType == dt_EZT ) ) { + OutText3 += + "; pant. " + to_string( tmp->MoverParameters->PantPress, 2 ) + + ( tmp->MoverParameters->bPantKurek3 ? "=" : "^" ) + "ZG"; + } + + // McZapkie: komenda i jej parametry + if( tmp->MoverParameters->CommandIn.Command != ( "" ) ) { + OutText4 = + "C:" + tmp->MoverParameters->CommandIn.Command + + " V1=" + to_string( tmp->MoverParameters->CommandIn.Value1, 0 ) + + " V2=" + to_string( tmp->MoverParameters->CommandIn.Value2, 0 ); + } + if( ( tmp->Mechanik ) + && ( tmp->Mechanik->AIControllFlag == AIdriver ) ) { + OutText4 += + "AI: Vd=" + to_string( tmp->Mechanik->VelDesired, 0 ) + + " ad=" + to_string( tmp->Mechanik->AccDesired, 2 ) + + " Pd=" + to_string( tmp->Mechanik->ActualProximityDist, 0 ) + + " Vn=" + to_string( tmp->Mechanik->VelNext, 0 ); + } + + // induction motor data + if( tmp->MoverParameters->EngineType == ElectricInductionMotor ) { + + UITable->text_lines.emplace_back( " eimc: eimv: press:", Global::UITextColor ); + for( int i = 0; i <= 20; ++i ) { + + std::string parameters = + to_string(tmp->MoverParameters->eimc[i], 2, 9) + + " " + to_string( tmp->MoverParameters->eimv[ i ], 2, 9 ); + + if( i <= 10 ) { + parameters += " " + to_string( Train->fPress[ i ][ 0 ], 2, 9 ); + } + else if( i == 12 ) { + parameters += " med:"; + } + else if( i >= 13 ) { + parameters += " " + to_string( tmp->MED[ 0 ][ i - 13 ], 2, 9 ); + } + + UITable->text_lines.emplace_back( parameters, Global::UITextColor ); + } + } + + } // if( DebugModeFlag && Controlled ) + + break; + } + } + +#ifdef EU07_USE_OLD_UI_CODE + if( Controlled && DebugModeFlag && !Global::iTextMode ) { - // double a= acos( DotProduct(Normalize(Controlled->GetDirection()),vWorldFront)); - // OutText+= AnsiString("; angle ")+FloatToStrF(a/M_PI*180,ffFixed,6,2); OutText1 += ( "; d_omega " ) + to_string( Controlled->MoverParameters->dizel_engagedeltaomega, 3 ); - OutText2 = ( "HamZ=" ) + to_string( Controlled->MoverParameters->fBrakeCtrlPos, 1 ); - OutText2 += ( "; HamP=" ) + to_string( mvControlled->LocalBrakePos ); - OutText2 += ( "/" ) + to_string( Controlled->MoverParameters->LocalBrakePosA, 2 ); - // mvControlled->MainCtrlPos; - // if (mvControlled->MainCtrlPos<0) - // OutText2+= AnsiString("; nastawnik 0"); - // if (mvControlled->MainCtrlPos>iPozSzereg) - OutText2 += ( "; NasJ=" ) + to_string( mvControlled->MainCtrlPos ); - // else - // OutText2+= AnsiString("; nastawnik S") + mvControlled->MainCtrlPos; - OutText2 += ( "(" ) + to_string( mvControlled->MainCtrlActualPos ); - - OutText2 += ( "); NasB=" ) + to_string( mvControlled->ScndCtrlPos ); - OutText2 += ( "(" ) + to_string( mvControlled->ScndCtrlActualPos ); - if( mvControlled->TrainType == dt_EZT ) - OutText2 += ( "); I=" ) + to_string( int( mvControlled->ShowCurrent( 0 ) ) ); - else - OutText2 += ( "); I=" ) + to_string( int( mvControlled->Im ) ); - // OutText2+=AnsiString("; - // I2=")+FloatToStrF(Controlled->NextConnected->MoverParameters->Im,ffFixed,6,2); - OutText2 += ( "; U=" ) + - to_string( int( mvControlled->RunningTraction.TractionVoltage + 0.5 ) ); - // OutText2+=AnsiString("; rvent=")+FloatToStrF(mvControlled->RventRot,ffFixed,6,2); - OutText2 += ( "; R=" ) + - to_string( Controlled->MoverParameters->RunningShape.R, 1 ); - OutText2 += ( " An=" ) + to_string( Controlled->MoverParameters->AccN, 2 ); // przyspieszenie poprzeczne - if( tprev != int( GlobalTime->mr ) ) { - tprev = GlobalTime->mr; - Acc = ( Controlled->MoverParameters->Vel - VelPrev ) / 3.6; - VelPrev = Controlled->MoverParameters->Vel; - } - OutText2 += ( "; As=" ) + to_string( Acc/*Controlled->MoverParameters->AccS*/, 2 ); // przyspieszenie wzdłużne - // OutText2+=AnsiString("; P=")+FloatToStrF(mvControlled->EnginePower,ffFixed,6,1); - OutText3 += ( "cyl.ham. " ) + - to_string( Controlled->MoverParameters->BrakePress, 2 ); - OutText3 += ( "; prz.gl. " ) + - to_string( Controlled->MoverParameters->PipePress, 2 ); - OutText3 += ( "; zb.gl. " ) + - to_string( Controlled->MoverParameters->CompressedVolume, 2 ); - // youBy - drugi wezyk - OutText3 += ( "; p.zas. " ) + - to_string( Controlled->MoverParameters->ScndPipePress, 2 ); if( Controlled->MoverParameters->EngineType == ElectricInductionMotor ) { - // glTranslatef(0.0f,0.0f,-0.50f); - glColor3f( 1.0f, 1.0f, 1.0f ); // a, damy białym - for( int i = 0; i <= 20; i++ ) { - glRasterPos2f( -0.25f, 0.16f - 0.01f * i ); - if( Controlled->MoverParameters->eimc[ i ] < 10 ) - OutText4 = to_string( Controlled->MoverParameters->eimc[ i ], 3 ); - else - OutText4 = to_string( Controlled->MoverParameters->eimc[ i ], 3 ); - glPrint( OutText4.c_str() ); - } - for( int i = 0; i <= 20; i++ ) { - glRasterPos2f( -0.2f, 0.16f - 0.01f * i ); - if( Controlled->MoverParameters->eimv[ i ] < 10 ) - OutText4 = to_string( Controlled->MoverParameters->eimv[ i ], 3 ); - else - OutText4 = to_string( Controlled->MoverParameters->eimv[ i ], 3 ); - glPrint( OutText4.c_str() ); - } - for( int i = 0; i <= 10; i++ ) { - glRasterPos2f( -0.15f, 0.16f - 0.01f * i ); - OutText4 = to_string( Train->fPress[ i ][ 0 ], 3 ); - glPrint( OutText4.c_str() ); - } - for( int i = 0; i <= 8; i++ ) { - glRasterPos2f( -0.15f, 0.04f - 0.01f * i ); - OutText4 = to_string( Controlled->MED[ 0 ][ i ], 3 ); - glPrint( OutText4.c_str() ); - } + for( int i = 0; i <= 8; i++ ) { for( int j = 0; j <= 9; j++ ) { glRasterPos2f( 0.05f + 0.03f * i, 0.16f - 0.01f * j ); OutText4 = to_string( Train->fEIMParams[ i ][ j ], 2 ); - glPrint( OutText4.c_str() ); - } - } - OutText4 = ""; - // glTranslatef(0.0f,0.0f,+0.50f); - glColor3f( 1.0f, 0.0f, 0.0f ); // a, damy czerwonym - } - - // ABu: testy sprzegow-> (potem przeniesc te zmienne z public do protected!) - // OutText3+=AnsiString("; EnginePwr=")+FloatToStrF(mvControlled->EnginePower,ffFixed,1,5); - // OutText3+=AnsiString("; nn=")+FloatToStrF(Controlled->NextConnectedNo,ffFixed,1,0); - // OutText3+=AnsiString("; PR=")+FloatToStrF(Controlled->dPantAngleR,ffFixed,3,0); - // OutText3+=AnsiString("; PF=")+FloatToStrF(Controlled->dPantAngleF,ffFixed,3,0); - // if(Controlled->bDisplayCab==true) - // OutText3+=AnsiString("; Wysw. kab");//+Controlled->mdKabina->GetSMRoot()->Name; - // else - // OutText3+=AnsiString("; test:")+AnsiString(Controlled->MoverParameters->TrainType[1]); - - // OutText3+=FloatToStrF(Train->Dynamic()->MoverParameters->EndSignalsFlag,ffFixed,3,0);; - - // OutText3+=FloatToStrF(Train->Dynamic()->MoverParameters->EndSignalsFlag&byte(((((1+Train->Dynamic()->MoverParameters->CabNo)/2)*30)+2)),ffFixed,3,0);; - - // OutText3+=AnsiString("; - // Ftmax=")+FloatToStrF(Controlled->MoverParameters->Ftmax,ffFixed,3,0); - // OutText3+=AnsiString("; - // FTotal=")+FloatToStrF(Controlled->MoverParameters->FTotal/1000.0f,ffFixed,3,2); - // OutText3+=AnsiString("; - // FTrain=")+FloatToStrF(Controlled->MoverParameters->FTrain/1000.0f,ffFixed,3,2); - // Controlled->mdModel->GetSMRoot()->SetTranslate(vector3(0,1,0)); - - // McZapkie: warto wiedziec w jakim stanie sa przelaczniki - if( mvControlled->ConvOvldFlag ) - OutText3 += " C! "; - else if( mvControlled->FuseFlag ) - OutText3 += " F! "; - else if( !mvControlled->Mains ) - OutText3 += " () "; - else - switch( mvControlled->ActiveDir * ( mvControlled->Imin == mvControlled->IminLo ? 1 : 2 ) ) { - case 2: - { - OutText3 += " >> "; - break; - } - case 1: - { - OutText3 += " -> "; - break; - } - case 0: - { - OutText3 += " -- "; - break; - } - case -1: - { - OutText3 += " <- "; - break; - } - case -2: - { - OutText3 += " << "; - break; - } - } - // OutText3+=AnsiString("; dpLocal - // ")+FloatToStrF(Controlled->MoverParameters->dpLocalValve,ffFixed,10,8); - // OutText3+=AnsiString("; dpMain - // ")+FloatToStrF(Controlled->MoverParameters->dpMainValve,ffFixed,10,8); - // McZapkie: predkosc szlakowa - if( Controlled->MoverParameters->RunningTrack.Velmax == -1 ) { - OutText3 += ( " Vtrack=Vmax" ); - } - else { - OutText3 += - ( " Vtrack " ) + - to_string( Controlled->MoverParameters->RunningTrack.Velmax, 2 ); - } - // WriteLog(Controlled->MoverParameters->TrainType.c_str()); - if( ( mvControlled->EnginePowerSource.SourceType == CurrentCollector ) || - ( mvControlled->TrainType == dt_EZT ) ) { - OutText3 += - ( "; pant. " ) + to_string( mvControlled->PantPress, 2 ); - OutText3 += ( mvControlled->bPantKurek3 ? "=ZG" : "|ZG" ); - } - // McZapkie: komenda i jej parametry - if( Controlled->MoverParameters->CommandIn.Command != ( "" ) ) - OutText4 = ( "C:" ) + - ( Controlled->MoverParameters->CommandIn.Command ) + - ( " V1=" ) + - to_string( Controlled->MoverParameters->CommandIn.Value1, 0 ) + - ( " V2=" ) + - to_string( Controlled->MoverParameters->CommandIn.Value2, 0 ); - if( Controlled->Mechanik && ( Controlled->Mechanik->AIControllFlag == AIdriver ) ) - OutText4 += - ( "AI: Vd=" ) + - to_string( Controlled->Mechanik->VelDesired, 0 ) + ( " ad=" ) + - to_string( Controlled->Mechanik->AccDesired, 2 ) + ( " Pd=" ) + - to_string( Controlled->Mechanik->ActualProximityDist, 0 ) + - ( " Vn=" ) + to_string( Controlled->Mechanik->VelNext, 0 ); - } - - // ABu 150205: prosty help, zeby sie na forum nikt nie pytal, jak ma ruszyc :) - - if( Global::detonatoryOK ) { - // if (Console::Pressed(VK_F9)) ShowHints(); //to nie działa prawidłowo - prosili wyłączyć - if( Global::iTextMode == GLFW_KEY_F9 ) { // informacja o wersji, sposobie wyświetlania i błędach OpenGL - // Global::iViewMode=VK_F9; - OutText1 = Global::asVersion; // informacja o wersji - OutText2 = std::string( "Rendering mode: " ) + ( Global::bUseVBO ? "VBO" : "Display Lists" ); - if( Global::iMultiplayer ) - OutText2 += ". Multiplayer is active"; - OutText2 += "."; - GLenum err = glGetError(); - if( err != GL_NO_ERROR ) { - OutText3 = "OpenGL error " + to_string( err ) + ": " + - Global::Bezogonkow( ( (char *)gluErrorString( err ) ) ); - } - } - if( Global::iTextMode == GLFW_KEY_F3 ) { // wyświetlenie rozkładu jazdy, na razie jakkolwiek - TDynamicObject *tmp = FreeFlyModeFlag ? - Ground.DynamicNearest( Camera.Pos ) : - Controlled; // w trybie latania lokalizujemy wg mapy - Mtable::TTrainParameters *tt = NULL; - if( tmp ) - if( tmp->Mechanik ) { - tt = tmp->Mechanik->Timetable(); - if( tt ) // musi być rozkład - { // wyświetlanie rozkładu - glColor3f( 1.0f, 1.0f, 1.0f ); // a, damy białym - // glTranslatef(0.0f,0.0f,-0.50f); - glRasterPos2f( -0.25f, 0.20f ); - OutText1 = tmp->Mechanik->Relation() + " (" + - tmp->Mechanik->Timetable()->TrainName + ")"; - glPrint( Global::Bezogonkow( OutText1, true ).c_str() ); - glRasterPos2f( -0.25f, 0.19f ); - // glPrint("|============================|=======|=======|=====|"); - // glPrint("| Posterunek | Przyj.| Odjazd| Vmax|"); - // glPrint("|============================|=======|=======|=====|"); - glPrint( "|----------------------------|-------|-------|-----|" ); - TMTableLine *t; - for( int i = tmp->Mechanik->iStationStart; i <= tt->StationCount; ++i ) { // wyświetlenie pozycji z rozkładu - t = tt->TimeTable + i; // linijka rozkładu - OutText1 = ( t->StationName + - " " ).substr( 0, 26 ); - OutText2 = ( t->Ah >= 0 ) ? - to_string( int( 100 + t->Ah ) ).substr( 1, 2 ) + ":" + - to_string( int( 100 + t->Am ) ).substr( 1, 2 ) : - std::string( " " ); - OutText3 = ( t->Dh >= 0 ) ? - to_string( int( 100 + t->Dh ) ).substr( 1, 2 ) + ":" + - to_string( int( 100 + t->Dm ) ).substr( 1, 2 ) : - std::string( " " ); - OutText4 = " " + to_string( t->vmax, 0 ); - OutText4 = OutText4.substr( OutText4.length() - 3, - 3 ); // z wyrównaniem do prawej - // if (AnsiString(t->StationWare).Pos("@")) - OutText1 = "| " + OutText1 + " | " + OutText2 + " | " + OutText3 + - " | " + OutText4 + " | " + t->StationWare; - glRasterPos2f( -0.25f, - 0.18f - 0.02f * ( i - tmp->Mechanik->iStationStart ) ); - if( ( tmp->Mechanik->iStationStart < tt->StationIndex ) ? - ( i < tt->StationIndex ) : - false ) { // czas minął i odjazd był, to nazwa stacji będzie na zielono - glColor3f( 0.0f, 1.0f, 0.0f ); // zielone - glRasterPos2f( - -0.25f, - 0.18f - 0.02f * ( i - tmp->Mechanik->iStationStart ) ); // dopiero - // ustawienie - // pozycji - // ustala - // kolor, - // dziwne... - glPrint( Global::Bezogonkow( OutText1, true ).c_str() ); - glColor3f( 1.0f, 1.0f, 1.0f ); // a reszta białym - } - else // normalne wyświetlanie, bez zmiany kolorów - glPrint( Global::Bezogonkow( OutText1, true ).c_str() ); - glRasterPos2f( -0.25f, - 0.17f - 0.02f * ( i - tmp->Mechanik->iStationStart ) ); - glPrint( "|----------------------------|-------|-------|-----|" ); - } - } - } - OutText1 = OutText2 = OutText3 = OutText4 = ""; - } - else if( OutText1 != "" ) { // ABu: i od razu czyszczenie tego, co bylo napisane - // glTranslatef(0.0f,0.0f,-0.50f); - glRasterPos2f( -0.25f, 0.20f ); - glPrint( OutText1.c_str() ); - OutText1 = ""; - if( OutText2 != "" ) { - glRasterPos2f( -0.25f, 0.19f ); - glPrint( OutText2.c_str() ); - OutText2 = ""; - } - if( OutText3 != "" ) { - glRasterPos2f( -0.25f, 0.18f ); - glPrint( OutText3.c_str() ); - OutText3 = ""; - if( OutText4 != "" ) { - glRasterPos2f( -0.25f, 0.17f ); - glPrint( OutText4.c_str() ); - OutText4 = ""; - } - } - } - // if ((Global::iTextMode!=GLFW_KEY_F3)) - { // stenogramy dźwięków (ukryć, gdy tabelka skanowania lub rozkład?) -/* - glColor3f( 1.0f, 1.0f, 0.0f ); //żółte - for( int i = 0; i < 5; ++i ) { // kilka linijek - if( Global::asTranscript[ i ].empty() ) - break; // dalej nie trzeba - else { - glRasterPos2f( -0.20f, -0.05f - 0.01f * i ); - glPrint( Global::Bezogonkow( Global::asTranscript[ i ] ).c_str() ); - } - } -*/ - int i = 0; - for( auto const &transcript : Global::tranTexts.aLines ) { - - if( Global::fTimeAngleDeg >= transcript.fShow ) { - - cParser parser( transcript.asText ); - while( true == parser.getTokens(1, false, "|") ) { - - std::string transcriptline; parser >> transcriptline; - ::glColor3f( 1.0f, 1.0f, 0.0f ); //żółte - ::glRasterPos2f( -0.20f, -0.05f - 0.01f * i ); - glPrint( transcriptline.c_str() ); - ++i; - } } } } } - // if (Global::iViewMode!=Global::iTextMode) - //{//Ra: taka maksymalna prowizorka na razie - // WriteLog("Pressed function key F"+AnsiString(Global::iViewMode-111)); - // Global::iTextMode=Global::iViewMode; - //} - glEnable( GL_LIGHTING ); +#endif + + // update the ui header texts + auto &headerdata = UIHeader->text_lines; + headerdata[ 0 ].data = OutText1; + headerdata[ 1 ].data = OutText2; + headerdata[ 2 ].data = OutText3; + headerdata[ 3 ].data = OutText4; + + { // stenogramy dźwięków (ukryć, gdy tabelka skanowania lub rozkład?) + auto &transcripts = UITranscripts->text_lines; + transcripts.clear(); + for( auto const &transcript : Global::tranTexts.aLines ) { + + if( Global::fTimeAngleDeg >= transcript.fShow ) { + + cParser parser( transcript.asText ); + while( true == parser.getTokens(1, false, "|") ) { + + std::string transcriptline; parser >> transcriptline; + transcripts.emplace_back( transcriptline, float4( 1.0f, 1.0f, 0.0f, 1.0f ) ); + } + } + } + } } //--------------------------------------------------------------------------- @@ -2921,8 +2259,75 @@ void TWorld::CabChange(TDynamicObject *old, TDynamicObject *now) if (Train->Dynamic() == old) Global::changeDynObj = now; // uruchomienie protezy }; + +void TWorld::ChangeDynamic() { + + // Ra: to nie może być tak robione, to zbytnia proteza jest + Train->Silence(); // wyłączenie dźwięków opuszczanej kabiny + if( Train->Dynamic()->Mechanik ) // AI może sobie samo pójść + if( !Train->Dynamic()->Mechanik->AIControllFlag ) // tylko jeśli ręcznie prowadzony + { // jeśli prowadzi AI, to mu nie robimy dywersji! + Train->Dynamic()->MoverParameters->CabDeactivisation(); + Train->Dynamic()->Controller = AIdriver; + // Train->Dynamic()->MoverParameters->SecuritySystem.Status=0; //rozwala CA w EZT + Train->Dynamic()->MoverParameters->ActiveCab = 0; + Train->Dynamic()->MoverParameters->BrakeLevelSet( + Train->Dynamic()->MoverParameters->Handle->GetPos( + bh_NP ) ); //rozwala sterowanie hamulcem GF 04-2016 + Train->Dynamic()->MechInside = false; + } + TDynamicObject *temp = Global::changeDynObj; + Train->Dynamic()->bDisplayCab = false; + Train->Dynamic()->ABuSetModelShake( vector3( 0, 0, 0 ) ); + + if( Train->Dynamic()->Mechanik ) // AI może sobie samo pójść + if( !Train->Dynamic()->Mechanik->AIControllFlag ) // tylko jeśli ręcznie prowadzony + Train->Dynamic()->Mechanik->MoveTo( temp ); // przsunięcie obiektu zarządzającego + + Train->DynamicSet( temp ); + Controlled = temp; + mvControlled = Controlled->ControlledFind()->MoverParameters; + Global::asHumanCtrlVehicle = Train->Dynamic()->GetName(); + if( Train->Dynamic()->Mechanik ) // AI może sobie samo pójść + if( !Train->Dynamic()->Mechanik->AIControllFlag ) // tylko jeśli ręcznie prowadzony + { + Train->Dynamic()->MoverParameters->LimPipePress = + Controlled->MoverParameters->PipePress; + Train->Dynamic() + ->MoverParameters->CabActivisation(); // załączenie rozrządu (wirtualne kabiny) + Train->Dynamic()->Controller = Humandriver; + Train->Dynamic()->MechInside = true; + } + Train->InitializeCab( Train->Dynamic()->MoverParameters->CabNo, + Train->Dynamic()->asBaseDir + + Train->Dynamic()->MoverParameters->TypeName + ".mmd" ); + if( !FreeFlyModeFlag ) { + Global::pUserDynamic = Controlled; // renerowanie względem kamery + Train->Dynamic()->bDisplayCab = true; + Train->Dynamic()->ABuSetModelShake( + vector3( 0, 0, 0 ) ); // zerowanie przesunięcia przed powrotem? + Train->MechStop(); + FollowView(); // na pozycję mecha + } + Global::changeDynObj = NULL; +} //--------------------------------------------------------------------------- +void +TWorld::ToggleDaylight() { + + Global::FakeLight = !Global::FakeLight; + + if( Global::FakeLight ) { + // for fake daylight enter fixed hour + Environment.time( 10, 30, 0 ); + } + else { + // local clock based calculation + Environment.time(); + } +} + void world_environment::init() { @@ -2993,7 +2398,8 @@ world_environment::render() { } World.shader.set_ambient(Global::daylight.ambient); - World.shader.set_light(0, gl_program_light::DIR, Global::daylight.position, Global::daylight.direction, 0.0f, 0.0f, Global::daylight.color, 0.0f, 0.0f); + World.shader.set_light(0, gl_program_light::DIR, Global::daylight.position, Global::daylight.direction, + 0.0f, 0.0f, Global::daylight.color * Global::daylight.intensity, 0.0f, 0.0f); ::glPopMatrix(); ::glDepthMask( GL_TRUE ); @@ -3001,3 +2407,9 @@ world_environment::render() { ::glEnable( GL_FOG ); ::glEnable( GL_LIGHTING ); } + +void +world_environment::time( int const Hour, int const Minute, int const Second ) { + + m_sun.setTime( Hour, Minute, Second ); +} diff --git a/World.h b/World.h index 09f85a78..128acfa6 100644 --- a/World.h +++ b/World.h @@ -18,7 +18,7 @@ http://mozilla.org/MPL/2.0/. #include "stars.h" #include "skydome.h" #include "mczapkie/mover.h" -#include "glfw/glfw3.h" +#include "renderer.h" // wrapper for environment elements -- sky, sun, stars, clouds etc class world_environment { @@ -27,6 +27,7 @@ public: void init(); void update(); void render(); + void time( int const Hour = -1, int const Minute = -1, int const Second = -1 ); private: CSkyDome m_skydome; @@ -37,6 +38,9 @@ private: class TWorld { + // NOTE: direct access is a shortcut, but world etc needs some restructuring regardless + friend opengl_renderer; + void InOutKey( bool const Near = true ); void FollowView(bool wycisz = true); void DistantView( bool const Near = false ); @@ -53,6 +57,8 @@ class TWorld void OnCommandGet(DaneRozkaz *pRozkaz); bool Update(); void TrainDelete(TDynamicObject *d = NULL); + // switches between static and dynamic daylight calculation + void ToggleDaylight(); TWorld(); ~TWorld(); // double Aspect; @@ -63,27 +69,24 @@ class TWorld std::string OutText4; void Update_Environment(); void Update_Camera( const double Deltatime ); - bool Render(); + void Update_UI(); + void ResourceSweep(); void Render_Cab(); - void Render_UI(); TCamera Camera; TGround Ground; world_environment Environment; TTrain *Train; TDynamicObject *pDynamicNearest; bool Paused{ true }; - GLuint base; // numer DL dla znaków w napisach - texture_manager::size_type light; // numer tekstury dla smugi TEvent *KeyEvents[10]; // eventy wyzwalane z klawiaury TMoverParameters *mvControlled; // wskaźnik na człon silnikowy, do wyświetlania jego parametrów - int iCheckFPS; // kiedy znów sprawdzić FPS, żeby wyłączać optymalizacji od razu do zera double fTime50Hz; // bufor czasu dla komunikacji z PoKeys double fTimeBuffer; // bufor czasu aktualizacji dla stałego kroku fizyki double fMaxDt; //[s] krok czasowy fizyki (0.01 dla normalnych warunków) double m_primaryupdaterate{ 1.0 / 100.0 }; - double m_primaryupdateaccumulator{ 0.0 }; // keeps track of elapsed simulation time, for core fixed step routines double m_secondaryupdaterate{ 1.0 / 50.0 }; - double m_secondaryupdateaccumulator{ 0.0 }; // keeps track of elapsed simulation time, for less important fixed step routines + double m_primaryupdateaccumulator{ m_secondaryupdaterate }; // keeps track of elapsed simulation time, for core fixed step routines + double m_secondaryupdateaccumulator{ m_secondaryupdaterate }; // keeps track of elapsed simulation time, for less important fixed step routines int iPause; // wykrywanie zmian w zapauzowaniu double VelPrev; // poprzednia prędkość int tprev; // poprzedni czas @@ -94,6 +97,8 @@ class TWorld void ModifyTGA(std::string const &dir = ""); void CreateE3D(std::string const &dir = "", bool dyn = false); void CabChange(TDynamicObject *old, TDynamicObject *now); + // handles vehicle change flag + void ChangeDynamic(); gl_program_light shader; //m7todo: tmp }; diff --git a/frustum.cpp b/frustum.cpp index f0244f5a..d9a9f3ad 100644 --- a/frustum.cpp +++ b/frustum.cpp @@ -11,15 +11,12 @@ http://mozilla.org/MPL/2.0/. #include "frustum.h" void -cFrustum::calculate() { +cFrustum::calculate( glm::mat4 &Projection, glm::mat4 &Modelview ) { - float proj[ 16 ]; - float modl[ 16 ]; + float *proj = &Projection[ 0 ][ 0 ]; + float *modl = &Modelview[ 0 ][ 0 ]; float clip[ 16 ]; - glGetFloatv( GL_PROJECTION_MATRIX, proj ); - glGetFloatv( GL_MODELVIEW_MATRIX, modl ); - // multiply the matrices to retrieve clipping planes clip[ 0 ] = modl[ 0 ] * proj[ 0 ] + modl[ 1 ] * proj[ 4 ] + modl[ 2 ] * proj[ 8 ] + modl[ 3 ] * proj[ 12 ]; clip[ 1 ] = modl[ 0 ] * proj[ 1 ] + modl[ 1 ] * proj[ 5 ] + modl[ 2 ] * proj[ 9 ] + modl[ 3 ] * proj[ 13 ]; diff --git a/frustum.h b/frustum.h index be8b9265..41ebb64a 100644 --- a/frustum.h +++ b/frustum.h @@ -22,7 +22,7 @@ public: // methods: // update the frustum to match current view orientation void - calculate(); + calculate(glm::mat4 &Projection, glm::mat4 &Modelview); // returns true if specified point is inside of the frustum inline bool diff --git a/lightarray.cpp b/lightarray.cpp index 3ab1c448..d37082e3 100644 --- a/lightarray.cpp +++ b/lightarray.cpp @@ -46,12 +46,12 @@ light_array::update() { // update light parameters to match current data of the owner if( light.index == 0 ) { // front light set - light.position = light.owner->GetPosition() + ( light.owner->VectorFront() * light.owner->GetLength() * 0.45 ); + light.position = light.owner->GetPosition() + ( light.owner->VectorFront() * light.owner->GetLength() * 0.4 ); light.direction = light.owner->VectorFront(); } else { // rear light set - light.position = light.owner->GetPosition() - ( light.owner->VectorFront() * light.owner->GetLength() * 0.45 ); + light.position = light.owner->GetPosition() - ( light.owner->VectorFront() * light.owner->GetLength() * 0.4 ); light.direction = light.owner->VectorFront(); light.direction.x = -light.direction.x; light.direction.z = -light.direction.z; @@ -67,8 +67,8 @@ light_array::update() { if( light.count > 0 ) { // TODO: intensity can be affected further by dim switch or other factors - light.intensity = std::max( 0.0f, std::log( (float)light.count + 1.0f ) ); -// light.intensity = std::max( 0.0f, std::log( (float)light.count + 3.0f ) ); + light.intensity = std::max( 0.0f, std::log( (float)light.count + 1.0f ) ); + light.intensity *= ( light.owner->DimHeadlights ? 0.6f : 1.0f ); } else { light.intensity = 0.0f; diff --git a/parser.cpp b/parser.cpp index f66a3e99..a9171bd3 100644 --- a/parser.cpp +++ b/parser.cpp @@ -238,6 +238,32 @@ int cParser::getProgress() const return static_cast( mStream->rdbuf()->pubseekoff(0, std::ios_base::cur) * 100 / mSize ); } +int cParser::getFullProgress() const { + + int progress = getProgress(); + if( mIncludeParser ) return progress + ( ( 100 - progress )*( mIncludeParser->getProgress() ) / 100 ); + else return progress; +} + +std::size_t cParser::countTokens( std::string const &Stream, std::string Path ) { + + return cParser( Stream, buffer_FILE, Path ).count(); +} + +std::size_t cParser::count() { + + std::string token; + size_t count{ 0 }; + do { + token = ""; + token = readToken( false ); + ++count; + } while( false == token.empty() ); + + return count - 1; +} + + void cParser::addCommentStyle( std::string const &Commentstart, std::string const &Commentend ) { mComments.insert( commentmap::value_type(Commentstart, Commentend) ); diff --git a/parser.h b/parser.h index 9dd49df8..b08d5a2b 100644 --- a/parser.h +++ b/parser.h @@ -80,6 +80,9 @@ class cParser //: public std::stringstream bool getTokens(unsigned int Count = 1, bool ToLower = true, const char *Break = "\n\r\t ;"); // returns percentage of file processed so far int getProgress() const; + int getFullProgress() const; + // + static std::size_t countTokens( std::string const &Stream, std::string Path = "" ); // add custom definition of text which should be ignored when retrieving tokens void addCommentStyle( std::string const &Commentstart, std::string const &Commentend ); @@ -91,6 +94,7 @@ class cParser //: public std::stringstream // std::string trtest; bool findQuotes( std::string &String ); bool trimComments( std::string &String ); + std::size_t count(); // members: bool LoadTraction; // load traction? std::istream *mStream; // relevant kind of buffer is attached on creation. diff --git a/renderer.cpp b/renderer.cpp index 1348a987..a6ac2e3b 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1,4 +1,4 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not @@ -8,16 +8,499 @@ http://mozilla.org/MPL/2.0/. */ #include "stdafx.h" + #include "renderer.h" #include "globals.h" #include "World.h" +#include "dynobj.h" +#include "uilayer.h" +#include "logs.h" opengl_renderer GfxRenderer; extern TWorld World; -void -opengl_renderer::Init() { +// returns true if specified object is within camera frustum, false otherwise +bool +opengl_camera::visible( bounding_area const &Area ) const { + return ( m_frustum.sphere_inside( Area.center, Area.radius ) > 0.0f ); +} + +bool +opengl_camera::visible( TDynamicObject const *Dynamic ) const { + + // sphere test is faster than AABB, so we'll use it here + float3 diagonal( + Dynamic->MoverParameters->Dim.L, + Dynamic->MoverParameters->Dim.H, + Dynamic->MoverParameters->Dim.W ); + float const radius = diagonal.Length() * 0.5f; + + return ( m_frustum.sphere_inside( Dynamic->GetPosition(), radius ) > 0.0f ); +} + +bool +opengl_renderer::Init( GLFWwindow *Window ) { + + if( false == Init_caps() ) { + + return false; + } + + m_window = Window; + + glClearDepth( 1.0f ); + glClearColor( 51.0f / 255.0f, 102.0f / 255.0f, 85.0f / 255.0f, 1.0f ); // initial background Color + + glPolygonMode( GL_FRONT, GL_FILL ); + glFrontFace( GL_CCW ); // Counter clock-wise polygons face out + glEnable( GL_CULL_FACE ); // Cull back-facing triangles + glShadeModel( GL_SMOOTH ); // Enable Smooth Shading + + glEnable( GL_DEPTH_TEST ); + glAlphaFunc( GL_GREATER, 0.04f ); + glEnable( GL_ALPHA_TEST ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glEnable( GL_BLEND ); + glEnable( GL_TEXTURE_2D ); // Enable Texture Mapping + + glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); // Really Nice Perspective Calculations + glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST ); + glHint( GL_LINE_SMOOTH_HINT, GL_NICEST ); + glLineWidth( 1.0f ); + glPointSize( 3.0f ); + glEnable( GL_POINT_SMOOTH ); + + glEnable( GL_COLOR_MATERIAL ); + glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); + + // setup lighting + GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); + glEnable( GL_LIGHTING ); + glEnable( GL_LIGHT0 ); + + // directional light + // TODO, TBD: test omni-directional variant + // rgb value for 5780 kelvin + Global::daylight.color.x = 255.0f / 255.0f; + Global::daylight.color.y = 242.0f / 255.0f; + Global::daylight.color.z = 231.0f / 255.0f; + + // setup fog + if( Global::fFogEnd > 0 ) { + // fog setup + ::glFogi( GL_FOG_MODE, GL_LINEAR ); + ::glFogfv( GL_FOG_COLOR, Global::FogColor ); + ::glFogf( GL_FOG_START, Global::fFogStart ); + ::glFogf( GL_FOG_END, Global::fFogEnd ); + ::glEnable( GL_FOG ); + } + else { ::glDisable( GL_FOG ); } + + World.shader = gl_program_light({ gl_shader("lighting.vert"), gl_shader("blinnphong.frag") }); + Global::daylight.intensity = 1.0f; //m7todo: przenieść + + return true; +} + +bool +opengl_renderer::Render() { + + auto timestart = std::chrono::steady_clock::now(); + + glUseProgram(World.shader); + + ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + ::glDepthFunc( GL_LEQUAL ); + + ::glMatrixMode( GL_PROJECTION ); // select the Projection Matrix + glm::mat4 projection = glm::perspective( + Global::FieldOfView / Global::ZoomFactor * 0.0174532925f, + std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ), + 0.1f * Global::ZoomFactor, + m_drawrange * Global::fDistanceFactor ); + ::glLoadMatrixf( &projection[0][0] ); + + ::glMatrixMode( GL_MODELVIEW ); // Select The Modelview Matrix + glm::mat4 modelview( 1.0f ); + ::glLoadIdentity(); + + if( World.InitPerformed() ) { + + World.Camera.SetMatrix( modelview ); + ::glLoadMatrixf( &modelview[ 0 ][ 0 ] ); + m_camera.update_frustum( projection, modelview ); + + if( !Global::bWireFrame ) { + // bez nieba w trybie rysowania linii + World.Environment.render(); + } + + glDebug("rendering ground"); + World.Ground.Render( World.Camera.Pos ); + + glDebug("rendering cab"); + World.Render_Cab(); + + // accumulate last 20 frames worth of render time (cap at 1000 fps to prevent calculations going awry) + m_drawtime = std::max( 20.0f, 0.95f * m_drawtime + std::chrono::duration_cast( ( std::chrono::steady_clock::now() - timestart ) ).count()); + } + + glUseProgram(0); + UILayer.render(); + + glfwSwapBuffers( m_window ); + return true; // for now always succeed +} + +#ifndef EU07_USE_OLD_RENDERCODE +bool +opengl_renderer::Render( TGround *Ground ) { + + glDisable( GL_BLEND ); + glAlphaFunc( GL_GREATER, 0.35f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + glEnable( GL_LIGHTING ); + glColor3f( 1.0f, 1.0f, 1.0f ); + + float3 const cameraposition = float3( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z ); + int const camerax = std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2; + int const cameraz = std::floor( cameraposition.z / 1000.0f ) + iNumRects / 2; + int const segmentcount = 2 * static_cast(std::ceil( m_drawrange * Global::fDistanceFactor / 1000.0f )); + int const originx = std::max( 0, camerax - segmentcount / 2 ); + int const originz = std::max( 0, cameraz - segmentcount / 2 ); + + 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(); + } + } + } + + return true; +} + +bool +opengl_renderer::Render( TDynamicObject *Dynamic ) { + + if( false == m_camera.visible( Dynamic ) ) { + + Dynamic->renderme = false; + return false; + } + + Dynamic->renderme = true; + + TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji + double squaredistance = SquareMagnitude( Global::pCameraPosition - Dynamic->vPosition ) / 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 + ::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 + + ::glMultMatrixd( Dynamic->mMatrix.getArray() ); + + if( Dynamic->fShade > 0.0f ) { + // change light level based on light level of the occupied track + Global::daylight.intensity = Dynamic->fShade; + } + + // TODO: implement universal render path down the road + if( Global::bUseVBO ) { + // wersja VBO + if( Dynamic->mdLowPolyInt ) { + if( FreeFlyModeFlag ? true : !Dynamic->mdKabina || !Dynamic->bDisplayCab ) { + // enable cab light if needed + 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 ); + } + + Dynamic->mdLowPolyInt->RaRender( squaredistance, Dynamic->Material()->replacable_skins, Dynamic->Material()->textures_alpha ); + + if( Dynamic->InteriorLightLevel > 0.0f ) { + // reset the overall ambient + GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); + } + } + } + + Dynamic->mdModel->RaRender( squaredistance, Dynamic->Material()->replacable_skins, Dynamic->Material()->textures_alpha ); + + if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku + Dynamic->mdLoad->RaRender( squaredistance, Dynamic->Material()->replacable_skins, Dynamic->Material()->textures_alpha ); + } + else { + // wersja Display Lists + if( Dynamic->mdLowPolyInt ) { + // low poly interior + if( FreeFlyModeFlag ? true : !Dynamic->mdKabina || !Dynamic->bDisplayCab ) { + // enable cab light if needed + 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 ); + } + + Render( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance ); + + if( Dynamic->InteriorLightLevel > 0.0f ) { + // reset the overall ambient + GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); + } + } + } + + Render( Dynamic->mdModel, Dynamic->Material(), squaredistance ); + + if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku + Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance ); + } + + if( Dynamic->fShade > 0.0f ) { + // restore regular light level + Global::daylight.intensity = 1.0f; + } + + ::glPopMatrix(); + + // TODO: check if this reset is needed. In theory each object should render all parts based on its own instance data anyway? + if( Dynamic->btnOn ) + Dynamic->TurnOff(); // przywrócenie domyślnych pozycji submodeli + + return true; +} + +bool +opengl_renderer::Render( TModel3d *Model, material_data const *Material, double const Squaredistance ) { + + auto alpha = + ( Material != nullptr ? + Material->textures_alpha : + 0x30300030 ); + alpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste + if( 0 == ( alpha & Model->iFlags & 0x1F1F001F ) ) { + // czy w ogóle jest co robić w tym cyklu? + return false; + } + + Model->Root->fSquareDist = Squaredistance; // zmienna globalna! + + Model->Root->ReplacableSet( + ( Material != nullptr ? + Material->replacable_skins : + nullptr ), + alpha ); + + Model->Root->RenderDL(); + + return true; +} + +bool +opengl_renderer::Render( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ) { + + ::glPushMatrix(); + ::glTranslated( Position.x, Position.y, Position.z ); + if( Angle.y != 0.0 ) + ::glRotated( Angle.y, 0.0, 1.0, 0.0 ); + if( Angle.x != 0.0 ) + ::glRotated( Angle.x, 1.0, 0.0, 0.0 ); + if( Angle.z != 0.0 ) + ::glRotated( Angle.z, 0.0, 0.0, 1.0 ); + + auto const result = Render( Model, Material, SquareMagnitude( Position - Global::GetCameraPosition() ) ); + + ::glPopMatrix(); + + return result; +} + +bool +opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { + + if( false == Dynamic->renderme ) { + + return false; + } + + TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji + double squaredistance = SquareMagnitude( Global::pCameraPosition - Dynamic->vPosition ); + 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 + + ::glMultMatrixd( Dynamic->mMatrix.getArray() ); + // wersja Display Lists + // NOTE: VBO path is removed + // TODO: implement universal render path down the road + if( Dynamic->mdLowPolyInt ) { + // low poly interior + if( FreeFlyModeFlag ? true : !Dynamic->mdKabina || !Dynamic->bDisplayCab ) { + // enable cab light if needed + 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 ); + } + + Render_Alpha( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance ); + + if( Dynamic->InteriorLightLevel > 0.0f ) { + // reset the overall ambient + GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); + } + } + } + + Render_Alpha( Dynamic->mdModel, Dynamic->Material(), squaredistance ); + + if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku + Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance ); + + ::glPopMatrix(); + + if( Dynamic->btnOn ) + Dynamic->TurnOff(); // przywrócenie domyślnych pozycji submodeli + + return true; +} + +bool +opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance ) { + + auto alpha = + ( Material != nullptr ? + Material->textures_alpha : + 0x30300030 ); + + if( 0 == ( alpha & Model->iFlags & 0x2F2F002F ) ) { + // nothing to render + return false; + } + + Model->Root->fSquareDist = Squaredistance; // zmienna globalna! + + Model->Root->ReplacableSet( + ( Material != nullptr ? + Material->replacable_skins : + nullptr ), + alpha ); + + Model->Root->RenderAlphaDL(); + + return true; +} + +bool +opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ) { + + ::glPushMatrix(); + ::glTranslated( Position.x, Position.y, Position.z ); + if( Angle.y != 0.0 ) + ::glRotated( Angle.y, 0.0, 1.0, 0.0 ); + if( Angle.x != 0.0 ) + ::glRotated( Angle.x, 1.0, 0.0, 0.0 ); + 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() ) ); + + ::glPopMatrix(); + + return result; +} +#endif + +void +opengl_renderer::Update ( double const Deltatime ) { + + m_updateaccumulator += Deltatime; + + if( m_updateaccumulator < 1.0 ) { + // too early for any work + return; + } + + m_updateaccumulator = 0.0; + + // adjust draw ranges etc, based on recent performance + auto const framerate = 1000.0f / (m_drawtime / 20.0f); + + // NOTE: until we have quadtree in place we have to rely on the legacy rendering + // once this is resolved we should be able to simply adjust draw range + int targetsegments; + float targetfactor; + + if( framerate > 65.0 ) { targetsegments = 400; targetfactor = 3.0f; } + else if( framerate > 40.0 ) { targetsegments = 225; targetfactor = 1.5f; } + else if( framerate > 15.0 ) { targetsegments = 90; targetfactor = Global::ScreenHeight / 768.0f; } + else { targetsegments = 9; targetfactor = Global::ScreenHeight / 768.0f * 0.75f; } + + if( targetsegments > Global::iSegmentsRendered ) { + + Global::iSegmentsRendered = std::min( targetsegments, Global::iSegmentsRendered + 5 ); + } + else if( targetsegments < Global::iSegmentsRendered ) { + + Global::iSegmentsRendered = std::max( targetsegments, Global::iSegmentsRendered - 5 ); + } + if( targetfactor > Global::fDistanceFactor ) { + + Global::fDistanceFactor = std::min( targetfactor, Global::fDistanceFactor + 0.05f ); + } + else if( targetfactor < Global::fDistanceFactor ) { + + Global::fDistanceFactor = std::max( targetfactor, Global::fDistanceFactor - 0.05f ); + } + + if( ( framerate < 15.0 ) && ( Global::iSlowMotion < 7 ) ) { + Global::iSlowMotion = ( Global::iSlowMotion << 1 ) + 1; // zapalenie kolejnego bitu + if( Global::iSlowMotionMask & 1 ) + if( Global::iMultisampling ) // a multisampling jest włączony + ::glDisable( GL_MULTISAMPLE ); // wyłączenie multisamplingu powinno poprawić FPS + } + else if( ( framerate > 20.0 ) && Global::iSlowMotion ) { // FPS się zwiększył, można włączyć bajery + Global::iSlowMotion = ( Global::iSlowMotion >> 1 ); // zgaszenie bitu + if( Global::iSlowMotion == 0 ) // jeśli jest pełna prędkość + if( Global::iMultisampling ) // a multisampling jest włączony + ::glEnable( GL_MULTISAMPLE ); + } + + // TODO: add garbage collection and other less frequent works here + if( DebugModeFlag ) + m_debuginfo = m_textures.Info(); +}; + +// debug performance string +std::string const & +opengl_renderer::Info() const { + + return m_debuginfo; } void @@ -66,4 +549,35 @@ opengl_renderer::Disable_Lights() { World.shader.set_light_count(0); } + +bool +opengl_renderer::Init_caps() { + + std::string oglversion = ( (char *)glGetString( GL_VERSION ) ); + + WriteLog( + "Gfx Renderer: " + std::string( (char *)glGetString( GL_RENDERER ) ) + + " Vendor: " + std::string( (char *)glGetString( GL_VENDOR ) ) + + " OpenGL Version: " + oglversion ); + + if( !GLEW_VERSION_1_4 ) { + ErrorLog( "Requires openGL >= 1.4" ); + return false; + } + + WriteLog( "Supported extensions:" + std::string((char *)glGetString( GL_EXTENSIONS )) ); + + if( Global::iMultisampling ) + WriteLog( "Using multisampling x" + std::to_string( 1 << Global::iMultisampling ) ); + { // ograniczenie maksymalnego rozmiaru tekstur - parametr dla skalowania tekstur + GLint i; + glGetIntegerv( GL_MAX_TEXTURE_SIZE, &i ); + if( i < Global::iMaxTextureSize ) + Global::iMaxTextureSize = i; + WriteLog( "Texture sizes capped at " + std::to_string( Global::iMaxTextureSize ) + " pixels" ); + + } + + return true; +} //--------------------------------------------------------------------------- diff --git a/renderer.h b/renderer.h index d5cc2750..df63534d 100644 --- a/renderer.h +++ b/renderer.h @@ -1,4 +1,4 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not @@ -9,10 +9,13 @@ http://mozilla.org/MPL/2.0/. #pragma once -#include "GL/glew.h" +#include #include "texture.h" #include "lightarray.h" #include "dumb3d.h" +#include "frustum.h" +#include "ground.h" +#include "shader.h" // encapsulates basic rendering setup. // for modern opengl this translates to a specific collection of glsl shaders, @@ -28,6 +31,24 @@ struct opengl_material { }; +// simple camera object. paired with 'virtual camera' in the scene +class opengl_camera { + +public: +// methods: + inline + void + update_frustum(glm::mat4 &Projection, glm::mat4 &Modelview) { m_frustum.calculate(Projection, Modelview); } + bool + visible( bounding_area const &Area ) const; + bool + visible( TDynamicObject const *Dynamic ) const; + +private: +// members: + cFrustum m_frustum; +}; + // bare-bones render controller, in lack of anything better yet class opengl_renderer { @@ -35,14 +56,40 @@ public: // types // methods + bool + Init( GLFWwindow *Window ); + // main draw call. returns false on error + bool + Render(); +#ifndef EU07_USE_OLD_RENDERCODE + bool + Render( TGround *Ground ); + bool + Render( TDynamicObject *Dynamic ); + bool + Render( TModel3d *Model, material_data const *Material, double const Squaredistance ); + bool + Render( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); + bool + Render_Alpha( TDynamicObject *Dynamic ); + bool + Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance ); + bool + Render_Alpha( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); +#endif + // maintenance jobs void - Init(); - + Update( double const Deltatime); void Update_Lights( light_array const &Lights ); - void Disable_Lights(); + inline + bool + Visible( TDynamicObject const *Dynamic ) const { return m_camera.visible( Dynamic ); } + // debug performance string + std::string const & + Info() const; texture_manager::size_type GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ) { @@ -70,10 +117,19 @@ private: enum class rendermode { color }; + +// methods + bool Init_caps(); // members rendermode renderpass{ rendermode::color }; texture_manager m_textures; + opengl_camera m_camera; + float m_drawrange{ 2500.0f }; // current drawing range + float m_drawtime{ 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps + double m_updateaccumulator{ 0.0 }; + std::string m_debuginfo; + GLFWwindow *m_window{ nullptr }; }; extern opengl_renderer GfxRenderer; diff --git a/sky.cpp b/sky.cpp index 7c3aa79f..fa9baa14 100644 --- a/sky.cpp +++ b/sky.cpp @@ -41,13 +41,18 @@ void TSky::Render( float3 const &Tint ) #endif if (Global::bUseVBO) { // renderowanie z VBO - mdCloud->RaRender(100, 0); + mdCloud->RaRender( 100, 0 ); mdCloud->RaRenderAlpha(100, 0); } else { // renderowanie z Display List +#ifdef EU07_USE_OLD_RENDERCODE mdCloud->Render(100, 0); mdCloud->RenderAlpha(100, 0); +#else + GfxRenderer.Render( mdCloud, nullptr, 100.0 ); + GfxRenderer.Render_Alpha( mdCloud, nullptr, 100.0 ); +#endif } #ifdef EU07_USE_OLD_LIGHTING_MODEL glPopMatrix(); diff --git a/stars.cpp b/stars.cpp index 451d6aa0..1dafcdcb 100644 --- a/stars.cpp +++ b/stars.cpp @@ -21,7 +21,11 @@ cStars::render() { ::glRotatef( -std::fmod( Global::fTimeAngleDeg, 360.0f ), 0.0f, 1.0f, 0.0f ); // obrót dobowy osi OX ::glPointSize( 2.0f ); +#ifdef EU07_USE_OLD_RENDERCODE m_stars.Render( 1.0 ); +#else + GfxRenderer.Render( &m_stars, nullptr, 1.0 ); +#endif ::glPointSize( 3.0f ); ::glPopMatrix(); diff --git a/stdafx.h b/stdafx.h index 98658b8f..e6a33fd7 100644 --- a/stdafx.h +++ b/stdafx.h @@ -60,14 +60,24 @@ #include #include +#ifdef EU07_BUILD_STATIC +#define GLEW_STATIC +#else +#ifdef _WINDOWS +#define GLFW_DLL +#endif // _windows +#endif // build_static #include "GL/glew.h" #ifdef _WINDOWS #include "GL/wglew.h" -#define GLFW_DLL #endif #define GLFW_INCLUDE_GLU //m7todo: jest tu bo nie chciao mi si wpycha do wszystkich plikw #include #include #include -#include \ No newline at end of file +#include + +#define STRINGIZE_DETAIL(x) #x +#define STRINGIZE(x) STRINGIZE_DETAIL(x) +#define glDebug(x) if (GLEW_GREMEDY_string_marker) glStringMarkerGREMEDY(0, __FILE__ ":" STRINGIZE(__LINE__) ": " x); \ No newline at end of file diff --git a/sun.cpp b/sun.cpp index b21ef312..4a5699c2 100644 --- a/sun.cpp +++ b/sun.cpp @@ -3,6 +3,7 @@ #include "sun.h" #include "globals.h" #include "mtable.h" +#include "usefull.h" ////////////////////////////////////////////////////////////////////////////////////////// // cSun -- class responsible for dynamic calculation of position and intensity of the Sun, @@ -94,6 +95,14 @@ void cSun::setLocation( float const Longitude, float const Latitude ) { m_observer.latitude = (int)Latitude + (Latitude - (int)(Latitude)) * 100.0 / 60.0 ; } +// sets current time, overriding one acquired from the system clock +void cSun::setTime( int const Hour, int const Minute, int const Second ) { + + m_observer.hour = clamp( Hour, -1, 23 ); + m_observer.minute = clamp( Minute, 0, 59 ); + m_observer.second = clamp( Second, 0, 59 ); +} + void cSun::setTemperature( float const Temperature ) { m_observer.temp = Temperature; @@ -112,6 +121,10 @@ void cSun::move() { SYSTEMTIME localtime; // time for the calculation time( &localtime ); + if( m_observer.hour >= 0 ) { localtime.wHour = m_observer.hour; } + if( m_observer.minute >= 0 ) { localtime.wMinute = m_observer.minute; } + if( m_observer.second >= 0 ) { localtime.wSecond = m_observer.second; } + double ut = localtime.wHour + localtime.wMinute / 60.0 // too low resolution, noticeable skips + localtime.wSecond / 3600.0; // good enough in normal circumstances diff --git a/sun.h b/sun.h index 03711464..e15abbbf 100644 --- a/sun.h +++ b/sun.h @@ -27,6 +27,8 @@ public: float getAngle(); // returns current intensity of the sun float getIntensity(); + // sets current time, overriding one acquired from the system clock + void setTime( int const Hour, int const Minute, int const Second ); // sets current geographic location void setLocation( float const Longitude, float const Latitude ); // sets ambient temperature in degrees C. @@ -87,7 +89,10 @@ protected: double latitude; // latitude, degrees north (south negative) double longitude; // longitude, degrees east (west negative) - double utime; // universal (Greenwich) standard time + int hour{ -1 }; // current time, used for calculation of utime. if set to -1, time for + int minute{ -1 };// calculation will be obtained from the local clock + int second{ -1 }; + double utime; // universal (Greenwich) standard time double timezone; // time zone, east (west negative). USA: Mountain = -7, Central = -6, etc. double gmst; // Greenwich mean sidereal time, hours double lmst; // local mean sidereal time, degrees diff --git a/uilayer.cpp b/uilayer.cpp new file mode 100644 index 00000000..315c5465 --- /dev/null +++ b/uilayer.cpp @@ -0,0 +1,232 @@ +#include "stdafx.h" +#include "uilayer.h" +#include "globals.h" +#include "usefull.h" +#include "renderer.h" +#include "logs.h" + +#include + +ui_layer UILayer; + +extern "C" +{ + GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); //m7todo: potrzebne do directsound +} + +ui_layer::~ui_layer() { +/* +// this should be invoked manually, or we risk trying to delete the lists after the context is gone + if( m_fontbase != -1 ) + ::glDeleteLists( m_fontbase, 96 ); +*/ +} + +bool +ui_layer::init( GLFWwindow *Window ) { + + if (Global::bGlutFont) + { + int zi = 0; + char zc = 0; + char *zcp = &zc; + glutInit(&zi, &zcp); + WriteLog("Used font from GLUT."); + Global::DLFont = true; + return true; + } + + HFONT font; // Windows Font ID + m_fontbase = ::glGenLists(96); // storage for 96 characters + HDC hDC = ::GetDC( glfwGetWin32Window( Window ) ); + font = ::CreateFont( -MulDiv( 10, ::GetDeviceCaps( hDC, LOGPIXELSY ), 72 ), // height of font + 0, // width of font + 0, // angle of escapement + 0, // orientation angle + FW_MEDIUM, // font weight + FALSE, // italic + FALSE, // underline + FALSE, // strikeout + DEFAULT_CHARSET, // character set identifier + OUT_DEFAULT_PRECIS, // output precision + CLIP_DEFAULT_PRECIS, // clipping precision + CLEARTYPE_QUALITY, // output quality + DEFAULT_PITCH | FF_DONTCARE, // family and pitch + "Lucida Console"); // font name + ::SelectObject(hDC, font); // selects the font we want + if (wglUseFontBitmaps( hDC, 32, 96, m_fontbase )) { + // builds 96 characters starting at character 32 + WriteLog( "Display Lists font used" ); //+AnsiString(glGetError()) + WriteLog( "Font init OK" ); //+AnsiString(glGetError()) + Global::DLFont = true; + return true; + } + else { + ErrorLog( "Font init failed" ); +// return false; + // NOTE: we report success anyway, given some cards can't produce fonts in this manner + Global::DLFont = false; + return true; + } +} + +void +ui_layer::render() { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho( 0.f, Global::ScreenWidth, Global::ScreenHeight, 0.f, -1.f, 1.f ); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT ); + glDisable( GL_LIGHTING ); + glDisable( GL_DEPTH_TEST ); + glDisable( GL_ALPHA_TEST ); + glEnable( GL_BLEND ); + + // render code here + render_background(); + render_progress(); + render_panels(); + + glPopAttrib(); +} + +void +ui_layer::set_progress( float const Progress, float const Subtaskprogress ) { + + m_progress = Progress * 0.01f; + m_subtaskprogress = Subtaskprogress * 0.01f; +} + +void +ui_layer::set_background( std::string const &Filename ) { + + if( false == Filename.empty() ) { + + m_background = GfxRenderer.GetTextureId( Filename, szTexturePath ); + } + else { + + m_background = 0; + } +} +/* +void cGuiLayer::setNote( const std::string Note ) { mNote = Note; } + +std::string cGuiLayer::getNote() { return mNote; } +*/ +void +ui_layer::render_progress() { + + if( (m_progress == 0.0f) && (m_subtaskprogress == 0.0f) ) return; + + glPushAttrib( GL_ENABLE_BIT ); + glDisable( GL_TEXTURE_2D ); + + quad( float4( 75.0f, 640.0f, 75.0f + 320.0f, 640.0f + 16.0f ), float4(0.0f, 0.0f, 0.0f, 0.25f) ); + // secondary bar + if( m_subtaskprogress ) { + quad( + float4( 75.0f, 640.0f, 75.0f + 320.0f * m_subtaskprogress, 640.0f + 16.0f), + float4( 8.0f/255.0f, 160.0f/255.0f, 8.0f/255.0f, 0.35f ) ); + } + // primary bar + if( m_progress ) { + quad( + float4( 75.0f, 640.0f, 75.0f + 320.0f * m_progress, 640.0f + 16.0f ), + float4( 8.0f / 255.0f, 160.0f / 255.0f, 8.0f / 255.0f, 1.0f ) ); + } + + glPopAttrib(); +} + +void +ui_layer::render_panels() { + + if( m_panels.empty() ) { return; } + + glPushAttrib( GL_ENABLE_BIT ); + glDisable( GL_TEXTURE_2D ); + + float const width = std::min( 4.0f / 3.0f, static_cast(Global::iWindowWidth) / Global::iWindowHeight ) * Global::iWindowHeight; + float const height = Global::iWindowHeight / 768.0; + + for( auto const &panel : m_panels ) { + + int lineidx = 0; + for( auto const &line : panel->text_lines ) { + + ::glColor4fv( &line.color.x ); + ::glRasterPos2f( + 0.5 * ( Global::iWindowWidth - width ) + panel->origin_x * height, + panel->origin_y * height + 20.0 * lineidx ); + print( line.data ); + ++lineidx; + } + } + + glPopAttrib(); +} + +void +ui_layer::render_background() { + + if( m_background == 0 ) return; + + // NOTE: we limit/expect the background to come with 4:3 ratio. + // TODO, TBD: if we expose texture width or ratio from texture object, this limitation could be lifted + + GfxRenderer.Bind( m_background ); + quad( float4( 0.0f, 0.0f, 1024.0f, 768.0f ), float4( 1.0f, 1.0f, 1.0f, 1.0f ) ); +} + +void +ui_layer::print( std::string const &Text ) +{ + if( (false == Global::DLFont) + || (true == Text.empty()) ) + return; + + if (Global::bGlutFont) + { + for (size_t i = 0; i < Text.size(); i++) + glutBitmapCharacter(GLUT_BITMAP_8_BY_13, Text[i]); + } + else + { + ::glPushAttrib(GL_LIST_BIT); + + ::glListBase(m_fontbase - 32); + ::glCallLists((GLsizei)Text.size(), GL_UNSIGNED_BYTE, Text.c_str()); + + ::glPopAttrib(); + } +} + +void +ui_layer::quad( float4 const &Coordinates, float4 const &Color ) { + + float const screenratio = static_cast( Global::iWindowWidth ) / Global::iWindowHeight; + float const width = + ( screenratio >= (4.0f/3.0f) ? + ( 4.0f / 3.0f ) * Global::iWindowHeight : + Global::iWindowWidth ); + float const heightratio = + ( screenratio >= ( 4.0f / 3.0f ) ? + Global::iWindowHeight / 768.0 : + Global::iWindowHeight / 768.0 * screenratio / ( 4.0f / 3.0f ) ); + float const height = 768.0f * heightratio; + + glColor4fv(&Color.x); + + glBegin( GL_TRIANGLE_STRIP ); + + glTexCoord2f( 0.0f, 1.0f ); glVertex2f( 0.5 * ( Global::iWindowWidth - width ) + Coordinates.x * heightratio, 0.5 * ( Global::iWindowHeight - height ) + Coordinates.y * heightratio ); + glTexCoord2f( 0.0f, 0.0f ); glVertex2f( 0.5 * ( Global::iWindowWidth - width ) + Coordinates.x * heightratio, 0.5 * ( Global::iWindowHeight - height ) + Coordinates.w * heightratio ); + glTexCoord2f( 1.0f, 1.0f ); glVertex2f( 0.5 * ( Global::iWindowWidth - width ) + Coordinates.z * heightratio, 0.5 * ( Global::iWindowHeight - height ) + Coordinates.y * heightratio ); + glTexCoord2f( 1.0f, 0.0f ); glVertex2f( 0.5 * ( Global::iWindowWidth - width ) + Coordinates.z * heightratio, 0.5 * ( Global::iWindowHeight - height ) + Coordinates.w * heightratio ); + + glEnd(); +} diff --git a/uilayer.h b/uilayer.h new file mode 100644 index 00000000..8966ec8b --- /dev/null +++ b/uilayer.h @@ -0,0 +1,86 @@ + +#pragma once + +#include +#include "texture.h" +#include "float3d.h" + +// GuiLayer -- basic user interface class. draws requested information on top of openGL screen + +struct ui_panel { + + struct text_line { + + float4 color; + std::string data; + + text_line( std::string const &Data, float4 const &Color): + data(Data), color(Color) + {} + }; + + ui_panel( const int X, const int Y): + origin_x(X), origin_y(Y) + {} + + std::vector text_lines; + float origin_x; + float origin_y; +}; + +class ui_layer { + +public: +// parameters: + +// constructors: + +// destructor: + ~ui_layer(); + +// methods: + bool + init( GLFWwindow *Window ); + // draws requested UI elements + void + render(); + // stores operation progress + void + set_progress( float const Progress = 0.0f, float const Subtaskprogress = 0.0f ); + // sets the ui background texture, if any + void + set_background( std::string const &Filename = "" ); + void + clear_texts() { m_panels.clear(); } + void + push_back( std::shared_ptr Panel ) { m_panels.emplace_back( Panel ); } + +// members: + +private: +// methods: + // draws background quad with specified earlier texture + void + render_background(); + // draws a progress bar in defined earlier state + void + render_progress(); + void + render_panels(); + // prints specified text, using display lists font + void + print( std::string const &Text ); + // draws a quad between coordinates x,y and z,w with uv-coordinates spanning 0-1 + void + quad( float4 const &Coordinates, float4 const &Color ); + + +// members: + GLuint m_fontbase{ (GLuint)-1 }; // numer DL dla znakw w napisach + float m_progress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. + float m_subtaskprogress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. + texture_manager::size_type m_background; // path to texture used as the background. size depends on mAspect. + std::vector > m_panels; +}; + +extern ui_layer UILayer;