16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-17 23:39:18 +02:00

Merge remote-tracking branch 'upstream/master' into utilities-simplification

This commit is contained in:
docentYT
2026-05-05 23:08:43 +02:00
17 changed files with 10693 additions and 9119 deletions

View File

@@ -1754,6 +1754,8 @@ class TMoverParameters
bool HasCamshaft{false};
int DynamicBrakeType = 0; /*patrz dbrake_**/
int DynamicBrakeAmpmeters = 2; /*liczba amperomierzy przy hamowaniu ED*/
bool SplitEDPneumaticBrake = false; /*czy hamulec ED i pneumatyczny pomocniczy są rozdzielone na osobne nastawniki*/
int DynamicBrakeCtrlPosNo = 10; /*ilosc pozycji nastawnika hamulca ED (DBPN, domyslnie 10)*/
double DynamicBrakeRes = 5.8; /*rezystancja oporników przy hamowaniu ED*/
double DynamicBrakeRes1 = 5.8; /*rezystancja oporników przy hamowaniu ED - 1 tryb*/
double DynamicBrakeRes2 = 5.8; /*rezystancja oporników przy hamowaniu ED - 2 tryb*/
@@ -2030,6 +2032,7 @@ class TMoverParameters
int ManualBrakePos = 0; /*nastawa hamulca recznego*/
double LocalBrakePosA = 0.0; /*nastawa hamulca pomocniczego*/
double LocalBrakePosAEIM = 0.0; /*pozycja hamulca pomocniczego ep dla asynchronicznych ezt*/
double DynamicBrakeCtrlPos = 0.0; /*nastawa nastawnika hamulca elektrodynamicznego (0..1) - aktywne tylko gdy SplitEDPneumaticBrake*/
bool UniversalBrakeButtonActive[3] = {false, false, false}; /* brake button pressed */
/*
int BrakeStatus = b_off; //0 - odham, 1 - ham., 2 - uszk., 4 - odluzniacz, 8 - antyposlizg, 16 - uzyte EP, 32 - pozycja R, 64 - powrot z R
@@ -2380,6 +2383,12 @@ class TMoverParameters
/*! ABu 010205: - skrajne polozenia ham. pomocniczego*/
bool IncManualBrakeLevel(int CtrlSpeed);
bool DecManualBrakeLevel(int CtrlSpeed);
/*! oddzielny nastawnik hamulca elektrodynamicznego (gdy SplitEDPneumaticBrake)*/
bool IncDynamicBrakeLevel(float const CtrlSpeed);
bool DecDynamicBrakeLevel(float const CtrlSpeed);
bool DynamicBrakeLevelSet(double Position);
double DynamicBrakeRatio(void) const;
bool DynamicBrakeAvailable(void) const; /*czy ED dostepny w aktualnym oknie predkosci Vh0..Vh1*/
bool DynamicBrakeSwitch(bool Switch);
bool RadiostopSwitch(bool Switch);
bool AlarmChainSwitch(bool const State);

View File

