From 215a5b60392e799e5148f0baa4dd4e6cc7a5fd54 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 20 Jul 2017 03:51:44 +0200 Subject: [PATCH 1/3] gauge animation precision fix, visualization fix for turntable animations, mouse control repeat rate tweak, rudimentary framebuffer implementation --- Button.cpp | 7 --- Button.h | 2 +- Gauge.cpp | 2 +- Globals.cpp | 6 +++ Globals.h | 1 + Track.cpp | 21 ++++---- mouseinput.cpp | 2 + renderer.cpp | 144 +++++++++++++++++++++++++++++++++++++++++-------- renderer.h | 4 ++ version.h | 2 +- 10 files changed, 148 insertions(+), 43 deletions(-) diff --git a/Button.cpp b/Button.cpp index 4af9a652..06211b1d 100644 --- a/Button.cpp +++ b/Button.cpp @@ -14,13 +14,6 @@ http://mozilla.org/MPL/2.0/. #include "Console.h" #include "logs.h" -TButton::TButton() -{ - iFeedbackBit = 0; - bData = NULL; - Clear(); -}; - void TButton::Clear(int i) { pModelOn = nullptr; diff --git a/Button.h b/Button.h index 76737cd8..67061a47 100644 --- a/Button.h +++ b/Button.h @@ -36,7 +36,7 @@ class TButton play( PSound Sound ); public: - TButton(); + TButton() = default; void Clear(int const i = -1); inline void FeedbackBitSet(int const i) { iFeedbackBit = 1 << i; }; diff --git a/Gauge.cpp b/Gauge.cpp index 125c1a1d..c2206bb7 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -180,7 +180,7 @@ void TGauge::DecValue(double fNewDesired) void TGauge::UpdateValue( double fNewDesired, PSound Fallbacksound ) { - if( static_cast( std::round( ( fDesiredValue - fOffset ) / fScale ) ) == static_cast( fNewDesired ) ) { + if( static_cast( std::round( 100.0 * ( fDesiredValue - fOffset ) / fScale ) ) == static_cast( 100.0 * fNewDesired ) ) { return; } fDesiredValue = fNewDesired * fScale + fOffset; diff --git a/Globals.cpp b/Globals.cpp index 2a9aa97b..a21a4cac 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -87,6 +87,7 @@ float Global::Overcast { 0.1f }; // NOTE: all this weather stuff should be moved opengl_light Global::DayLight; int Global::DynamicLightCount { 3 }; bool Global::ScaleSpecularValues { true }; +bool Global::RenderShadows { false }; bool Global::bRollFix = true; // czy wykonać przeliczanie przechyłki bool Global::bJoinEvents = false; // czy grupować eventy o tych samych nazwach int Global::iHiddenEvents = 1; // czy łączyć eventy z torami poprzez nazwę toru @@ -544,6 +545,11 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens(); Parser >> Global::ScaleSpecularValues; } + else if( token == "shadows" ) { + // shadow render toggle + Parser.getTokens(); + Parser >> Global::RenderShadows; + } else if (token == "smoothtraction") { // podwójna jasność ambient diff --git a/Globals.h b/Globals.h index 4aa05ee3..948eae86 100644 --- a/Globals.h +++ b/Globals.h @@ -226,6 +226,7 @@ class Global static opengl_light DayLight; static int DynamicLightCount; static bool ScaleSpecularValues; + static bool RenderShadows; static int iSlowMotion; static TDynamicObject *changeDynObj; diff --git a/Track.cpp b/Track.cpp index 29e85e3f..433a344e 100644 --- a/Track.cpp +++ b/Track.cpp @@ -1267,31 +1267,32 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { } vertex_array vertices; Segment->RenderLoft(vertices, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength); + if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) { + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + } if( ( Bank == 0 ) && ( false == Geometry2.empty() ) ) { // special variant, replace existing data for a turntable track GfxRenderer.Replace( vertices, Geometry2[ 0 ] ); } - else { - Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); - } } if (TextureID1) { // szyny - generujemy dwie, najwyżej rysować się będzie jedną vertex_array vertices; + if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) { + Segment->RenderLoft( vertices, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); // reuse the scratchpad + Segment->RenderLoft( vertices, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + } if( ( Bank == 0 ) && ( false == Geometry1.empty() ) ) { + // special variant, replace existing data for a turntable track Segment->RenderLoft( vertices, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); GfxRenderer.Replace( vertices, Geometry1[ 0 ] ); vertices.clear(); // reuse the scratchpad Segment->RenderLoft( vertices, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); GfxRenderer.Replace( vertices, Geometry1[ 1 ] ); } - else { - Segment->RenderLoft( vertices, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); - Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); - vertices.clear(); // reuse the scratchpad - Segment->RenderLoft( vertices, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); - Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); - } } break; case tt_Switch: // dla zwrotnicy dwa razy szyny diff --git a/mouseinput.cpp b/mouseinput.cpp index c38b64f1..97e1f6dc 100644 --- a/mouseinput.cpp +++ b/mouseinput.cpp @@ -125,9 +125,11 @@ mouse_input::button( int const Button, int const Action ) { // TODO: pass correct entity id once the missing systems are in place m_relay.post( mousecommand, 0, 0, Action, 0 ); m_updateaccumulator = 0.0; // prevent potential command repeat right after issuing one +/* if( mousecommand == user_command::mastercontrollerincrease ) { m_updateaccumulator -= 0.15; // extra pause on first increase of master controller } +*/ switch( mousecommand ) { case user_command::mastercontrollerincrease: case user_command::mastercontrollerdecrease: diff --git a/renderer.cpp b/renderer.cpp index 97690ec0..6800e1e4 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -120,10 +120,9 @@ opengl_renderer::Init( GLFWwindow *Window ) { m_lights.emplace_back( light ); } #ifdef EU07_USE_PICKING_FRAMEBUFFER + // pick buffer resources if( true == m_framebuffersupport ) { - // try to create the pick buffer. RGBA8 2D texture, 24 bit depth texture, 1024x512 - int const width { 1024 }; - int const height { 512 }; + // try to create the pick buffer. RGBA8 2D texture, 24 bit depth texture, 1024x1024 (height of 512 would suffice but, eh) // texture ::glGenTextures( 1, &m_picktexture ); ::glBindTexture( GL_TEXTURE_2D, m_picktexture ); @@ -131,18 +130,17 @@ 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, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL ); + ::glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, m_pickbuffersize, m_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, width, height ); - // create and set up the framebuffer + ::glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, m_pickbuffersize, m_pickbuffersize ); + // create and assemble the framebuffer ::glGenFramebuffersEXT( 1, &m_pickframebuffer ); ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_pickframebuffer ); ::glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_picktexture, 0 ); ::glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_pickdepthbuffer ); - //------------------------- - //Does the GPU support current FBO configuration? + // check if we got it working GLenum status = ::glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT ); if( status == GL_FRAMEBUFFER_COMPLETE_EXT ) { WriteLog( "Picking framebuffer setup complete" ); @@ -154,6 +152,41 @@ opengl_renderer::Init( GLFWwindow *Window ) { ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch back to primary render target for now } #endif + // shadowmap resources + if( ( true == Global::RenderShadows ) + && ( true == m_framebuffersupport ) ) { + // texture: + ::glGenTextures( 1, &m_shadowtexture ); + ::glBindTexture( GL_TEXTURE_2D, m_shadowtexture ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + ::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 ); + // enable shadow comparison: true (ie not in shadow) if r<=texture... + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL ); + // ...shadow comparison should generate an INTENSITY result + ::glTexParameteri( GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY ); + ::glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, m_shadowbuffersize, m_shadowbuffersize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL ); + // create and assemble the framebuffer + ::glGenFramebuffersEXT( 1, &m_shadowframebuffer ); + ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_shadowframebuffer ); + ::glDrawBuffer( GL_NONE ); // we won't be rendering colour data, so can skip the colour attachment + ::glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_shadowtexture, 0 ); + // check if we got it working + GLenum status = ::glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT ); + if( status == GL_FRAMEBUFFER_COMPLETE_EXT ) { + WriteLog( "Shadows framebuffer setup complete" ); + } + else { + ErrorLog( "Shadows framebuffer setup failed" ); + m_framebuffersupport = false; + Global::RenderShadows = false; + } + ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch back to primary render target for now + ::glDrawBuffer( GL_BACK ); + } + ::glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // preload some common textures WriteLog( "Loading common gfx data..." ); @@ -205,7 +238,9 @@ opengl_renderer::Render_pass( rendermode const Mode ) { // TODO: run shadowmap pass before color -// ::glViewport( 0, 0, Global::ScreenWidth, Global::ScreenHeight ); +#ifdef EU07_USE_PICKING_FRAMEBUFFER + ::glViewport( 0, 0, Global::ScreenWidth, Global::ScreenHeight ); +#endif if( World.InitPerformed() ) { auto const skydomecolour = World.Environment.m_skydome.GetAverageColor(); ::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 0.0f ); // kolor nieba @@ -234,9 +269,33 @@ opengl_renderer::Render_pass( rendermode const Mode ) { break; } + case rendermode::shadows: { + +#ifdef EU07_USE_PICKING_FRAMEBUFFER + ::glViewport( 0, 0, m_pickbuffersize, m_pickbuffersize ); // TODO: separate shadow buffer +#endif + ::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + if( World.InitPerformed() ) { + // setup + m_renderpass.draw_range = 500.0f; // 1.5km square centered around camera + Render_projection(); + Render_camera(); + ::glDepthFunc( GL_LEQUAL ); + // render + // opaque parts... + Render_setup(); + Render( &World.Ground ); + } + break; + } + case rendermode::pickcontrols: { -// ::glViewport( 0, 0, 1024, 512 ); +#ifdef EU07_USE_PICKING_FRAMEBUFFER + ::glViewport( 0, 0, m_pickbuffersize, m_pickbuffersize ); +#endif ::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); @@ -259,7 +318,9 @@ opengl_renderer::Render_pass( rendermode const Mode ) { case rendermode::pickscenery: { -// ::glViewport( 0, 0, 1024, 512 ); +#ifdef EU07_USE_PICKING_FRAMEBUFFER + ::glViewport( 0, 0, m_pickbuffersize, m_pickbuffersize ); +#endif ::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); @@ -319,6 +380,12 @@ opengl_renderer::Render_projection() { */ case rendermode::shadows: { // TODO: set parallel projection + ::gluPerspective( + Global::FieldOfView, + 1.f, +// std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ), + 2.f, + m_renderpass.draw_range * Global::fDistanceFactor ); break; } @@ -346,7 +413,7 @@ opengl_renderer::Render_camera() { break; } case rendermode::shadows: { - m_renderpass.camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction * 750.f }; + m_renderpass.camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction * 250.f }; m_renderpass.camera.position().y = std::max( 50.0, m_renderpass.camera.position().y ); // prevent shadow source from dipping too low viewmatrix = glm::lookAt( m_renderpass.camera.position(), @@ -1258,6 +1325,9 @@ opengl_renderer::Render( TSubModel *Submodel ) { // rysuj gdy element nieprzezroczysty switch( m_renderpass.draw_mode ) { case rendermode::color: { +// NOTE: code disabled as normalization marking doesn't take into account scaling propagation down hierarchy chains +// for the time being we'll do with enforced worst-case scaling method, when speculars are enabled +#ifdef EU07_USE_OPTIMIZED_NORMALIZATION switch( Submodel->m_normalizenormals ) { case TSubModel::normalize: { ::glEnable( GL_NORMALIZE ); break; } @@ -1266,6 +1336,11 @@ opengl_renderer::Render( TSubModel *Submodel ) { default: { break; } } +#else + if( true == m_renderspecular ) { + ::glEnable( GL_NORMALIZE ); + } +#endif // material configuration: // textures... if( Submodel->TextureID < 0 ) { // zmienialne skóry @@ -1280,6 +1355,7 @@ opengl_renderer::Render( TSubModel *Submodel ) { if( ( true == m_renderspecular ) && ( Global::DayLight.specular.a > 0.01f ) ) { // specular strength in legacy models is set uniformly to 150, 150, 150 so we scale it down for opaque elements ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( Submodel->f4Specular * Global::DayLight.specular.a * m_specularopaquescalefactor ) ); + ::glEnable( GL_RESCALE_NORMAL ); } // ...luminance if( Global::fLuminance < Submodel->fLight ) { @@ -1298,6 +1374,7 @@ opengl_renderer::Render( TSubModel *Submodel ) { // restore default (lack of) brightness ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( colors::none ) ); } +#ifdef EU07_USE_OPTIMIZED_NORMALIZATION switch( Submodel->m_normalizenormals ) { case TSubModel::normalize: { ::glDisable( GL_NORMALIZE ); break; } @@ -1306,6 +1383,11 @@ opengl_renderer::Render( TSubModel *Submodel ) { default: { break; } } +#else + if( true == m_renderspecular ) { + ::glDisable( GL_NORMALIZE ); + } +#endif break; } case rendermode::shadows: @@ -1800,6 +1882,9 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { // renderowanie obiektów OpenGL if( Submodel->iAlpha & Submodel->iFlags & 0x2F ) // rysuj gdy element przezroczysty { +// NOTE: code disabled as normalization marking doesn't take into account scaling propagation down hierarchy chains +// for the time being we'll do with enforced worst-case scaling method, when speculars are enabled +#ifdef EU07_USE_OPTIMIZED_NORMALIZATION switch( Submodel->m_normalizenormals ) { case TSubModel::normalize: { ::glEnable( GL_NORMALIZE ); break; } @@ -1808,6 +1893,11 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { default: { break; } } +#else + if( true == m_renderspecular ) { + ::glEnable( GL_NORMALIZE ); + } +#endif // textures... if( Submodel->TextureID < 0 ) { // zmienialne skóry Bind( Submodel->ReplacableSkinId[ -Submodel->TextureID ] ); @@ -1838,6 +1928,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { // restore default (lack of) brightness ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( colors::none ) ); } +#ifdef EU07_USE_OPTIMIZED_NORMALIZATION switch( Submodel->m_normalizenormals ) { case TSubModel::normalize: { ::glDisable( GL_NORMALIZE ); break; } @@ -1846,6 +1937,11 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { default: { break; } } +#else + if( true == m_renderspecular ) { + ::glDisable( GL_NORMALIZE ); + } +#endif } } else if( Submodel->eType == TP_FREESPOTLIGHT ) { @@ -1954,12 +2050,14 @@ opengl_renderer::Update_Pick_Control() { glm::dvec2 mousepos; glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); mousepos.y = Global::ScreenHeight - mousepos.y; // cursor coordinates are flipped compared to opengl -/* + +#ifdef EU07_USE_PICKING_FRAMEBUFFER glm::ivec2 pickbufferpos { - mousepos.x * 1024.0f / Global::ScreenWidth, - mousepos.y * 512.0f / Global::ScreenHeight }; -*/ + mousepos.x * m_pickbuffersize / Global::ScreenWidth, + mousepos.y * m_pickbuffersize / Global::ScreenHeight }; +#else glm::ivec2 pickbufferpos{ mousepos }; +#endif unsigned char pickreadout[4]; ::glReadPixels( pickbufferpos.x, pickbufferpos.y, 1, 1, GL_BGRA, GL_UNSIGNED_BYTE, pickreadout ); @@ -1998,12 +2096,14 @@ opengl_renderer::Update_Pick_Node() { glm::dvec2 mousepos; glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); mousepos.y = Global::ScreenHeight - mousepos.y; // cursor coordinates are flipped compared to opengl -/* + +#ifdef EU07_USE_PICKING_FRAMEBUFFER glm::ivec2 pickbufferpos { - mousepos.x * 1024.0f / Global::ScreenWidth, - mousepos.y * 512.0f / Global::ScreenHeight }; -*/ + mousepos.x * m_pickbuffersize / Global::ScreenWidth, + mousepos.y * m_pickbuffersize / Global::ScreenHeight }; +#else glm::ivec2 pickbufferpos{ mousepos }; +#endif unsigned char pickreadout[4]; ::glReadPixels( pickbufferpos.x, pickbufferpos.y, 1, 1, GL_BGRA, GL_UNSIGNED_BYTE, pickreadout ); @@ -2198,15 +2298,13 @@ opengl_renderer::Init_caps() { WriteLog( "Supported extensions:" + std::string((char *)glGetString( GL_EXTENSIONS )) ); WriteLog( std::string("Render path: ") + ( Global::bUseVBO ? "VBO" : "Display lists" ) ); -#ifdef EU07_USE_PICKING_FRAMEBUFFER if( GLEW_EXT_framebuffer_object ) { m_framebuffersupport = true; WriteLog( "Framebuffer objects enabled" ); } else { - WriteLog( "Framebuffer objects not supported, resorting to back buffer rendering" ); + WriteLog( "Framebuffer objects not supported, resorting to back buffer rendering where possible" ); } -#endif if( Global::iMultisampling ) WriteLog( "Using multisampling x" + std::to_string( 1 << Global::iMultisampling ) ); // ograniczenie maksymalnego rozmiaru tekstur - parametr dla skalowania tekstur diff --git a/renderer.h b/renderer.h index 4459e48d..1157e563 100644 --- a/renderer.h +++ b/renderer.h @@ -254,7 +254,11 @@ private: GLuint m_pickframebuffer { 0 }; // TODO: refactor pick framebuffer stuff into an object GLuint m_picktexture { 0 }; GLuint m_pickdepthbuffer { 0 }; + int m_pickbuffersize { 1024 }; // size of (square) textures bound with the pick framebuffer #endif + GLuint m_shadowframebuffer { 0 }; + GLuint m_shadowtexture { 0 }; + int m_shadowbuffersize { 2048 }; GLUquadricObj *m_quadric { nullptr }; // helper object for drawing debug mode scene elements geometry_handle m_billboardgeometry { 0, 0 }; diff --git a/version.h b/version.h index a4437670..dedc7d9c 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 715 +#define VERSION_MINOR 717 #define VERSION_REVISION 0 From 8d5fde73710ba352da1519595c15973b3add8fc1 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 21 Jul 2017 01:27:20 +0200 Subject: [PATCH 2/3] completed basic separation of visual renderer from simulation --- AnimModel.cpp | 5 +- AnimModel.h | 2 + DynObj.cpp | 20 +++--- Ground.cpp | 7 +-- Model3d.cpp | 4 +- Track.cpp | 32 +++------- Track.h | 2 - renderer.cpp | 171 ++++++++++++++++++++++++++++++++++++-------------- renderer.h | 32 +++++----- sky.cpp | 15 +++-- sky.h | 16 ++--- stars.cpp | 8 ++- stars.h | 9 ++- stdafx.h | 2 +- uilayer.cpp | 2 +- 15 files changed, 197 insertions(+), 130 deletions(-) diff --git a/AnimModel.cpp b/AnimModel.cpp index 73b5524e..58d8ecb0 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -445,7 +445,7 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable asText = asReplacableTexture.substr(1, asReplacableTexture.length() - 1); // zapamiętanie tekstu else if (asReplacableTexture != "none") m_materialdata.replacable_skins[1] = - GfxRenderer.GetTextureId( asReplacableTexture, "" ); + GfxRenderer.Fetch_Texture( 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 @@ -606,6 +606,7 @@ int TAnimModel::Flags() //----------------------------------------------------------------------------- // 2011-03-16 funkcje renderowania z możliwością pochylania obiektów //----------------------------------------------------------------------------- +#ifdef EU07_USE_OLD_RENDERCODE void TAnimModel::Render( vector3 const &Position ) { RaAnimate(); // jednorazowe przeliczenie animacji RaPrepare(); @@ -617,7 +618,7 @@ void TAnimModel::RenderAlpha( vector3 const &Position ) { if( pModel ) // renderowanie rekurencyjne submodeli GfxRenderer.Render_Alpha( pModel, Material(), Position, vAngle ); }; - +#endif //--------------------------------------------------------------------------- bool TAnimModel::TerrainLoaded() { // zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy diff --git a/AnimModel.h b/AnimModel.h index 17957f16..69866f56 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -164,8 +164,10 @@ class TAnimModel { bool Load(cParser *parser, bool ter = false); TAnimContainer * AddContainer(char *pName); TAnimContainer * GetContainer(char *pName); +#ifdef EU07_USE_OLD_RENDERCODE void Render( vector3 const &Position ); void RenderAlpha( vector3 const &Position ); +#endif int Flags(); void RaAnglesSet(double a, double b, double c) { diff --git a/DynObj.cpp b/DynObj.cpp index 05b2ac47..2a5c9254 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -4064,7 +4064,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, { std::string nowheretexture = TextureTest(Global::asCurrentTexturePath + "nowhere"); // na razie prymitywnie if( false == nowheretexture.empty() ) { - m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( nowheretexture, "", 9 ); + m_materialdata.replacable_skins[ 4 ] = GfxRenderer.Fetch_Texture( nowheretexture, "", 9 ); } if (m_materialdata.multi_textures > 0) { @@ -4076,7 +4076,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, int skinindex = 0; std::string texturename; nameparser >> texturename; while( ( texturename != "" ) && ( skinindex < 4 ) ) { - m_materialdata.replacable_skins[ skinindex + 1 ] = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + texturename, "" ); + m_materialdata.replacable_skins[ skinindex + 1 ] = GfxRenderer.Fetch_Texture( Global::asCurrentTexturePath + texturename, "" ); ++skinindex; texturename = ""; nameparser >> texturename; } @@ -4086,7 +4086,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, // otherwise try the basic approach int skinindex = 0; do { - texture_handle texture = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + ReplacableSkin + "," + std::to_string( skinindex + 1 ), "", Global::iDynamicFiltering, true ); + texture_handle texture = GfxRenderer.Fetch_Texture( Global::asCurrentTexturePath + ReplacableSkin + "," + std::to_string( skinindex + 1 ), "", Global::iDynamicFiltering, true ); if( texture == NULL ) { break; } @@ -4096,12 +4096,12 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, m_materialdata.multi_textures = skinindex; if( m_materialdata.multi_textures == 0 ) { // zestaw nie zadziałał, próbujemy normanie - m_materialdata.replacable_skins[ 1 ] = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + ReplacableSkin, "", Global::iDynamicFiltering ); + m_materialdata.replacable_skins[ 1 ] = GfxRenderer.Fetch_Texture( Global::asCurrentTexturePath + ReplacableSkin, "", Global::iDynamicFiltering ); } } } else { - m_materialdata.replacable_skins[ 1 ] = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + ReplacableSkin, "", Global::iDynamicFiltering ); + m_materialdata.replacable_skins[ 1 ] = GfxRenderer.Fetch_Texture( Global::asCurrentTexturePath + ReplacableSkin, "", Global::iDynamicFiltering ); } if( GfxRenderer.Texture( m_materialdata.replacable_skins[ 1 ] ).has_alpha ) { // tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych @@ -5424,13 +5424,13 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer) 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ę + m_materialdata.replacable_skins[ 4 ] = GfxRenderer.Fetch_Texture( 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ę + m_materialdata.replacable_skins[ 4 ] = GfxRenderer.Fetch_Texture( x, "", 9 ); // rozmywania 0,1,4,5 nie nadają się return; } if (to.empty()) @@ -5438,17 +5438,17 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer) 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ę + m_materialdata.replacable_skins[ 4 ] = GfxRenderer.Fetch_Texture( 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ę + m_materialdata.replacable_skins[ 4 ] = GfxRenderer.Fetch_Texture( 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 ); + m_materialdata.replacable_skins[ 4 ] = GfxRenderer.Fetch_Texture( x, "", 9 ); } // Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa tekstury nr 4 }; diff --git a/Ground.cpp b/Ground.cpp index b4640ea4..9f66a6e3 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -53,9 +53,8 @@ std::string LogComment; bool degenerate( glm::dvec3 const &Vertex1, glm::dvec3 const &Vertex2, glm::dvec3 const &Vertex3 ) { - return ( ( Vertex1 == Vertex2 ) - || ( Vertex2 == Vertex3 ) - || ( Vertex3 == Vertex1 ) ); +// degenerate( A, B, C, minarea ) = ( ( B - A ).cross( C - A ) ).lengthSquared() < ( 4.0f * minarea * minarea ); + return glm::length2( glm::cross( Vertex2 - Vertex1, Vertex3 - Vertex1 ) ) < std::numeric_limits::epsilon(); } //--------------------------------------------------------------------------- @@ -1330,7 +1329,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) *parser >> token; } str = token; - tmp->TextureID = GfxRenderer.GetTextureId( str, szTexturePath ); + tmp->TextureID = GfxRenderer.Fetch_Texture( str ); bool const clamps = ( tmp->TextureID ? GfxRenderer.Texture( tmp->TextureID ).traits.find( 's' ) != std::string::npos : diff --git a/Model3d.cpp b/Model3d.cpp index b77b9329..06a5f43c 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -341,7 +341,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic if( texture.find_first_of( "/\\" ) == texture.npos ) { texture.insert( 0, Global::asCurrentTexturePath ); } - TextureID = GfxRenderer.GetTextureId( texture, szTexturePath ); + TextureID = GfxRenderer.Fetch_Texture( texture ); // renderowanie w cyklu przezroczystych tylko jeśli: // 1. Opacity=0 (przejściowo <1, czy tam <100) oraz // 2. tekstura ma przezroczystość @@ -1670,7 +1670,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, pTexture = t->at(iTexture); if (pTexture.find_last_of("/\\") == std::string::npos) pTexture.insert(0, Global::asCurrentTexturePath); - TextureID = GfxRenderer.GetTextureId(pTexture, szTexturePath); + TextureID = GfxRenderer.Fetch_Texture(pTexture); if( ( iFlags & 0x30 ) == 0 ) { // texture-alpha based fallback if for some reason we don't have opacity flag set yet iFlags |= diff --git a/Track.cpp b/Track.cpp index 433a344e..8b55c4ca 100644 --- a/Track.cpp +++ b/Track.cpp @@ -483,20 +483,20 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) { parser->getTokens(); *parser >> str; // railtex - TextureID1 = (str == "none" ? 0 : GfxRenderer.GetTextureId( - str, szTexturePath, - (iCategoryFlag & 1) ? Global::iRailProFiltering : - Global::iBallastFiltering)); + TextureID1 = ( + str == "none" ? + NULL : + GfxRenderer.Fetch_Texture( str ) ); parser->getTokens(); *parser >> fTexLength; // tex tile length if (fTexLength < 0.01) fTexLength = 4; // Ra: zabezpiecznie przed zawieszeniem parser->getTokens(); *parser >> str; // sub || railtex - TextureID2 = (str == "none" ? 0 : GfxRenderer.GetTextureId( - str, szTexturePath, - (eType == tt_Normal) ? Global::iBallastFiltering : - Global::iRailProFiltering)); + TextureID2 = ( + str == "none" ? + NULL : + GfxRenderer.Fetch_Texture( str ) ); parser->getTokens(3); *parser >> fTexHeight1 >> fTexWidth >> fTexSlope; if (iCategoryFlag & 4) @@ -1866,22 +1866,6 @@ void TTrack::EnvironmentReset() } }; -void TTrack::RenderDyn() -{ // renderowanie nieprzezroczystych fragmentów pojazdów - for( auto dynamic : Dynamics ) { - // sam sprawdza, czy VBO; zmienia kontekst VBO! - GfxRenderer.Render( dynamic ); - } -}; - -void TTrack::RenderDynAlpha() -{ // renderowanie przezroczystych fragmentów pojazdów - for( auto dynamic : Dynamics ) { - // sam sprawdza, czy VBO; zmienia kontekst VBO! - GfxRenderer.Render_Alpha( dynamic ); - } -}; - void TTrack::RenderDynSounds() { // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania for( auto dynamic : Dynamics ) { diff --git a/Track.h b/Track.h index f7bf31e6..884d6907 100644 --- a/Track.h +++ b/Track.h @@ -236,8 +236,6 @@ public: /* void RaRenderVBO(int iPtr); // renderowanie z VBO sektora */ - void RenderDyn(); // renderowanie nieprzezroczystych pojazdów (oba tryby) - void RenderDynAlpha(); // renderowanie przezroczystych pojazdów (oba tryby) void RenderDynSounds(); // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania void RaOwnerSet(TSubRect *o) { diff --git a/renderer.cpp b/renderer.cpp index 6800e1e4..4ddb6df5 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -190,9 +190,9 @@ opengl_renderer::Init( GLFWwindow *Window ) { ::glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // preload some common textures WriteLog( "Loading common gfx data..." ); - m_glaretexture = GetTextureId( "fx\\lightglare", szTexturePath ); - m_suntexture = GetTextureId( "fx\\sun", szTexturePath ); - m_moontexture = GetTextureId( "fx\\moon", szTexturePath ); + m_glaretexture = Fetch_Texture( "fx\\lightglare" ); + m_suntexture = Fetch_Texture( "fx\\sun" ); + m_moontexture = Fetch_Texture( "fx\\moon" ); WriteLog( "...gfx data pre-loading done" ); // prepare basic geometry chunks auto const geometrybank = m_geometry.create_bank(); @@ -236,15 +236,27 @@ opengl_renderer::Render_pass( rendermode const Mode ) { case rendermode::color: { - // TODO: run shadowmap pass before color + if( Global::RenderShadows && World.InitPerformed() ) { + // run shadowmap pass before color + ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_shadowframebuffer ); + ::glDrawBuffer( GL_NONE ); // we won't be rendering colour data, so can skip the colour attachment + + Render_pass( rendermode::shadows ); + m_renderpass.draw_mode = rendermode::color; // restore draw mode. TODO: render mode stack + + ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch back to primary render target + ::glDrawBuffer( GL_BACK ); + } -#ifdef EU07_USE_PICKING_FRAMEBUFFER ::glViewport( 0, 0, Global::ScreenWidth, Global::ScreenHeight ); -#endif + if( World.InitPerformed() ) { auto const skydomecolour = World.Environment.m_skydome.GetAverageColor(); ::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 0.0f ); // kolor nieba } + else { + ::glClearColor( 51.0f / 255.0f, 102.0f / 255.0f, 85.0f / 255.0f, 1.0f ); // initial background Color + } ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); if( World.InitPerformed() ) { @@ -271,15 +283,14 @@ opengl_renderer::Render_pass( rendermode const Mode ) { case rendermode::shadows: { -#ifdef EU07_USE_PICKING_FRAMEBUFFER - ::glViewport( 0, 0, m_pickbuffersize, m_pickbuffersize ); // TODO: separate shadow buffer -#endif + ::glViewport( 0, 0, m_shadowbuffersize, m_shadowbuffersize ); + ::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); - ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + ::glClear( GL_DEPTH_BUFFER_BIT ); if( World.InitPerformed() ) { // setup - m_renderpass.draw_range = 500.0f; // 1.5km square centered around camera + m_renderpass.draw_range = 500.0f; // 1.0km square centered around camera Render_projection(); Render_camera(); ::glDepthFunc( GL_LEQUAL ); @@ -355,9 +366,11 @@ opengl_renderer::Render_projection() { switch( m_renderpass.draw_mode ) { - case rendermode::color: +#ifndef EU07_USE_PICKING_FRAMEBUFFER case rendermode::pickcontrols: - case rendermode::pickscenery: { + case rendermode::pickscenery: +#endif + case rendermode::color: { ::gluPerspective( Global::FieldOfView / Global::ZoomFactor, std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ), @@ -365,19 +378,20 @@ opengl_renderer::Render_projection() { m_renderpass.draw_range * Global::fDistanceFactor ); break; } -/* - // version for the smaller pickbuffer. ultimately scratched because resolution isn't comfortable/reliable enough for the user +#ifdef EU07_USE_PICKING_FRAMEBUFFER case rendermode::pickcontrols: case rendermode::pickscenery: { - // TODO: render to buffer and scissor test for pick modes + // 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 / 1024.0f ), + 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 ); break; } -*/ +#endif case rendermode::shadows: { // TODO: set parallel projection ::gluPerspective( @@ -447,6 +461,9 @@ opengl_renderer::Render_setup( bool const Alpha ) { case rendermode::color: { ::glEnable( GL_LIGHTING ); ::glShadeModel( GL_SMOOTH ); + if( Global::iMultisampling ) { + ::glEnable( GL_MULTISAMPLE ); + } // setup fog if( Global::fFogEnd > 0 ) { // fog setup @@ -474,9 +491,12 @@ opengl_renderer::Render_setup( bool const Alpha ) { case rendermode::shadows: case rendermode::pickcontrols: case rendermode::pickscenery: { - ::glDisable( GL_FOG ); ::glDisable( GL_LIGHTING ); ::glShadeModel( GL_FLAT ); + if( Global::iMultisampling ) { + ::glDisable( GL_MULTISAMPLE ); + } + ::glDisable( GL_FOG ); if( m_texenvmode != m_renderpass.draw_mode ) { // solid colour with texture alpha @@ -508,19 +528,32 @@ opengl_renderer::Render( world_environment *Environment ) { } Bind( NULL ); - ::glDisable( GL_LIGHTING ); ::glDisable( GL_DEPTH_TEST ); ::glDepthMask( GL_FALSE ); ::glPushMatrix(); + // skydome Environment->m_skydome.Render(); if( true == Global::bUseVBO ) { // skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh opengl_vbogeometrybank::reset(); } - Environment->m_stars.render(); + // stars + if( Environment->m_stars.m_stars != nullptr ) { + // setup + ::glPushMatrix(); + ::glRotatef( Environment->m_stars.m_latitude, 1.f, 0.f, 0.f ); // ustawienie osi OY na północ + ::glRotatef( -std::fmod( (float)Global::fTimeAngleDeg, 360.f ), 0.f, 1.f, 0.f ); // obrót dobowy osi OX + ::glPointSize( 2.f ); + // render + GfxRenderer.Render( Environment->m_stars.m_stars, nullptr, 1.0 ); + // post-render cleanup + ::glPointSize( 3.f ); + ::glPopMatrix(); + } + // celestial bodies float const duskfactor = 1.0f - clamp( std::abs( Environment->m_sun.getAngle() ), 0.0f, 12.0f ) / 12.0f; glm::vec3 suncolor = interpolate( glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ), @@ -601,10 +634,26 @@ opengl_renderer::Render( world_environment *Environment ) { ::glPopAttrib(); // clouds - Environment->m_clouds.Render( - interpolate( Environment->m_skydome.GetAverageColor(), suncolor, duskfactor * 0.25f ) - * ( 1.0f - Global::Overcast * 0.5f ) // overcast darkens the clouds - * 2.5f ); // arbitrary adjustment factor + if( Environment->m_clouds.mdCloud ) { + // setup + Disable_Lights(); + ::glEnable( GL_LIGHTING ); + ::glLightModelfv( + GL_LIGHT_MODEL_AMBIENT, + glm::value_ptr( + interpolate( Environment->m_skydome.GetAverageColor(), suncolor, duskfactor * 0.25f ) + * ( 1.0f - Global::Overcast * 0.5f ) // overcast darkens the clouds + * 2.5f // arbitrary adjustment factor + ) ); + // render + Render( Environment->m_clouds.mdCloud, nullptr, 100.0 ); + Render_Alpha( Environment->m_clouds.mdCloud, nullptr, 100.0 ); + // post-render cleanup + GLfloat noambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, noambient ); + ::glEnable( GL_LIGHT0 ); // other lights will be enabled during lights update + ::glDisable( GL_LIGHTING ); + } Global::DayLight.apply_angle(); Global::DayLight.apply_intensity(); @@ -655,7 +704,7 @@ opengl_renderer::Vertices( geometry_handle const &Geometry ) const { // texture methods texture_handle -opengl_renderer::GetTextureId( std::string Filename, std::string const &Dir, int const Filter, bool const Loadnow ) { +opengl_renderer::Fetch_Texture( std::string const &Filename, std::string const &Dir, int const Filter, bool const Loadnow ) { return m_textures.create( Filename, Dir, Filter, Loadnow ); } @@ -854,7 +903,7 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) { #ifdef EU07_SCENERY_EDITOR // memcells if( EditorModeFlag ) { - for( auto const memcell : m_memcells ) { + for( auto const memcell : Groundsubcell->m_memcells ) { Render( memcell ); } } @@ -888,7 +937,7 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) { #ifdef EU07_SCENERY_EDITOR // memcells if( EditorModeFlag ) { - for( auto const memcell : m_memcells ) { + for( auto const memcell : Groundsubcell->m_memcells ) { ::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) ); Render( memcell ); } @@ -961,7 +1010,14 @@ 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 ) // renderowanie rekurencyjne submodeli + Render( Node->Model->pModel, Node->Model->Material(), Node->pCenter - m_renderpass.camera.position(), Node->Model->vAngle ); +#endif return true; } @@ -1559,19 +1615,35 @@ opengl_renderer::Render( TTrack *Track ) { void opengl_renderer::Render( TMemCell *Memcell ) { - ::glPushAttrib( GL_ENABLE_BIT ); -// ::glDisable( GL_LIGHTING ); - ::glDisable( GL_TEXTURE_2D ); -// ::glEnable( GL_BLEND ); ::glPushMatrix(); - - auto const position = Memcell->Position(); + auto const position = Memcell->Position() - m_renderpass.camera.position(); ::glTranslated( position.x, position.y + 0.5, position.z ); - ::glColor3f( 0.36f, 0.75f, 0.35f ); - ::gluSphere( m_quadric, 0.35, 4, 2 ); + + switch( m_renderpass.draw_mode ) { + case rendermode::color: { + ::glPushAttrib( GL_ENABLE_BIT ); + ::glDisable( GL_TEXTURE_2D ); + ::glColor3f( 0.36f, 0.75f, 0.35f ); + + ::gluSphere( m_quadric, 0.35, 4, 2 ); + + ::glPopAttrib(); + break; + } + case rendermode::pickscenery: + case rendermode::shadows: { + ::gluSphere( m_quadric, 0.35, 4, 2 ); + break; + } + case rendermode::pickcontrols: { + break; + } + default: { + break; + } + } ::glPopMatrix(); - ::glPopAttrib(); } bool @@ -1615,8 +1687,11 @@ opengl_renderer::Render_Alpha( TSubRect *Groundsubcell ) { Render_Alpha( node ); // przezroczyste z mieszanych modeli for( node = Groundsubcell->nRenderAlpha; node; node = node->nNext3 ) Render_Alpha( node ); // przezroczyste modele - for( int j = 0; j < Groundsubcell->iTracks; ++j ) - Groundsubcell->tTracks[ j ]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach + for( int trackidx = 0; trackidx < Groundsubcell->iTracks; ++trackidx ) { + for( auto dynamic : Groundsubcell->tTracks[ trackidx ]->Dynamics ) { + Render_Alpha( dynamic ); // przezroczyste fragmenty pojazdów na torach + } + } return true; } @@ -1677,7 +1752,13 @@ 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 + Render_Alpha( Node->Model->pModel, Node->Model->Material(), Node->pCenter - m_renderpass.camera.position(), Node->Model->vAngle ); +#endif return true; } @@ -2137,15 +2218,11 @@ opengl_renderer::Update( double const Deltatime ) { // 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 > 90.0 ) { targetsegments = 400; targetfactor = 3.0f; } - else if( framerate > 60.0 ) { targetsegments = 225; targetfactor = 1.5f; } - else if( framerate > 30.0 ) { targetsegments = 90; targetfactor = Global::ScreenHeight / 768.0f; } - else { targetsegments = 9; targetfactor = Global::ScreenHeight / 768.0f * 0.75f; } + 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; } if( targetfactor > Global::fDistanceFactor ) { diff --git a/renderer.h b/renderer.h index 1157e563..8095a188 100644 --- a/renderer.h +++ b/renderer.h @@ -119,21 +119,6 @@ public: // main draw call. returns false on error bool Render(); - // render sub-methods, temporarily exposed until we complete migrating render code to the renderer - bool - Render( TDynamicObject *Dynamic ); - bool - Render( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); - bool - Render( TModel3d *Model, material_data const *Material, double const Squaredistance ); - void - Render( TSubModel *Submodel ); - bool - Render_Alpha( TDynamicObject *Dynamic ); - bool - Render_Alpha( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); - bool - Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance ); // geometry methods // NOTE: hands-on geometry management is exposed as a temporary measure; ultimately all visualization data should be generated/handled automatically by the renderer itself // creates a new geometry bank. returns: handle to the bank or NULL @@ -153,7 +138,7 @@ public: Vertices( geometry_handle const &Geometry ) const; // texture methods texture_handle - GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ); + Fetch_Texture( std::string const &Filename, std::string const &Dir = szTexturePath, int const Filter = -1, bool const Loadnow = true ); void Bind( texture_handle const Texture ); opengl_texture const & @@ -225,6 +210,14 @@ private: Render( TSubRect *Groundsubcell ); bool Render( TGroundNode *Node ); + bool + Render( TDynamicObject *Dynamic ); + bool + Render( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); + bool + Render( TModel3d *Model, material_data const *Material, double const Squaredistance ); + void + Render( TSubModel *Submodel ); void Render( TTrack *Track ); bool @@ -237,6 +230,12 @@ private: Render_Alpha( TSubRect *Groundsubcell ); bool Render_Alpha( TGroundNode *Node ); + bool + Render_Alpha( TDynamicObject *Dynamic ); + bool + Render_Alpha( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); + bool + Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance ); void Render_Alpha( TSubModel *Submodel ); void @@ -277,6 +276,7 @@ private: bool m_framebuffersupport { false }; rendermode m_texenvmode { rendermode::color }; // last configured texture environment renderpass_config m_renderpass; +// std::stack m_renderpasses; bool m_renderspecular { false }; // controls whether to include specular component in the calculations std::vector m_picksceneryitems; std::vector m_pickcontrolsitems; diff --git a/sky.cpp b/sky.cpp index 284825ab..86aba2fe 100644 --- a/sky.cpp +++ b/sky.cpp @@ -9,24 +9,22 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "sky.h" -#include "Logs.h" #include "Globals.h" #include "MdlMngr.h" //--------------------------------------------------------------------------- -GLfloat lightPos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; +//GLfloat lightPos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; -TSky::~TSky(){}; +void TSky::Init() { -TSky::TSky(){}; + if( ( Global::asSky != "1" ) + && ( Global::asSky != "0" ) ) { -void TSky::Init() -{ - WriteLog( "Clouds init" ); - if ((Global::asSky != "1") && (Global::asSky != "0")) mdCloud = TModelsManager::GetModel( Global::asSky ); + } }; +#ifdef EU07_USE_OLD_RENDERCODE void TSky::Render( glm::vec3 const &Tint ) { if (mdCloud) @@ -45,5 +43,6 @@ void TSky::Render( glm::vec3 const &Tint ) ::glDisable( GL_LIGHTING ); } }; +#endif //--------------------------------------------------------------------------- diff --git a/sky.h b/sky.h index ebee49a2..4b544e0e 100644 --- a/sky.h +++ b/sky.h @@ -12,16 +12,18 @@ http://mozilla.org/MPL/2.0/. #include "Model3d.h" -class TSky -{ - private: - TModel3d *mdCloud; +class TSky { - public: - TSky(); - ~TSky(); + friend class opengl_renderer; + +private: + TModel3d *mdCloud { nullptr }; + +public: void Init(); +#ifdef EU07_USE_OLD_RENDERCODE void Render( glm::vec3 const &Tint = glm::vec3(1.0f, 1.0f, 1.0f) ); +#endif }; //--------------------------------------------------------------------------- diff --git a/stars.cpp b/stars.cpp index 08b2b926..ebbd84a6 100644 --- a/stars.cpp +++ b/stars.cpp @@ -2,6 +2,7 @@ #include "stdafx.h" #include "stars.h" #include "globals.h" +#include "MdlMngr.h" ////////////////////////////////////////////////////////////////////////////////////////// // cStars -- simple starfield model, simulating appearance of starry sky @@ -9,9 +10,9 @@ void cStars::init() { - m_stars.LoadFromFile( "models\\skydome_stars.t3d", false ); + m_stars = TModelsManager::GetModel( "models\\skydome_stars.t3d", false ); } - +#ifdef EU07_USE_OLD_RENDERCODE void cStars::render() { // setup @@ -27,4 +28,5 @@ cStars::render() { ::glPointSize( 3.0f ); ::glPopMatrix(); -} \ No newline at end of file +} +#endif diff --git a/stars.h b/stars.h index d5eb7989..dc579ff5 100644 --- a/stars.h +++ b/stars.h @@ -8,13 +8,16 @@ class cStars { + friend class opengl_renderer; + public: // types: // methods: void init(); - void render(); - +#ifdef EU07_USE_OLD_RENDERCODE + void render(); +#endif // constructors: // deconstructor: @@ -29,5 +32,5 @@ private: // members: float m_longitude{ 19.0f }; // geograpic coordinates hardcoded roughly to Poland location, for the time being float m_latitude{ 52.0f }; - TModel3d m_stars; + TModel3d *m_stars { nullptr }; }; diff --git a/stdafx.h b/stdafx.h index cca09510..ca6107c9 100644 --- a/stdafx.h +++ b/stdafx.h @@ -91,4 +91,4 @@ #include #include -#include "openglmatrixstack.h" \ No newline at end of file +#include "openglmatrixstack.h" diff --git a/uilayer.cpp b/uilayer.cpp index 0a98e41b..0b1474f9 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -96,7 +96,7 @@ void ui_layer::set_background( std::string const &Filename ) { if( false == Filename.empty() ) { - m_background = GfxRenderer.GetTextureId( Filename, szTexturePath ); + m_background = GfxRenderer.Fetch_Texture( Filename ); } else { m_background = NULL; From ba5a3613adf29fdd811656b09f0a400079fa1651 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 22 Jul 2017 00:14:07 +0200 Subject: [PATCH 3/3] build 170721. increased size of light points at long distances --- Ground.cpp | 8 -------- Model3d.cpp | 6 ++---- renderer.cpp | 35 +++++++++++++++++++++++++---------- usefull.h | 9 +++++++++ version.h | 2 +- 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/Ground.cpp b/Ground.cpp index 9f66a6e3..91f84e87 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -49,14 +49,6 @@ extern "C" bool bCondition; // McZapkie: do testowania warunku na event multiple std::string LogComment; -// tests whether provided points form a degenerate triangle -bool -degenerate( glm::dvec3 const &Vertex1, glm::dvec3 const &Vertex2, glm::dvec3 const &Vertex3 ) { - -// degenerate( A, B, C, minarea ) = ( ( B - A ).cross( C - A ) ).lengthSquared() < ( 4.0f * minarea * minarea ); - return glm::length2( glm::cross( Vertex2 - Vertex1, Vertex3 - Vertex1 ) ) < std::numeric_limits::epsilon(); -} - //--------------------------------------------------------------------------- // Obiekt renderujący siatkę jest sztucznie tworzonym obiektem pomocniczym, // grupującym siatki obiektów dla danej tekstury. Obiektami składowymi mogą diff --git a/Model3d.cpp b/Model3d.cpp index 06a5f43c..e2168583 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -460,10 +460,8 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic >> Vertices[i].texture.t; if (i % 3 == 2) { // jeżeli wczytano 3 punkty - if (Vertices[i ].position == Vertices[i - 1].position - || Vertices[i - 1].position == Vertices[i - 2].position - || Vertices[i - 2].position == Vertices[i ].position) - { // jeżeli punkty się nakładają na siebie + if( true == degenerate( Vertices[ i ].position, Vertices[ i - 1 ].position, Vertices[ i - 2 ].position ) ) { + // jeżeli punkty się nakładają na siebie --facecount; // o jeden trójkąt mniej iNumVerts -= 3; // czyli o 3 wierzchołki i -= 3; // wczytanie kolejnego w to miejsce diff --git a/renderer.cpp b/renderer.cpp index 4ddb6df5..07453165 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1493,32 +1493,42 @@ opengl_renderer::Render( TSubModel *Submodel ) { // spotlights are only rendered in colour mode(s) case rendermode::color: { auto const &modelview = OpenGLMatrices.data( GL_MODELVIEW ); - auto const lightcenter = modelview * glm::vec4( 0.0f, 0.0f, -0.05f, 1.0f ); // pozycja punktu świecącego względem kamery - Submodel->fCosViewAngle = glm::dot( glm::normalize( modelview * glm::vec4( 0.0f, 0.0f, -1.0f, 1.0f ) - lightcenter ), glm::normalize( -lightcenter ) ); + auto const lightcenter = + modelview + * interpolate( + glm::vec4( 0.f, 0.f, -0.05f, 1.f ), + glm::vec4( 0.f, 0.f, -0.25f, 1.f ), + static_cast( TSubModel::fSquareDist / Submodel->fSquareMaxDist ) ); // pozycja punktu świecącego względem kamery + Submodel->fCosViewAngle = glm::dot( glm::normalize( modelview * glm::vec4( 0.f, 0.f, -1.f, 1.f ) - lightcenter ), glm::normalize( -lightcenter ) ); - if( Submodel->fCosViewAngle > Submodel->fCosFalloffAngle ) // kąt większy niż maksymalny stożek swiatła - { - float lightlevel = 1.0f; // TODO, TBD: parameter to control light strength - // view angle attenuation + if( Submodel->fCosViewAngle > Submodel->fCosFalloffAngle ) { + // kąt większy niż maksymalny stożek swiatła + float lightlevel = 1.f; // TODO, TBD: parameter to control light strength + // view angle attenuation float const anglefactor = ( Submodel->fCosViewAngle - Submodel->fCosFalloffAngle ) / ( 1.0f - Submodel->fCosFalloffAngle ); // distance attenuation. NOTE: since it's fixed pipeline with built-in gamma correction we're using linear attenuation // we're capping how much effect the distance attenuation can have, otherwise the lights get too tiny at regular distances float const distancefactor = static_cast( std::max( 0.5, ( Submodel->fSquareMaxDist - TSubModel::fSquareDist ) / ( Submodel->fSquareMaxDist * Global::fDistanceFactor ) ) ); - if( lightlevel > 0.0f ) { + if( lightlevel > 0.f ) { // material configuration: ::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_POINT_BIT ); Bind( 0 ); - ::glPointSize( std::max( 2.0f, 4.0f * distancefactor * anglefactor ) ); + ::glPointSize( std::max( 3.f, 5.f * distancefactor * anglefactor ) ); ::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], lightlevel * anglefactor ); ::glDisable( GL_LIGHTING ); ::glEnable( GL_BLEND ); + ::glPushMatrix(); + ::glLoadIdentity(); + ::glTranslatef( lightcenter.x, lightcenter.y, lightcenter.z ); // początek układu zostaje bez zmian + // main draw call m_geometry.draw( Submodel->m_geometry ); // post-draw reset + ::glPopMatrix(); ::glPopAttrib(); } } @@ -2031,8 +2041,13 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { // NOTE: we're forced here to redo view angle calculations etc, because this data isn't instanced but stored along with the single mesh // TODO: separate instance data from reusable geometry auto const &modelview = OpenGLMatrices.data( GL_MODELVIEW ); - auto const lightcenter = modelview * glm::vec4( 0.0f, 0.0f, -0.05f, 1.0f ); // pozycja punktu świecącego względem kamery - Submodel->fCosViewAngle = glm::dot( glm::normalize( modelview * glm::vec4( 0.0f, 0.0f, -1.0f, 1.0f ) - lightcenter ), glm::normalize( -lightcenter ) ); + auto const lightcenter = + modelview + * interpolate( + glm::vec4( 0.f, 0.f, -0.05f, 1.f ), + glm::vec4( 0.f, 0.f, -0.10f, 1.f ), + static_cast( TSubModel::fSquareDist / Submodel->fSquareMaxDist ) ); // pozycja punktu świecącego względem kamery + Submodel->fCosViewAngle = glm::dot( glm::normalize( modelview * glm::vec4( 0.f, 0.f, -1.f, 1.f ) - lightcenter ), glm::normalize( -lightcenter ) ); float glarelevel = 0.6f; // luminosity at night is at level of ~0.1, so the overall resulting transparency is ~0.5 at full 'brightness' if( Submodel->fCosViewAngle > Submodel->fCosFalloffAngle ) { diff --git a/usefull.h b/usefull.h index cd747876..6474da98 100644 --- a/usefull.h +++ b/usefull.h @@ -71,4 +71,13 @@ interpolate( Type_ const &First, Type_ const &Second, double const Factor ) { return ( First * ( 1.0 - Factor ) ) + ( Second * Factor ); } +// tests whether provided points form a degenerate triangle +template +bool +degenerate( VecType_ const &Vertex1, VecType_ const &Vertex2, VecType_ const &Vertex3 ) { + + // degenerate( A, B, C, minarea ) = ( ( B - A ).cross( C - A ) ).lengthSquared() < ( 4.0f * minarea * minarea ); + return glm::length2( glm::cross( Vertex2 - Vertex1, Vertex3 - Vertex1 ) ) < std::numeric_limits::epsilon(); +} + //--------------------------------------------------------------------------- diff --git a/version.h b/version.h index dedc7d9c..a54feaa0 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 717 +#define VERSION_MINOR 721 #define VERSION_REVISION 0