From 3a63d1d346f2d961b35dbf51bbf19515b979e1c9 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 22 Aug 2017 20:07:27 +0200 Subject: [PATCH 1/3] better AI handling of emergency stop procedure, simplified lod visibility calculations, adjustable track geometry fidelity --- Driver.cpp | 96 +++++++++++++++++++++++-------------------- Globals.cpp | 17 ++++---- Globals.h | 4 +- Model3d.cpp | 2 +- Model3d.h | 2 +- Track.cpp | 2 +- renderer.cpp | 114 +++++++++++++++++++-------------------------------- renderer.h | 8 ++-- 8 files changed, 109 insertions(+), 136 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index dd7a5004..cb0aa49c 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3614,11 +3614,11 @@ bool TController::UpdateSituation(double dt) } // basic emergency stop handling, while at it if( ( true == mvOccupied->EmergencyBrakeFlag ) // radio-stop - && ( mvOccupied->Vel < 0.01 ) // and actual stop + && ( mvOccupied->Vel == 0.0 ) // and actual stop && ( true == mvOccupied->Radio ) ) { // and we didn't touch the radio yet // turning off the radio should reset the flag, during security system check - if( m_radiocontroltime > 2.5 ) { - // arbitrary 2.5 sec delay between stop and disabling the radio + if( m_radiocontroltime > 5.0 ) { + // arbitrary delay between stop and disabling the radio mvOccupied->Radio = false; m_radiocontroltime = 0.0; } @@ -3629,7 +3629,7 @@ bool TController::UpdateSituation(double dt) if( ( false == mvOccupied->Radio ) && ( false == mvOccupied->EmergencyBrakeFlag ) ) { // otherwise if it's safe to do so, turn the radio back on - if( m_radiocontroltime > 5.0 ) { + if( m_radiocontroltime > 10.0 ) { // arbitrary 5 sec delay before switching radio back on mvOccupied->Radio = true; m_radiocontroltime = 0.0; @@ -4200,8 +4200,8 @@ bool TController::UpdateSituation(double dt) } ReactionTime = ( vel != 0.0 ? - 0.1 : // orientuj się, bo jest goraco - 2.0 ); // we're already standing still, so take it easy + 0.1 : // orientuj się, bo jest goraco + 2.0 ); // we're already standing still, so take it easy } else { if( OrderCurrentGet() & Connect ) { @@ -4498,13 +4498,47 @@ bool TController::UpdateSituation(double dt) // last step sanity check, until the whole calculation is straightened out AccDesired = std::min( AccDesired, AccPreferred ); - if (AIControllFlag) - { // część wykonawcza tylko dla AI, dla człowieka jedynie napisy + + + if (AIControllFlag) { + // część wykonawcza tylko dla AI, dla człowieka jedynie napisy + + // zapobieganie poslizgowi u nas + if (mvControlling->SlippingWheels) { + + if (!mvControlling->DecScndCtrl(2)) // bocznik na zero + mvControlling->DecMainCtrl(1); +/* + if (mvOccupied->BrakeCtrlPos == + mvOccupied->BrakeCtrlPosNo) // jeśli ostatnia pozycja hamowania + //yB: ten warunek wyżej nie ma sensu + mvOccupied->DecBrakeLevel(); // to cofnij hamulec + DecBrake(); // to cofnij hamulec + else + mvControlling->AntiSlippingButton(); +*/ + DecBrake(); // to cofnij hamulec + mvControlling->AntiSlippingButton(); + ++iDriverFailCount; + mvControlling->SlippingWheels = false; // flaga już wykorzystana + } + if (iDriverFailCount > maxdriverfails) + { + Psyche = Easyman; + if (iDriverFailCount > maxdriverfails * 2) + SetDriverPsyche(); + } + + if( ( true == mvOccupied->EmergencyBrakeFlag ) // radio-stop + && ( mvOccupied->Vel > 0.0 ) ) { // and still moving + // if the radio-stop was issued don't waste effort trying to fight it + while( true == DecSpeed() ) { ; } // just throttle down... + goto maintenance; // ...and don't touch any other controls + } + if (mvControlling->ConvOvldFlag || !mvControlling->Mains) // WS może wywalić z powodu błędu w drutach { // wywalił bezpiecznik nadmiarowy przetwornicy - // while (DecSpeed()); //zerowanie napędu - // Controlling->ConvOvldFlag=false; //reset nadmiarowego PrepareEngine(); // próba ponownego załączenia } // włączanie bezpiecznika @@ -4513,14 +4547,10 @@ bool TController::UpdateSituation(double dt) (mvControlling->EngineType == DieselElectric)) if (mvControlling->FuseFlag || Need_TryAgain) { - Need_TryAgain = - false; // true, jeśli druga pozycja w elektryku nie załapała - // if (!Controlling->DecScndCtrl(1)) //kręcenie po mału - // if (!Controlling->DecMainCtrl(1)) //nastawnik jazdy na 0 + Need_TryAgain = false; // true, jeśli druga pozycja w elektryku nie załapała mvControlling->DecScndCtrl(2); // nastawnik bocznikowania na 0 mvControlling->DecMainCtrl(2); // nastawnik jazdy na 0 - mvControlling->MainSwitch( - true); // Ra: dodałem, bo EN57 stawały po wywaleniu + mvControlling->MainSwitch(true); // Ra: dodałem, bo EN57 stawały po wywaleniu if (!mvControlling->FuseOn()) HelpMeFlag = true; else @@ -4532,7 +4562,7 @@ bool TController::UpdateSituation(double dt) SetDriverPsyche(); } } - // NOTE: stop-gap measure, effect limited to trains only while car calculations seem off + // NOTE: as a stop-gap measure the routine is limited to trains only while car calculations seem off if( mvControlling->CategoryFlag == 1 ) { if( -AccDesired * BrakeAccFactor() < ( ( fReady > 0.4 ) || ( VelNext > vel - 40.0 ) ? fBrake_a0[ 0 ] * 0.8 : -fAccThreshold ) ) AccDesired = std::max( -0.06, AccDesired ); @@ -4744,31 +4774,6 @@ bool TController::UpdateSituation(double dt) WriteLog("BrakePos=" + AnsiString(mvOccupied->BrakeCtrlPos) + ", MainCtrl=" + AnsiString(mvControlling->MainCtrlPos)); #endif - // zapobieganie poslizgowi u nas - if (mvControlling->SlippingWheels) - { - if (!mvControlling->DecScndCtrl(2)) // bocznik na zero - mvControlling->DecMainCtrl(1); -/* - if (mvOccupied->BrakeCtrlPos == - mvOccupied->BrakeCtrlPosNo) // jeśli ostatnia pozycja hamowania - //yB: ten warunek wyżej nie ma sensu - mvOccupied->DecBrakeLevel(); // to cofnij hamulec - DecBrake(); // to cofnij hamulec - else - mvControlling->AntiSlippingButton(); -*/ - DecBrake(); // to cofnij hamulec - mvControlling->AntiSlippingButton(); - ++iDriverFailCount; - mvControlling->SlippingWheels = false; // flaga już wykorzystana - } - if (iDriverFailCount > maxdriverfails) - { - Psyche = Easyman; - if (iDriverFailCount > maxdriverfails * 2) - SetDriverPsyche(); - } } // if (AIControllFlag) } // kierunek różny od zera else @@ -4801,6 +4806,8 @@ bool TController::UpdateSituation(double dt) else LastReactionTime += dt; +maintenance: + if ((fLastStopExpDist > 0.0) && (mvOccupied->DistCounter > fLastStopExpDist)) { iStationStart = TrainParams->StationIndex; // zaktualizować wyświetlanie rozkładu @@ -4817,9 +4824,8 @@ bool TController::UpdateSituation(double dt) ReactionTime = fWarningDuration; // wcześniejszy przebłysk świadomości, by zakończyć trąbienie } - if (mvOccupied->Vel >= - 3.0) // jesli jedzie, można odblokować trąbienie, bo się wtedy nie włączy - { + if (mvOccupied->Vel >= 3.0) { + // jesli jedzie, można odblokować trąbienie, bo się wtedy nie włączy iDrivigFlags &= ~moveStartHornDone; // zatrąbi dopiero jak następnym razem stanie iDrivigFlags |= moveStartHorn; // i trąbić przed następnym ruszeniem } diff --git a/Globals.cpp b/Globals.cpp index 6bc61dc2..323c849d 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -51,7 +51,6 @@ bool Global::ControlPicking = false; // indicates controls pick mode is enabled bool Global::InputMouse = true; // whether control pick mode can be activated int Global::iTextMode = 0; // tryb pracy wyświetlacza tekstowego int Global::iScreenMode[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // numer ekranu wyświetlacza tekstowego -double Global::fSunDeclination = 0.0; // deklinacja Słońca double Global::fTimeAngleDeg = 0.0; // godzina w postaci kąta float Global::fClockAngleDeg[6]; // kąty obrotu cylindrów dla zegara cyfrowego std::string Global::szTexturesTGA = ".tga"; // lista tekstur od TGA @@ -63,7 +62,6 @@ int Global::iErorrCounter = 0; // licznik sprawdzań do śledzenia błędów Ope int Global::iTextures = 0; // licznik użytych tekstur TWorld *Global::pWorld = NULL; 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 TTranscripts Global::tranTexts; // obiekt obsługujący stenogramy dźwięków na ekranie @@ -132,6 +130,7 @@ bool Global::bUseVBO = false; // czy jest VBO w karcie graficznej (czy użyć) std::string Global::LastGLError; GLint Global::iMaxTextureSize = 4096; // maksymalny rozmiar tekstury bool Global::bSmoothTraction = false; // wygładzanie drutów starym sposobem +float Global::SplineFidelity { 1.f }; // determines segment size during conversion of splines to geometry std::string Global::szDefaultExt = Global::szTexturesDDS; // domyślnie od DDS int Global::iMultisampling = 2; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px bool Global::DLFont{ false }; // switch indicating presence of basic font @@ -150,7 +149,6 @@ double Global::fFpsMax = 65.0; // górna granica FPS, przy której promień scen double Global::fFpsRadiusMax = 3000.0; // maksymalny promień renderowania int Global::iFpsRadiusMax = 225; // maksymalny promień renderowania double Global::fRadiusFactor = 1.1; // współczynnik jednorazowej zmiany promienia scenerii -bool Global::bOldSmudge = false; // Używanie starej smugi // parametry testowe (do testowania scenerii i obiektów) bool Global::bWireFrame = false; @@ -572,6 +570,13 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens(); Parser >> Global::bSmoothTraction; } + else if( token == "splinefidelity" ) { + // segment size during spline->geometry conversion + float splinefidelity; + Parser.getTokens(); + Parser >> splinefidelity; + Global::SplineFidelity = clamp( splinefidelity, 1.f, 4.f ); + } else if (token == "timespeed") { // przyspieszenie czasu, zmienna do testów @@ -631,12 +636,6 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens(); Parser >> Global::bHideConsole; } - else if (token == "oldsmudge") - { - - Parser.getTokens(); - Parser >> Global::bOldSmudge; - } else if (token == "rollfix") { // Ra: poprawianie przechyłki, aby wewnętrzna szyna była "pozioma" diff --git a/Globals.h b/Globals.h index 73f52cb2..db70de30 100644 --- a/Globals.h +++ b/Globals.h @@ -274,7 +274,7 @@ class Global static double fMoveLight; // numer dnia w roku albo -1 static bool FakeLight; // toggle between fixed and dynamic daylight static bool bSmoothTraction; // wygładzanie drutów - static double fSunDeclination; // deklinacja Słońca + static float SplineFidelity; // determines segment size during conversion of splines to geometry static double fTimeSpeed; // przyspieszenie czasu, zmienna do testów static double fTimeAngleDeg; // godzina w postaci kąta static float fClockAngleDeg[6]; // kąty obrotu cylindrów dla zegara cyfrowego @@ -294,14 +294,12 @@ class Global static int iSlowMotionMask; // maska wyłączanych właściwości static int iModifyTGA; // czy korygować pliki TGA dla szybszego wczytywania static bool bHideConsole; // hunter-271211: ukrywanie konsoli - static bool bOldSmudge; // Używanie starej smugi static TWorld *pWorld; // wskaźnik na świat do usuwania pojazdów static TAnimModel *pTerrainCompact; // obiekt terenu do ewentualnego zapisania w pliku static std::string asTerrainModel; // nazwa obiektu terenu do zapisania w pliku static bool bRollFix; // czy wykonać przeliczanie przechyłki static cParser *pParser; - static int iSegmentsRendered; // ilość segmentów do regulacji wydajności static double fFpsAverage; // oczekiwana wartosć FPS static double fFpsDeviation; // odchylenie standardowe FPS static double fFpsMin; // dolna granica FPS, przy której promień scenerii będzie zmniejszany diff --git a/Model3d.cpp b/Model3d.cpp index 12862a9d..802e918e 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -28,7 +28,7 @@ Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others using namespace Mtable; -double TSubModel::fSquareDist = 0; +float TSubModel::fSquareDist = 0.f; size_t TSubModel::iInstance; // numer renderowanego egzemplarza obiektu texture_handle const *TSubModel::ReplacableSkinId = NULL; int TSubModel::iAlpha = 0x30300030; // maska do testowania flag tekstur wymiennych diff --git a/Model3d.h b/Model3d.h index a1072228..395bf40a 100644 --- a/Model3d.h +++ b/Model3d.h @@ -153,7 +153,7 @@ public: static size_t iInstance; // identyfikator egzemplarza, który aktualnie renderuje model static material_handle const *ReplacableSkinId; static int iAlpha; // maska bitowa dla danego przebiegu - static double fSquareDist; + static float fSquareDist; static TModel3d *pRoot; static std::string *pasText; // tekst dla wyświetlacza (!!!! do przemyślenia) ~TSubModel(); diff --git a/Track.cpp b/Track.cpp index 7dbb6be7..528b955c 100644 --- a/Track.cpp +++ b/Track.cpp @@ -527,7 +527,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) // na przechyłce doliczyć jeszcze pół przechyłki } if( fRadius != 0 ) // gdy podany promień - segsize = clamp( 0.2 + std::fabs( fRadius ) * 0.02, 2.0, 10.0 ); + segsize = clamp( std::fabs( fRadius ) * ( 0.02 / Global::SplineFidelity ), 2.0 / Global::SplineFidelity, 10.0 ); else segsize = 10.0; // for straights, 10m per segment works good enough diff --git a/renderer.cpp b/renderer.cpp index 39e4cd5c..4359b3f4 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1616,16 +1616,16 @@ opengl_renderer::Render( TGroundNode *Node ) { switch( m_renderpass.draw_mode ) { case rendermode::shadows: { // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ); + distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; break; } default: { - distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ); + distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; break; } } - if( ( distancesquared > ( Node->fSquareRadius * Global::fDistanceFactor ) ) - || ( distancesquared < ( Node->fSquareMinRadius / Global::fDistanceFactor ) ) ) { + if( ( distancesquared > Node->fSquareRadius ) + || ( distancesquared < Node->fSquareMinRadius ) ) { return false; } @@ -1671,28 +1671,12 @@ opengl_renderer::Render( TGroundNode *Node ) { Node->Model->RaPrepare(); if( Node->Model->pModel ) { // renderowanie rekurencyjne submodeli - switch( m_renderpass.draw_mode ) { - case rendermode::shadows: { - Render( - Node->Model->pModel, - Node->Model->Material(), - // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - SquareMagnitude( Node->pCenter - Global::pCameraPosition ), - Node->pCenter - m_renderpass.camera.position(), - Node->Model->vAngle ); - break; - } - default: { - auto const position = Node->pCenter - m_renderpass.camera.position(); - Render( - Node->Model->pModel, - Node->Model->Material(), - SquareMagnitude( position ), - position, - Node->Model->vAngle ); - break; - } - } + Render( + Node->Model->pModel, + Node->Model->Material(), + distancesquared, + Node->pCenter - m_renderpass.camera.position(), + Node->Model->vAngle ); } return true; } @@ -1726,7 +1710,7 @@ opengl_renderer::Render( TGroundNode *Node ) { break; } } - auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 32.0 ); + auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 8.0 ); if( linewidth > 1.0 ) { ::glLineWidth( static_cast( linewidth ) ); } @@ -1832,15 +1816,16 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { } // setup TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji - auto const originoffset = Dynamic->vPosition - m_renderpass.camera.position(); - double squaredistance; + glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.camera.position(); + // lod visibility ranges are defined for base (x 1.0) viewing distance. for render we adjust them for actual range multiplier and zoom + float squaredistance; switch( m_renderpass.draw_mode ) { case rendermode::shadows: { - squaredistance = SquareMagnitude( ( Dynamic->vPosition - Global::pCameraPosition ) / Global::ZoomFactor ); + squaredistance = glm::length2( glm::vec3{ glm::dvec3{ Dynamic->vPosition - Global::pCameraPosition } } / Global::ZoomFactor ) / Global::fDistanceFactor; break; } default: { - squaredistance = SquareMagnitude( originoffset / Global::ZoomFactor ); + squaredistance = glm::length2( glm::vec3{ originoffset } / Global::ZoomFactor ) / Global::fDistanceFactor; break; } } @@ -1995,7 +1980,7 @@ opengl_renderer::Render_cab( TDynamicObject *Dynamic ) { } bool -opengl_renderer::Render( TModel3d *Model, material_data const *Material, double const Squaredistance ) { +opengl_renderer::Render( TModel3d *Model, material_data const *Material, float const Squaredistance ) { auto alpha = ( Material != nullptr ? @@ -2027,7 +2012,7 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, double } bool -opengl_renderer::Render( TModel3d *Model, material_data const *Material, double const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ) { +opengl_renderer::Render( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ) { ::glPushMatrix(); ::glTranslated( Position.x, Position.y, Position.z ); @@ -2049,8 +2034,8 @@ void opengl_renderer::Render( TSubModel *Submodel ) { if( ( Submodel->iVisible ) - && ( TSubModel::fSquareDist >= ( Submodel->fSquareMinDist / std::max( 1.f, Global::fDistanceFactor ) ) ) - && ( TSubModel::fSquareDist <= ( Submodel->fSquareMaxDist * std::max( 1.f, Global::fDistanceFactor ) ) ) ) { + && ( TSubModel::fSquareDist >= Submodel->fSquareMinDist ) + && ( TSubModel::fSquareDist <= Submodel->fSquareMaxDist ) ) { if( Submodel->iFlags & 0xC000 ) { ::glPushMatrix(); @@ -2205,7 +2190,7 @@ opengl_renderer::Render( TSubModel *Submodel ) { 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 ) ) ); + float const distancefactor = std::max( 0.5f, ( Submodel->fSquareMaxDist - TSubModel::fSquareDist ) / Submodel->fSquareMaxDist ); if( lightlevel > 0.f ) { // material configuration: @@ -2424,16 +2409,16 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { switch( m_renderpass.draw_mode ) { case rendermode::shadows: { // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ); + distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor; break; } default: { - distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ); + distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor; break; } } - if( ( distancesquared > ( Node->fSquareRadius * Global::fDistanceFactor ) ) - || ( distancesquared < ( Node->fSquareMinRadius / Global::fDistanceFactor ) ) ) { + if( ( distancesquared > Node->fSquareRadius ) + || ( distancesquared < Node->fSquareMinRadius ) ) { return false; } @@ -2488,28 +2473,12 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { Node->Model->RaPrepare(); if( Node->Model->pModel ) { // renderowanie rekurencyjne submodeli - switch( m_renderpass.draw_mode ) { - case rendermode::shadows: { - Render_Alpha( - Node->Model->pModel, - Node->Model->Material(), - // 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees - SquareMagnitude( Node->pCenter - Global::pCameraPosition ), - Node->pCenter - m_renderpass.camera.position(), - Node->Model->vAngle ); - break; - } - default: { - auto const position = Node->pCenter - m_renderpass.camera.position(); - Render_Alpha( - Node->Model->pModel, - Node->Model->Material(), - SquareMagnitude( position ), - position, - Node->Model->vAngle ); - break; - } - } + Render_Alpha( + Node->Model->pModel, + Node->Model->Material(), + distancesquared, + Node->pCenter - m_renderpass.camera.position(), + Node->Model->vAngle ); } return true; } @@ -2531,7 +2500,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { glm::vec4( Node->Diffuse * glm::vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla std::min( 1.0, linealpha ) ) ) ); - auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 32.0 ); + auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 8.0 ); if( linewidth > 1.0 ) { ::glLineWidth( static_cast(linewidth) ); } @@ -2589,15 +2558,16 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { // setup TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji - auto const originoffset = Dynamic->vPosition - m_renderpass.camera.position(); - double squaredistance; + glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.camera.position(); + // lod visibility ranges are defined for base (x 1.0) viewing distance. for render we adjust them for actual range multiplier and zoom + float squaredistance; switch( m_renderpass.draw_mode ) { case rendermode::shadows: { - squaredistance = SquareMagnitude( ( Dynamic->vPosition - Global::pCameraPosition ) / Global::ZoomFactor ); + squaredistance = glm::length2( glm::vec3{ glm::dvec3{ Dynamic->vPosition - Global::pCameraPosition } } / Global::ZoomFactor ) / Global::fDistanceFactor; break; } default: { - squaredistance = SquareMagnitude( originoffset / Global::ZoomFactor ); + squaredistance = glm::length2( glm::vec3{ originoffset } / Global::ZoomFactor ) / Global::fDistanceFactor; break; } } @@ -2656,7 +2626,7 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { } bool -opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance ) { +opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance ) { auto alpha = ( Material != nullptr ? @@ -2688,7 +2658,7 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, d } bool -opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ) { +opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ) { ::glPushMatrix(); ::glTranslated( Position.x, Position.y, Position.z ); @@ -2710,8 +2680,8 @@ void opengl_renderer::Render_Alpha( TSubModel *Submodel ) { // renderowanie przezroczystych przez DL if( ( Submodel->iVisible ) - && ( TSubModel::fSquareDist >= ( Submodel->fSquareMinDist / std::max( 1.f, Global::fDistanceFactor ) ) ) - && ( TSubModel::fSquareDist <= ( Submodel->fSquareMaxDist * std::max( 1.f, Global::fDistanceFactor ) ) ) ) { + && ( TSubModel::fSquareDist >= Submodel->fSquareMinDist ) + && ( TSubModel::fSquareDist <= Submodel->fSquareMaxDist ) ) { if( Submodel->iFlags & 0xC000 ) { ::glPushMatrix(); @@ -3009,7 +2979,7 @@ opengl_renderer::Update( double const Deltatime ) { m_framerate = 1000.f / ( m_drawtime / 20.f ); // adjust draw ranges etc, based on recent performance - auto const framerate = 1000.0f / (m_drawtimecolorpass / 20.0f); + auto const framerate = 1000.f / (m_drawtimecolorpass / 20.f); float targetfactor; if( framerate > 90.0 ) { targetfactor = 3.0f; } diff --git a/renderer.h b/renderer.h index 81d991a7..51b3b374 100644 --- a/renderer.h +++ b/renderer.h @@ -277,9 +277,9 @@ private: bool Render( TDynamicObject *Dynamic ); bool - Render( TModel3d *Model, material_data const *Material, double const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); + Render( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); bool - Render( TModel3d *Model, material_data const *Material, double const Squaredistance ); + Render( TModel3d *Model, material_data const *Material, float const Squaredistance ); void Render( TSubModel *Submodel ); void @@ -297,9 +297,9 @@ private: bool Render_Alpha( TDynamicObject *Dynamic ); bool - Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); + Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); bool - Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance ); + Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance ); void Render_Alpha( TSubModel *Submodel ); void From a41a666184fb4a803036cf960e5ecef0f786fdb9 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 23 Aug 2017 16:56:56 +0200 Subject: [PATCH 2/3] fixed animation rate of scene elements --- AnimModel.cpp | 43 +++++++++++-------- AnimModel.h | 5 ++- Driver.cpp | 14 +++---- Ground.cpp | 12 +++--- Ground.h | 8 +--- renderer.cpp | 113 ++++++++++++++++++++++++-------------------------- renderer.h | 1 + 7 files changed, 98 insertions(+), 98 deletions(-) diff --git a/AnimModel.cpp b/AnimModel.cpp index 778b4704..c0ff498b 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -205,8 +205,9 @@ void TAnimContainer::AnimSetVMD(double fNewSpeed) // "+AnsiString(pMovementData->f3Vector.y)+" "+AnsiString(pMovementData->f3Vector.z)); } -void TAnimContainer::UpdateModel() -{ // przeliczanie animacji wykonać tylko raz na model +// przeliczanie animacji wykonać tylko raz na model +void TAnimContainer::UpdateModel() { + if (pSubModel) // pozbyć się tego - sprawdzać wcześniej { if (fTranslateSpeed != 0.0) @@ -236,7 +237,7 @@ void TAnimContainer::UpdateModel() // zakończeniu } } - if (fRotateSpeed != 0) + if (fRotateSpeed != 0.0) { /* @@ -303,8 +304,9 @@ void TAnimContainer::UpdateModel() // zakończeniu } } - if (fAngleSpeed != 0.0) - { // obrót kwaternionu (interpolacja) + if( fAngleSpeed != 0.f ) { + // NOTE: this is angle- not quaternion-based rotation TBD, TODO: switch to quaternion rotations? + fAngleCurrent += fAngleSpeed * Timer::GetDeltaTime(); // aktualny parametr interpolacji } } }; @@ -322,15 +324,14 @@ void TAnimContainer::PrepareModel() { if (fAngleSpeed > 0.0f) { - fAngleCurrent += - fAngleSpeed * Timer::GetDeltaTime(); // aktualny parametr interpolacji if (fAngleCurrent >= 1.0f) { // interpolacja zakończona, ustawienie na pozycję końcową qCurrent = qDesired; fAngleSpeed = 0.0; // wyłączenie przeliczania wektora - if (evDone) - Global::AddToQuery(evDone, - NULL); // wykonanie eventu informującego o zakończeniu + if( evDone ) { + // wykonanie eventu informującego o zakończeniu + Global::AddToQuery( evDone, NULL ); + } } else { // obliczanie pozycji pośredniej @@ -412,9 +413,9 @@ TAnimModel::TAnimModel() iNumLights = 0; fBlinkTimer = 0; - for (int i = 0; i < iMaxNumLights; i++) + for (int i = 0; i < iMaxNumLights; ++i) { - LightsOn[i] = LightsOff[i] = NULL; // normalnie nie ma + LightsOn[i] = LightsOff[i] = nullptr; // normalnie nie ma lsLights[i] = ls_Off; // a jeśli są, to wyłączone } vAngle.x = vAngle.y = vAngle.z = 0.0; // zerowanie obrotów egzemplarza @@ -550,8 +551,15 @@ TAnimContainer * TAnimModel::GetContainer(char *pName) return AddContainer(pName); } -void TAnimModel::RaAnimate() -{ // przeliczenie animacji - jednorazowo na klatkę +// przeliczenie animacji - jednorazowo na klatkę +void TAnimModel::RaAnimate( unsigned int const Framestamp ) { + + if( Framestamp == m_framestamp ) { return; } + + fBlinkTimer -= Timer::GetDeltaTime(); + if( fBlinkTimer <= 0 ) + fBlinkTimer += fOffTime; + // Ra 2F1I: to by można pomijać dla modeli bez animacji, których jest większość TAnimContainer *pCurrent; for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext) @@ -560,15 +568,14 @@ void TAnimModel::RaAnimate() // if () //tylko dla modeli z IK !!!! for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext) // albo osobny łańcuch pCurrent->UpdateModelIK(); // przeliczenie odwrotnej kinematyki + + m_framestamp = Framestamp; }; void TAnimModel::RaPrepare() { // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza - fBlinkTimer -= Timer::GetDeltaTime(); - if (fBlinkTimer <= 0) - fBlinkTimer = fOffTime; bool state; // stan światła - for (int i = 0; i < iNumLights; i++) + for (int i = 0; i < iNumLights; ++i) { switch (lsLights[i]) { diff --git a/AnimModel.h b/AnimModel.h index a542fe50..1aa11735 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -149,8 +149,9 @@ class TAnimModel { TLightState lsLights[iMaxNumLights]; float fDark; // poziom zapalanie światła (powinno być chyba powiązane z danym światłem?) float fOnTime, fOffTime; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza - private: - void RaAnimate(); // przeliczenie animacji egzemplarza + unsigned int m_framestamp { 0 }; // id of last rendered gfx frame +private: + void RaAnimate( unsigned int const Framestamp ); // przeliczenie animacji egzemplarza void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu public: static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania diff --git a/Driver.cpp b/Driver.cpp index cb0aa49c..ee243d95 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1253,7 +1253,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN if( fBrakeDist > 0.0 ) { // maintain desired acc while we have enough room to brake safely, when close enough start paying attention // try to make a smooth transition instead of sharp change - a = interpolate( a, fAcc, clamp( ( d - fBrakeDist ) / fBrakeDist, 0.0, 1.0 ) ); + a = interpolate( a, AccPreferred, clamp( ( d - fBrakeDist ) / fBrakeDist, 0.0, 1.0 ) ); } if( ( d < fMinProximityDist ) && ( v < fVelDes ) ) { @@ -4059,17 +4059,13 @@ bool TController::UpdateSituation(double dt) switch (comm) { // ustawienie VelSignal - trochę proteza = do przemyślenia case cm_Ready: // W4 zezwolił na jazdę - TableCheck( - scanmax); // ewentualne doskanowanie trasy za W4, który zezwolił na jazdę - TableUpdate(VelDesired, ActualProximityDist, VelNext, - AccDesired); // aktualizacja po skanowaniu - // if (comm!=cm_SetVelocity) //jeśli dalej jest kolejny W4, to ma zwrócić - // cm_SetVelocity + // ewentualne doskanowanie trasy za W4, który zezwolił na jazdę + TableCheck( scanmax); + TableUpdate(VelDesired, ActualProximityDist, VelNext, AccDesired); // aktualizacja po skanowaniu if (VelNext == 0.0) break; // ale jak coś z przodu zamyka, to ma stać if (iDrivigFlags & moveStopCloser) - VelSignal = -1.0; // niech jedzie, jak W4 puściło - nie, ma czekać na - // sygnał z sygnalizatora! + VelSignal = -1.0; // ma czekać na sygnał z sygnalizatora! case cm_SetVelocity: // od wersji 357 semafor nie budzi wyłączonej lokomotywy if (!(OrderList[OrderPos] & ~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders diff --git a/Ground.cpp b/Ground.cpp index f87bb069..d5f309dc 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -356,13 +356,17 @@ bool TSubRect::RaTrackAnimAdd(TTrack *t) return false; // będzie animowane... } -void TSubRect::RaAnimate() -{ // wykonanie animacji - if( tTrackAnim == nullptr ) { +// wykonanie animacji +void TSubRect::RaAnimate( unsigned int const Framestamp ) { + + if( ( tTrackAnim == nullptr ) + || ( Framestamp == m_framestamp ) ) { // nie ma nic do animowania return; } tTrackAnim = tTrackAnim->RaAnimate(); // przeliczenie animacji kolejnego + + m_framestamp = Framestamp; }; TTraction * TSubRect::FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude) @@ -431,8 +435,6 @@ void TSubRect::RenderSounds() //--------------------------------------------------------------------------- //------------------ Kwadrat kilometrowy ------------------------------------ //--------------------------------------------------------------------------- -int TGroundRect::iFrameNumber = 0; // licznik wyświetlanych klatek - TGroundRect::~TGroundRect() { SafeDeleteArray(pSubRects); diff --git a/Ground.h b/Ground.h index 13bc46cd..21dd6399 100644 --- a/Ground.h +++ b/Ground.h @@ -171,6 +171,7 @@ class TSubRect : /*public Resource,*/ public CMesh { // sektor składowy kwadratu kilometrowego public: bounding_area m_area; + unsigned int m_framestamp { 0 }; // id of last rendered gfx frame int iTracks = 0; // ilość torów w (tTracks) TTrack **tTracks = nullptr; // tory do renderowania pojazdów protected: @@ -192,15 +193,12 @@ class TSubRect : /*public Resource,*/ public CMesh void LoadNodes(); // utworzenie VBO sektora public: virtual ~TSubRect(); -/* - virtual void Release(); // zwalnianie VBO sektora -*/ virtual void NodeAdd(TGroundNode *Node); // dodanie obiektu do sektora na etapie rozdzielania na sektory void Sort(); // optymalizacja obiektów w sektorze (sortowanie wg tekstur) TTrack * FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude); TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude); bool RaTrackAnimAdd(TTrack *t); // zgłoszenie toru do animacji - void RaAnimate(); // przeliczenie animacji torów + void RaAnimate( unsigned int const Framestamp ); // przeliczenie animacji torów void RenderSounds(); // dźwięki pojazdów z niewidocznych sektorów }; @@ -221,7 +219,6 @@ class TGroundRect : public TSubRect private: TSubRect *pSubRects { nullptr }; - int iLastDisplay; // numer klatki w której był ostatnio wyświetlany void Init(); @@ -251,7 +248,6 @@ public: // optymalizacja obiektów w sektorach pSubRects[ i ].Sort(); } } }; - static int iFrameNumber; // numer kolejny wyświetlanej klatki TGroundNode *nTerrain { nullptr }; // model terenu z E3D - użyć nRootMesh? }; diff --git a/renderer.cpp b/renderer.cpp index 4359b3f4..4cd8d5da 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -320,6 +320,7 @@ opengl_renderer::Render() { m_renderpass.draw_mode = rendermode::none; // force setup anew m_debuginfo.clear(); + ++m_framestamp; Render_pass( rendermode::color ); m_drawcount = m_drawqueue.size(); @@ -1330,8 +1331,6 @@ opengl_renderer::Texture( texture_handle const Texture ) const { bool opengl_renderer::Render( TGround *Ground ) { - ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji) - m_drawqueue.clear(); switch( m_renderpass.draw_mode ) { @@ -1440,73 +1439,70 @@ opengl_renderer::Render( TGroundRect *Groundcell ) { bool result { false }; // will be true if we do any rendering - if( Groundcell->iLastDisplay != Groundcell->iFrameNumber ) { - // tylko jezeli dany kwadrat nie był jeszcze renderowany - Groundcell->LoadNodes(); // ewentualne tworzenie siatek + Groundcell->LoadNodes(); // ewentualne tworzenie siatek - switch( m_renderpass.draw_mode ) { - case rendermode::pickscenery: { - // non-interactive scenery elements get neutral colour - ::glColor3fv( glm::value_ptr( colors::none ) ); - } - case rendermode::color: - case rendermode::reflections: { - if( Groundcell->nRenderRect != nullptr ) { - // nieprzezroczyste trójkąty kwadratu kilometrowego - for( TGroundNode *node = Groundcell->nRenderRect; node != nullptr; node = node->nNext3 ) { - Render( node ); - } + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // non-interactive scenery elements get neutral colour + ::glColor3fv( glm::value_ptr( colors::none ) ); + } + case rendermode::color: + case rendermode::reflections: { + if( Groundcell->nRenderRect != nullptr ) { + // nieprzezroczyste trójkąty kwadratu kilometrowego + for( TGroundNode *node = Groundcell->nRenderRect; node != nullptr; node = node->nNext3 ) { + Render( node ); } - break; + result = true; } - case rendermode::shadows: { - if( Groundcell->nRenderRect != nullptr ) { - // experimental, for shadows render both back and front faces, to supply back faces of the 'forest strips' - ::glDisable( GL_CULL_FACE ); - // nieprzezroczyste trójkąty kwadratu kilometrowego - for( TGroundNode *node = Groundcell->nRenderRect; node != nullptr; node = node->nNext3 ) { - Render( node ); - } - ::glEnable( GL_CULL_FACE ); + break; + } + case rendermode::shadows: { + if( Groundcell->nRenderRect != nullptr ) { + // experimental, for shadows render both back and front faces, to supply back faces of the 'forest strips' + ::glDisable( GL_CULL_FACE ); + // nieprzezroczyste trójkąty kwadratu kilometrowego + for( TGroundNode *node = Groundcell->nRenderRect; node != nullptr; node = node->nNext3 ) { + Render( node ); } - } - case rendermode::pickcontrols: - default: { - break; + result = true; + ::glEnable( GL_CULL_FACE ); } } + case rendermode::pickcontrols: + default: { + break; + } + } #ifdef EU07_USE_OLD_TERRAINCODE - if( Groundcell->nTerrain ) { + if( Groundcell->nTerrain ) { - Render( Groundcell->nTerrain ); - } + Render( Groundcell->nTerrain ); + } #endif - Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba - result = true; - // add the subcells of the cell to the draw queue - switch( m_renderpass.draw_mode ) { - case rendermode::color: - case rendermode::shadows: - case rendermode::pickscenery: { - if( Groundcell->pSubRects != nullptr ) { - for( std::size_t subcellindex = 0; subcellindex < iNumSubRects * iNumSubRects; ++subcellindex ) { - auto subcell = Groundcell->pSubRects + subcellindex; - if( subcell->iNodeCount ) { - // o ile są jakieś obiekty, bo po co puste sektory przelatywać - m_drawqueue.emplace_back( - glm::length2( m_renderpass.camera.position() - glm::dvec3( subcell->m_area.center ) ), - subcell ); - } + // add the subcells of the cell to the draw queue + switch( m_renderpass.draw_mode ) { + case rendermode::color: + case rendermode::shadows: + case rendermode::pickscenery: { + if( Groundcell->pSubRects != nullptr ) { + for( std::size_t subcellindex = 0; subcellindex < iNumSubRects * iNumSubRects; ++subcellindex ) { + auto subcell = Groundcell->pSubRects + subcellindex; + if( subcell->iNodeCount ) { + // o ile są jakieś obiekty, bo po co puste sektory przelatywać + m_drawqueue.emplace_back( + glm::length2( m_renderpass.camera.position() - glm::dvec3( subcell->m_area.center ) ), + subcell ); } } - break; - } - case rendermode::reflections: - case rendermode::pickcontrols: - default: { - break; } + break; + } + case rendermode::reflections: + case rendermode::pickcontrols: + default: { + break; } } return result; @@ -1518,7 +1514,8 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) { // oznaczanie aktywnych sektorów Groundsubcell->LoadNodes(); - Groundsubcell->RaAnimate(); // przeliczenia animacji torów w sektorze + // przeliczenia animacji torów w sektorze + Groundsubcell->RaAnimate( m_framestamp ); TGroundNode *node; @@ -1667,7 +1664,7 @@ opengl_renderer::Render( TGroundNode *Node ) { break; } } - Node->Model->RaAnimate(); // jednorazowe przeliczenie animacji + Node->Model->RaAnimate( m_framestamp ); // jednorazowe przeliczenie animacji Node->Model->RaPrepare(); if( Node->Model->pModel ) { // renderowanie rekurencyjne submodeli diff --git a/renderer.h b/renderer.h index 51b3b374..067f64c0 100644 --- a/renderer.h +++ b/renderer.h @@ -350,6 +350,7 @@ private: int m_diffusetextureunit{ GL_TEXTURE3 }; units_state m_unitstate; + unsigned int m_framestamp; // id of currently rendered gfx frame float m_drawtime { 1000.f / 30.f * 20.f }; // start with presumed 'neutral' average of 30 fps std::chrono::steady_clock::time_point m_drawstart; // cached start time of previous frame float m_framerate; From 42aab5203806b32a57d7a91b5d3d54dc17dab397 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 24 Aug 2017 03:12:04 +0200 Subject: [PATCH 3/3] Build 170823. tweaks to AI brake handling --- Driver.cpp | 126 +++++++++++++++++++++++++++++++---------------------- Driver.h | 3 ++ World.cpp | 2 +- version.h | 2 +- 4 files changed, 78 insertions(+), 55 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index ee243d95..2872d265 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1250,10 +1250,11 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN else { // przyspieszenie: ujemne, gdy trzeba hamować a = ( v * v - mvOccupied->Vel * mvOccupied->Vel ) / ( 25.92 * d ); - if( fBrakeDist > 0.0 ) { + auto const brakingdistance = fBrakeDist * braking_distance_multiplier( v ); + if( brakingdistance > 0.0 ) { // maintain desired acc while we have enough room to brake safely, when close enough start paying attention // try to make a smooth transition instead of sharp change - a = interpolate( a, AccPreferred, clamp( ( d - fBrakeDist ) / fBrakeDist, 0.0, 1.0 ) ); + a = interpolate( a, AccPreferred, clamp( ( d - brakingdistance ) / brakingdistance, 0.0, 1.0 ) ); } if( ( d < fMinProximityDist ) && ( v < fVelDes ) ) { @@ -1318,6 +1319,16 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN return go; }; +// modifies brake distance for low target speeds, to ease braking rate in such situations +float +TController::braking_distance_multiplier( float const Targetvelocity ) { + + if( Targetvelocity > 65.f ) { return 1.f; } + if( Targetvelocity < 5.f ) { return 1.f; } + // stretch the braking distance up to 3 times; the lower the speed, the greater the stretch + return interpolate( 3.f, 1.f, ( Targetvelocity - 5.f ) / 60.f ); +} + void TController::TablePurger() { // odtykacz: usuwa mniej istotne pozycje ze środka tabelki, aby uniknąć zatkania //(np. brak ograniczenia pomiędzy zwrotnicami, usunięte sygnały, minięte odcinki łuku) @@ -1998,10 +2009,11 @@ void TController::SetVelocity(double NewVel, double NewVelNext, TStopReason r) double TController::BrakeAccFactor() { -// double Factor = 1 + fBrakeReaction*mvOccupied->Vel / (std::max(0.0, ActualProximityDist) + 1); - double Factor = 1; - if((ActualProximityDist>fMinProximityDist)||(mvOccupied->VelBrakeCtrlPosR < 0.5 ? 1.5 : 1))*mvOccupied->Vel / (std::max(0.0, ActualProximityDist) + 1) * ((AccDesired - AbsAccS_pub) / fAccThreshold); + double Factor = 1.0; + if( ( ActualProximityDist > fMinProximityDist ) + || ( mvOccupied->Vel > VelDesired + fVelPlus ) ) { + Factor += ( fBrakeReaction * ( mvOccupied->BrakeCtrlPosR < 0.5 ? 1.5 : 1 ) ) * mvOccupied->Vel / ( std::max( 0.0, ActualProximityDist ) + 1 ) * ( ( AccDesired - AbsAccS_pub ) / fAccThreshold ); + } return Factor; } @@ -2375,8 +2387,12 @@ bool TController::IncBrake() if( deltaAcc > fBrake_a1[0]) { - if (mvOccupied->BrakeCtrlPosR<0.1) - OK = mvOccupied->BrakeLevelAdd(1.0); + if( mvOccupied->BrakeCtrlPosR < 0.1 ) { + OK = mvOccupied->BrakeLevelAdd( ( + mvOccupied->BrakeDelayFlag > bdelay_G ? + 1.0 : + 1.25 ) ); + } else { OK = mvOccupied->BrakeLevelAdd(0.25); @@ -3860,7 +3876,8 @@ bool TController::UpdateSituation(double dt) // margines prędkości powodujący załączenie napędu; min 1.0 żeby nie ruszał przy 0.1 fVelMinus = clamp( std::round( 0.05 * VelDesired ), 1.0, 5.0 ); // normalnie dopuszczalne przekroczenie to 5% prędkości ale nie więcej niż 5km/h - fVelPlus = std::min( 5.0, std::ceil( 0.05 * VelDesired ) ); + // bottom margin raised to 2 km/h to give the AI more leeway at low speed limits + fVelPlus = clamp( std::ceil( 0.05 * VelDesired ), 2.0, 5.0 ); } } else { @@ -4324,24 +4341,24 @@ bool TController::UpdateSituation(double dt) // gdy zbliża się i jest za szybki do nowej prędkości, albo stoi na zatrzymaniu if (vel > 0.0) { // jeśli jedzie - if ((vel < VelNext) ? - (ActualProximityDist > fMaxProximityDist * (1 + 0.1 * vel)) : - false) // dojedz do semafora/przeszkody - { // jeśli jedzie wolniej niż można i jest wystarczająco daleko, to można - // przyspieszyć + if( ( vel < VelNext ) + && ( ActualProximityDist > fMaxProximityDist * ( 1.0 + 0.1 * vel ) ) ) { + // dojedz do semafora/przeszkody + // jeśli jedzie wolniej niż można i jest wystarczająco daleko, to można przyspieszyć if (AccPreferred > 0.0) // jeśli nie ma zawalidrogi AccDesired = AccPreferred; - // VelDesired:=Min0R(VelDesired,VelReduced+VelNext); } else if (ActualProximityDist > fMinProximityDist) { // jedzie szybciej, niż trzeba na końcu ActualProximityDist, ale jeszcze jest daleko if (ActualProximityDist < fMaxProximityDist) { // jak minął już maksymalny dystans po prostu hamuj (niski stopień) // ma stanąć, a jest w drodze hamowania albo ma jechać - // hamowanie tak, aby stanąć - AccDesired = ( VelNext * VelNext - vel * vel ) / ( 25.92 * ( ActualProximityDist + 0.1 - 0.5*fMinProximityDist ) ); - AccDesired = std::min(AccDesired, fAccThreshold); - VelDesired = 0.0; + VelDesired = VelNext; + if( VelDesired == 0.0 ) { + // hamowanie tak, aby stanąć + AccDesired = ( VelNext * VelNext - vel * vel ) / ( 25.92 * ( ActualProximityDist + 0.1 - 0.5*fMinProximityDist ) ); + AccDesired = std::min( AccDesired, fAccThreshold ); + } } else if ((vel < VelNext + fVelPlus)||((vel fBrakeDist) { // jeśli ma stanąć, a mieści się w drodze hamowania if (vel < 10.0) // jeśli prędkość jest łatwa do zatrzymania @@ -4402,7 +4418,9 @@ bool TController::UpdateSituation(double dt) } } } - else { // przy dużej różnicy wysoki stopień (1,00 potrzebnego opoznienia) +*/ + else { + // przy dużej różnicy wysoki stopień (1,00 potrzebnego opoznienia) double dist = 0;// (VelNext * VelNext - (VelNext + 20) * (VelNext + 20)) / (25.92)*(-1 / fBrake_a0[0] - 1 / fAccThreshold); // ensure some minimal coasting speed, otherwise a vehicle entering this zone at very low speed will be crawling forever AccDesired = @@ -4415,21 +4433,14 @@ bool TController::UpdateSituation(double dt) VelNext + dist ) ) + 0.1 ); // najpierw hamuje mocniej, potem zluzuje } - if (AccPreferred < AccDesired) - AccDesired = AccPreferred; //(1+abs(AccDesired)) - // ReactionTime=0.5*mvOccupied->BrakeDelay[2+2*mvOccupied->BrakeDelayFlag]; - // //aby szybkosc hamowania zalezala od przyspieszenia i opoznienia - // hamulcow - // fBrakeTime=0.5*mvOccupied->BrakeDelay[2+2*mvOccupied->BrakeDelayFlag]; - // //aby szybkosc hamowania zalezala od przyspieszenia i opoznienia - // hamulcow + AccDesired = std::min( AccDesired, AccPreferred ); } else { // jest bliżej niż fMinProximityDist VelDesired = Global::Min0RSpeed( VelDesired, VelNext ); // utrzymuj predkosc bo juz blisko - if( vel < VelNext + fVelPlus ) { + if( vel <= VelNext + fVelPlus ) { // jeśli niewielkie przekroczenie, ale ma jechać - AccDesired = std::min( 0.0, AccPreferred ); // to olej (zacznij luzować) + AccDesired = std::max( 0.0, AccPreferred ); // to olej (zacznij luzować) } ReactionTime = 0.1; // i orientuj się szybciej } @@ -4560,10 +4571,16 @@ bool TController::UpdateSituation(double dt) } // NOTE: as a stop-gap measure the routine is limited to trains only while car calculations seem off if( mvControlling->CategoryFlag == 1 ) { - if( -AccDesired * BrakeAccFactor() < ( ( fReady > 0.4 ) || ( VelNext > vel - 40.0 ) ? fBrake_a0[ 0 ] * 0.8 : -fAccThreshold ) ) + if( -AccDesired * BrakeAccFactor() < ( + ( ( fReady > 0.4 ) || ( VelNext > vel - 40.0 ) ) ? + fBrake_a0[ 0 ] * 0.8 : + -fAccThreshold ) + / braking_distance_multiplier( VelNext ) ) { AccDesired = std::max( -0.06, AccDesired ); - else + } + else { ReactionTime = 0.25; // i orientuj się szybciej, jeśli hamujesz + } } if (mvOccupied->BrakeSystem == Pneumatic) // napełnianie uderzeniowe if (mvOccupied->BrakeHandle == FV4a) @@ -4719,23 +4736,26 @@ bool TController::UpdateSituation(double dt) } // type & dt_ezt else { // a stara wersja w miarę dobrze działa na składy wagonowe - if( ( ( fAccGravity < -0.05 ) && ( vel < 0.0 ) ) - || ( ( AccDesired < fAccGravity - 0.1 ) && ( AbsAccS > AccDesired + fBrake_a1[ 0 ] ) ) ) { - // u góry ustawia się hamowanie na fAccThreshold - if( ( fBrakeTime < 0.0 ) - || ( AccDesired < fAccGravity - 0.3 ) - || ( mvOccupied->BrakeCtrlPos <= 0 ) ) { - // jeśli upłynął czas reakcji hamulca, chyba że nagłe albo luzował - if( true == IncBrake() ) { - fBrakeTime = - 3.0 - + 0.5 * ( ( - mvOccupied->BrakeDelayFlag > bdelay_G ? - mvOccupied->BrakeDelay[ 1 ] : - mvOccupied->BrakeDelay[ 3 ] ) - - 3.0 ); - // Ra: ten czas należy zmniejszyć, jeśli czas dojazdu do zatrzymania jest mniejszy - fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1 + if( ( VelNext == 0.0 ) + || ( vel > VelNext + fVelPlus ) ) { + if( ( ( fAccGravity < -0.05 ) && ( vel < 0.0 ) ) + || ( ( AccDesired < fAccGravity - 0.1 ) && ( AbsAccS > AccDesired + fBrake_a1[ 0 ] ) ) ) { + // u góry ustawia się hamowanie na fAccThreshold + if( ( fBrakeTime < 0.0 ) + || ( AccDesired < fAccGravity - 0.3 ) + || ( mvOccupied->BrakeCtrlPos <= 0 ) ) { + // jeśli upłynął czas reakcji hamulca, chyba że nagłe albo luzował + if( true == IncBrake() ) { + fBrakeTime = + 3.0 + + 0.5 * ( ( + mvOccupied->BrakeDelayFlag > bdelay_G ? + mvOccupied->BrakeDelay[ 1 ] : + mvOccupied->BrakeDelay[ 3 ] ) + - 3.0 ); + // Ra: ten czas należy zmniejszyć, jeśli czas dojazdu do zatrzymania jest mniejszy + fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1 + } } } } diff --git a/Driver.h b/Driver.h index a182f9b1..e0c145e7 100644 --- a/Driver.h +++ b/Driver.h @@ -369,6 +369,9 @@ class TController void TableTraceRoute(double fDistance, TDynamicObject *pVehicle = nullptr); void TableCheck(double fDistance); TCommandType TableUpdate(double &fVelDes, double &fDist, double &fNext, double &fAcc); + // modifies brake distance for low target speeds, to ease braking rate in such situations + float + braking_distance_multiplier( float const Targetvelocity ); void TablePurger(); public: std::size_t TableSize() const { return sSpeedTable.size(); } diff --git a/World.cpp b/World.cpp index 4d4451da..56ec89a8 100644 --- a/World.cpp +++ b/World.cpp @@ -1696,7 +1696,7 @@ TWorld::Update_UI() { + ")"; uitextline2 = - "HamZ=" + to_string( tmp->MoverParameters->fBrakeCtrlPos, 1 ) + "HamZ=" + to_string( tmp->MoverParameters->fBrakeCtrlPos, 2 ) + "; HamP=" + std::to_string( tmp->MoverParameters->LocalBrakePos ) + "/" + to_string( tmp->MoverParameters->LocalBrakePosA, 2 ) + "; NasJ=" + std::to_string( tmp->MoverParameters->MainCtrlPos ) + "(" + std::to_string( tmp->MoverParameters->MainCtrlActualPos ) + ")" + "; NasB=" + std::to_string( tmp->MoverParameters->ScndCtrlPos ) + "(" + std::to_string( tmp->MoverParameters->ScndCtrlActualPos ) + ")" diff --git a/version.h b/version.h index 99ba44c0..1db998a7 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 821 +#define VERSION_MINOR 823 #define VERSION_REVISION 0