From 4357919272d58c78d4c15d638e2a639aaa66255f Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 29 Jul 2017 00:28:37 +0200 Subject: [PATCH] mvp matrices cached separately for each render pass, eliminated duplicate screen width/height variables --- EU07.cpp | 14 +- Globals.cpp | 6 +- Globals.h | 4 +- World.cpp | 34 +++-- frustum.cpp | 25 ++++ frustum.h | 18 ++- maszyna.vcxproj.filters | 6 - moon.cpp | 2 +- mouseinput.cpp | 2 +- openglmatrixstack.h | 21 ++- renderer.cpp | 284 +++++++++++++++++++++++----------------- renderer.h | 107 +++++++++------ uilayer.cpp | 15 +-- 13 files changed, 322 insertions(+), 216 deletions(-) diff --git a/EU07.cpp b/EU07.cpp index c226a225..00852213 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -78,8 +78,8 @@ void screenshot_save_thread( char *img ) png_image png; memset(&png, 0, sizeof(png_image)); png.version = PNG_IMAGE_VERSION; - png.width = Global::ScreenWidth; - png.height = Global::ScreenHeight; + png.width = Global::iWindowWidth; + png.height = Global::iWindowHeight; png.format = PNG_FORMAT_RGB; char datetime[64]; @@ -95,7 +95,7 @@ void screenshot_save_thread( char *img ) std::string filename = "screenshots/" + std::string(datetime) + "_" + std::to_string(perf) + ".png"; - if (png_image_write_to_file(&png, filename.c_str(), 0, img, -Global::ScreenWidth * 3, nullptr) == 1) + if (png_image_write_to_file(&png, filename.c_str(), 0, img, -Global::iWindowWidth * 3, nullptr) == 1) WriteLog("saved " + filename + "."); else WriteLog("failed to save screenshot."); @@ -105,8 +105,8 @@ void screenshot_save_thread( char *img ) void make_screenshot() { - char *img = new char[Global::ScreenWidth * Global::ScreenHeight * 3]; - glReadPixels(0, 0, Global::ScreenWidth, Global::ScreenHeight, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)img); + char *img = new char[Global::iWindowWidth * Global::iWindowHeight * 3]; + glReadPixels(0, 0, Global::iWindowWidth, Global::iWindowHeight, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)img); std::thread t(screenshot_save_thread, img); t.detach(); @@ -117,8 +117,8 @@ void window_resize_callback(GLFWwindow *window, int w, int 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::iWindowWidth = w; + 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); } diff --git a/Globals.cpp b/Globals.cpp index 4310ec3a..7aa9094f 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -66,9 +66,6 @@ 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 -/* -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.0 / 255.0f, 225.0f / 255.0f, 225.0f / 255.0f, 1.0f ); @@ -84,6 +81,7 @@ GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f}; double Global::fFogStart = 1700; double Global::fFogEnd = 2000; float Global::Overcast { 0.1f }; // NOTE: all this weather stuff should be moved elsewhere +float Global::BaseDrawRange { 2500.f }; opengl_light Global::DayLight; int Global::DynamicLightCount { 3 }; bool Global::ScaleSpecularValues { true }; @@ -98,7 +96,7 @@ int Global::Keys[MaxKeys]; bool Global::RealisticControlMode{ false }; int Global::iWindowWidth = 800; int Global::iWindowHeight = 600; -float Global::fDistanceFactor = Global::ScreenHeight / 768.0; // baza do przeliczania odległości dla LoD +float Global::fDistanceFactor = Global::iWindowHeight / 768.0; // baza do przeliczania odległości dla LoD int Global::iFeedbackMode = 1; // tryb pracy informacji zwrotnej int Global::iFeedbackPort = 0; // dodatkowy adres dla informacji zwrotnych bool Global::InputGamepad{ true }; diff --git a/Globals.h b/Globals.h index 752aca31..485a8a2f 100644 --- a/Globals.h +++ b/Globals.h @@ -223,6 +223,7 @@ class Global // static bool bTimeChange; // TODO: put these things in the renderer + static float BaseDrawRange; static opengl_light DayLight; static int DynamicLightCount; static bool ScaleSpecularValues; @@ -315,9 +316,6 @@ 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 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 diff --git a/World.cpp b/World.cpp index 4ed9ac6e..c4c1d5fa 100644 --- a/World.cpp +++ b/World.cpp @@ -489,9 +489,8 @@ void TWorld::OnKeyDown(int cKey) } else // również przeskakiwanie { // Ra: to z tą kamerą (Camera.Pos i Global::pCameraPosition) jest trochę bez sensu - Global::SetCameraPosition( - Global::FreeCameraInit[i]); // nowa pozycja dla generowania obiektów - Ground.Silence(Camera.Pos); // wyciszenie wszystkiego z poprzedniej pozycji + Ground.Silence( Global::pCameraPosition ); // wyciszenie wszystkiego z poprzedniej pozycji + Global::SetCameraPosition( Global::FreeCameraInit[i] ); // nowa pozycja dla generowania obiektów Camera.Init(Global::FreeCameraInit[i], Global::FreeCameraInitAngle[i]); // przestawienie } @@ -1136,25 +1135,25 @@ bool TWorld::Update() void TWorld::Update_Camera( double const Deltatime ) { - // Console::Update(); //tu jest zależne od FPS, co nie jest korzystne if( false == Global::ControlPicking ) { if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_LEFT ) == GLFW_PRESS ) { Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na południe - // if (!FreeFlyModeFlag) //jeśli wewnątrz - patrzymy do tyłu - // Camera.LookAt=Train->pMechPosition-Normalize(Train->GetDirection())*10; - if( Controlled && LengthSquared3( Controlled->GetPosition() - Camera.Pos ) < ( 1500 * 1500 ) ) // gdy bliżej niż 1.5km + if( Controlled && LengthSquared3( Controlled->GetPosition() - Camera.Pos ) < ( 1500 * 1500 ) ) { + // gdy bliżej niż 1.5km Camera.LookAt = Controlled->GetPosition(); + } else { TDynamicObject *d = Ground.DynamicNearest( Camera.Pos, 300 ); // szukaj w promieniu 300m if( !d ) - d = Ground.DynamicNearest( Camera.Pos, - 1000 ); // dalej szukanie, jesli bliżej nie ma - if( d && pDynamicNearest ) // jeśli jakiś jest znaleziony wcześniej - if( 100.0 * LengthSquared3( d->GetPosition() - Camera.Pos ) > - LengthSquared3( pDynamicNearest->GetPosition() - Camera.Pos ) ) + d = Ground.DynamicNearest( Camera.Pos, 1000 ); // dalej szukanie, jesli bliżej nie ma + if( d && pDynamicNearest ) { + // jeśli jakiś jest znaleziony wcześniej + if( 100.0 * LengthSquared3( d->GetPosition() - Camera.Pos ) > LengthSquared3( pDynamicNearest->GetPosition() - Camera.Pos ) ) { d = pDynamicNearest; // jeśli najbliższy nie jest 10 razy bliżej niż + } + } // poprzedni najbliższy, zostaje poprzedni if( d ) pDynamicNearest = d; // zmiana na nowy, jeśli coś znaleziony niepusty @@ -1164,7 +1163,7 @@ TWorld::Update_Camera( double const Deltatime ) { if( FreeFlyModeFlag ) Camera.RaLook(); // jednorazowe przestawienie kamery } - else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_RIGHT ) == GLFW_PRESS ) { //||Console::Pressed(VK_F4)) + else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_RIGHT ) == GLFW_PRESS ) { FollowView( false ); // bez wyciszania dźwięków } else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) == GLFW_PRESS ) { @@ -1179,12 +1178,7 @@ TWorld::Update_Camera( double const Deltatime ) { } Camera.Update(); // uwzględnienie ruchu wywołanego klawiszami -/* - if( Camera.Type == tp_Follow ) { - if( Train ) { // jeśli jazda w kabinie, przeliczyć trzeba parametry kamery - Train->UpdateMechPosition( Deltatime / - Global::fTimeSpeed ); // ograniczyć telepanie po przyspieszeniu -*/ + if( (Train != nullptr) && (Camera.Type == tp_Follow )) { // jeśli jazda w kabinie, przeliczyć trzeba parametry kamery @@ -1248,6 +1242,8 @@ TWorld::Update_Camera( double const Deltatime ) { else { // kamera nieruchoma Global::SetCameraRotation( Camera.Yaw - M_PI ); } + // all done, update camera position to the new value + Global::SetCameraPosition( Camera.Pos ); } void TWorld::Update_Environment() { diff --git a/frustum.cpp b/frustum.cpp index 0f4624b7..c2420c89 100644 --- a/frustum.cpp +++ b/frustum.cpp @@ -10,6 +10,10 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "frustum.h" +std::vector ndcfrustumshapepoints = { + { -1, -1, -1, 1 }, { 1, -1, -1, 1 }, { 1, 1, -1, 1 }, { -1, 1, -1, 1 }, // z-near + { -1, -1, 1, 1 }, { 1, -1, 1, 1 }, { 1, 1, 1, 1 }, { -1, 1, 1, 1 } }; // z-far + void cFrustum::calculate() { @@ -83,6 +87,14 @@ cFrustum::calculate( glm::mat4 const &Projection, glm::mat4 const &Modelview ) { m_frustum[ side_FRONT ][ plane_C ] = clip[ 11 ] + clip[ 10 ]; m_frustum[ side_FRONT ][ plane_D ] = clip[ 15 ] + clip[ 14 ]; normalize_plane( side_FRONT ); + + m_inversetransformation = glm::inverse( Projection * Modelview ); + + // calculate frustum corners + m_frustumpoints = ndcfrustumshapepoints; + transform_to_world( + std::begin( m_frustumpoints ), + std::end( m_frustumpoints ) ); } bool @@ -169,6 +181,19 @@ cFrustum::cube_inside( float const X, float const Y, float const Z, float const return true; } +std::vector const frustumshapepoinstorder{ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 }; + +// debug helper, draws shape of frustum in world space +void +cFrustum::draw( glm::vec3 const &Offset ) const { + + ::glBegin( GL_LINES ); + for( auto const pointindex : frustumshapepoinstorder ) { + ::glVertex3fv( glm::value_ptr( glm::vec3{ m_frustumpoints[ pointindex ] } - Offset ) ); + } + ::glEnd(); +} + void cFrustum::normalize_plane( cFrustum::side const Side ) { float magnitude = diff --git a/frustum.h b/frustum.h index 360f8a5a..4333e25a 100644 --- a/frustum.h +++ b/frustum.h @@ -61,6 +61,20 @@ public: cube_inside( Math3D::vector3 const &Center, float const Size ) const { return cube_inside( static_cast( Center.x ), static_cast( Center.y ), static_cast( Center.z ), Size ); } bool cube_inside( float const X, float const Y, float const Z, float const Size ) const; + // transforms provided set of clip space points to world space + template + void + transform_to_world( Iterator_ First, Iterator_ Last ) { + std::for_each( + First, Last, + [this]( glm::vec4 &point ) { + // transform each point using the cached matrix... + point = this->m_inversetransformation * point; + // ...and scale by transformed w + point = glm::vec4{ glm::vec3{ point } / point.w, 1.f }; } ); } + // debug helper, draws shape of frustum in world space + void + draw( glm::vec3 const &Offset ) const; protected: // types: @@ -74,5 +88,7 @@ protected: normalize_plane( cFrustum::side const Side ); // normalizes a plane (A side) from the frustum // members: - float m_frustum[6][4]; // holds the A B C and D values (normal & distance) for each side of the frustum. + float m_frustum[6][4]; // holds the A B C and D values (normal & distance) for each side of the frustum. + glm::mat4 m_inversetransformation; // cached inverse transformation matrix + std::vector m_frustumpoints; // coordinates of corners for defined frustum, in world space }; diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 67cb75d1..b375a4c0 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -120,9 +120,6 @@ Source Files - - Source Files - Source Files @@ -374,9 +371,6 @@ Header Files - - Header Files - Header Files diff --git a/moon.cpp b/moon.cpp index feb72ba3..02db79f1 100644 --- a/moon.cpp +++ b/moon.cpp @@ -55,7 +55,7 @@ cMoon::render() { glEnd(); glPushMatrix(); glTranslatef( position.x, position.y, position.z ); - gluSphere( moonsphere, /* (float)( Global::ScreenHeight / Global::FieldOfView ) * 0.5 * */ ( m_body.distance / 60.2666 ) * 9.037461, 12, 12 ); + gluSphere( moonsphere, /* (float)( Global::iWindowHeight / Global::FieldOfView ) * 0.5 * */ ( m_body.distance / 60.2666 ) * 9.037461, 12, 12 ); glPopMatrix(); } diff --git a/mouseinput.cpp b/mouseinput.cpp index 97e1f6dc..e5b8c1de 100644 --- a/mouseinput.cpp +++ b/mouseinput.cpp @@ -168,7 +168,7 @@ mouse_input::poll() { auto updaterate { m_updaterate }; if( m_varyingpollrate ) { - updaterate /= std::max( 0.15, 2.0 * glm::length( m_cursorposition - m_commandstartcursor ) / std::max( 1, Global::ScreenHeight ) ); + updaterate /= std::max( 0.15, 2.0 * glm::length( m_cursorposition - m_commandstartcursor ) / std::max( 1, Global::iWindowHeight ) ); } if( m_updateaccumulator < updaterate ) { diff --git a/openglmatrixstack.h b/openglmatrixstack.h index b75e37c7..27a875ab 100644 --- a/openglmatrixstack.h +++ b/openglmatrixstack.h @@ -31,17 +31,23 @@ public: // methods: glm::mat4 const & - data() const { return m_stack.top(); } + data() const { + return m_stack.top(); } void - push_matrix() { m_stack.emplace(m_stack.top()); } + push_matrix() { + m_stack.emplace( m_stack.top() ); } void pop_matrix() { m_stack.pop(); - if( m_stack.empty() ) { m_stack.emplace(1.0f); } + if( m_stack.empty() ) { m_stack.emplace( 1.f ); } upload(); } void load_identity() { - m_stack.top() = glm::mat4( 1.0f ); + m_stack.top() = glm::mat4( 1.f ); + upload(); } + void + load_matrix( glm::mat4 const &Matrix ) { + m_stack.top() = Matrix; upload(); } void rotate( float const Angle, glm::vec3 const &Axis ) { @@ -113,6 +119,11 @@ public: pop_matrix() { m_stacks[ m_mode ].pop_matrix(); } void load_identity() { m_stacks[ m_mode ].load_identity(); } + void + load_matrix( glm::mat4 const &Matrix ) { m_stacks[ m_mode ].load_matrix( Matrix ); } + template + void + load_matrix( Type_ const *Matrix ) { load_matrix( glm::make_mat4( Matrix ) ); } template void rotate( Type_ const Angle, Type_ const X, Type_ const Y, Type_ const Z ) { @@ -184,6 +195,8 @@ extern opengl_matrices OpenGLMatrices; #define glPushMatrix OpenGLMatrices.push_matrix #define glPopMatrix OpenGLMatrices.pop_matrix #define glLoadIdentity OpenGLMatrices.load_identity +#define glLoadMatrixf OpenGLMatrices.load_matrix +#define glLoadMatrixd OpenGLMatrices.load_matrix #define glRotated OpenGLMatrices.rotate #define glRotatef OpenGLMatrices.rotate #define glTranslated OpenGLMatrices.translate diff --git a/renderer.cpp b/renderer.cpp index 9fbe6f33..ee935681 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -27,6 +27,8 @@ extern TWorld World; //#define EU07_USE_ORTHO_SHADOWS +int const EU07_PICKBUFFERSIZE { 1024 }; // size of (square) textures bound with the pick framebuffer + namespace colors { glm::vec4 const none { 0.f, 0.f, 0.f, 1.f }; @@ -77,6 +79,7 @@ opengl_renderer::Init( GLFWwindow *Window ) { m_geometry.units().texture = m_diffusetextureunit; UILayer.set_unit( m_diffusetextureunit ); + ::glDepthFunc( GL_LEQUAL ); glEnable( GL_DEPTH_TEST ); glAlphaFunc( GL_GREATER, 0.04f ); glEnable( GL_ALPHA_TEST ); @@ -150,11 +153,11 @@ opengl_renderer::Init( GLFWwindow *Window ) { ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - ::glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, m_pickbuffersize, m_pickbuffersize, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL ); + ::glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, EU07_PICKBUFFERSIZE, EU07_PICKBUFFERSIZE, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL ); // depth buffer ::glGenRenderbuffersEXT( 1, &m_pickdepthbuffer ); ::glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, m_pickdepthbuffer ); - ::glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, m_pickbuffersize, m_pickbuffersize ); + ::glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, EU07_PICKBUFFERSIZE, EU07_PICKBUFFERSIZE ); // create and assemble the framebuffer ::glGenFramebuffersEXT( 1, &m_pickframebuffer ); ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_pickframebuffer ); @@ -229,10 +232,10 @@ opengl_renderer::Init( GLFWwindow *Window ) { float const size = 2.5f; m_billboardgeometry = m_geometry.create_chunk( vertex_array{ - { { -size, size, 0.0f }, glm::vec3(), { 1.0f, 1.0f } }, - { { size, size, 0.0f }, glm::vec3(), { 0.0f, 1.0f } }, - { { -size, -size, 0.0f }, glm::vec3(), { 1.0f, 0.0f } }, - { { size, -size, 0.0f }, glm::vec3(), { 0.0f, 0.0f } } }, + { { -size, size, 0.f }, glm::vec3(), { 1.f, 1.f } }, + { { size, size, 0.f }, glm::vec3(), { 0.f, 1.f } }, + { { -size, -size, 0.f }, glm::vec3(), { 1.f, 0.f } }, + { { size, -size, 0.f }, glm::vec3(), { 0.f, 0.f } } }, geometrybank, GL_TRIANGLE_STRIP ); // prepare debug mode objects @@ -251,9 +254,9 @@ opengl_renderer::Render() { Render_pass( rendermode::color ); glfwSwapBuffers( m_window ); - m_drawcount = m_renderpass.draw_queue.size(); + m_drawcount = m_drawqueue.size(); // 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() - drawstart ) ).count() ); + m_drawtime = std::max( 20.f, 0.95f * m_drawtime + std::chrono::duration_cast( ( std::chrono::steady_clock::now() - drawstart ) ).count() ); return true; // for now always succeed } @@ -262,37 +265,46 @@ opengl_renderer::Render() { void opengl_renderer::Render_pass( rendermode const Mode ) { - m_renderpass.draw_mode = Mode; + m_renderpass.setup( Mode ); switch( m_renderpass.draw_mode ) { case rendermode::color: { + opengl_camera shadowcamera; if( Global::RenderShadows && World.InitPerformed() ) { // run shadowmap pass before color Render_pass( rendermode::shadows ); #ifdef EU07_USE_DEBUG_SHADOWMAP UILayer.set_texture( m_shadowdebugtexture ); #endif - m_renderpass.draw_mode = rendermode::color; // restore draw mode. TODO: render mode stack + shadowcamera = m_renderpass.camera; // cache shadow camera placement for visualization + + m_renderpass.setup( rendermode::color ); // restore draw mode. TBD, TODO: render mode stack + // setup shadowmap matrix + m_shadowtexturematrix = + //bias from [-1, 1] to [0, 1] }; + glm::mat4{ 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f } + * shadowcamera.projection() + // during colour pass coordinates are moved from camera-centric to light-centric, essentially the difference between these two origins + * glm::translate( + glm::mat4{ glm::mat3{ shadowcamera.modelview() } }, + glm::vec3{ m_renderpass.camera.position() - shadowcamera.position() } ); } - ::glViewport( 0, 0, Global::ScreenWidth, Global::ScreenHeight ); - m_renderpass.draw_range = 2500.0f; // arbitrary base draw range + ::glViewport( 0, 0, Global::iWindowWidth, Global::iWindowHeight ); if( World.InitPerformed() ) { auto const skydomecolour = World.Environment.m_skydome.GetAverageColor(); - ::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 0.0f ); // kolor nieba + ::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 0.f ); // kolor nieba } else { - ::glClearColor( 51.0f / 255.0f, 102.0f / 255.0f, 85.0f / 255.0f, 1.0f ); // initial background Color + ::glClearColor( 51.0f / 255.f, 102.0f / 255.f, 85.0f / 255.f, 1.f ); // initial background Color } ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); if( World.InitPerformed() ) { // setup - setup_projection(); - setup_camera(); - ::glDepthFunc( GL_LEQUAL ); + setup_matrices(); // render setup_drawing( true ); setup_units( true, false, false ); @@ -300,6 +312,19 @@ opengl_renderer::Render_pass( rendermode const Mode ) { // opaque parts... setup_drawing( false ); setup_units( true, true, true ); + + if( DebugModeFlag ) { + // draw light frustum + ::glLineWidth( 2.f ); + ::glColor4f( 1.f, 0.9f, 0.8f, 1.f ); + ::glDisable( GL_LIGHTING ); + ::glDisable( GL_TEXTURE_2D ); + shadowcamera.frustum().draw( m_renderpass.camera.position() ); + ::glLineWidth( 1.f ); + ::glEnable( GL_LIGHTING ); + ::glEnable( GL_TEXTURE_2D ); + } + Render( &World.Ground ); // ...translucent parts setup_drawing( true ); @@ -322,31 +347,34 @@ opengl_renderer::Render_pass( rendermode const Mode ) { ::glViewport( 0, 0, m_shadowbuffersize, m_shadowbuffersize ); #ifdef EU07_USE_DEBUG_SHADOWMAP - ::glClearColor( 0.f / 255.0f, 0.f / 255.0f, 0.f / 255.f, 1.f ); // initial background Color + ::glClearColor( 0.f / 255.f, 0.f / 255.f, 0.f / 255.f, 1.f ); // initial background Color ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + opengl_camera worldcamera{ m_renderpass.camera }; // cache shadow camera placement for visualization #else ::glClear( GL_DEPTH_BUFFER_BIT ); #endif ::glScissor( 1, 1, m_shadowbuffersize - 2, m_shadowbuffersize - 2 ); ::glEnable( GL_SCISSOR_TEST ); - - m_renderpass.draw_range = Global::shadowtune.depth; // 1.0km square centered around camera - m_shadowtexturematrix = - glm::mat4{ - 0.5f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.5f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.5f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f }; //bias from [-1, 1] to [0, 1] }; - setup_projection(); - setup_camera(); - ::glDepthFunc( GL_LEQUAL ); + setup_matrices(); ::glEnable( GL_POLYGON_OFFSET_FILL ); // alleviate depth-fighting - ::glPolygonOffset( 2.f, 4.f ); + ::glPolygonOffset( 4.f, 8.f ); // render // opaque parts... setup_drawing( false ); #ifdef EU07_USE_DEBUG_SHADOWMAP setup_units( true, false, false ); + + if( DebugModeFlag ) { + // draw camera frustum + ::glLineWidth( 2.f ); + ::glColor4f( 1.f, 0.9f, 0.8f, 1.f ); + ::glDisable( GL_LIGHTING ); + ::glDisable( GL_TEXTURE_2D ); + worldcamera.frustum().draw( m_renderpass.camera.position() ); + ::glLineWidth( 1.f ); + ::glEnable( GL_LIGHTING ); + ::glEnable( GL_TEXTURE_2D ); + } #else setup_units( false, false, false ); #endif @@ -364,16 +392,13 @@ opengl_renderer::Render_pass( rendermode const Mode ) { if( World.InitPerformed() ) { // setup #ifdef EU07_USE_PICKING_FRAMEBUFFER - ::glViewport( 0, 0, m_pickbuffersize, m_pickbuffersize ); + ::glViewport( 0, 0, EU07_PICKBUFFERSIZE, EU07_PICKBUFFERSIZE ); #endif - ::glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + ::glClearColor( 0.f, 0.f, 0.f, 1.f ); ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); m_pickcontrolsitems.clear(); - m_renderpass.draw_range = 50.0f; // doesn't really matter for control picking - setup_projection(); - setup_camera(); - ::glDepthFunc( GL_LEQUAL ); + setup_matrices(); // render // opaque parts... setup_drawing( false ); @@ -388,17 +413,14 @@ opengl_renderer::Render_pass( rendermode const Mode ) { case rendermode::pickscenery: { if( World.InitPerformed() ) { // setup + m_picksceneryitems.clear(); #ifdef EU07_USE_PICKING_FRAMEBUFFER - ::glViewport( 0, 0, m_pickbuffersize, m_pickbuffersize ); + ::glViewport( 0, 0, EU07_PICKBUFFERSIZE, EU07_PICKBUFFERSIZE ); #endif - ::glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + ::glClearColor( 0.f, 0.f, 0.f, 1.f ); ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - m_picksceneryitems.clear(); - m_renderpass.draw_range = 1000.0f; // scenery picking is likely to focus on nearby nodes - setup_projection(); - setup_camera(); - ::glDepthFunc( GL_LEQUAL ); + setup_matrices(); // render // opaque parts... setup_drawing( false ); @@ -415,14 +437,32 @@ opengl_renderer::Render_pass( rendermode const Mode ) { } } +void +opengl_renderer::renderpass_config::setup( rendermode const Mode ) { + + draw_mode = Mode; + + if( false == World.InitPerformed() ) { return; } + + switch( draw_mode ) { + case rendermode::color: { draw_range = Global::BaseDrawRange; break; } + case rendermode::shadows: { draw_range = Global::shadowtune.depth; break; } + case rendermode::pickcontrols: { draw_range = 50.f; break; } + case rendermode::pickscenery: { draw_range = Global::BaseDrawRange * 0.5f; break; } + default: { draw_range = 0.f; break; } + } + + setup_projection(); + setup_modelview(); +} + // configures projection matrix for the current render pass void -opengl_renderer::setup_projection() { +opengl_renderer::renderpass_config::setup_projection() { - ::glMatrixMode( GL_PROJECTION ); - ::glLoadIdentity(); + camera.projection() = glm::mat4( 1.f ); - switch( m_renderpass.draw_mode ) { + switch( draw_mode ) { #ifndef EU07_USE_PICKING_FRAMEBUFFER case rendermode::pickcontrols: @@ -437,12 +477,13 @@ opengl_renderer::setup_projection() { case rendermode::pickscenery: { // TODO: scissor test for pick modes auto const angle = Global::FieldOfView / Global::ZoomFactor; - auto const height = std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ) / ( Global::ScreenWidth / m_pickbuffersize ); - ::gluPerspective( - Global::FieldOfView / Global::ZoomFactor, - std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ) / ( Global::ScreenWidth / m_pickbuffersize ), - 0.1f * Global::ZoomFactor, - m_renderpass.draw_range * Global::fDistanceFactor ); + auto const height = std::max( 1.0f, (float)Global::iWindowWidth ) / std::max( 1.0f, (float)Global::iWindowHeight ) / ( Global::iWindowWidth / EU07_PICKBUFFERSIZE ); + camera.projection() *= + glm::perspective( + glm::radians( Global::FieldOfView / Global::ZoomFactor ), + std::max( 1.0f, (float)Global::iWindowWidth ) / std::max( 1.0f, (float)Global::iWindowHeight ) / ( Global::iWindowWidth / EU07_PICKBUFFERSIZE ), + 0.1f * Global::ZoomFactor, + draw_range * Global::fDistanceFactor ); break; } #endif @@ -452,7 +493,6 @@ opengl_renderer::setup_projection() { #else setup_projection_light_perspective(); #endif - m_shadowtexturematrix *= OpenGLMatrices.data( GL_PROJECTION ); break; } @@ -463,103 +503,114 @@ opengl_renderer::setup_projection() { } void -opengl_renderer::setup_projection_world() { +opengl_renderer::renderpass_config::setup_projection_world() { - ::gluPerspective( - Global::FieldOfView / Global::ZoomFactor, - std::max( 1.f, (float)Global::ScreenWidth ) / std::max( 1.f, (float)Global::ScreenHeight ), - 0.1f * Global::ZoomFactor, - m_renderpass.draw_range * Global::fDistanceFactor ); + camera.projection() *= + glm::perspective( + glm::radians( Global::FieldOfView / Global::ZoomFactor ), + std::max( 1.f, (float)Global::iWindowWidth ) / std::max( 1.f, (float)Global::iWindowHeight ), + 0.1f * Global::ZoomFactor, + draw_range * Global::fDistanceFactor ); } void -opengl_renderer::setup_projection_light_ortho() { +opengl_renderer::renderpass_config::setup_projection_light_ortho() { // TODO: calculate lightview boundaries based on area of the world camera frustum - ::glOrtho( - -Global::shadowtune.width, Global::shadowtune.width, - -Global::shadowtune.width, Global::shadowtune.width, - -Global::shadowtune.depth, Global::shadowtune.depth ); + camera.projection() *= + glm::ortho( + -Global::shadowtune.width, Global::shadowtune.width, + -Global::shadowtune.width, Global::shadowtune.width, + -Global::shadowtune.depth, Global::shadowtune.depth ); } void -opengl_renderer::setup_projection_light_perspective() { +opengl_renderer::renderpass_config::setup_projection_light_perspective() { - ::gluPerspective( - 45.f, - 1.f, - m_renderpass.draw_range * 0.1f, // light source is pulled back far enough we won't likely have anything too close to it, can get some z-range here - m_renderpass.draw_range * Global::fDistanceFactor ); + camera.projection() *= + glm::perspective( + glm::radians( 45.f ), + 1.f, + draw_range * 0.1f, // light source is pulled back far enough we won't likely have anything too close to it, can get some z-range here + draw_range * Global::fDistanceFactor ); } // configures modelview matrix for the current render pass void -opengl_renderer::setup_camera() { +opengl_renderer::renderpass_config::setup_modelview() { - ::glMatrixMode( GL_MODELVIEW ); // Select The Modelview Matrix - ::glLoadIdentity(); + camera.modelview() = glm::mat4( 1.f ); glm::dmat4 viewmatrix; - switch( m_renderpass.draw_mode ) { + switch( draw_mode ) { case rendermode::color: case rendermode::pickcontrols: case rendermode::pickscenery: { - setup_camera_world( viewmatrix ); + setup_modelview_world( viewmatrix ); break; } case rendermode::shadows: { #ifdef EU07_USE_ORTHO_SHADOWS - setup_camera_light_ortho( viewmatrix ); + setup_modelview_light_ortho( viewmatrix ); #else - setup_camera_light_perspective( viewmatrix ); + setup_modelview_light_perspective( viewmatrix ); #endif - // during colour pass coordinates are moved from camera-centric to light-centric, essentially the difference between these two origins - m_shadowtexturematrix *= - glm::translate( - glm::mat4{ glm::dmat3{ viewmatrix } }, - glm::vec3{ glm::dvec3{ Global::pCameraPosition } - m_renderpass.camera.position() } ); break; } default: { break; } } - +#ifdef EU07_USE_ORTHO_SHADOWS m_renderpass.camera.update_frustum( OpenGLMatrices.data( GL_PROJECTION ), viewmatrix ); // frustum tests are performed in 'world space' but after we set up frustum we no longer need camera translation, only rotation ::glMultMatrixd( glm::value_ptr( glm::dmat4( glm::dmat3( viewmatrix ) ) ) ); +#else + camera.modelview() = viewmatrix; + camera.update_frustum(); +#endif } void -opengl_renderer::setup_camera_world( glm::dmat4 &Viewmatrix ) { +opengl_renderer::renderpass_config::setup_modelview_world( glm::dmat4 &Viewmatrix ) { + camera.position() = Global::pCameraPosition; World.Camera.SetMatrix( Viewmatrix ); - m_renderpass.camera.position() = Global::pCameraPosition; } void -opengl_renderer::setup_camera_light_ortho( glm::dmat4 &Viewmatrix ) { +opengl_renderer::renderpass_config::setup_modelview_light_ortho( glm::dmat4 &Viewmatrix ) { - m_renderpass.camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction }; - if( m_renderpass.camera.position().y - Global::pCameraPosition.y < 0.1 ) { - m_renderpass.camera.position().y = Global::pCameraPosition.y + 0.1; + camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction }; + if( camera.position().y - Global::pCameraPosition.y < 0.1 ) { + camera.position().y = Global::pCameraPosition.y + 0.1; } Viewmatrix *= glm::lookAt( - m_renderpass.camera.position(), + camera.position(), glm::dvec3{ Global::pCameraPosition }, glm::dvec3{ 0.f, 1.f, 0.f } ); } void -opengl_renderer::setup_camera_light_perspective( glm::dmat4 &Viewmatrix ) { +opengl_renderer::renderpass_config::setup_modelview_light_perspective( glm::dmat4 &Viewmatrix ) { - m_renderpass.camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction * m_renderpass.draw_range * 0.5f }; - m_renderpass.camera.position().y = std::max( m_renderpass.draw_range * 0.5f * 0.1f, m_renderpass.camera.position().y ); // prevent shadow source from dipping too low + camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction * draw_range * 0.5f }; + camera.position().y = std::max( draw_range * 0.5f * 0.1f, camera.position().y ); // prevent shadow source from dipping too low Viewmatrix *= glm::lookAt( - m_renderpass.camera.position(), + camera.position(), glm::dvec3{ Global::pCameraPosition }, glm::dvec3{ 0.f, 1.f, 0.f } ); } +void +opengl_renderer::setup_matrices() { + + ::glMatrixMode( GL_PROJECTION ); + OpenGLMatrices.load_matrix( m_renderpass.camera.projection() ); + // trim modelview matrix just to rotation, since rendering is done in camera-centric world space + ::glMatrixMode( GL_MODELVIEW ); + OpenGLMatrices.load_matrix( glm::mat4( glm::mat3( m_renderpass.camera.modelview() ) ) ); +} + void opengl_renderer::setup_drawing( bool const Alpha ) { @@ -982,7 +1033,7 @@ opengl_renderer::Render( TGround *Ground ) { ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji) - m_renderpass.draw_queue.clear(); + m_drawqueue.clear(); switch( m_renderpass.draw_mode ) { case rendermode::color: { @@ -1034,12 +1085,12 @@ opengl_renderer::Render( TGround *Ground ) { } // draw queue was filled while rendering content of ground cells. now sort the nodes based on their distance to viewer... std::sort( - std::begin( m_renderpass.draw_queue ), - std::end( m_renderpass.draw_queue ), + std::begin( m_drawqueue ), + std::end( m_drawqueue ), []( distancesubcell_pair const &Left, distancesubcell_pair const &Right ) { return ( Left.first ) < ( Right.first ); } ); // ...then render the opaque content of the visible subcells. - for( auto subcellpair : m_renderpass.draw_queue ) { + for( auto subcellpair : m_drawqueue ) { Render( subcellpair.second ); } break; @@ -1058,7 +1109,7 @@ opengl_renderer::Render( TGround *Ground ) { } // they can also skip queue sorting, as they only deal with opaque geometry // NOTE: there's benefit from rendering front-to-back, but is it significant enough? TODO: investigate - for( auto subcellpair : m_renderpass.draw_queue ) { + for( auto subcellpair : m_drawqueue ) { Render( subcellpair.second ); } break; @@ -1125,7 +1176,7 @@ opengl_renderer::Render( TGroundRect *Groundcell ) { auto subcell = Groundcell->pSubRects + subcellindex; if( subcell->iNodeCount ) { // o ile są jakieś obiekty, bo po co puste sektory przelatywać - m_renderpass.draw_queue.emplace_back( + m_drawqueue.emplace_back( glm::length2( m_renderpass.camera.position() - glm::dvec3( subcell->m_area.center ) ), subcell ); } @@ -1290,9 +1341,6 @@ opengl_renderer::Render( TGroundNode *Node ) { break; } } -#ifdef EU07_USE_OLD_RENDERCODE - Node->Model->Render( Node->pCenter - m_renderpass.camera.position() ); -#else Node->Model->RaAnimate(); // jednorazowe przeliczenie animacji Node->Model->RaPrepare(); if( Node->Model->pModel ) { @@ -1320,7 +1368,6 @@ opengl_renderer::Render( TGroundNode *Node ) { } } } -#endif return true; } @@ -1981,21 +2028,21 @@ opengl_renderer::Render_Alpha( TGround *Ground ) { TGroundNode *node; TSubRect *tmp; // Ra: renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - for( auto subcellpair = std::rbegin( m_renderpass.draw_queue ); subcellpair != std::rend( m_renderpass.draw_queue ); ++subcellpair ) { + for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) { // przezroczyste trójkąty w oddzielnym cyklu przed modelami tmp = subcellpair->second; for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) { Render_Alpha( node ); } } - for( auto subcellpair = std::rbegin( m_renderpass.draw_queue ); subcellpair != std::rend( m_renderpass.draw_queue ); ++subcellpair ) + for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) { // renderowanie przezroczystych modeli oraz pojazdów Render_Alpha( subcellpair->second ); } ::glDisable( GL_LIGHTING ); // linie nie powinny świecić - for( auto subcellpair = std::rbegin( m_renderpass.draw_queue ); subcellpair != std::rend( m_renderpass.draw_queue ); ++subcellpair ) { + for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) { // druty na końcu, żeby się nie robiły białe plamy na tle lasu tmp = subcellpair->second; for( node = tmp->nRenderWires; node; node = node->nNext3 ) { @@ -2092,9 +2139,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { } } case TP_MODEL: { -#ifdef EU07_USE_OLD_RENDERCODE - Node->Model->RenderAlpha( Node->pCenter - m_renderpass.camera.position() ); -#else + Node->Model->RaPrepare(); if( Node->Model->pModel ) { // renderowanie rekurencyjne submodeli @@ -2121,7 +2166,6 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { } } } -#endif return true; } @@ -2508,15 +2552,15 @@ opengl_renderer::Update_Pick_Control() { // determine point to examine glm::dvec2 mousepos; glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); - mousepos.y = Global::ScreenHeight - mousepos.y; // cursor coordinates are flipped compared to opengl + mousepos.y = Global::iWindowHeight - mousepos.y; // cursor coordinates are flipped compared to opengl #ifdef EU07_USE_PICKING_FRAMEBUFFER glm::ivec2 pickbufferpos; if( true == m_framebuffersupport ) { // ::glReadBuffer( GL_COLOR_ATTACHMENT0_EXT ); pickbufferpos = glm::ivec2{ - mousepos.x * m_pickbuffersize / Global::ScreenWidth, - mousepos.y * m_pickbuffersize / Global::ScreenHeight + mousepos.x * EU07_PICKBUFFERSIZE / Global::iWindowWidth, + mousepos.y * EU07_PICKBUFFERSIZE / Global::iWindowHeight }; } else { @@ -2556,15 +2600,15 @@ opengl_renderer::Update_Pick_Node() { // determine point to examine glm::dvec2 mousepos; glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); - mousepos.y = Global::ScreenHeight - mousepos.y; // cursor coordinates are flipped compared to opengl + mousepos.y = Global::iWindowHeight - mousepos.y; // cursor coordinates are flipped compared to opengl #ifdef EU07_USE_PICKING_FRAMEBUFFER glm::ivec2 pickbufferpos; if( true == m_framebuffersupport ) { // ::glReadBuffer( GL_COLOR_ATTACHMENT0_EXT ); pickbufferpos = glm::ivec2{ - mousepos.x * m_pickbuffersize / Global::ScreenWidth, - mousepos.y * m_pickbuffersize / Global::ScreenHeight + mousepos.x * EU07_PICKBUFFERSIZE / Global::iWindowWidth, + mousepos.y * EU07_PICKBUFFERSIZE / Global::iWindowHeight }; } else { @@ -2611,8 +2655,8 @@ opengl_renderer::Update( double const Deltatime ) { float targetfactor; if( framerate > 90.0 ) { targetfactor = 3.0f; } else if( framerate > 60.0 ) { targetfactor = 1.5f; } - else if( framerate > 30.0 ) { targetfactor = Global::ScreenHeight / 768.0f; } - else { targetfactor = Global::ScreenHeight / 768.0f * 0.75f; } + else if( framerate > 30.0 ) { targetfactor = Global::iWindowHeight / 768.0f; } + else { targetfactor = Global::iWindowHeight / 768.0f * 0.75f; } if( targetfactor > Global::fDistanceFactor ) { diff --git a/renderer.h b/renderer.h index 05b5c6bc..81a85d19 100644 --- a/renderer.h +++ b/renderer.h @@ -26,10 +26,10 @@ struct opengl_light { GLuint id{ (GLuint)-1 }; glm::vec3 direction; glm::vec4 - position { 0.0f, 0.0f, 0.0f, 1.0f }, // 4th parameter specifies directional(0) or omni-directional(1) light source - ambient { 0.0f, 0.0f, 0.0f, 1.0f }, - diffuse { 1.0f, 1.0f, 1.0f, 1.0f }, - specular { 1.0f, 1.0f, 1.0f, 1.0f }; + position { 0.f, 0.f, 0.f, 1.f }, // 4th parameter specifies directional(0) or omni-directional(1) light source + ambient { 0.f, 0.f, 0.f, 1.f }, + diffuse { 1.f, 1.f, 1.f, 1.f }, + specular { 1.f, 1.f, 1.f, 1.f }; inline void apply_intensity( float const Factor = 1.0f ) { @@ -54,7 +54,7 @@ struct opengl_light { void apply_angle() { glLightfv( id, GL_POSITION, glm::value_ptr(position) ); - if( position.w == 1.0f ) { + if( position.w == 1.f ) { glLightfv( id, GL_SPOT_DIRECTION, glm::value_ptr(direction) ); } } @@ -86,7 +86,7 @@ public: // methods: inline void - update_frustum() { m_frustum.calculate(); } + update_frustum() { m_frustum.calculate( m_projection, m_modelview ); } inline void update_frustum(glm::mat4 const &Projection, glm::mat4 const &Modelview) { m_frustum.calculate(Projection, Modelview); } @@ -100,11 +100,28 @@ public: inline glm::dvec3 & position() { return m_position; } + inline + glm::mat4 const & + projection() const { return m_projection; } + inline + glm::mat4 & + projection() { return m_projection; } + inline + glm::mat4 const & + modelview() const { return m_modelview; } + inline + glm::mat4 & + modelview() { return m_modelview; } + inline + cFrustum const & + frustum() { return m_frustum; } private: // members: cFrustum m_frustum; glm::dvec3 m_position; + glm::mat4 m_projection; + glm::mat4 m_modelview; }; // bare-bones render controller, in lack of anything better yet @@ -185,7 +202,28 @@ private: opengl_camera camera; rendermode draw_mode { rendermode::none }; float draw_range { 0.0f }; - std::vector draw_queue; // list of subcells to be drawn in current render pass + + void + setup( rendermode const Mode ); + private: + // configures projection matrix for the current render pass + void + setup_projection(); + void + setup_projection_world(); + void + setup_projection_light_ortho(); + void + setup_projection_light_perspective(); + // configures camera for the current render pass + void + setup_modelview(); + void + setup_modelview_world( glm::dmat4 &Viewmatrix ); + void + setup_modelview_light_ortho( glm::dmat4 &Viewmatrix ); + void + setup_modelview_light_perspective( glm::dmat4 &Viewmatrix ); }; typedef std::vector opengllight_array; @@ -196,24 +234,8 @@ private: // runs jobs needed to generate graphics for specified render pass void Render_pass( rendermode const Mode ); - // configures projection matrix for the current render pass void - setup_projection(); - void - setup_projection_world(); - void - setup_projection_light_ortho(); - void - setup_projection_light_perspective(); - // configures camera for the current render pass - void - setup_camera(); - void - setup_camera_world( glm::dmat4 &Viewmatrix ); - void - setup_camera_light_ortho( glm::dmat4 &Viewmatrix ); - void - setup_camera_light_perspective( glm::dmat4 &Viewmatrix ); + setup_matrices(); void setup_drawing( bool const Alpha = false ); void @@ -267,46 +289,49 @@ private: std::size_t pick_index( glm::ivec3 const &Color ); // members + GLFWwindow *m_window { nullptr }; geometrybank_manager m_geometry; texture_manager m_textures; opengllight_array m_lights; - GLFWwindow *m_window { nullptr }; + + geometry_handle m_billboardgeometry { NULL, NULL }; + texture_handle m_glaretexture { -1 }; + texture_handle m_suntexture { -1 }; + texture_handle m_moontexture { -1 }; + texture_handle m_reflectiontexture { -1 }; + GLUquadricObj *m_quadric { nullptr }; // helper object for drawing debug mode scene elements + + bool m_framebuffersupport { false }; #ifdef EU07_USE_PICKING_FRAMEBUFFER GLuint m_pickframebuffer { NULL }; // TODO: refactor pick framebuffer stuff into an object GLuint m_picktexture { NULL }; GLuint m_pickdepthbuffer { NULL }; - int m_pickbuffersize { 1024 }; // size of (square) textures bound with the pick framebuffer #endif + int m_shadowbuffersize { 4096 }; GLuint m_shadowframebuffer { NULL }; GLuint m_shadowtexture { NULL }; #ifdef EU07_USE_DEBUG_SHADOWMAP GLuint m_shadowdebugtexture{ NULL }; #endif - int m_shadowbuffersize { 4096 }; - glm::mat4 m_shadowtexturematrix; - glm::vec4 m_shadowcolor{ 0.5f, 0.5f, 0.5f, 1.f }; - GLUquadricObj *m_quadric { nullptr }; // helper object for drawing debug mode scene elements + glm::mat4 m_shadowtexturematrix; // conversion from camera-centric world space to light-centric clip space + int m_shadowtextureunit { GL_TEXTURE1 }; int m_helpertextureunit { GL_TEXTURE0 }; int m_diffusetextureunit { GL_TEXTURE2 }; - geometry_handle m_billboardgeometry { 0, 0 }; - texture_handle m_glaretexture { -1 }; - texture_handle m_suntexture { -1 }; - texture_handle m_moontexture { -1 }; - texture_handle m_reflectiontexture { -1 }; - - float m_drawtime { 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps + float m_drawtime { 1000.f / 30.f * 20.f }; // start with presumed 'neutral' average of 30 fps double m_updateaccumulator { 0.0 }; std::string m_debuginfo; glm::vec4 m_baseambient { 0.0f, 0.0f, 0.0f, 1.0f }; - float m_specularopaquescalefactor { 1.0f }; - float m_speculartranslucentscalefactor { 1.0f }; + glm::vec4 m_shadowcolor { 0.5f, 0.5f, 0.5f, 1.f }; + float m_specularopaquescalefactor { 1.f }; + float m_speculartranslucentscalefactor { 1.f }; + bool m_renderspecular{ false }; // controls whether to include specular component in the calculations - bool m_framebuffersupport { false }; renderpass_config m_renderpass; - bool m_renderspecular { false }; // controls whether to include specular component in the calculations + std::vector m_drawqueue; // list of subcells to be drawn in current render pass + std::vector m_picksceneryitems; std::vector m_pickcontrolsitems; TSubModel const *m_pickcontrolitem { nullptr }; diff --git a/uilayer.cpp b/uilayer.cpp index 67ca6c60..4680a728 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -65,7 +65,7 @@ ui_layer::render() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glOrtho( 0, std::max( 1, Global::ScreenWidth ), std::max( 1, Global::ScreenHeight ), 0, -1, 1 ); + glOrtho( 0, std::max( 1, Global::iWindowWidth ), std::max( 1, Global::iWindowHeight ), 0, -1, 1 ); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -107,11 +107,7 @@ ui_layer::set_background( std::string const &Filename ) { m_progressbottom = ( texture.width() != texture.height() ); } } -/* -void cGuiLayer::setNote( const std::string Note ) { mNote = Note; } -std::string cGuiLayer::getNote() { return mNote; } -*/ void ui_layer::render_progress() { @@ -247,13 +243,14 @@ ui_layer::render_texture() { ::glBindTexture( GL_TEXTURE_2D, m_texture ); auto const size = 512.f; + auto const offset = 64.f; glBegin( GL_TRIANGLE_STRIP ); - glMultiTexCoord2f( m_textureunit, 0.f, 1.f ); glVertex2f( 0.f, 256.f ); - glMultiTexCoord2f( m_textureunit, 0.f, 0.f ); glVertex2f( 0.f, 256.f + size ); - glMultiTexCoord2f( m_textureunit, 1.f, 1.f ); glVertex2f( size, 256.f ); - glMultiTexCoord2f( m_textureunit, 1.f, 0.f ); glVertex2f( size, 256.f + size ); + glMultiTexCoord2f( m_textureunit, 0.f, 1.f ); glVertex2f( offset, Global::iWindowHeight - offset - size ); + glMultiTexCoord2f( m_textureunit, 0.f, 0.f ); glVertex2f( offset, Global::iWindowHeight - offset ); + glMultiTexCoord2f( m_textureunit, 1.f, 1.f ); glVertex2f( offset + size, Global::iWindowHeight - offset - size ); + glMultiTexCoord2f( m_textureunit, 1.f, 0.f ); glVertex2f( offset + size, Global::iWindowHeight - offset ); glEnd();