diff --git a/EU07.cpp b/EU07.cpp index d32294d1..d97b4b27 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -188,7 +188,7 @@ void focus_callback( GLFWwindow *window, int focus ) void scroll_callback( GLFWwindow* window, double xoffset, double yoffset ) { - if( DebugModeFlag && Global::ctrlState ) { + 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 ); } diff --git a/Globals.cpp b/Globals.cpp index 826c8640..a8221a28 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -162,8 +162,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 @@ -941,10 +941,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 diff --git a/Ground.cpp b/Ground.cpp index 1fa5180d..59421974 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -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 * 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 * 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() @@ -4826,26 +4933,31 @@ bool TGround::GetTraction(TDynamicObject *model) }; bool -TGround::Render( Math3D::vector3 const &Camera ) { +TGround::Render_Hidden( Math3D::vector3 const &Camera ) { GfxRenderer.Update_Lights( m_lights ); -/* - if( Global::bUseVBO ) { // renderowanie przez VBO - if( !RenderVBO( Camera ) ) - return false; - if( !RenderAlphaVBO( Camera ) ) - return false; - } - else { -*/ - // renderowanie przez Display List - if( !RenderDL( Camera ) ) - return false; - if( !RenderAlphaDL( Camera ) ) - return false; -/* - } -*/ + + ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji) + + TGroundNode *node; + int n = 2 * iNumSubRects; //(2*==2km) promień wyświetlanej mapy w sektorach + int c = GetColFromX( Camera.x ); + int r = GetRowFromZ( Camera.z ); + TSubRect *tmp; + for( node = srGlobal.nRenderHidden; node; node = node->nNext3 ) + node->RenderHidden(); // rednerowanie globalnych (nie za często?) + int i, j, k; + // renderowanie czołgowe dla obiektów aktywnych a niewidocznych + for( j = r - n; j <= r + n; j++ ) + for( i = c - n; i <= c + n; i++ ) + if( ( tmp = FastGetSubRect( i, j ) ) != NULL ) { + tmp->LoadNodes(); // oznaczanie aktywnych sektorów + for( node = tmp->nRenderHidden; node; node = node->nNext3 ) + node->RenderHidden(); + tmp->RenderSounds(); // jeszcze dźwięki pojazdów by się przydały, również + // niewidocznych + } + return true; } @@ -4897,8 +5009,11 @@ 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) if (tmp->iNodeCount) // o ile są jakieś obiekty, bo po co puste sektory przelatywać pRendered[iRendered++] = tmp; // tworzenie listy sektorów do renderowania diff --git a/Ground.h b/Ground.h index 67ef46c2..1354aa06 100644 --- a/Ground.h +++ b/Ground.h @@ -185,9 +185,16 @@ class TGroundNode : public Resource */ }; +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: @@ -209,7 +216,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 @@ -246,16 +252,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) @@ -282,6 +284,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 @@ -361,7 +365,7 @@ class TGround void Update_Lights(); // updates scene lights array bool AddToQuery(TEvent *Event, TDynamicObject *Node); bool GetTraction(TDynamicObject *model); - bool Render( Math3D::vector3 const &Camera ); + bool Render_Hidden( Math3D::vector3 const &Camera ); bool RenderDL(vector3 pPosition); bool RenderAlphaDL(vector3 pPosition); /* diff --git a/World.cpp b/World.cpp index 617521ed..e1be615d 100644 --- a/World.cpp +++ b/World.cpp @@ -1004,51 +1004,37 @@ bool TWorld::Update() --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 + auto const framerate = Timer::GetFPS(); + // 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 + if( framerate > 65.0 ) { + + Global::iSegmentsRendered = std::min( 400, Global::iSegmentsRendered + 5 ); + Global::fDistanceFactor = std::min( 3.0f, Global::fDistanceFactor + 0.025f ); } - 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)) + else if( framerate > 45.0 ) { + + Global::iSegmentsRendered = std::min( 225, Global::iSegmentsRendered + 5 ); + } + else if ( framerate < Global::fFpsMin) { + // 9=minimalny promień to 600m + Global::iSegmentsRendered = std::max( 9, Global::iSegmentsRendered - 3 ); + Global::fDistanceFactor = std::max( Global::ScreenHeight / 768.0f * 0.75f, Global::fDistanceFactor - 0.1f ); + } + 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 ((Timer::GetFPS() > 20) && Global::iSlowMotion) + 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); } - /* - 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); @@ -1728,14 +1714,12 @@ TWorld::Render_UI() { if( Global::iTextMode == GLFW_KEY_F8 ) { Global::iViewMode = GLFW_KEY_F8; - OutText1 = "FPS: " + to_string( Timer::GetFPS(), 2 ); + OutText1 = "Draw range x " + to_string( Global::fDistanceFactor, 1 ) + "; FPS: " + to_string( Timer::GetFPS(), 2 ); //OutText1 += sprintf(); if( Global::iSlowMotion ) OutText1 += " (slowmotion " + to_string( Global::iSlowMotion ) + ")"; - OutText1 += ", sectors: " + to_string( Ground.iRendered ); - if( DebugModeFlag ) { - OutText1 += " FoV: " + to_string( Global::FieldOfView / Global::ZoomFactor, 1 ); - } + OutText1 += ", sectors: " + to_string( Ground.iRendered ) + "/" + to_string( Global::iSegmentsRendered ); + OutText1 += "; FoV: " + to_string( Global::FieldOfView / Global::ZoomFactor, 1 ); } // if (Console::Pressed(VK_F7)) diff --git a/renderer.cpp b/renderer.cpp index 2b0221db..23f25498 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -14,6 +14,12 @@ http://mozilla.org/MPL/2.0/. #include "dynobj.h" // 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 { @@ -63,7 +69,7 @@ opengl_renderer::Render() { Global::FieldOfView / Global::ZoomFactor, (GLdouble)Global::ScreenWidth / std::max( (GLdouble)Global::ScreenHeight, 1.0 ), 0.1f * Global::ZoomFactor, - m_drawrange ); + m_drawrange * Global::fDistanceFactor ); ::glMatrixMode( GL_MODELVIEW ); // Select The Modelview Matrix ::glLoadIdentity(); @@ -75,7 +81,10 @@ opengl_renderer::Render() { World.Environment.render(); } - if( false == World.Ground.Render( World.Camera.Pos ) ) { return false; } + World.Ground.Render_Hidden( World.Camera.Pos ); + Render( &World.Ground ); + World.Ground.RenderDL( World.Camera.Pos ); + World.Ground.RenderAlphaDL( World.Camera.Pos ); World.Render_Cab(); World.Render_UI(); @@ -83,6 +92,33 @@ opengl_renderer::Render() { return true; // for now always succeed } +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 ) { diff --git a/renderer.h b/renderer.h index f4dfe212..5d340855 100644 --- a/renderer.h +++ b/renderer.h @@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/. #include "lightarray.h" #include "dumb3d.h" #include "frustum.h" +#include "ground.h" struct opengl_light { @@ -78,6 +79,8 @@ public: inline void update_frustum() { m_frustum.calculate(); } + bool + visible( bounding_area const &Area ) const; bool visible( TDynamicObject const *Dynamic ) const; @@ -98,6 +101,8 @@ public: // main draw call. returns false on error bool Render(); + bool + Render( TGround *Ground ); bool Render( TDynamicObject *Dynamic ); bool