@@ -3882,6 +3882,79 @@ bool TMoverParameters::DecLocalBrakeLevel(float const CtrlSpeed)
return DBL;
}
// *************************************************************************************************
// zwiększenie nastawy nastawnika hamulca elektrodynamicznego (DynamicBrakeCtrl)
// uzywane gdy SplitEDPneumaticBrake = true
// *************************************************************************************************
bool TMoverParameters::IncDynamicBrakeLevel(float const CtrlSpeed)
{
if (false == SplitEDPneumaticBrake)
return false;
if (DynamicBrakeCtrlPosNo < 1)
return false;
if (DynamicBrakeCtrlPos < 1.0)
{
DynamicBrakeCtrlPos = std::min(1.0, DynamicBrakeCtrlPos + (double)CtrlSpeed / (double)DynamicBrakeCtrlPosNo);
return true;
}
return false;
}
// *************************************************************************************************
// zmniejszenie nastawy nastawnika hamulca elektrodynamicznego (DynamicBrakeCtrl)
// *************************************************************************************************
bool TMoverParameters::DecDynamicBrakeLevel(float const CtrlSpeed)
{
if (false == SplitEDPneumaticBrake)
return false;
if (DynamicBrakeCtrlPosNo < 1)
return false;
if (DynamicBrakeCtrlPos > 0.0)
{
DynamicBrakeCtrlPos = std::max(0.0, DynamicBrakeCtrlPos - (double)CtrlSpeed / (double)DynamicBrakeCtrlPosNo);
return true;
}
return false;
}
// *************************************************************************************************
// bezposrednie ustawienie nastawnika hamulca elektrodynamicznego (DynamicBrakeCtrl)
// *************************************************************************************************
bool TMoverParameters::DynamicBrakeLevelSet(double Position)
{
if (false == SplitEDPneumaticBrake)
return false;
DynamicBrakeCtrlPos = clamp(Position, 0.0, 1.0);
return true;
}
// *************************************************************************************************
// odczyt nastawy nastawnika hamulca elektrodynamicznego (DynamicBrakeCtrl)
// zwraca 0 jezeli SplitEDPneumaticBrake nie jest aktywne (dla zachowania starej logiki)
// *************************************************************************************************
double TMoverParameters::DynamicBrakeRatio(void) const
{
if (false == SplitEDPneumaticBrake)
return 0.0;
return clamp(DynamicBrakeCtrlPos, 0.0, 1.0);
}
// *************************************************************************************************
// czy hamulec ED jest aktualnie dostepny w oknie predkosci Vh0..Vh1
// *************************************************************************************************
bool TMoverParameters::DynamicBrakeAvailable(void) const
{
double const vh0{eimc[eimc_p_Vh0]};
double const vh1{eimc[eimc_p_Vh1]};
if (vh1 <= 0.001)
{
// brak zdefiniowanej strefy - ED dziala zawsze
return true;
}
// strefa wylaczenia jest definiowana przez Vh0 (minimum); powyzej Vh0 ED dziala
return (Vel >= vh0);
}
// *************************************************************************************************
// Q: 20160711
// zwiększenie nastawy hamulca ręcznego
@@ -4438,7 +4511,13 @@ void TMoverParameters::UpdatePipePressure(double dt)
dpLocalValve = LocHandle->GetPF(std::max(lbpa, LocalBrakePosAEIM), Hamulec->GetBCP(), ScndPipePress, dt, 0);
}
else
dpLocalValve = LocHandle->GetPF(LocalBrakePosAEIM, Hamulec->GetBCP(), ScndPipePress, dt, 0);
{
// in EIM stock the pneumatic local brake is normally driven only by the MED algorithm
// (LocalBrakePosAEIM). When SplitEDPneumaticBrake is active the dedicated LocalBrake
// lever should apply pneumatic pressure on the locomotive directly, bypassing MED.
double lbpa = SplitEDPneumaticBrake ? LocalBrakePosA : 0.0;
dpLocalValve = LocHandle->GetPF(std::max(lbpa, LocalBrakePosAEIM), Hamulec->GetBCP(), ScndPipePress, dt, 0);
}
LockPipe = PipePress < (LockPipe ? LockPipeOff : LockPipeOn);
bool lock_new = (LockPipe && !UnlockPipe && (BrakeCtrlPosR > HandleUnlock)) || ((EmergencyCutsOffHandle) && (EmergencyValveFlow > 0)); // new simple codition based on .fiz
@@ -6232,14 +6311,19 @@ double TMoverParameters::TractionForce(double dt)
}
double edBCP = Hamulec->GetEDBCP();
auto const localbrakeactive{(CabOccupied != 0) && (LocHandle->GetCP() > 0.25)};
// gdy SplitEDPneumaticBrake jest aktywne, hamulec pomocniczy (LocalBrake) NIE wymusza
// zalaczenia hamulca elektrodynamicznego - ED jest sterowany wlasnym nastawnikiem
auto const dynbrakectrlactive{SplitEDPneumaticBrake && (DynamicBrakeRatio() > 0.01) && DynamicBrakeAvailable()};
auto const localbrakeforED{SplitEDPneumaticBrake ? false : localbrakeactive};
if ((false == Doors.instances[side::left].is_closed) || (false == Doors.instances[side::right].is_closed) ||
(Doors.permit_needed && (Doors.instances[side::left].open_permit || Doors.instances[side::right].open_permit)))
{
DynamicBrakeFlag = true;
}
else if (((edBCP < 0.25) && (false == localbrakeactive) && (AnPos < 0.01)) || ((edBCP < 0.25) && (ShuntModeAllow) && (LocalBrakePosA < 0.01)))
else if (((edBCP < 0.25) && (false == localbrakeforED) && (false == dynbrakectrlactive) && (AnPos < 0.01)) ||
((edBCP < 0.25) && (ShuntModeAllow) && (false == dynbrakectrlactive) && (LocalBrakePosA < 0.01)))
DynamicBrakeFlag = false;
else if ((((BrakePress > 0.25) && (edBCP > 0.25) || localbrakeactive)) || (AnPos > 0.02))
else if ((((BrakePress > 0.25) && (edBCP > 0.25) || localbrakeforED)) || (AnPos > 0.02) || dynbrakectrlactive)
DynamicBrakeFlag = true;
edBCP = Hamulec->GetEDBCP() * eimc[eimc_p_abed]; // stala napedu
if ((DynamicBrakeFlag))
@@ -6266,8 +6350,21 @@ double TMoverParameters::TractionForce(double dt)
}
else
{
PosRatio = -std::max(std::min(edBCP * 1.0 / MaxBrakePress[0], 1.0), AnPos) * std::max(0.0, std::min(1.0, (Vel - eimc[eimc_p_Vh0]) / (eimc[eimc_p_Vh1] - eimc[eimc_p_Vh0])));
eimv[eimv_Fzad] = -std::min(1.0, std::max(LocalBrakeRatio(), edBCP / MaxBrakePress[0]));
// strefa wylaczenia ED (Vh0..Vh1) - mnoznik 0..1 zaleznie od predkosci
double const vhRamp = std::max(0.0, std::min(1.0, (Vel - eimc[eimc_p_Vh0]) / (eimc[eimc_p_Vh1] - eimc[eimc_p_Vh0])));
if (SplitEDPneumaticBrake)
{
// w trybie split LocalBrake nie zaleca ED; uzywany jest DynamicBrakeCtrl
// oraz zwykle zapotrzebowanie z hamulca zespolonego (edBCP)
double const edLeverDemand = DynamicBrakeRatio();
PosRatio = -std::max(std::max(edLeverDemand, std::min(edBCP / MaxBrakePress[0], 1.0)), AnPos) * vhRamp;
eimv[eimv_Fzad] = -std::min(1.0, std::max(edLeverDemand, edBCP / MaxBrakePress[0]));
}
else
{
PosRatio = -std::max(std::min(edBCP * 1.0 / MaxBrakePress[0], 1.0), AnPos) * vhRamp;
eimv[eimv_Fzad] = -std::min(1.0, std::max(LocalBrakeRatio(), edBCP / MaxBrakePress[0]));
}
}
tmp = 5;
}
@@ -7230,10 +7327,26 @@ void TMoverParameters::CheckEIMIC(double dt)
{
double offset = EIMCtrlAdditionalZeros ? 1.0 : 0.0;
double multiplier = (EIMCtrlEmergency ? 1.0 : 0.0) + offset;
// gdy SplitEDPneumaticBrake jest wlaczone, sterowanie ujemne (hamowanie ED) bierzemy
// z osobnego nastawnika DynamicBrakeCtrl, a nie z hamulca pomocniczego (LocalBrake).
// Dodatkowo zapotrzebowanie ED jest ograniczone przez strefe Vh0..Vh1: powyzej Vh1 - pelny ED,
// pomiedzy Vh1 a Vh0 - liniowe zanikanie, ponizej Vh0 - zerowe (brak hamowania pneumatycznego
// jako uzupelnienia, poniewaz LocalBrake jest oddzielny i operuje wylacznie pneumatyka).
double brakeDemand = SplitEDPneumaticBrake ? DynamicBrakeRatio() : LocalBrakeRatio();
if (SplitEDPneumaticBrake)
{
double const vh0 = eimc[eimc_p_Vh0];
double const vh1 = eimc[eimc_p_Vh1];
if (vh1 > vh0 + 0.001)
{
double const vhRamp = clamp((Vel - vh0) / (vh1 - vh0), 0.0, 1.0);
brakeDemand *= vhRamp;
}
}
switch (EIMCtrlType)
{
case 0:
eimic = (LocalBrakeRatio() > 0.01 ? -LocalBrakeRatio() : eimic_analog > 0.01 ? eimic_analog : (double)MainCtrlPos / (double)MainCtrlPosNo);
eimic = (brakeDemand > 0.01 ? -brakeDemand : eimic_analog > 0.01 ? eimic_analog : (double)MainCtrlPos / (double)MainCtrlPosNo);
if (EIMCtrlAdditionalZeros || EIMCtrlEmergency)
{
if (eimic > 0.001)
@@ -7347,7 +7460,9 @@ void TMoverParameters::CheckEIMIC(double dt)
eimic = 0; // shut off retarder
if ((UniCtrlIntegratedBrakeCtrl == false) && (UniCtrlIntegratedLocalBrakeCtrl == false))
{
eimic = (LocalBrakeRatio() > 0.01 ? -LocalBrakeRatio() : eimic);
// w trybie SplitEDPneumaticBrake hamowanie ED przychodzi z osobnego nastawnika,
// LocalBrake operuje wylacznie pneumatycznym hamulcem lokomotywy
eimic = (brakeDemand > 0.01 ? -brakeDemand : eimic);
}
}
if (LocHandleTimeTraxx)
@@ -10707,6 +10822,18 @@ void TMoverParameters::LoadFIZ_Cntrl(std::string const &line)
extract_value(DynamicBrakeAmpmeters, "DBAM", line, "");
}
// split ED/pneumatic brake control: when true the local brake operates only on the
// pneumatic locomotive cylinder while electrodynamic braking is commanded by a
// separate "dynamicbrakectrl" lever (or the negative range of jointctrl).
extract_value(SplitEDPneumaticBrake, "SplitEDPneumaticBrake", line, "");
// number of stepped positions for the dedicated ED brake controller (default 10)
DynamicBrakeCtrlPosNo = 10;
extract_value(DynamicBrakeCtrlPosNo, "DBPN", line, "");
if (DynamicBrakeCtrlPosNo < 1)
{
DynamicBrakeCtrlPosNo = 10;
}
extract_value(MainCtrlPosNo, "MCPN", line, "");
extract_value(ScndCtrlPosNo, "SCPN", line, "");
extract_value(ScndInMain, "SCIM", line, "");

View File

@@ -319,6 +319,12 @@ int eu07_application::init(int Argc, char *Argv[])
return result;
}
// configure the OS console according to Globals.ShowSystemConsole.
// must run AFTER init_settings (so the ini-loaded value is honoured) and
// BEFORE the first WriteLog below (so colored \033[...] sequences emitted
// by utilities/Logs.cpp land in a console with VT processing enabled).
init_console();
WriteLog("Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")");
WriteLog("For online documentation and additional files refer to: http://eu07.pl");
WriteLog("Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, "
@@ -978,6 +984,102 @@ void eu07_application::init_debug()
#endif
}
// Honours Globals.ShowSystemConsole (default: true).
//
// Windows: if the toggle is on, ensure a console is attached (allocate one when
// the binary was linked as the WINDOWS subsystem and none is inherited), then
// reopen the C stdio streams onto it and turn on ENABLE_VIRTUAL_TERMINAL_PROCESSING
// so the ANSI colour escapes used by utilities/Logs.cpp render correctly.
// If the toggle is off, hide the console window (or free an allocated one) so
// the GUI launches without a stray cmd window.
//
// Other platforms: no-op. stdout is the launching terminal (or already detached);
// hiding it on Linux/macOS would mean redirecting to /dev/null and is left to the
// user's shell (e.g. "./eu07 >/dev/null 2>&1").
void eu07_application::init_console()
{
#ifdef _WIN32
HWND consoleWnd = ::GetConsoleWindow();
const bool hadConsole = (consoleWnd != nullptr);
if (Global.ShowSystemConsole)
{
if (!hadConsole)
{
// no console inherited (e.g. WINDOWS subsystem build, or launched
// detached) -- create one and wire stdio to it so printf in
// utilities/Logs.cpp actually reaches the user
if (::AllocConsole())
{
FILE *fp = nullptr;
freopen_s(&fp, "CONOUT$", "w", stdout);
freopen_s(&fp, "CONOUT$", "w", stderr);
freopen_s(&fp, "CONIN$", "r", stdin);
// keep C++ streams in sync with the redirected C streams
std::ios::sync_with_stdio(true);
std::cout.clear();
std::cerr.clear();
std::clog.clear();
std::cin.clear();
consoleWnd = ::GetConsoleWindow();
}
}
// enable ANSI virtual-terminal processing so the colour escapes in
// utilities/Logs.cpp ("\033[1;37;41m...", "\033[32m...") render as
// colours instead of literal garbage on the conhost.
//
// IMPORTANT: do NOT rely on GetStdHandle(STD_OUTPUT_HANDLE). After
// AllocConsole + freopen_s the CRT may have rewired things, and on a
// console-subsystem build the std handle can also point to a redirected
// pipe/file rather than the actual console screen buffer -- in either
// case SetConsoleMode silently fails and the escape bytes leak through
// as text ("←[32m" etc). Open CONOUT$ directly to get the real screen
// buffer handle, then flip VT on it.
auto enable_vt = [](const char *devName) {
HANDLE h = ::CreateFileA(
devName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
OPEN_EXISTING,
0,
nullptr);
if (h == INVALID_HANDLE_VALUE)
return;
DWORD mode = 0;
if (::GetConsoleMode(h, &mode))
{
::SetConsoleMode(h, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT);
}
::CloseHandle(h);
};
// CONOUT$ is the console's active screen buffer; enabling VT on it
// affects everything that ends up being written there, regardless of
// which FILE* / std handle the writer used
enable_vt("CONOUT$");
if (consoleWnd)
{
::ShowWindow(consoleWnd, SW_SHOW);
// give the console a recognisable title
::SetConsoleTitleA("MaSzyna log");
}
}
else
{
// user wants no console window -- hide whatever we have
if (consoleWnd)
{
::ShowWindow(consoleWnd, SW_HIDE);
}
// if we'd allocated one ourselves on a previous run path we'd FreeConsole here,
// but on first init the console (if any) was inherited from the launcher and
// belongs to it -- just hiding the window is the least-surprising behaviour
}
#endif
}
void eu07_application::init_files()
{

View File

@@ -101,6 +101,7 @@ private:
// methods
bool needs_ogl() const;
void init_debug();
void init_console();
void init_files();
int init_settings( int Argc, char *Argv[] );
int init_locale();

View File

@@ -17,11 +17,16 @@ gl::cubemap::~cubemap()
void gl::cubemap::alloc(GLint format, int width, int height, GLenum components, GLenum type)
{
glBindTexture(GL_TEXTURE_CUBE_MAP, *this);
for (GLuint tgt = GL_TEXTURE_CUBE_MAP_POSITIVE_X; tgt <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; tgt++)
glTexImage2D(tgt, 0, format, width, height, 0, components, type, nullptr);
glBindTexture(GL_TEXTURE_CUBE_MAP, *this);
for (GLuint tgt = GL_TEXTURE_CUBE_MAP_POSITIVE_X; tgt <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; tgt++)
glTexImage2D(tgt, 0, format, width, height, 0, components, type, nullptr);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
// make the cubemap sample-complete with no mipmaps required.
// generate_mipmaps() will later override MIN_FILTER once mips actually exist.
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
void gl::cubemap::bind(int unit)

View File

@@ -29,6 +29,13 @@ commanddescription_sequence Commands_descriptions = {
{"mastercontrollerdecrease", command_target::vehicle, command_mode::oneoff},
{"mastercontrollerdecreasefast", command_target::vehicle, command_mode::oneoff},
{"mastercontrollerset", command_target::vehicle, command_mode::oneoff},
{"dynamicbrakecontrollerincrease", command_target::vehicle, command_mode::oneoff},
{"dynamicbrakecontrollerdecrease", command_target::vehicle, command_mode::oneoff},
{"dynamicbrakecontrollerset", command_target::vehicle, command_mode::oneoff},
{"dynamicbrakecontrollerincreasefast", command_target::vehicle, command_mode::oneoff},
{"dynamicbrakecontrollerdecreasefast", command_target::vehicle, command_mode::oneoff},
{"secondcontrollerincrease", command_target::vehicle, command_mode::oneoff},
{"secondcontrollerincreasefast", command_target::vehicle, command_mode::oneoff},
{"secondcontrollerdecrease", command_target::vehicle, command_mode::oneoff},
@@ -409,6 +416,11 @@ std::unordered_map<std::string, user_command> commandMap = {
{"mastercontrollerdecrease", user_command::mastercontrollerdecrease},
{"mastercontrollerdecreasefast", user_command::mastercontrollerdecreasefast},
{"mastercontrollerset", user_command::mastercontrollerset},
{"dynamicbrakecontrollerincrease", user_command::dynamicbrakecontrollerincrease},
{"dynamicbrakecontrollerdecrease", user_command::dynamicbrakecontrollerdecrease},
{"dynamicbrakecontrollerset", user_command::dynamicbrakecontrollerset},
{"dynamicbrakecontrollerincreasefast", user_command::dynamicbrakecontrollerincreasefast},
{"dynamicbrakecontrollerdecreasefast", user_command::dynamicbrakecontrollerdecreasefast},
{"secondcontrollerincrease", user_command::secondcontrollerincrease},
{"secondcontrollerincreasefast", user_command::secondcontrollerincreasefast},
{"secondcontrollerdecrease", user_command::secondcontrollerdecrease},

View File

@@ -24,6 +24,11 @@ enum class user_command
mastercontrollerdecrease,
mastercontrollerdecreasefast,
mastercontrollerset,
dynamicbrakecontrollerincrease,
dynamicbrakecontrollerdecrease,
dynamicbrakecontrollerset,
dynamicbrakecontrollerincreasefast,
dynamicbrakecontrollerdecreasefast,
secondcontrollerincrease,
secondcontrollerincreasefast,
secondcontrollerdecrease,

View File

@@ -32,6 +32,13 @@ driverkeyboard_input::default_bindings() {
{ user_command::mastercontrollerdecrease, {GLFW_KEY_KP_SUBTRACT, ""} },
{ user_command::mastercontrollerdecreasefast, {GLFW_KEY_KP_SUBTRACT | keymodifier::shift, ""} },
// mastercontrollerset,
{ user_command::dynamicbrakecontrollerincrease, {GLFW_KEY_KP_3 | keymodifier::control, ""} },
{ user_command::dynamicbrakecontrollerdecrease, {GLFW_KEY_KP_9 | keymodifier::control, ""} },
// mastercontrollerset,
{ user_command::dynamicbrakecontrollerincreasefast, {GLFW_KEY_KP_3 | keymodifier::control | keymodifier::shift, ""} },
{ user_command::dynamicbrakecontrollerdecreasefast, {GLFW_KEY_KP_9 | keymodifier::control | keymodifier::shift, ""} },
{ user_command::secondcontrollerincrease, {GLFW_KEY_KP_DIVIDE, ""} },
{ user_command::secondcontrollerincreasefast, {GLFW_KEY_KP_DIVIDE | keymodifier::shift, ""} },
{ user_command::secondcontrollerdecrease, {GLFW_KEY_KP_MULTIPLY, ""} },

View File

@@ -533,6 +533,9 @@ drivermouse_input::default_bindings() {
{ "mainctrl:", {
user_command::mastercontrollerset,
user_command::none } },
{ "dynamicbrakectrl:", {
user_command::dynamicbrakecontrollerset,
user_command::none } },
{ "scndctrl:", {
user_command::secondcontrollerset,
user_command::none } },

View File

@@ -312,15 +312,37 @@ void python_taskqueue::exit()
m_condition.notify_all();
// let them free up their shit before we proceed
m_workers = {};
// get rid of the leftover tasks
// with the workers dead we don't have to worry about concurrent access anymore
for (auto task : m_tasks.data)
// drop any pending render/upload tasks. the workers are joined at this
// point so the locks are strictly defensive, but they cost nothing and
// document intent. clearing the deque also actually releases the tasks,
// which the previous code did not do (cancel() is a no-op stub).
{
task->cancel();
std::lock_guard<std::mutex> lock(m_tasks.mutex);
for (auto &task : m_tasks.data)
{
task->cancel();
}
m_tasks.data.clear();
}
// take a bow
{
std::lock_guard<std::mutex> lock(m_uploadtasks.mutex);
m_uploadtasks.data.clear();
}
// reclaim cached python objects while the interpreter is still alive,
// so no Py_DECREF lands on a finalized interpreter during later teardown
acquire_lock();
for (auto &entry : m_renderers)
{
Py_XDECREF(entry.second);
}
m_renderers.clear();
Py_XDECREF(m_stderr);
m_stderr = nullptr;
Py_XDECREF(m_main);
m_main = nullptr;
// take a bow
Py_Finalize();
m_initialized = false;
}
// adds specified task along with provided collection of data to the work queue. returns true on success
@@ -518,8 +540,10 @@ void python_taskqueue::run(GLFWwindow *Context, rendertask_sequence &Tasks, uplo
// TBD, TODO: add some idle time between tasks in case we're on a single thread cpu?
} while (task != nullptr);
// if there's nothing left to do wait until there is
// but check every now and then on your own to minimize potential deadlock situations
Condition.wait_for(std::chrono::seconds(5));
// short timeout: notify_all() in exit() can race with the worker's
// transition into the wait, and the run loop also drives prompt
// shutdown checks
Condition.wait_for(std::chrono::milliseconds(250));
}
// clean up thread state data
PyEval_AcquireLock();
@@ -527,6 +551,12 @@ void python_taskqueue::run(GLFWwindow *Context, rendertask_sequence &Tasks, uplo
PyThreadState_Clear(threadstate);
PyThreadState_Delete(threadstate);
PyEval_ReleaseLock();
// detach the GL context before the worker terminates; some drivers
// (NVIDIA on X11, certain Mesa/Wayland configs) hang in process teardown
// if a context is still current on a dying thread
if (Context)
glfwMakeContextCurrent(nullptr);
}
void python_taskqueue::update()

View File

@@ -8,6 +8,14 @@ vec3 envmap_color( vec3 normal )
vec3 refvec = reflect(f_pos.xyz, normal); // view space
refvec = vec3(inv_view * vec4(refvec, 0.0)); // world space
vec3 envcolor = texture(envmap, refvec).rgb;
// Sanitize. The env cubemap can briefly contain NaN/Inf after a
// reflection-pass regeneration (m_empty_cubemap was bound during the
// face render and on NVIDIA can sample as undefined). Without this
// guard, a single bad texel propagates through env_reflection in
// apply_lights() and produces one-frame black flashes on glossy
// (esp. specgloss) surfaces.
if (any(isnan(envcolor)) || any(isinf(envcolor))) envcolor = vec3(0.0);
envcolor = max(envcolor, vec3(0.0));
#else
vec3 envcolor = vec3(0.5);
#endif
@@ -21,8 +29,13 @@ vec3 envmap_color_lod(vec3 fragnormal, float lod)
#if ENVMAP_ENABLED
vec3 refvec = reflect(f_pos.xyz, fragnormal); // view space — matches envmap_color exactly
refvec = vec3(inv_view * vec4(refvec, 0.0)); // world space — was missing
return textureLod(envmap, refvec, lod).rgb;
vec3 envcolor = textureLod(envmap, refvec, lod).rgb;
// See envmap_color() above — same NaN/Inf sanitize, also needed here
// because mipmap generation propagates a single NaN texel across the
// whole mip chain.
if (any(isnan(envcolor)) || any(isinf(envcolor))) envcolor = vec3(0.0);
return max(envcolor, vec3(0.0));
#else
return vec3(0.5); // was vec3(0.0), match the non-LOD fallback
#endif
}
}

View File

@@ -46,6 +46,17 @@ vec4 tonemap(vec4 x)
// with pureWhite=1.0 it collapses to identity (L*(1+L)/(1+L) = L) and
// just clips HDR>1.0 at the framebuffer -> washed-out / burnt look.
// ACES gives a smooth highlight shoulder + slight toe contrast.
return FBOUT(vec4(ACESFilm(x.rgb), x.a));
// Last-line-of-defense sanitize. ACESFilm has the form
// (x*(a*x+b)) / (x*(c*x+d)+e)
// which maps NaN -> NaN and +Inf -> NaN (Inf/Inf). Either turns the
// pixel black after framebuffer clamp. A negative HDR input feeds a
// negative numerator/denominator and can produce non-physical output
// that also looks like a black flash. Clamp to a sensible range
// before the curve so a single bad upstream pixel can't escape.
vec3 hdr = x.rgb;
hdr = mix(hdr, vec3(0.0), vec3(any(isnan(hdr)) || any(isinf(hdr))));
hdr = max(hdr, vec3(0.0));
return FBOUT(vec4(ACESFilm(hdr), x.a));
//return FBOUT(vec4(reinhard(x.rgb), x.a));
}

View File

@@ -1086,6 +1086,12 @@ bool global_settings::ConfigParseDebug(cParser& Parser, const std::string& token
return true;
}
if (token == "showsystemconsole")
{
ParseOne(Parser, ShowSystemConsole);
return true;
}
if (token == "shakefactor")
{
ParseOne(Parser, ShakingMultiplierBF);
@@ -1516,6 +1522,7 @@ global_settings::export_as_text( std::ostream &Output ) const {
export_as_text( Output, "fullphysics", FullPhysics );
export_as_text( Output, "debuglog", iWriteLogEnabled );
export_as_text( Output, "multiplelogs", MultipleLogs );
export_as_text( Output, "showsystemconsole", ShowSystemConsole );
export_as_text( Output, "logs.filter", DisabledLogTypes );
Output
<< "mousescale "

View File

@@ -86,6 +86,7 @@ struct global_settings {
bool priorityLoadText3D{false}; // ladowanie T3D priorytetowo
int iWriteLogEnabled{ 3 }; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów
bool MultipleLogs{ false };
bool ShowSystemConsole{ false }; // toggle visibility of the OS console window with log output
unsigned int DisabledLogTypes{ 0 };
bool ParserLogIncludes{ true };
// simulation

View File

@@ -293,7 +293,7 @@ material_data::assign( std::string const &Replacableskin ) {
// check for the pipe method first
if( contains( Replacableskin, '|' ) ) {
cParser nameparser( Replacableskin );
nameparser.getTokens( 4, true, "|" );
nameparser.getTokens( 4, false, "|" );
int skinindex = 0;
std::string texturename; nameparser >> texturename;
while( ( texturename != "" ) && ( skinindex < 4 ) ) {

File diff suppressed because it is too large Load Diff

View File

@@ -236,11 +236,19 @@ class TTrain {
static void OnCommand_aidriverenable( TTrain *Train, command_data const &Command );
static void OnCommand_aidriverdisable( TTrain *Train, command_data const &Command );
static void OnCommand_jointcontrollerset( TTrain *Train, command_data const &Command );
static void OnCommand_mastercontrollerincrease( TTrain *Train, command_data const &Command );
static void OnCommand_mastercontrollerincreasefast( TTrain *Train, command_data const &Command );
static void OnCommand_mastercontrollerdecrease( TTrain *Train, command_data const &Command );
static void OnCommand_mastercontrollerdecreasefast( TTrain *Train, command_data const &Command );
static void OnCommand_mastercontrollerset( TTrain *Train, command_data const &Command );
static void OnCommand_DynamicBrakeControllerIncrease( TTrain *Train, command_data const &Command );
static void OnCommand_DynamicBrakeControllerIncreaseFast( TTrain *Train, command_data const &Command );
static void OnCommand_DynamicBrakeControllerDecrease( TTrain *Train, command_data const &Command );
static void OnCommand_DynamicBrakeControllerDecreaseFast( TTrain *Train, command_data const &Command );
static void OnCommand_DynamicBrakeControllerSet( TTrain *Train, command_data const &Command );
static void OnCommand_secondcontrollerincrease( TTrain *Train, command_data const &Command );
static void OnCommand_secondcontrollerincreasefast( TTrain *Train, command_data const &Command );
static void OnCommand_secondcontrollerdecrease( TTrain *Train, command_data const &Command );