From 913541bbee8ba811dd54fb375c47983d6b1ff4f6 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 1 Oct 2018 15:54:46 +0200 Subject: [PATCH] build 181001. texture size definition, fog influence on skydome, minor vehicle logic bug fixes --- Driver.cpp | 2 +- DynObj.cpp | 15 +++-- McZapkie/Mover.cpp | 9 ++- Model3d.cpp | 8 +-- PyInt.cpp | 4 ++ Track.cpp | 119 +++++++++++++++++++++++--------------- Track.h | 3 +- material.cpp | 7 +++ material.h | 1 + openglmatrixstack.h | 21 +++++-- renderer.cpp | 26 +++++---- simulationenvironment.cpp | 4 +- station.cpp | 1 + version.h | 2 +- 14 files changed, 142 insertions(+), 80 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index be6c926e..a4666bea 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -962,7 +962,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // perform loading/unloading auto const platformside = static_cast( std::floor( std::abs( sSpeedTable[ i ].evEvent->input_value( 2 ) ) ) ) % 10; - auto const exchangetime = simulation::Station.update_load( pVehicles[ 0 ], *TrainParams, platformside ); + auto const exchangetime = std::max( 5.0, simulation::Station.update_load( pVehicles[ 0 ], *TrainParams, platformside ) ); WaitingSet( std::max( -fStopTime, exchangetime ) ); // na końcu rozkładu się ustawia 60s i tu by było skrócenie if( TrainParams->CheckTrainLatency() < 0.0 ) { diff --git a/DynObj.cpp b/DynObj.cpp index f9321f88..360ff418 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -3971,9 +3971,15 @@ void TDynamicObject::RenderSounds() { sSmallCompressor.stop(); } - // heating sound - if( MoverParameters->Heating ) { - sHeater.play( sound_flags::exclusive | sound_flags::looping ); + // heater sound + if( ( true == MoverParameters->Heating ) + && ( std::abs( MoverParameters->enrot ) > 0.01 ) ) { + // TBD: check whether heating should depend on 'engine rotations' for electric vehicles + sHeater + .pitch( true == sHeater.is_combined() ? + std::abs( MoverParameters->enrot ) * 60.f * 0.01f : + 1.f ) + .play( sound_flags::exclusive | sound_flags::looping ); } else { sHeater.stop(); @@ -3997,8 +4003,7 @@ void TDynamicObject::RenderSounds() { } else if( quantizedratiochange < 0 ) { m_brakecylinderpistonrecede - .pitch( - true == m_brakecylinderpistonrecede.is_combined() ? + .pitch( true == m_brakecylinderpistonrecede.is_combined() ? quantizedratio * 0.01f : m_brakecylinderpistonrecede.m_frequencyoffset + m_brakecylinderpistonrecede.m_frequencyfactor * 1.f ) .play(); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index b9f521e8..34fd7fd3 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1570,11 +1570,12 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) { OilPump.is_active = ( ( true == Battery ) + && ( false == Mains ) && ( false == OilPump.is_disabled ) && ( ( OilPump.is_active ) || ( OilPump.start_type == start_t::manual ? ( OilPump.is_enabled ) : - OilPump.start_type == start_t::automatic ? ( dizel_startup || Mains ) : - OilPump.start_type == start_t::manualwithautofallback ? ( OilPump.is_enabled || dizel_startup || Mains ) : + OilPump.start_type == start_t::automatic ? ( dizel_startup ) : + OilPump.start_type == start_t::manualwithautofallback ? ( OilPump.is_enabled || dizel_startup ) : false ) ) ); // shouldn't ever get this far but, eh auto const maxrevolutions { @@ -2642,7 +2643,6 @@ bool TMoverParameters::MainSwitch( bool const State, range_t const Notify ) Mains = false; // potentially knock out the pumps if their switch doesn't force them on WaterPump.is_active &= WaterPump.is_enabled; - OilPump.is_active &= OilPump.is_enabled; FuelPump.is_active &= FuelPump.is_enabled; } @@ -4765,7 +4765,7 @@ double TMoverParameters::TractionForce( double dt ) { Voltage = 0; // przekazniki bocznikowania, kazdy inny dla kazdej pozycji - if ((MainCtrlPos == 0) || (ShuntMode)) + if ((MainCtrlPos == 0) || (ShuntMode) || (false==Mains)) ScndCtrlPos = 0; else { @@ -9305,7 +9305,6 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C Mains = false; // potentially knock out the pumps if their switch doesn't force them on WaterPump.is_active &= WaterPump.is_enabled; - OilPump.is_active &= OilPump.is_enabled; FuelPump.is_active &= FuelPump.is_enabled; } OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); diff --git a/Model3d.cpp b/Model3d.cpp index 63f75d55..272cb7cb 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -135,7 +135,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic iVboPtr = Pos; // pozycja w VBO */ if (!parser.expectToken("type:")) - Error("Model type parse failure!"); + ErrorLog("Bad model: expected submodel type definition not found while loading model \"" + Model->NameGet() + "\"" ); { std::string type = parser.getToken(); if (type == "mesh") @@ -1225,8 +1225,10 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic) } */ auto const name { FileName }; + // cache the file name, in case someone wants it later + m_filename = name; - asBinary = name + ".e3d"; + asBinary = name + ".e3d"; if (FileExists(asBinary)) { LoadFromBinFile(asBinary, dynamic); @@ -1244,8 +1246,6 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic) } } } - // cache the file name, in case someone wants it later - m_filename = name; bool const result = Root ? (iSubModelsCount > 0) : false; // brak pliku albo problem z wczytaniem if (false == result) diff --git a/PyInt.cpp b/PyInt.cpp index 7a201cfc..ff4ddeb3 100644 --- a/PyInt.cpp +++ b/PyInt.cpp @@ -32,6 +32,10 @@ void render_task::run() { ::glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + if( GLEW_EXT_texture_filter_anisotropic ) { + // anisotropic filtering + ::glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, Global.AnisotropicFiltering ); + } ::glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -1.0 ); // build texture ::glTexImage2D( diff --git a/Track.cpp b/Track.cpp index 982b77c6..598e7f52 100644 --- a/Track.cpp +++ b/Track.cpp @@ -1254,8 +1254,10 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { case tt_Normal: if (m_material2) { // podsypka z podkładami jest tylko dla zwykłego toru + // potentially retrieve texture length override from the assigned material + auto const texturelength { texture_length( m_material2 ) }; gfx::basic_vertex bpts1[ 8 ]; // punkty głównej płaszczyzny nie przydają się do robienia boków - if( fTexLength == 4.f ) { + if( texturelength == 4.f ) { // stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil auto const normalx = std::cos( glm::radians( 75.f ) ); auto const normaly = std::sin( glm::radians( 75.f ) ); @@ -1318,7 +1320,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { } else { // mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa fTexLength - auto const max = fTexRatio2 * fTexLength; // szerokość proporcjonalna do długości + auto const max = fTexRatio2 * texturelength; // szerokość proporcjonalna do długości auto const map11 = max > 0.f ? (fHTW + side) / max : 0.25f; // załamanie od strony 1 auto const map12 = max > 0.f ? (fHTW + side + hypot1) / max : 0.5f; // brzeg od strony 1 if (iTrapezoid) { @@ -1383,7 +1385,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { } } gfx::vertex_array vertices; - Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -4 : 4, fTexLength); + Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -4 : 4, texturelength); if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) { Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); } @@ -1394,20 +1396,21 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { } if (m_material1) { // szyny - generujemy dwie, najwyżej rysować się będzie jedną + auto const texturelength { texture_length( m_material1 ) }; gfx::vertex_array vertices; if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) { - Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); + Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, texturelength ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); // reuse the scratchpad - Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); + Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, texturelength ); 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, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); + Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, texturelength ); GfxRenderer.Replace( vertices, Geometry1[ 0 ] ); vertices.clear(); // reuse the scratchpad - Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); + Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, texturelength ); GfxRenderer.Replace( vertices, Geometry1[ 1 ] ); } } @@ -1452,28 +1455,30 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { { // nowa wersja z SPKS, ale odwrotnie lewa/prawa gfx::vertex_array vertices; if( m_material1 ) { + auto const texturelength { texture_length( m_material1 ) }; // fixed parts - SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength ); + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); - SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, bladelength ); + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); // left blade - SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, SwitchExtension->fOffset2 ); + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, SwitchExtension->fOffset2 ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } if( m_material2 ) { + auto const texturelength { texture_length( m_material2 ) }; // fixed parts - SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength ); + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); - SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, bladelength ); + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); // right blade - SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 ); + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } @@ -1482,28 +1487,30 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { { // lewa działa lepiej niż prawa gfx::vertex_array vertices; if( m_material1 ) { + auto const texturelength { texture_length( m_material1 ) }; // fixed parts - SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength ); // lewa szyna normalna cała Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); - SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, bladelength ); // prawa szyna za iglicą + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength ); // prawa szyna za iglicą Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); // right blade - SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 ); + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } if( m_material2 ) { + auto const texturelength { texture_length( m_material2 ) }; // fixed parts - SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength ); // prawa szyna normalnie cała Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); - SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, bladelength ); // lewa szyna za iglicą + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength ); // lewa szyna za iglicą Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); // left blade - SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 ); + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } @@ -1521,10 +1528,8 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków if (m_material1 || m_material2) { // punkty się przydadzą, nawet jeśli nawierzchni nie ma -/* - double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% -*/ - auto const max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości + auto const texturelength { texture_length( m_material1 ) }; + auto const max = fTexRatio1 * texturelength; // test: szerokość proporcjonalna do długości auto const map1 = max > 0.f ? fHTW / max : 0.5f; // obcięcie tekstury od strony 1 auto const map2 = max > 0.f ? fHTW2 / max : 0.5f; // obcięcie tekstury od strony 2 if (iTrapezoid) { @@ -1561,12 +1566,14 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { } if (m_material1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy + auto const texturelength { texture_length( m_material1 ) }; gfx::vertex_array vertices; - Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); + Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, texturelength); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); } if (m_material2) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) + auto const texturelength { texture_length( m_material2 ) }; gfx::basic_vertex rpts1[6], rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony @@ -1629,7 +1636,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { // mapowanie propocjonalne do szerokości chodnika // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy auto const d = -fTexHeight1 / 3.75f; // krawężnik o wysokości 150mm jest pochylony 40mm - auto const max = fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości + auto const max = fTexRatio2 * texturelength; // test: szerokość proporcjonalna do długości auto const map1l = ( max > 0.f ? side / max : @@ -1726,24 +1733,24 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony // odcinka if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { - Segment->RenderLoft( vertices, m_origin, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej + Segment->RenderLoft( vertices, m_origin, rpts1, -3, texturelength ); // tylko jeśli jest z prawej Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - Segment->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej + Segment->RenderLoft( vertices, m_origin, rpts2, -3, texturelength ); // tylko jeśli jest z lewej Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } } else { // pobocza zwykłe, brak przechyłki if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { - Segment->RenderLoft( vertices, m_origin, rpts1, 3, fTexLength ); + Segment->RenderLoft( vertices, m_origin, rpts1, 3, texturelength ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - Segment->RenderLoft( vertices, m_origin, rpts2, 3, fTexLength ); + Segment->RenderLoft( vertices, m_origin, rpts2, 3, texturelength ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } @@ -1803,7 +1810,8 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków if (m_material1 || m_material2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% - auto const max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości + auto const texturelength { texture_length( m_material1 ) }; + auto const max = fTexRatio1 * texturelength; // test: szerokość proporcjonalna do długości auto const map1 = max > 0.f ? fHTW / max : 0.5f; // obcięcie tekstury od strony 1 auto const map2 = max > 0.f ? fHTW2 / max : 0.5f; // obcięcie tekstury od strony 2 // if (iTrapezoid) //trapez albo przechyłki @@ -1833,6 +1841,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { // ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie w swoim czasie if( m_material2 ) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) + auto const texturelength { texture_length( m_material2 ) }; gfx::basic_vertex rpts1[6], rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony @@ -1896,7 +1905,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { // mapowanie propocjonalne do szerokości chodnika // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy auto const d = -fTexHeight1 / 3.75f; // krawężnik o wysokości 150mm jest pochylony 40mm - auto const max = fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości + auto const max = fTexRatio2 * texturelength; // test: szerokość proporcjonalna do długości auto const map1l = ( max > 0.f ? side / max : @@ -1976,22 +1985,22 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { if (SwitchExtension->iRoads == 4) { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); if( true == render ) { Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } - SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); if( true == render ) { Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } - SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); if( true == render ) { Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } - SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); if( true == render ) { Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); @@ -2001,17 +2010,17 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { else { // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4 + SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4 if( true == render ) { Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } - SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony) + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony) if( true == render ) { Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); } - SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2 + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2 if( true == render ) { Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); vertices.clear(); @@ -2028,6 +2037,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { } if( m_material1 ) { + auto const texturelength { texture_length( m_material1 ) }; gfx::vertex_array vertices; // jeśli podana tekstura nawierzchni // we start with a vertex in the middle... @@ -2039,8 +2049,8 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { glm::vec3{ 0.0f, 1.0f, 0.0f }, glm::vec2{ 0.5f, 0.5f } ); // ...and add one extra vertex to close the fan... - u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + m_origin.x ) / fTexLength; - v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + m_origin.z ) / ( fTexRatio1 * fTexLength ); + u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + m_origin.x ) / texturelength; + v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + m_origin.z ) / ( fTexRatio1 * texturelength ); vertices.emplace_back( glm::vec3 { SwitchExtension->vPoints[ 0 ].x, @@ -2054,8 +2064,8 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { // ...then draw the precalculated rest for (int i = pointcount + SwitchExtension->iRoads - 1; i >= 0; --i) { // mapowanie we współrzędnych scenerii - u = ( SwitchExtension->vPoints[ i ].x - oxz.x + m_origin.x ) / fTexLength; - v = ( SwitchExtension->vPoints[ i ].z - oxz.z + m_origin.z ) / ( fTexRatio1 * fTexLength ); + u = ( SwitchExtension->vPoints[ i ].x - oxz.x + m_origin.x ) / texturelength; + v = ( SwitchExtension->vPoints[ i ].z - oxz.z + m_origin.z ) / ( fTexRatio1 * texturelength ); vertices.emplace_back( glm::vec3 { SwitchExtension->vPoints[ i ].x, @@ -2507,28 +2517,32 @@ TTrack * TTrack::RaAnimate() if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa if( m_material1 ) { + auto const texturelength { texture_length( m_material1 ) }; // left blade - SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, SwitchExtension->fOffset2 ); + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, SwitchExtension->fOffset2 ); GfxRenderer.Replace( vertices, Geometry1[ 2 ] ); vertices.clear(); } if( m_material2 ) { + auto const texturelength { texture_length( m_material2 ) }; // right blade - SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 ); + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 ); GfxRenderer.Replace( vertices, Geometry2[ 2 ] ); vertices.clear(); } } else { // lewa działa lepiej niż prawa if( m_material1 ) { + auto const texturelength { texture_length( m_material1 ) }; // right blade - SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 ); + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 ); GfxRenderer.Replace( vertices, Geometry1[ 2 ] ); vertices.clear(); } if( m_material2 ) { + auto const texturelength { texture_length( m_material2 ) }; // left blade - SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 ); + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 ); GfxRenderer.Replace( vertices, Geometry2[ 2 ] ); vertices.clear(); } @@ -2868,6 +2882,19 @@ TTrack::export_as_text_( std::ostream &Output ) const { << "\n"; } +float +TTrack::texture_length( material_handle const Material ) { + + if( Material == null_handle ) { + return fTexLength; + } + auto const texturelength { GfxRenderer.Material( Material ).size.y }; + return ( + texturelength < 0.f ? + fTexLength : + texturelength ); +} + void TTrack::MovedUp1(float const dh) { // poprawienie przechyłki wymaga wydłużenia podsypki fTexHeight1 += dh; diff --git a/Track.h b/Track.h index 9fb57165..e3ca3233 100644 --- a/Track.h +++ b/Track.h @@ -298,7 +298,8 @@ private: void deserialize_( std::istream &Input ); // export() subclass details, sends basic content of the class in legacy (text) format to provided stream void export_as_text_( std::ostream &Output ) const; - + // returns texture length for specified material + float texture_length( material_handle const Material ); }; diff --git a/material.cpp b/material.cpp index d5c03784..f83c5e58 100644 --- a/material.cpp +++ b/material.cpp @@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/. #include "material.h" #include "renderer.h" #include "utilities.h" +#include "sn_utils.h" #include "globals.h" bool @@ -73,6 +74,12 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c priority2 = Priority; } } + else if( key == "size:" ) { + Input.getTokens( 2 ); + Input + >> size.x + >> size.y; + } else { auto const value { Input.getToken( true, "\n\r\t ;" ) }; if( value == "{" ) { diff --git a/material.h b/material.h index d4f64088..104990de 100644 --- a/material.h +++ b/material.h @@ -24,6 +24,7 @@ struct opengl_material { bool has_alpha { false }; // alpha state, calculated from presence of alpha in texture1 std::string name; + glm::vec2 size { -1.f, -1.f }; // 'physical' size of bound texture, in meters // constructors opengl_material() = default; diff --git a/openglmatrixstack.h b/openglmatrixstack.h index d37a8cf1..b37a1532 100644 --- a/openglmatrixstack.h +++ b/openglmatrixstack.h @@ -57,6 +57,10 @@ public: translate( glm::vec3 const &Translation ) { m_stack.top() = glm::translate( m_stack.top(), Translation ); upload(); } + void + scale( glm::vec3 const &Scale ) { + m_stack.top() = glm::scale( m_stack.top(), Scale ); + upload(); } void multiply( glm::mat4 const &Matrix ) { m_stack.top() *= Matrix; @@ -133,9 +137,9 @@ public: m_stacks[ m_mode ].rotate( static_cast(glm::radians(Angle)), glm::vec3( - static_cast(X), - static_cast(Y), - static_cast(Z) ) ); } + static_cast( X ), + static_cast( Y ), + static_cast( Z ) ) ); } template void translate( Type_ const X, Type_ const Y, Type_ const Z ) { @@ -145,6 +149,14 @@ public: static_cast( Y ), static_cast( Z ) ) ); } template + void + scale( Type_ const X, Type_ const Y, Type_ const Z ) { + m_stacks[ m_mode ].scale( + glm::vec3( + static_cast( X ), + static_cast( Y ), + static_cast( Z ) ) ); } + template void multiply( Type_ const *Matrix ) { m_stacks[ m_mode ].multiply( @@ -204,7 +216,8 @@ extern opengl_matrices OpenGLMatrices; #define glRotatef OpenGLMatrices.rotate #define glTranslated OpenGLMatrices.translate #define glTranslatef OpenGLMatrices.translate -// NOTE: no scale override as we aren't using it anywhere +#define glScaled OpenGLMatrices.scale +#define glScalef OpenGLMatrices.scale #define glMultMatrixd OpenGLMatrices.multiply #define glMultMatrixf OpenGLMatrices.multiply #define glOrtho OpenGLMatrices.ortho diff --git a/renderer.cpp b/renderer.cpp index f5d6d9c4..bdcd6d15 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1433,9 +1433,12 @@ opengl_renderer::Render( world_environment *Environment ) { ::glDisable( GL_LIGHTING ); ::glDisable( GL_DEPTH_TEST ); ::glDepthMask( GL_FALSE ); - ::glPushMatrix(); // skydome + // drawn with 500m radius to blend in if the fog range is low + ::glPushMatrix(); + ::glScalef( 500.f, 500.f, 500.f ); Environment->m_skydome.Render(); + ::glPopMatrix(); // stars if( Environment->m_stars.m_stars != nullptr ) { // setup @@ -1450,12 +1453,6 @@ opengl_renderer::Render( world_environment *Environment ) { ::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 ), - glm::vec3( 235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f ), - duskfactor ); - if( DebugModeFlag == true ) { // mark sun position for easier debugging Environment->m_sun.render(); @@ -1470,10 +1467,17 @@ opengl_renderer::Render( world_environment *Environment ) { ::glBlendFunc( GL_SRC_ALPHA, GL_ONE ); auto const &modelview = OpenGLMatrices.data( GL_MODELVIEW ); + + auto const fogfactor { clamp( Global.fFogEnd / 2000.f, 0.f, 1.f ) }; // stronger fog reduces opacity of the 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 ), + glm::vec3( 235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f ), + duskfactor ); // sun { Bind_Texture( m_suntexture ); - ::glColor4f( suncolor.x, suncolor.y, suncolor.z, clamp( 1.5f - Global.Overcast, 0.f, 1.f ) ); + ::glColor4f( suncolor.x, suncolor.y, suncolor.z, clamp( 1.5f - Global.Overcast, 0.f, 1.f ) * fogfactor ); auto const sunvector = Environment->m_sun.getDirection(); auto const sunposition = modelview * glm::vec4( sunvector.x, sunvector.y, sunvector.z, 1.0f ); @@ -1495,14 +1499,15 @@ opengl_renderer::Render( world_environment *Environment ) { { Bind_Texture( m_moontexture ); glm::vec3 mooncolor( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ); - // fade the moon if it's near the sun in the sky, especially during the day ::glColor4f( mooncolor.r, mooncolor.g, mooncolor.b, + // fade the moon if it's near the sun in the sky, especially during the day std::max( 0.f, 1.0 - 0.5 * Global.fLuminance - - 0.65 * std::max( 0.f, glm::dot( Environment->m_sun.getDirection(), Environment->m_moon.getDirection() ) ) ) ); + - 0.65 * std::max( 0.f, glm::dot( Environment->m_sun.getDirection(), Environment->m_moon.getDirection() ) ) ) + * fogfactor ); auto const moonposition = modelview * glm::vec4( Environment->m_moon.getDirection(), 1.0f ); ::glPushMatrix(); @@ -1563,7 +1568,6 @@ opengl_renderer::Render( world_environment *Environment ) { ::glDisable( GL_LIGHTING ); } - ::glPopMatrix(); ::glDepthMask( GL_TRUE ); ::glEnable( GL_DEPTH_TEST ); ::glEnable( GL_LIGHTING ); diff --git a/simulationenvironment.cpp b/simulationenvironment.cpp index 5602f7af..5033c753 100644 --- a/simulationenvironment.cpp +++ b/simulationenvironment.cpp @@ -62,8 +62,8 @@ void world_environment::compute_weather() const { Global.Weather = ( - Global.Overcast < 0.25 ? "clear:" : - Global.Overcast < 1.0 ? "cloudy:" : + Global.Overcast <= 0.25 ? "clear:" : + Global.Overcast <= 1.0 ? "cloudy:" : ( Global.Season != "winter:" ? "rain:" : "snow:" ) ); diff --git a/station.cpp b/station.cpp index 75f7f267..63b5b0a6 100644 --- a/station.cpp +++ b/station.cpp @@ -51,6 +51,7 @@ basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Sch if( parameters.LoadType.name.empty() ) { // (try to) set the cargo type for empty cars + parameters.LoadAmount = 0.f; // safety measure against edge cases parameters.AssignLoad( "passengers" ); } diff --git a/version.h b/version.h index 66a33f7e..abf7d5cf 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 928 +#define VERSION_MINOR 1001 #define VERSION_REVISION 0