diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 66213c23..6916872c 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -92,6 +92,7 @@ jobs: with: ref: master path: .trusted + persist-credentials: false - name: Download analysis input uses: actions/download-artifact@v4 diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index e7bd1d23..accbbbaa 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1732,7 +1732,11 @@ class TMoverParameters // bounds-safe read access to MotorParam TMotorParameters const &motor_param(int const Position) const { - return MotorParam[std::clamp(Position, 0, MotorParametersArraySize)]; + if (Position < 0) + return MotorParam[0]; + if (Position > MotorParametersArraySize) + return MotorParam[MotorParametersArraySize]; + return MotorParam[Position]; } TTransmision Transmision; // record {liczba zebow przekladni} diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 82dd245f..06358b3c 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1752,6 +1752,11 @@ void TMoverParameters::LowVoltagePowerCheck(double const Deltatime) void TMoverParameters::PowerCouplersCheck(double const Deltatime, coupling const Coupling) { + if (Coupling != coupling::highvoltage && Coupling != coupling::power110v && Coupling != coupling::power24v) + { + // only power couplings carry voltage + return; + } auto localvoltage{0.0}; @@ -6392,10 +6397,7 @@ double TMoverParameters::TractionForce(double dt) // PosRatio = 1.0 * (PosRatio * 0 + 1) * PosRatio; // 1 * 1 * PosRatio = PosRatio Hamulec->SetED(0); // (Hamulec as TLSt).SetLBP(LocBrakePress); - if (PosRatio > eimv_pr) - tmp = 4; - else - tmp = 4; // szybkie malenie, powolne wzrastanie + tmp = 4; // szybkie malenie, powolne wzrastanie } dmoment = eimv[eimv_Fful]; // NOTE: the commands to operate the sandbox are likely to conflict with other similar ai decisions @@ -8022,8 +8024,6 @@ double TMoverParameters::dizel_fillcheck(int mcp, double dt) } if (enrot > nreg) // nad predkoscia regulatora zeruj dawke realfill = 0; - if (enrot < nreg) // pod predkoscia regulatora dawka zadana - realfill = realfill; if (enrot < dizel_nreg_min && RList[mcp].R > 0.001) // jesli ponizej biegu jalowego i niezerowa dawka, to dawaj pelna realfill = 1; } @@ -9118,7 +9118,7 @@ bool TMoverParameters::readMPT0(std::string const &line) } if (true == parser.getTokens(1, false)) { - int autoswitch; + int autoswitch{0}; parser >> autoswitch; MotorParam[idx].AutoSwitch = autoswitch == 1; } @@ -9174,7 +9174,7 @@ bool TMoverParameters::readMPTElectricSeries(std::string const &line) parser >> MotorParam[idx].mfi >> MotorParam[idx].mIsat >> MotorParam[idx].fi >> MotorParam[idx].Isat; if (true == parser.getTokens(1, false)) { - int autoswitch; + int autoswitch{0}; parser >> autoswitch; MotorParam[idx].AutoSwitch = autoswitch == 1; } @@ -9223,7 +9223,7 @@ bool TMoverParameters::readMPTDieselEngine(std::string const &line) parser >> MotorParam[idx].mIsat >> MotorParam[idx].fi >> MotorParam[idx].mfi; if (true == parser.getTokens(1, false)) { - int autoswitch; + int autoswitch{0}; parser >> autoswitch; MotorParam[idx].AutoSwitch = autoswitch == 1; } @@ -11048,7 +11048,7 @@ void TMoverParameters::LoadFIZ_DCEMUED(std::string const &line) void TMoverParameters::LoadFIZ_SpringBrake(std::string const &line) { - double vol; + double vol{1.0}; extract_value(vol, "Volume", line, "1"); if (!SpringBrake.Cylinder) SpringBrake.Cylinder = std::make_shared(); diff --git a/McZapkie/hamulce.cpp b/McZapkie/hamulce.cpp index 44e8be4b..ad75bac4 100644 --- a/McZapkie/hamulce.cpp +++ b/McZapkie/hamulce.cpp @@ -3516,10 +3516,7 @@ double TMHZ_K5P::GetPF(double i_bcp, double PP, double HP, double dt, double ep) LimCP = std::min(LimCP, HP); // pozycja + czasowy lub zasilanie ActFlowSpeed = 4; - if (LimCP > CP) // podwyzszanie szybkie - CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy; - else - CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy + CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy double uop = UnbrakeOverPressure; // unbrake over pressure in actual state ManualOvrldActive = UniversalFlag & TUniversalBrake::ub_HighPressure; // button is pressed @@ -3699,10 +3696,7 @@ double TMHZ_6P::GetPF(double i_bcp, double PP, double HP, double dt, double ep) LimCP = std::min(LimCP, HP); // pozycja + czasowy lub zasilanie ActFlowSpeed = 4; - if (LimCP > CP) // podwyzszanie szybkie - CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy; - else - CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy + CP = CP + 9 * std::min(abs(LimCP - CP), 0.05) * PR(CP, LimCP) * dt; // zbiornik sterujacy dpPipe = std::min(HP, CP + TP + RedAdj); diff --git a/application/application.cpp b/application/application.cpp index ceb5ec6c..81e96c3d 100644 --- a/application/application.cpp +++ b/application/application.cpp @@ -498,7 +498,7 @@ int eu07_application::run() { command_queue::commands_map commands_to_exec; command_queue::commands_map local_commands = simulation::Commands.pop_intercept_queue(); - double slave_sync; + double slave_sync{0.0}; // if we're the server if (m_network && m_network->servers) diff --git a/application/drivermode.cpp b/application/drivermode.cpp index 80fd3b17..b5b78634 100644 --- a/application/drivermode.cpp +++ b/application/drivermode.cpp @@ -667,7 +667,7 @@ void driver_mode::update_camera(double const Deltatime) // reset window state, it'll be set again if applicable in a check below Global.CabWindowOpen = false; - if (simulation::Train != nullptr && Camera.m_owner != nullptr && false == DebugCameraFlag) + if (simulation::Train != nullptr && controlled != nullptr && Camera.m_owner != nullptr && false == DebugCameraFlag) { // jeśli jazda w kabinie, przeliczyć trzeba parametry kamery /* diff --git a/application/uitranscripts.cpp b/application/uitranscripts.cpp index 96c9f735..c9780e10 100644 --- a/application/uitranscripts.cpp +++ b/application/uitranscripts.cpp @@ -42,7 +42,7 @@ TTranscripts::Add( std::string const &txt, bool backgorund ) { cParser parser( asciitext ); while( true == parser.getTokens( 3, false, "[]\n" ) ) { - float begin, end; + float begin{ 0.f }, end{ 0.f }; std::string transcript; parser >> begin diff --git a/audio/audiorenderer.cpp b/audio/audiorenderer.cpp index 81f81570..50a6f727 100644 --- a/audio/audiorenderer.cpp +++ b/audio/audiorenderer.cpp @@ -563,15 +563,12 @@ openal_renderer::init_caps() { if( ::alcIsExtensionPresent( nullptr, "ALC_ENUMERATION_EXT" ) == AL_TRUE ) { // enumeration supported WriteLog( "available audio devices:" ); - auto const *devices { ::alcGetString( nullptr, ALC_DEVICE_SPECIFIER ) }; - auto const - *device { devices }, - *next { devices + 1 }; - while( device && *device != '\0' && next && *next != '\0' ) { - WriteLog( { device } ); - auto const len { std::strlen( device ) }; - device += len + 1; - next += len + 2; + // device list is a sequence of null-terminated names, ending with an empty name + auto const *device { ::alcGetString( nullptr, ALC_DEVICE_SPECIFIER ) }; + while( device != nullptr && *device != '\0' ) { + std::string const devicename { device }; + WriteLog( devicename ); + device += devicename.size() + 1; } } diff --git a/launcher/deferred_image.h b/launcher/deferred_image.h index fcd25fd6..2ad6ec9f 100644 --- a/launcher/deferred_image.h +++ b/launcher/deferred_image.h @@ -1,22 +1,43 @@ #pragma once +#include +#include + #include "model/Texture.h" #include "rendering/renderer.h" class deferred_image { public: + // value returned by get() when the image isn't (yet) available + static constexpr GLuint invalid_id { std::numeric_limits::max() }; + deferred_image() = default; deferred_image(const std::string &p) : path(p) { } deferred_image(const deferred_image&) = delete; - deferred_image(deferred_image&&) = default; - deferred_image &operator=(deferred_image&&) = default; + deferred_image(deferred_image &&other) noexcept + { + std::lock_guard lock(other.mutex); + path = std::move(other.path); + image = other.image; + } + deferred_image &operator=(deferred_image &&other) noexcept + { + if (this != &other) { + std::scoped_lock lock(mutex, other.mutex); + path = std::move(other.path); + image = other.image; + } + return *this; + } operator bool() const { + std::lock_guard lock(mutex); return image != null_handle || !path.empty(); } GLuint get() const { + std::lock_guard lock(mutex); if (!path.empty()) { image = GfxRenderer->Fetch_Texture(path, true); path.clear(); @@ -30,11 +51,12 @@ public: return tex.get_id(); } - return -1; + return invalid_id; } glm::ivec2 size() const { + std::lock_guard lock(mutex); if (image != null_handle) { auto &tex = GfxRenderer->Texture(image); return glm::ivec2(tex.get_width(), tex.get_height()); @@ -43,6 +65,8 @@ public: } private: + // guards lazy loading performed by the const accessors + mutable std::mutex mutex; mutable std::string path; mutable texture_handle image = 0; }; diff --git a/launcher/scenery_list.cpp b/launcher/scenery_list.cpp index 77f69a35..518669e5 100644 --- a/launcher/scenery_list.cpp +++ b/launcher/scenery_list.cpp @@ -281,7 +281,7 @@ void ui::scenerylist_panel::draw_trainset(trainset_desc &trainset) for (auto &dyn_desc : trainset.vehicles) { deferred_image *mini = nullptr; - if (dyn_desc.skin && dyn_desc.skin->mini.get() != (GLuint)-1) + if (dyn_desc.skin && dyn_desc.skin->mini.get() != deferred_image::invalid_id) mini = &dyn_desc.skin->mini; else mini = &placeholder_mini; diff --git a/launcher/vehicle_picker.cpp b/launcher/vehicle_picker.cpp index f7d3503f..58a11f59 100644 --- a/launcher/vehicle_picker.cpp +++ b/launcher/vehicle_picker.cpp @@ -270,7 +270,7 @@ bool ui::vehiclepicker_panel::selectable_image(const char *desc, bool selected, } GLuint tex = image->get(); - if (tex != (GLuint)-1) { + if (tex != deferred_image::invalid_id) { glm::ivec2 size = image->size(); float width = 30.0f / size.y * size.x; ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); diff --git a/model/AnimModel.cpp b/model/AnimModel.cpp index cc54a2a2..1d808676 100644 --- a/model/AnimModel.cpp +++ b/model/AnimModel.cpp @@ -598,11 +598,11 @@ void TAnimModel::on_season_update() { void TAnimModel::RaPrepare() { // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza - bool state; // stan światła if (Global.UpdateMaterials) on_season_update(); for (int i = 0; i < iNumLights; ++i) { + bool state{ false }; // stan światła auto const lightmode { static_cast( std::abs( lsLights[ i ] ) ) }; switch( lightmode ) { case ls_On: diff --git a/model/Model3d.cpp b/model/Model3d.cpp index e1a3a79e..b67663f9 100644 --- a/model/Model3d.cpp +++ b/model/Model3d.cpp @@ -1529,7 +1529,9 @@ void TSubModel::ParentMatrix(float4x4 *m) const void TSubModel::ReplaceMatrix(const glm::mat4 &mat) { - *fMatrix = float4x4(glm::value_ptr(mat)); + for (int column = 0; column < 4; ++column) + for (int row = 0; row < 4; ++row) + fMatrix->e[column * 4 + row] = mat[column][row]; } void TSubModel::ReplaceMaterial(const std::string &name) @@ -1618,13 +1620,8 @@ TSubModel *TModel3d::GetFromName(std::string const &Name) const { // wyszukanie submodelu po nazwie if (Name.empty()) return Root; // potrzebne do terenu z E3D - if (iFlags & 0x0200) // wczytany z pliku tekstowego, wyszukiwanie rekurencyjne - return Root ? Root->GetFromName(Name) : nullptr; - else // wczytano z pliku binarnego, można wyszukać iteracyjnie - { - // for (int i=0;iGetFromName(Name) : nullptr; - } + // both text and binary models are searched recursively + return Root ? Root->GetFromName(Name) : nullptr; }; // locates particle source submodels and stores them on internal list diff --git a/model/Texture.cpp b/model/Texture.cpp index 5c1d852f..a4b9def4 100644 --- a/model/Texture.cpp +++ b/model/Texture.cpp @@ -394,12 +394,12 @@ opengl_texture::make_from_memory(size_t width, size_t height, const uint8_t *raw void opengl_texture::update_from_memory(size_t width, size_t height, const uint8_t *raw) { - if (id != (GLuint)-1 && (width != data_width || height != data_height || GL_SRGB8_ALPHA8 != data_format || GL_RGBA != data_components)) + if (id != invalid_id && (width != data_width || height != data_height || GL_SRGB8_ALPHA8 != data_format || GL_RGBA != data_components)) { glDeleteTextures(1, &id); - id = (GLuint)-1; + id = invalid_id; } - if (id == (GLuint)-1) + if (id == invalid_id) { data_width = width; data_height = height; diff --git a/model/Texture.h b/model/Texture.h index 1f582640..7b285ee3 100644 --- a/model/Texture.h +++ b/model/Texture.h @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include +#include #include "winheaders.h" #include #include "model/ResourceManager.h" @@ -84,7 +85,8 @@ struct opengl_texture : public ITexture { virtual void update_from_memory(size_t width, size_t height, const uint8_t *data) override; // members - GLuint id{ (GLuint)-1 }; // associated GL resource + static constexpr GLuint invalid_id { std::numeric_limits::max() }; // id value of texture without GL resource + GLuint id{ invalid_id }; // associated GL resource bool has_alpha{ false }; // indicates the texture has alpha channel bool is_ready{ false }; // indicates the texture was processed and is ready for use std::string traits; // requested texture attributes: wrapping modes etc diff --git a/network/message.h b/network/message.h index 871e833f..979c69ce 100644 --- a/network/message.h +++ b/network/message.h @@ -25,22 +25,22 @@ struct message struct client_hello : public message { - client_hello() : message(CLIENT_HELLO) {} + client_hello() : message(CLIENT_HELLO), version(0), start_packet(0) {} virtual void serialize(std::ostream &stream) const override; virtual void deserialize(std::istream &stream) override; - int32_t version{}; - uint32_t start_packet{}; + int32_t version; + uint32_t start_packet; }; struct server_hello : public message { - server_hello() : message(SERVER_HELLO) {} + server_hello() : message(SERVER_HELLO), seed(0), timestamp(0), config(0) {} - uint32_t seed{}; - int64_t timestamp{}; - int64_t config{}; + uint32_t seed; + int64_t timestamp; + int64_t config; std::string scenario; virtual void serialize(std::ostream &stream) const override; @@ -60,11 +60,11 @@ struct request_command : public message struct frame_info : public request_command { - frame_info() : request_command(FRAME_INFO) {} + frame_info() : request_command(FRAME_INFO), render_dt(0.0), dt(0.0), sync(0.0) {} - double render_dt{}; - double dt{}; - double sync{}; + double render_dt; + double dt; + double sync; virtual void serialize(std::ostream &stream) const override; virtual void deserialize(std::istream &stream) override; diff --git a/rendering/frustum.cpp b/rendering/frustum.cpp index afe16441..f4677065 100644 --- a/rendering/frustum.cpp +++ b/rendering/frustum.cpp @@ -22,30 +22,14 @@ cFrustum::calculate() { void cFrustum::calculate( glm::mat4 const &Projection, glm::mat4 const &Modelview ) { - float const *proj = glm::value_ptr( Projection ); - float const *modl = glm::value_ptr( Modelview ); + // multiply the matrices to retrieve clipping planes (column-major, same layout as the old float[16] form) + auto const clipmatrix { Projection * Modelview }; float clip[ 16 ]; - - // multiply the matrices to retrieve clipping planes - clip[ 0 ] = modl[ 0 ] * proj[ 0 ] + modl[ 1 ] * proj[ 4 ] + modl[ 2 ] * proj[ 8 ] + modl[ 3 ] * proj[ 12 ]; - clip[ 1 ] = modl[ 0 ] * proj[ 1 ] + modl[ 1 ] * proj[ 5 ] + modl[ 2 ] * proj[ 9 ] + modl[ 3 ] * proj[ 13 ]; - clip[ 2 ] = modl[ 0 ] * proj[ 2 ] + modl[ 1 ] * proj[ 6 ] + modl[ 2 ] * proj[ 10 ] + modl[ 3 ] * proj[ 14 ]; - clip[ 3 ] = modl[ 0 ] * proj[ 3 ] + modl[ 1 ] * proj[ 7 ] + modl[ 2 ] * proj[ 11 ] + modl[ 3 ] * proj[ 15 ]; - - clip[ 4 ] = modl[ 4 ] * proj[ 0 ] + modl[ 5 ] * proj[ 4 ] + modl[ 6 ] * proj[ 8 ] + modl[ 7 ] * proj[ 12 ]; - clip[ 5 ] = modl[ 4 ] * proj[ 1 ] + modl[ 5 ] * proj[ 5 ] + modl[ 6 ] * proj[ 9 ] + modl[ 7 ] * proj[ 13 ]; - clip[ 6 ] = modl[ 4 ] * proj[ 2 ] + modl[ 5 ] * proj[ 6 ] + modl[ 6 ] * proj[ 10 ] + modl[ 7 ] * proj[ 14 ]; - clip[ 7 ] = modl[ 4 ] * proj[ 3 ] + modl[ 5 ] * proj[ 7 ] + modl[ 6 ] * proj[ 11 ] + modl[ 7 ] * proj[ 15 ]; - - clip[ 8 ] = modl[ 8 ] * proj[ 0 ] + modl[ 9 ] * proj[ 4 ] + modl[ 10 ] * proj[ 8 ] + modl[ 11 ] * proj[ 12 ]; - clip[ 9 ] = modl[ 8 ] * proj[ 1 ] + modl[ 9 ] * proj[ 5 ] + modl[ 10 ] * proj[ 9 ] + modl[ 11 ] * proj[ 13 ]; - clip[ 10 ] = modl[ 8 ] * proj[ 2 ] + modl[ 9 ] * proj[ 6 ] + modl[ 10 ] * proj[ 10 ] + modl[ 11 ] * proj[ 14 ]; - clip[ 11 ] = modl[ 8 ] * proj[ 3 ] + modl[ 9 ] * proj[ 7 ] + modl[ 10 ] * proj[ 11 ] + modl[ 11 ] * proj[ 15 ]; - - clip[ 12 ] = modl[ 12 ] * proj[ 0 ] + modl[ 13 ] * proj[ 4 ] + modl[ 14 ] * proj[ 8 ] + modl[ 15 ] * proj[ 12 ]; - clip[ 13 ] = modl[ 12 ] * proj[ 1 ] + modl[ 13 ] * proj[ 5 ] + modl[ 14 ] * proj[ 9 ] + modl[ 15 ] * proj[ 13 ]; - clip[ 14 ] = modl[ 12 ] * proj[ 2 ] + modl[ 13 ] * proj[ 6 ] + modl[ 14 ] * proj[ 10 ] + modl[ 15 ] * proj[ 14 ]; - clip[ 15 ] = modl[ 12 ] * proj[ 3 ] + modl[ 13 ] * proj[ 7 ] + modl[ 14 ] * proj[ 11 ] + modl[ 15 ] * proj[ 15 ]; + for( int column = 0; column < 4; ++column ) { + for( int row = 0; row < 4; ++row ) { + clip[ column * 4 + row ] = clipmatrix[ column ][ row ]; + } + } // get the sides of the frustum. m_frustum[ side_RIGHT ][ plane_A ] = clip[ 3 ] - clip[ 0 ]; diff --git a/rendering/lightarray.h b/rendering/lightarray.h index 670cbea8..d7459fe9 100644 --- a/rendering/lightarray.h +++ b/rendering/lightarray.h @@ -18,7 +18,7 @@ public: int index{ -1 }; // 0: front lights, 1: rear lights glm::dvec3 position; // position of the light in 3d scene glm::vec3 direction; // direction of the light in 3d scene - glm::vec3 color{ 255.0f / 255.0f, 241.0f / 255.0f, 224.0f / 255.0f }; // color of the light, default is halogen light + glm::vec3 color{ 1.0f, 241.0f / 255.0f, 224.0f / 255.0f }; // color of the light, default is halogen light float intensity{ 0.0f }; // (combined) intensity of the light(s) int count{ 0 }; // number (or pattern) of active light(s) glm::vec3 state{ 0.f }; // state of individual lights diff --git a/rendering/opengl33renderer.cpp b/rendering/opengl33renderer.cpp index 2f587033..fcd90aba 100644 --- a/rendering/opengl33renderer.cpp +++ b/rendering/opengl33renderer.cpp @@ -28,6 +28,23 @@ http://mozilla.org/MPL/2.0/. int constexpr EU07_PICKBUFFERSIZE{ 1024 }; // size of (square) textures bound with the pick framebuffer int constexpr EU07_REFLECTIONFIDELITYOFFSET { 250 }; // artificial increase of range for reflection pass detail reduction +namespace { + +// returns material assigned to the submodel, resolving replacable skins. null_handle if no skin set is bound +material_handle +submodel_material( TSubModel const *Submodel ) { + + if( Submodel->m_material >= 0 ) { + return Submodel->m_material; + } + return ( + TSubModel::ReplacableSkinId != nullptr ? + TSubModel::ReplacableSkinId[ -Submodel->m_material ] : + null_handle ); +} + +} // namespace + void GLAPIENTRY ErrorCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam ) { /* @@ -1935,7 +1952,7 @@ bool opengl33_renderer::Render(world_environment *Environment) auto const fogfactor{std::clamp(Global.fFogEnd / 2000.f, 0.f, 1.f)}; // stronger fog reduces opacity of the celestial bodies float const duskfactor = 1.0f - std::clamp(std::abs(Environment->m_sun.getAngle()), 0.0f, 12.0f) / 12.0f; - glm::vec3 suncolor = glm::mix(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); + glm::vec3 suncolor = glm::mix(glm::vec3(1.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 { @@ -2341,8 +2358,7 @@ opengl_material &opengl33_renderer::Material(material_handle const Material) opengl_material const & opengl33_renderer::Material( TSubModel const * Submodel ) const { - auto const material { Submodel->m_material >= 0 ? Submodel->m_material : Submodel->ReplacableSkinId[ -Submodel->m_material ] }; - return m_materials.material( material ); + return m_materials.material( submodel_material( Submodel ) ); } texture_handle opengl33_renderer::Fetch_Texture(std::string const &Filename, bool const Loadnow, GLint format_hint) @@ -3767,7 +3783,7 @@ void opengl33_renderer::Render(TSubModel *Submodel) // textures... if (Submodel->m_material < 0) { // zmienialne skóry - Bind_Material(Submodel->ReplacableSkinId[-Submodel->m_material], Submodel); + Bind_Material(submodel_material(Submodel), Submodel); } else { @@ -3804,7 +3820,7 @@ void opengl33_renderer::Render(TSubModel *Submodel) if (Submodel->m_material < 0) { // zmienialne skóry - Bind_Material_Shadow(Submodel->ReplacableSkinId[-Submodel->m_material]); + Bind_Material_Shadow(submodel_material(Submodel)); } else { @@ -4689,7 +4705,7 @@ void opengl33_renderer::Render_Alpha(TSubModel *Submodel) // textures... if (Submodel->m_material < 0) { // zmienialne skóry - Bind_Material(Submodel->ReplacableSkinId[-Submodel->m_material], Submodel); + Bind_Material(submodel_material(Submodel), Submodel); } else { @@ -4721,7 +4737,7 @@ void opengl33_renderer::Render_Alpha(TSubModel *Submodel) if (Submodel->m_material < 0) { // zmienialne skóry - Bind_Material_Shadow(Submodel->ReplacableSkinId[-Submodel->m_material]); + Bind_Material_Shadow(submodel_material(Submodel)); } else { diff --git a/rendering/openglrenderer.cpp b/rendering/openglrenderer.cpp index b675c38f..27c94da8 100644 --- a/rendering/openglrenderer.cpp +++ b/rendering/openglrenderer.cpp @@ -1588,7 +1588,7 @@ opengl_renderer::Render( world_environment *Environment ) { auto const fogfactor { std::clamp( Global.fFogEnd / 2000.f, 0.f, 1.f ) }; // closer/denser fog reduces opacity of the celestial bodies float const duskfactor = 1.0f - std::clamp( std::abs( Environment->m_sun.getAngle() ), 0.0f, 12.0f ) / 12.0f; glm::vec3 suncolor = glm::mix( - glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ), + glm::vec3( 1.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 diff --git a/rendering/precipitation.cpp b/rendering/precipitation.cpp index 3f9ecaec..02baaada 100644 --- a/rendering/precipitation.cpp +++ b/rendering/precipitation.cpp @@ -31,7 +31,7 @@ basic_precipitation::init() { void basic_precipitation::update() { - auto const timedelta { static_cast( ( DebugModeFlag ? Timer::GetDeltaTime() : Timer::GetDeltaTime() ) ) }; + auto const timedelta { static_cast( Timer::GetDeltaTime() ) }; if( timedelta == 0.0 ) { return; } diff --git a/simulation/simulation.cpp b/simulation/simulation.cpp index a1493f63..36edc4c7 100644 --- a/simulation/simulation.cpp +++ b/simulation/simulation.cpp @@ -137,6 +137,11 @@ state_manager::update_scripting_interface() { auto *time{ Memory.find( "__simulation.time" ) }; auto *date{ Memory.find( "__simulation.date" ) }; + if( weather == nullptr || time == nullptr || date == nullptr ) { + // scripting interface cells weren't created, nothing to synchronize + return; + } + if( simulation::is_ready ) { // potentially adjust weather if( weather->Value1() != m_scriptinginterface.weather->Value1() ) { @@ -396,7 +401,6 @@ void state_manager::process_commands() { pantograph.fLenL1 * std::sin( pantograph.fAngleL ) + pantograph.fLenU1 * std::sin( pantograph.fAngleU ) + pantograph.fHeight; - vehicle->MoverParameters->EnginePowerSource.CollectorParameters.CollectorsNo; } vehicle = vehicle->Prev(); diff --git a/simulation/simulationenvironment.cpp b/simulation/simulationenvironment.cpp index b96cea20..6c4061c4 100644 --- a/simulation/simulationenvironment.cpp +++ b/simulation/simulationenvironment.cpp @@ -78,7 +78,6 @@ world_environment::compute_weather() { Global.Overcast <= 0.70 ? 6 : Global.Overcast <= 0.80 ? 7 : Global.Overcast <= 0.90 ? 8 : - Global.Overcast > 0.90 ? 9 : 9; } diff --git a/utilities/Logs.cpp b/utilities/Logs.cpp index 737d25d7..3a0a3d08 100644 --- a/utilities/Logs.cpp +++ b/utilities/Logs.cpp @@ -80,29 +80,20 @@ std::mutex logMutex; void LogService() { - // prevent crash if mutex is not initialized - while (true) - { - try - { - logMutex.lock(); - break; - } - catch (...) {} - } - logMutex.unlock(); - while (!Global.applicationQuitOrder) { { // --- Obsługa InfoStack --- while (!InfoStack.empty()) { - logMutex.lock(); - std::string msg = InfoStack.front().first; - bool isError = InfoStack.front().second; - InfoStack.pop_front(); - logMutex.unlock(); + std::string msg; + bool isError; + { + std::lock_guard lock(logMutex); + msg = InfoStack.front().first; + isError = InfoStack.front().second; + InfoStack.pop_front(); + } // log to file if (Global.iWriteLogEnabled & 1) @@ -134,10 +125,12 @@ void LogService() // --- Obsługa ErrorStack --- while (!ErrorStack.empty()) { - logMutex.lock(); - std::string msg = ErrorStack.front(); - ErrorStack.pop_front(); - logMutex.unlock(); + std::string msg; + { + std::lock_guard lock(logMutex); + msg = ErrorStack.front(); + ErrorStack.pop_front(); + } if (!(Global.iWriteLogEnabled & 1)) continue; diff --git a/utilities/parser.cpp b/utilities/parser.cpp index 7209df01..77f91ee3 100644 --- a/utilities/parser.cpp +++ b/utilities/parser.cpp @@ -272,10 +272,9 @@ void cParser::stripFirstTokenBOM(std::string& token, bool ToLower, const char* B } // if first "token" was standalone BOM, read the next real token (avoid recursion) - while (token.empty() && mStream->peek() != EOF) { - readToken(token, ToLower, Break); + if (token.empty() && mStream->peek() != EOF) { // readToken will not re-enter BOM stripping because mFirstToken is now false - break; + readToken(token, ToLower, Break); } } diff --git a/utilities/parser.h b/utilities/parser.h index 0cf51d8c..131efd8b 100644 --- a/utilities/parser.h +++ b/utilities/parser.h @@ -39,7 +39,7 @@ class cParser //: public std::stringstream Output_ getToken( bool const ToLower = true, char const *Break = "\n\r\t ;" ) { getTokens( 1, ToLower, Break ); - Output_ output; + Output_ output{}; *this >> output; return output; }; inline diff --git a/vehicle/Driver.cpp b/vehicle/Driver.cpp index 9f1b2586..48bf0993 100644 --- a/vehicle/Driver.cpp +++ b/vehicle/Driver.cpp @@ -2231,7 +2231,7 @@ void TController::AutoRewident() BrakingInitialLevel = IsHeavyCargoTrain ? 1.25 : IsCargoTrain ? 1.25 : 1.00; - BrakingLevelIncrease = IsHeavyCargoTrain ? 0.25 : IsCargoTrain ? 0.25 : 0.25; + BrakingLevelIncrease = 0.25; if( is_emu() ) { auto ep_factor { ( BrakeSystem == TBrakeSystem::ElectroPneumatic ? 8 : 4 ) }; @@ -2385,7 +2385,7 @@ bool TController::CheckVehicles(TOrders user) } // with the order established the virtual train manager can do their work p = pVehicles[ end::front ]; - ControlledEnginesCount = p->MoverParameters->Power > 1.0 ? 1 : 0; + ControlledEnginesCount = ( p != nullptr && p->MoverParameters->Power > 1.0 ) ? 1 : 0; auto hasheaters { false }; while (p) { @@ -4042,7 +4042,7 @@ void TController::SetTimeControllers() } } - if( std::abs( DizelPercentage_Speed - DizelActualPercentage ) > ( DizelPercentage > 1 ? 0 : 0 ) ) { + if( std::abs( DizelPercentage_Speed - DizelActualPercentage ) > 0 ) { if( PosDec > 0 && ( DizelActualPercentage - DizelPercentage_Speed > 50 @@ -5425,32 +5425,23 @@ TCommandType TController::BackwardScan( double const Range ) } else { + // jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości + // jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył + // w przeciwnym razie ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma stać + // ruszać stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam +#if LOGBACKSCAN if (scandist > fMinProximityDist && mvOccupied->Vel > EU07_AI_NOMOVEMENT && (OrderCurrentGet() & (Shunt | Loose_shunt)) == 0) { - // jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości - // jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył -#if LOGBACKSCAN - // WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist) + - // AnsiString(scanvel)); WriteLog(edir); -#endif - // SetProximityVelocity(scandist,scanvel,&sl); - return scanvel > 0 ? TCommandType::cm_SetVelocity : TCommandType::cm_Unknown; } else { - // ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma stać - // if ((MoverParameters->Vel==0.0)||(scanvel==0.0)) //jeśli stoi lub ma stanąć/stać - // semafor na tym torze albo lokomtywa stoi, a ma ruszyć, albo ma stanąć, albo nie - // ruszać stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam - // PutCommand("SetVelocity",scanvel,e->Params[9].asMemCell->Value2(),&sl,stopSem); -#if LOGBACKSCAN WriteLog(edir + " - [SetVelocity] [" + to_string(scanvel, 2) + "] [" + to_string(e->input_value(2), 2) + "]"); -#endif - return scanvel > 0 ? TCommandType::cm_SetVelocity : TCommandType::cm_Unknown; } +#endif + return scanvel > 0 ? TCommandType::cm_SetVelocity : TCommandType::cm_Unknown; } } // reakcja AI w trybie manewrowym dodatkowo na sygnały manewrowe diff --git a/vehicle/Driver.h b/vehicle/Driver.h index b76dbf08..c6eaa366 100644 --- a/vehicle/Driver.h +++ b/vehicle/Driver.h @@ -542,7 +542,7 @@ private: double fLastVel = 0.0; // prędkość na poprzednio sprawdzonym torze TTrack *tLast = nullptr; // ostatni analizowany tor basic_event *eSignSkip = nullptr; // można pominąć ten SBL po zatrzymaniu - static constexpr std::size_t npos{ std::size_t( -1 ) }; + static constexpr std::size_t npos{ std::numeric_limits::max() }; std::size_t SemNextIndex{ npos }; std::size_t SemNextStopIndex{ npos }; double dMoveLen = 0.0; // odległość przejechana od ostatniego sprawdzenia tabelki @@ -645,9 +645,16 @@ private: }; inline TOrders TController::OrderCurrentGet() const { + if( OrderPos < 0 || OrderPos >= maxorders ) { + return Wait_for_orders; + } return OrderList[ OrderPos ]; } inline TOrders TController::OrderNextGet() const { - return OrderList[ OrderPos + 1 ]; + if( OrderPos < 0 || OrderPos >= maxorders ) { + return Wait_for_orders; + } + // the order list wraps around, same as in JumpToNextOrder() + return OrderList[ ( OrderPos + 1 ) % maxorders ]; } diff --git a/vehicle/DynObj.cpp b/vehicle/DynObj.cpp index 873cc4d3..6af23f07 100644 --- a/vehicle/DynObj.cpp +++ b/vehicle/DynObj.cpp @@ -1408,7 +1408,7 @@ TDynamicObject * TDynamicObject::ABuScanNearestObject(glm::vec3 pos, TTrack *Tra TDynamicObject *FoundedObj; FoundedObj = ABuFindNearestObject(pos, Track, this, CouplNr); // zwraca numer sprzęgu znalezionego pojazdu - if (FoundedObj == nullptr) + if (FoundedObj == nullptr && Track != nullptr) { double ActDist; // Przeskanowana odleglosc. double CurrDist = 0; // Aktualna dlugosc toru. @@ -1448,7 +1448,7 @@ TDynamicObject * TDynamicObject::ABuScanNearestObject(glm::vec3 pos, TTrack *Tra ActDist = ScanDist; } else // Jesli nie ma, to wychodzimy. - ActDist = ScanDist; + break; } } // Koniec szukania najblizszego toru z jakims obiektem. return FoundedObj; diff --git a/vehicle/Gauge.cpp b/vehicle/Gauge.cpp index a510b05f..63c042d3 100644 --- a/vehicle/Gauge.cpp +++ b/vehicle/Gauge.cpp @@ -241,8 +241,7 @@ TGauge::Load_mapping( cParser &Input, TGauge::scratch_data &Scratchpad ) { gaugetype == "return" ? TGaugeType::push : gaugetype == "delayed" ? TGaugeType::push_delayed : gaugetype == "pushtoggle" ? TGaugeType::pushtoggle : - gaugetype == "toggle" ? TGaugeType::toggle : - TGaugeType::toggle; // default + TGaugeType::toggle; // "toggle" and default } else if( key == "soundinc:" ) { m_soundfxincrease.deserialize( Input, sound_type::single ); diff --git a/vehicle/Train.cpp b/vehicle/Train.cpp index 8d2117c4..6f97769b 100644 --- a/vehicle/Train.cpp +++ b/vehicle/Train.cpp @@ -1435,7 +1435,7 @@ void TTrain::OnCommand_secondcontrollerincrease(TTrain *Train, command_data cons // HACK: potentially animate push or pushtoggle control if (Train->ggScndCtrl.is_push()) { - auto const activeposition{Train->ggScndCtrl.is_toggle() ? 1.f : 1.f}; + auto const activeposition{1.f}; auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f}; Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch); } @@ -12398,7 +12398,8 @@ uint16_t TTrain::id() return vid; } -#include +#include +#include #include void train_table::updateAsync(double dt) @@ -12407,8 +12408,9 @@ void train_table::updateAsync(double dt) const size_t total = m_items.size(); const size_t chunkSize = (total + threads - 1) / threads; - std::vector> futures; - futures.reserve(threads); + std::vector workers; + std::vector errors(threads); + workers.reserve(threads); for (int i = 0; i < threads; ++i) { @@ -12418,21 +12420,35 @@ void train_table::updateAsync(double dt) if (start >= end) break; // brak więcej danych - futures.emplace_back(std::async(std::launch::async, - [this, start, end, dt]() - { - for (size_t j = start; j < end; ++j) - { - TTrain *train = m_items[j]; - if (train) - train->Update(dt); - } - })); + workers.emplace_back( + [this, start, end, dt, &error = errors[i]]() + { + try + { + for (size_t j = start; j < end; ++j) + { + TTrain *train = m_items[j]; + if (train) + train->Update(dt); + } + } + catch (...) + { + // przekaż wyjątek do głównego wątku + error = std::current_exception(); + } + }); } // Poczekaj aż wszystkie wątki skończą - for (auto &f : futures) - f.get(); + for (auto &worker : workers) + worker.join(); + + for (auto const &error : errors) + { + if (error) + std::rethrow_exception(error); + } // Teraz kasowanie (tylko w głównym wątku) for (TTrain *train : m_items) diff --git a/world/Segment.cpp b/world/Segment.cpp index 2afa264e..c963922a 100644 --- a/world/Segment.cpp +++ b/world/Segment.cpp @@ -294,7 +294,7 @@ TSegment::find_nearest_point( glm::dvec3 const &Point ) const { else { // for curves iterate through segment chunks, and find the one which gives us the least distance to the specified point double distance = std::numeric_limits::max(); - double nearest; + double nearest { 0.0 }; // NOTE: we're reusing already created segment chunks, which are created based on splinefidelity setting // this means depending on splinefidelity the results can be potentially slightly different for( int segmentidx = 0; segmentidx < iSegCount; ++segmentidx ) {