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

tmj merge (broken)

This commit is contained in:
milek7
2018-01-24 22:48:41 +01:00
26 changed files with 539 additions and 408 deletions

View File

@@ -422,9 +422,8 @@ TAnimModel::~TAnimModel()
bool TAnimModel::Init(TModel3d *pNewModel)
{
fBlinkTimer = double(Random(1000 * fOffTime)) / (1000 * fOffTime);
;
pModel = pNewModel;
return (pModel != NULL);
return (pModel != nullptr);
}
bool TAnimModel::Init(std::string const &asName, std::string const &asReplacableTexture)
@@ -578,10 +577,10 @@ void TAnimModel::RaPrepare()
switch (lightmode)
{
case ls_Blink: // migotanie
state = fBlinkTimer < fOnTime;
state = ( fBlinkTimer < fOnTime );
break;
case ls_Dark: // zapalone, gdy ciemno
state = Global::fLuminance <= ( lsLights[i] - 3.0 );
state = ( Global::fLuminance <= ( lsLights[i] - 3.0 ) );
break;
default: // zapalony albo zgaszony
state = (lightmode == ls_On);

View File

@@ -71,7 +71,7 @@ void TButton::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *pMod
if( ( pModelOn == nullptr )
&& ( pModelOff == nullptr ) ) {
// if we failed to locate even one state submodel, cry
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + pModel1->NameGet() + "\"" );
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + pModel1->NameGet() + "\"", logtype::model );
}
// pass submodel location to defined sounds
@@ -105,7 +105,7 @@ TButton::model_offset() const {
return (
submodel != nullptr ?
submodel->offset( 1.f ) :
submodel->offset( 2.5f ) :
glm::vec3() );
}

View File

@@ -282,16 +282,16 @@ void Console::ValueSet(int x, double y)
{
x = Global::iPoKeysPWM[x];
if (Global::iCalibrateOutDebugInfo == x)
WriteLog("CalibrateOutDebugInfo: oryginal=" + std::to_string(y), false);
WriteLog("CalibrateOutDebugInfo: oryginal=" + std::to_string(y));
if (Global::fCalibrateOutMax[x] > 0)
{
y = clamp( y, 0.0, Global::fCalibrateOutMax[x]);
if (Global::iCalibrateOutDebugInfo == x)
WriteLog(" cutted=" + std::to_string(y), false);
WriteLog(" cutted=" + std::to_string(y));
y = y / Global::fCalibrateOutMax[x]; // sprowadzenie do <0,1> jeśli podana
// maksymalna wartość
if (Global::iCalibrateOutDebugInfo == x)
WriteLog(" fraction=" + std::to_string(y), false);
WriteLog(" fraction=" + std::to_string(y));
}
double temp = (((((Global::fCalibrateOut[x][5] * y) + Global::fCalibrateOut[x][4]) * y +
Global::fCalibrateOut[x][3]) *

View File

@@ -2977,7 +2977,7 @@ bool TDynamicObject::Update(double dt, double dt1)
// crude bump simulation, drop down on even axles, move back up on the odd ones
MoverParameters->AccVert +=
interpolate(
0.25, 0.50,
0.01, 0.05,
clamp(
GetVelocity() / ( 1 + MoverParameters->Vmax ),
0.0, 1.0 ) )
@@ -3699,6 +3699,7 @@ void TDynamicObject::RenderSounds() {
}
// szum w czasie jazdy
if( ( GetVelocity() > 0.5 )
&& ( false == rsOuterNoise.empty() )
&& ( // compound test whether the vehicle belongs to user-driven consist (as these don't emit outer noise in cab view)
FreeFlyModeFlag ? true : // in external view all vehicles emit outer noise
// Global::pWorld->train() == nullptr ? true : // (can skip this check, with no player train the external view is a given)
@@ -3707,12 +3708,22 @@ void TDynamicObject::RenderSounds() {
Global::CabWindowOpen ? true : // sticking head out we get to hear outer noise
false ) ) {
volume = rsOuterNoise.m_amplitudefactor * MoverParameters->Vel + rsOuterNoise.m_amplitudeoffset;
frequency = rsOuterNoise.m_frequencyfactor * MoverParameters->Vel + rsOuterNoise.m_frequencyoffset;
// frequency calculation
auto const normalizer { (
true == rsOuterNoise.is_combined() ?
MoverParameters->Vmax * 0.01f :
1.f ) };
frequency =
rsOuterNoise.m_frequencyoffset
+ rsOuterNoise.m_frequencyfactor * MoverParameters->Vel * normalizer;
// volume calculation
volume =
rsOuterNoise.m_amplitudeoffset +
rsOuterNoise.m_amplitudefactor * MoverParameters->Vel;
if( brakeforceratio > 0.0 ) {
// hamulce wzmagaja halas
volume *= 1 + 0.25 * brakeforceratio;
volume *= 1 + 0.125 * brakeforceratio;
}
// scale volume by track quality
volume *= ( 20.0 + MyTrack->iDamageFlag ) / 21;
@@ -3725,10 +3736,15 @@ void TDynamicObject::RenderSounds() {
MoverParameters->Vel / 40.0,
0.0, 1.0 ) );
rsOuterNoise
.pitch( frequency ) // arbitrary limits to prevent the pitch going out of whack
.gain( volume )
.play( sound_flags::exclusive | sound_flags::looping );
if( volume > 0.05 ) {
rsOuterNoise
.pitch( frequency ) // arbitrary limits to prevent the pitch going out of whack
.gain( volume )
.play( sound_flags::exclusive | sound_flags::looping );
}
else {
rsOuterNoise.stop();
}
}
else {
// don't play the optional ending sound if the listener switches views
@@ -3979,9 +3995,12 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
}
else {
// Ra: tu wczytywanie modelu ładunku jest w porządku
if( false == asLoadName.empty() ) {
// try first specialized version of the load model, vehiclename_loadname
mdLoad = TModelsManager::GetModel( BaseDir + TypeName + "_" + MoverParameters->LoadType + ".t3d", true );
if( false == asLoadName.empty() ) {
// try first specialized version of the load model, vehiclename_loadname
auto const specializedloadfilename { BaseDir + TypeName + "_" + MoverParameters->LoadType + ".t3d" };
if( true == FileExists( specializedloadfilename ) ) {
mdLoad = TModelsManager::GetModel( specializedloadfilename, true );
}
if( mdLoad == nullptr ) {
// if this fails, try generic load model
mdLoad = TModelsManager::GetModel( asLoadName, true );
@@ -4231,15 +4250,15 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
{ // gdy ktoś przesadził ze skalowaniem
pants[i].fParamPants->fHeight =
0.0; // niech będzie odczyt z pantfactors:
ErrorLog("Bad model: " + asModel + ", scale of " +
(sm->pName) + " is " +
std::to_string(100.0 * det) + "%");
ErrorLog(
"Bad model: " + asModel + ", scale of " + (sm->pName) + " is " + std::to_string(100.0 * det) + "%",
logtype::model );
}
}
}
}
else
ErrorLog("Bad model: " + asFileName + " - missed submodel " + asAnimName); // brak ramienia
ErrorLog("Bad model: " + asFileName + " - missed submodel " + asAnimName, logtype::model); // brak ramienia
}
}
@@ -4273,7 +4292,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
}
}
else
ErrorLog( "Bad model: " + asFileName + " - missed submodel " + asAnimName ); // brak ramienia
ErrorLog( "Bad model: " + asFileName + " - missed submodel " + asAnimName, logtype::model ); // brak ramienia
}
}
}
@@ -4579,16 +4598,19 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
m_powertrainsounds.motor.m_amplitudefactor /= amplitudedivisor;
}
else if( token == "ventilator:" ) {
else if( token == "inverter:" ) {
// plik z dzwiekiem wentylatora, mnozniki i ofsety amp. i czest.
m_powertrainsounds.inverter.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency );
m_powertrainsounds.inverter.owner( this );
}
else if( token == "ventilator:" ) {
// plik z dzwiekiem wentylatora, mnozniki i ofsety amp. i czest.
m_powertrainsounds.rsWentylator.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency );
m_powertrainsounds.rsWentylator.owner( this );
if( ( MoverParameters->EngineType == ElectricSeriesMotor )
|| ( MoverParameters->EngineType == ElectricInductionMotor ) ) {
m_powertrainsounds.rsWentylator.m_amplitudefactor /= MoverParameters->RVentnmax;
m_powertrainsounds.rsWentylator.m_frequencyfactor /= MoverParameters->RVentnmax;
}
m_powertrainsounds.rsWentylator.m_amplitudefactor /= MoverParameters->RVentnmax;
m_powertrainsounds.rsWentylator.m_frequencyfactor /= MoverParameters->RVentnmax;
}
else if(token == "transmission:") {
@@ -5503,12 +5525,13 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
|| ( Vehicle.EngineType == Dumb ) ) {
// frequency calculation
auto normalizer { 1.f };
if( true == engine.is_combined() ) {
// for combined engine sound we calculate sound point in rpm, to make .mmd files setup easier
// NOTE: we supply 1/100th of actual value, as the sound module converts does the opposite, converting received (typically) 0-1 values to 0-100 range
normalizer = 60.f * 0.01f;
}
auto const normalizer { (
true == engine.is_combined() ?
// for combined engine sound we calculate sound point in rpm, to make .mmd files setup easier
// NOTE: we supply 1/100th of actual value, as the sound module converts does the opposite, converting received (typically) 0-1 values to 0-100 range
60.f * 0.01f :
// for legacy single-piece sounds the standard frequency calculation is left untouched
1.f ) };
frequency =
engine.m_frequencyoffset
+ engine.m_frequencyfactor * std::abs( Vehicle.enrot ) * normalizer;
@@ -5545,15 +5568,11 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
}
if( engine_volume >= 0.05 ) {
engine
.pitch( frequency )
.gain( engine_volume )
.play( sound_flags::exclusive | sound_flags::looping );
auto enginerevvolume { 0.f };
if( ( Vehicle.EngineType == DieselElectric )
|| ( Vehicle.EngineType == DieselEngine ) ) {
// diesel engine revolutions increase
float enginerevvolume { 0 };
// diesel engine revolutions increase; it can potentially decrease volume of base engine sound
if( engine_revs_last != -1.f ) {
// calculate potential recent increase of engine revolutions
auto const revolutionsperminute { Vehicle.enrot * 60 };
@@ -5568,25 +5587,36 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
&& ( revolutionsdifference > 1.0 * Deltatime ) ) {
engine_revs_change = clamp( engine_revs_change + 5.0 * Deltatime, 0.0, 1.25 );
}
enginerevvolume = engine_revs_change;
enginerevvolume = 0.8 * engine_revs_change;
}
engine_revs_last = Vehicle.enrot * 60;
if( false == engine_revving.is_combined() ) {
// if the sound comes with multiple samples we reuse rpm-based calculation from the engine
frequency = engine_revving.m_frequencyoffset + engine_revving.m_frequencyfactor * 1.0;
}
auto const enginerevfrequency { (
true == engine_revving.is_combined() ?
// if the sound contains multiple samples we reuse rpm-based calculation from the engine
frequency :
engine_revving.m_frequencyoffset + 1.f * engine_revving.m_frequencyfactor ) };
if( enginerevvolume > 0.02 ) {
engine_revving
.pitch( frequency )
.pitch( enginerevfrequency )
.gain( enginerevvolume )
.play( sound_flags::exclusive | sound_flags::looping );
.play( sound_flags::exclusive );
}
else {
engine_revving.stop();
}
}
} // diesel engines
// multi-part revving sound pieces replace base engine sound, single revving simply gets mixed with the base
auto const enginevolume { (
( ( enginerevvolume > 0.02 ) && ( true == engine_revving.is_combined() ) ) ?
std::max( 0.0, engine_volume - enginerevvolume ) :
engine_volume ) };
engine
.pitch( frequency )
.gain( enginevolume )
.play( sound_flags::exclusive | sound_flags::looping );
} // enginevolume > 0.05
}
else {
@@ -5754,7 +5784,34 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
if( motor_volume < 0.05 ) {
motor.stop();
}
// inverter sounds
if( Vehicle.EngineType == ElectricInductionMotor ) {
if( Vehicle.InverterFrequency > 0.1 ) {
volume = inverter.m_amplitudeoffset + inverter.m_amplitudefactor * std::sqrt( std::fabs( Vehicle.dizel_fill ) );
inverter
.pitch( inverter.m_frequencyoffset + inverter.m_frequencyfactor * Vehicle.InverterFrequency )
.gain( volume )
.play( sound_flags::exclusive | sound_flags::looping );
}
else {
inverter.stop();
}
}
// ventillator sounds
if( Vehicle.RventRot > 0.1 ) {
rsWentylator
.pitch( rsWentylator.m_frequencyoffset + rsWentylator.m_frequencyfactor * Vehicle.RventRot )
.gain( rsWentylator.m_amplitudeoffset + rsWentylator.m_amplitudefactor * Vehicle.RventRot )
.play( sound_flags::exclusive | sound_flags::looping );
}
else {
// ...otherwise shut down the sound
rsWentylator.stop();
}
// relay sounds
auto const soundflags { Vehicle.SoundFlag };
if( TestFlag( soundflags, sound::relay ) ) {
// przekaznik - gdy bezpiecznik, automatyczny rozruch itp
@@ -5764,7 +5821,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
.pitch(
true == motor_shuntfield.is_combined() ?
Vehicle.ScndCtrlActualPos * 0.01f :
motor_shuntfield.m_frequencyoffset + 1.f * motor_shuntfield.m_frequencyfactor )
motor_shuntfield.m_frequencyoffset + motor_shuntfield.m_frequencyfactor * 1.f )
.gain(
motor_shuntfield.m_amplitudeoffset + (
true == TestFlag( soundflags, sound::loud ) ?
@@ -5788,7 +5845,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
.pitch(
true == motor_relay.is_combined() ?
Vehicle.MainCtrlActualPos * 0.01f :
motor_relay.m_frequencyoffset + 1.f * motor_relay.m_frequencyfactor )
motor_relay.m_frequencyoffset + motor_relay.m_frequencyfactor * 1.f )
.gain(
motor_relay.m_amplitudeoffset + (
true == TestFlag( soundflags, sound::loud ) ?
@@ -5799,32 +5856,11 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
}
}
if( ( Vehicle.EngineType == ElectricSeriesMotor )
|| ( Vehicle.EngineType == ElectricInductionMotor ) ) {
if( Vehicle.RventRot > 0.1 ) {
// play ventilator sound if the ventilators are rotating fast enough...
volume = (
Vehicle.EngineType == ElectricInductionMotor ?
rsWentylator.m_amplitudefactor * std::sqrt( std::fabs( Vehicle.dizel_fill ) ) + rsWentylator.m_amplitudeoffset :
rsWentylator.m_amplitudefactor * Vehicle.RventRot + rsWentylator.m_amplitudeoffset );
rsWentylator
.pitch( rsWentylator.m_frequencyfactor * Vehicle.RventRot + rsWentylator.m_frequencyoffset )
.gain( volume )
.play( sound_flags::exclusive | sound_flags::looping );
}
else {
// ...otherwise shut down the sound
rsWentylator.stop();
}
}
if( Vehicle.TrainType == dt_ET40 ) {
if( Vehicle.Vel > 0.1 ) {
transmission
.pitch( transmission.m_frequencyfactor * ( Vehicle.Vel ) + transmission.m_frequencyoffset )
.gain( transmission.m_amplitudefactor * ( Vehicle.Vel ) + transmission.m_amplitudeoffset )
.pitch( transmission.m_frequencyoffset + transmission.m_frequencyfactor * Vehicle.Vel )
.gain( transmission.m_amplitudeoffset + transmission.m_amplitudefactor * Vehicle.Vel )
.play( sound_flags::exclusive | sound_flags::looping );
}
else {

View File

@@ -284,6 +284,7 @@ private:
};
struct powertrain_sounds {
sound_source inverter { sound_placement::engine };
sound_source motor { sound_placement::external }; // generally traction motor
double motor_volume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal
float motor_momentum { 0.f }; // recent change in motor revolutions

View File

@@ -99,7 +99,7 @@ bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1,
scale *= mul;
TSubModel *submodel = md1->GetFromName( submodelname );
if( scale == 0.0 ) {
ErrorLog( "Bad model: scale of 0.0 defined for sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0" );
ErrorLog( "Bad model: scale of 0.0 defined for sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0", logtype::model );
scale = 1.0;
}
if (submodel) // jeśli nie znaleziony
@@ -107,7 +107,7 @@ bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1,
else if (md2) // a jest podany drugi model (np. zewnętrzny)
submodel = md2->GetFromName(submodelname); // to może tam będzie, co za różnica gdzie
if( submodel == nullptr ) {
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"" );
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"", logtype::model );
}
std::map<std::string, TGaugeType> gaugetypes {

View File

@@ -115,6 +115,8 @@ std::string Global::LastGLError;
GLint Global::iMaxTextureSize = 4096; // maksymalny rozmiar tekstury
bool Global::bSmoothTraction { true }; // wygładzanie drutów starym sposobem
float Global::SplineFidelity { 1.f }; // determines segment size during conversion of splines to geometry
bool Global::ResourceSweep { true }; // gfx resource garbage collection
bool Global::ResourceMove { false }; // gfx resources are moved between cpu and gpu side instead of sending a copy
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
@@ -138,7 +140,8 @@ float Global::AudioVolume = 1.5f;
std::string Global::AudioRenderer;
int Global::iWriteLogEnabled = 3; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów
bool Global::MultipleLogs{ false };
bool Global::MultipleLogs { false };
unsigned int Global::DisabledLogTypes { 0 };
// parametry do kalibracji
// kolejno współczynniki dla potęg 0, 1, 2, 3 wartości odczytanej z urządzenia
@@ -322,6 +325,10 @@ void Global::ConfigParse(cParser &Parser)
Parser.getTokens();
Parser >> Global::MultipleLogs;
}
else if( token == "logs.filter" ) {
Parser.getTokens();
Parser >> Global::DisabledLogTypes;
}
else if( token == "adjustscreenfreq" )
{
// McZapkie-240403 - czestotliwosc odswiezania ekranu
@@ -523,6 +530,16 @@ void Global::ConfigParse(cParser &Parser)
Parser >> splinefidelity;
Global::SplineFidelity = clamp( splinefidelity, 1.f, 4.f );
}
else if( token == "gfx.resource.sweep" ) {
Parser.getTokens();
Parser >> Global::ResourceSweep;
}
else if( token == "gfx.resource.move" ) {
Parser.getTokens();
Parser >> Global::ResourceMove;
}
else if (token == "timespeed")
{
// przyspieszenie czasu, zmienna do testów

View File

@@ -181,6 +181,7 @@ public:
static std::string asCurrentDynamicPath;
static int iWriteLogEnabled; // maska bitowa: 1-zapis do pliku, 2-okienko
static bool MultipleLogs;
static unsigned int DisabledLogTypes;
// McZapkie-170602: zewnetrzna definicja pojazdu uzytkownika
static std::string asHumanCtrlVehicle;
// world environment
@@ -212,6 +213,8 @@ public:
static bool bSmoothTraction; // wygładzanie drutów
static float SplineFidelity; // determines segment size during conversion of splines to geometry
static GLfloat FogColor[];
static bool ResourceSweep; // gfx resource garbage collection
static bool ResourceMove; // gfx resources are moved between cpu and gpu side instead of sending a copy
// sound renderer variables
static bool bSoundEnabled;
static float AudioVolume;

View File

@@ -62,78 +62,50 @@ std::string filename_scenery() {
}
}
void WriteConsoleOnly(const char *str, double value) {
#ifdef _WIN32
std::snprintf(logbuffer , sizeof(logbuffer), "%s %f \n", str, value);
// stdout= GetStdHandle(STD_OUTPUT_HANDLE);
DWORD wr = 0;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), logbuffer, (DWORD)strlen(logbuffer), &wr, NULL);
// WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),endstring,strlen(endstring),&wr,NULL);
#endif
}
void WriteLog( const char *str, logtype const Type ) {
void WriteConsoleOnly(const char *str, bool newline)
{
#ifdef _WIN32
// printf("%n ffafaf /n",str);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_GREEN | FOREGROUND_INTENSITY);
DWORD wr = 0;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), str, (DWORD)strlen(str), &wr, NULL);
if (newline)
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), endstring, (DWORD)strlen(endstring), &wr, NULL);
#endif
}
if( str == nullptr ) { return; }
if( true == TestFlag( Global::DisabledLogTypes, Type ) ) { return; }
void WriteLog(const char *str, double value) {
if (Global::iWriteLogEnabled & 1) {
if( !output.is_open() ) {
if (Global::iWriteLogEnabled) {
if (str) {
std::snprintf(logbuffer, sizeof(logbuffer), "%s %f", str, value);
WriteLog(logbuffer);
}
}
};
void WriteLog(const char *str, bool newline)
{
if (str)
{
if (Global::iWriteLogEnabled & 1)
{
if( !output.is_open() ) {
std::string const filename =
( Global::MultipleLogs ?
std::string const filename =
( Global::MultipleLogs ?
"logs/log (" + filename_scenery() + ") " + filename_date() + ".txt" :
"log.txt" );
output.open( filename, std::ios::trunc );
}
output << str;
if (newline)
output << "\n";
output.flush();
output.open( filename, std::ios::trunc );
}
// hunter-271211: pisanie do konsoli tylko, gdy nie jest ukrywana
if (Global::iWriteLogEnabled & 2)
WriteConsoleOnly(str, newline);
output << str << "\n";
output.flush();
}
};
void ErrorLog(const char *str)
{ // Ra: bezwarunkowa rejestracja poważnych błędów
if( Global::iWriteLogEnabled & 2 ) {
// hunter-271211: pisanie do konsoli tylko, gdy nie jest ukrywana
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), FOREGROUND_GREEN | FOREGROUND_INTENSITY );
DWORD wr = 0;
WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), str, (DWORD)strlen( str ), &wr, NULL );
WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), endstring, (DWORD)strlen( endstring ), &wr, NULL );
}
}
// Ra: bezwarunkowa rejestracja poważnych błędów
void ErrorLog( const char *str, logtype const Type ) {
if( str == nullptr ) { return; }
if( true == TestFlag( Global::DisabledLogTypes, Type ) ) { return; }
if (!errors.is_open()) {
std::string const filename =
( Global::MultipleLogs ?
"logs/errors (" + filename_scenery() + ") " + filename_date() + ".txt" :
"errors.txt" );
"logs/errors (" + filename_scenery() + ") " + filename_date() + ".txt" :
"errors.txt" );
errors.open( filename, std::ios::trunc );
errors << "EU07.EXE " + Global::asVersion << "\n";
}
if (str)
errors << str;
errors << "\n";
errors << str << "\n";
errors.flush();
};
@@ -152,15 +124,15 @@ void Error(const char *&asMessage, bool box)
WriteLog(asMessage);
}
void ErrorLog(const std::string &str, bool newline)
void ErrorLog(const std::string &str, logtype const Type )
{
ErrorLog(str.c_str());
WriteLog(str.c_str(), newline);
ErrorLog( str.c_str(), Type );
WriteLog( str.c_str(), Type );
}
void WriteLog(const std::string &str, bool newline)
void WriteLog(const std::string &str, logtype const Type )
{ // Ra: wersja z AnsiString jest zamienna z Error()
WriteLog(str.c_str(), newline);
WriteLog( str.c_str(), Type );
};
void CommLog(const char *str)

25
Logs.h
View File

@@ -10,13 +10,18 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include <string>
void WriteConsoleOnly(const char *str, double value);
void WriteConsoleOnly(const char *str, bool newline = true);
void WriteLog(const char *str, double value);
void WriteLog(const char *str, bool newline = true);
void Error(const std::string &asMessage, bool box = false);
void Error(const char* &asMessage, bool box = false);
void ErrorLog(const std::string &str, bool newline = true);
void WriteLog(const std::string &str, bool newline = true);
void CommLog(const char *str);
void CommLog(const std::string &str);
enum logtype : unsigned int {
generic = 0x1,
file = 0x2,
model = 0x4,
texture = 0x8
};
void WriteLog( const char *str, logtype const Type = logtype::generic );
void Error( const std::string &asMessage, bool box = false );
void Error( const char* &asMessage, bool box = false );
void ErrorLog( const std::string &str, logtype const Type = logtype::generic );
void WriteLog( const std::string &str, logtype const Type = logtype::generic );
void CommLog( const char *str );
void CommLog( const std::string &str );

View File

@@ -84,7 +84,7 @@ extern int ConversionError;
const double Steel2Steel_friction = 0.15; //tarcie statyczne
const double g = 9.81; //przyspieszenie ziemskie
const double SandSpeed = 0.1; //ile kg/s}
const double RVentSpeed = 0.4; //rozpedzanie sie wentylatora obr/s^2}
const double RVentSpeed = 3.5; //rozpedzanie sie wentylatora obr/s^2}
const double RVentMinI = 50.0; //przy jakim pradzie sie wylaczaja}
const double Pirazy2 = 6.2831853071794f;
#define PI 3.1415926535897f
@@ -816,6 +816,7 @@ public:
double eimc[26];
bool EIMCLogForce; //
static std::vector<std::string> const eimc_labels;
double InverterFrequency { 0.0 }; // current frequency of power inverters
/*-dla wagonow*/
double MaxLoad = 0.0; /*masa w T lub ilosc w sztukach - ladownosc*/
std::string LoadAccepted; std::string LoadQuantity; /*co moze byc zaladowane, jednostki miary*/
@@ -944,17 +945,21 @@ public:
bool InsideConsist = false;
/*-zmienne dla lokomotywy elektrycznej*/
TTractionParam RunningTraction;/*parametry sieci trakcyjnej najblizej lokomotywy*/
double enrot = 0.0;
double Im = 0.0;
double Itot = 0.0;
double enrot = 0.0; // ilosc obrotow silnika
double Im = 0.0; // prad silnika
/*
// currently not used
double IHeating = 0.0;
double ITraction = 0.0;
*/
double Itot = 0.0; // prad calkowity
double TotalCurrent = 0.0;
// momenty
double Mm = 0.0;
double Mw = 0.0;
// sily napedne
double Fw = 0.0;
double Ft = 0.0;
/*ilosc obrotow, prad silnika i calkowity, momenty, sily napedne*/
//Ra: Im jest ujemny, jeśli lok jedzie w stronę sprzęgu 1
//a ujemne powinien być przy odwróconej polaryzacji sieci...
//w wielu miejscach jest używane abs(Im)

View File

@@ -605,11 +605,12 @@ void TMoverParameters::BrakeLevelSet(double b)
if (fBrakeCtrlPos == b)
return; // nie przeliczać, jak nie ma zmiany
fBrakeCtrlPos = b;
BrakeCtrlPosR = b;
if (fBrakeCtrlPos < Handle->GetPos(bh_MIN))
fBrakeCtrlPos = Handle->GetPos(bh_MIN); // odcięcie
else if (fBrakeCtrlPos > Handle->GetPos(bh_MAX))
fBrakeCtrlPos = Handle->GetPos(bh_MAX);
// TODO: verify whether BrakeCtrlPosR and fBrakeCtrlPos can be rolled into single variable
BrakeCtrlPosR = fBrakeCtrlPos;
int x = static_cast<int>(std::floor(fBrakeCtrlPos)); // jeśli odwołujemy się do BrakeCtrlPos w pośrednich, to musi być
// obcięte a nie zaokrągone
while ((x > BrakeCtrlPos) && (BrakeCtrlPos < BrakeCtrlPosNo)) // jeśli zwiększyło się o 1
@@ -4237,46 +4238,24 @@ double TMoverParameters::TractionForce(double dt)
*/
// hunter-091012: przeniesione z if ActiveDir<>0 (zeby po zejsciu z kierunku dalej spadala predkosc wentylatorow)
// wentylatory rozruchowe
// TODO: move this to update, it doesn't exactly have much to do with traction
if( true == Mains ) {
// TBD, TODO: move this to update, it doesn't exactly have much to do with traction
switch( EngineType ) {
switch( EngineType ) {
case ElectricInductionMotor: {
// TBD, TODO: currently ignores RVentType, fix this?
auto const tmpV { std::abs( eimv[ eimv_fp ] ) };
if( ( RlistSize > 0 )
&& ( ( std::abs( eimv[ eimv_If ] ) > 1.0 )
|| ( tmpV > 0.1 ) ) ) {
int i = 0;
while( ( i < RlistSize - 1 )
&& ( DElist[ i + 1 ].RPM < tmpV ) ) {
++i;
}
RventRot =
( tmpV - DElist[ i ].RPM )
/ std::max( 1.0, ( DElist[ i + 1 ].RPM - DElist[ i ].RPM ) )
* ( DElist[ i + 1 ].GenPower - DElist[ i ].GenPower )
+ DElist[ i ].GenPower;
}
else {
RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt );
}
break;
}
case ElectricSeriesMotor: {
case ElectricSeriesMotor: {
if( true == Mains ) {
switch( RVentType ) {
case 1: { // manual
if( ( ActiveDir != 0 )
&& ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) {
RventRot += ( RVentnmax - RventRot ) * RVentSpeed * dt;
}
else {
RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt );
RventRot = std::max( 0.0, RventRot - RVentSpeed * dt );
}
break;
}
case 2: { // automatic
if( ( std::abs( Itot ) > RVentMinI )
&& ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) {
@@ -4287,30 +4266,36 @@ double TMoverParameters::TractionForce(double dt)
RventRot += ( RVentnmax * Im / ImaxLo - RventRot ) * RVentSpeed * dt;
}
else {
RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt );
RventRot = std::max( 0.0, RventRot - RVentSpeed * dt );
}
break;
}
default: {
break;
}
} // rventtype
} // mains
else {
RventRot = std::max( 0.0, RventRot - RVentSpeed * dt );
}
case DieselElectric: {
}
case DieselElectric: {
if( true == Mains ) {
// TBD, TODO: currently ignores RVentType, fix this?
RventRot += clamp( DElist[ MainCtrlPos ].RPM - RventRot, -100.0, 50.0 ) * dt;
break;
}
case DieselEngine:
default: {
break;
else {
RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt );
}
} // enginetype
break;
}
default: {
break;
}
}
else {
RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt );
}
RventRot = std::max( 0.0, RventRot );
if (ActiveDir != 0)
switch (EngineType)
@@ -4443,29 +4428,36 @@ double TMoverParameters::TractionForce(double dt)
}
else // jazda ciapongowa
{
auto power = Power;
if( true == Heating ) { power -= HeatingPower; }
if( power < 0.0 ) { power = 0.0; }
tmp = std::min( DElist[ MainCtrlPos ].GenPower, power );// Power - HeatingPower * double( Heating ));
// NOTE: very crude way to approximate power generated at current rpm instead of instant top output
auto const currentgenpower { (
DElist[ MainCtrlPos ].RPM > 0 ?
DElist[ MainCtrlPos ].GenPower * ( 60.0 * enrot / DElist[ MainCtrlPos ].RPM ) :
0.0 ) };
tmp = std::min( power, currentgenpower );
PosRatio = DElist[MainCtrlPos].GenPower / DElist[MainCtrlPosNo].GenPower;
PosRatio = currentgenpower / DElist[MainCtrlPosNo].GenPower;
// stosunek mocy teraz do mocy max
if ((MainCtrlPos > 0) && (ConverterFlag))
if (tmpV <
(Vhyp * power /
DElist[MainCtrlPosNo].GenPower)) // czy na czesci prostej, czy na hiperboli
Ft = (Ftmax -
((Ftmax - 1000.0 * DElist[MainCtrlPosNo].GenPower / (Vhyp + Vadd)) *
(tmpV / Vhyp) / PowerCorRatio)) *
PosRatio; // posratio - bo sila jakos tam sie rozklada
if( ( MainCtrlPos > 0 ) && ( ConverterFlag ) ) {
// Ft:=(Ftmax - (Ftmax - (1000.0 * DEList[MainCtrlPosNo].genpower /
//(Vhyp+Vadd) / PowerCorRatio)) * (tmpV/Vhyp)) * PosRatio //wersja z Megapacka
else // na hiperboli //1.107 -
// wspolczynnik sredniej nadwyzki Ft w symku nad charakterystyka
Ft = 1000.0 * tmp / (tmpV + Vadd) /
PowerCorRatio; // tu jest zawarty stosunek mocy
if( tmpV < ( Vhyp * power / DElist[ MainCtrlPosNo ].GenPower ) ) {
// czy na czesci prostej, czy na hiperboli
Ft = ( Ftmax
- ( ( Ftmax - 1000.0 * DElist[ MainCtrlPosNo ].GenPower / ( Vhyp + Vadd ) )
* ( tmpV / Vhyp )
/ PowerCorRatio ) )
* PosRatio; // posratio - bo sila jakos tam sie rozklada
}
else {
// na hiperboli
// 1.107 - wspolczynnik sredniej nadwyzki Ft w symku nad charakterystyka
Ft = 1000.0 * tmp / ( tmpV + Vadd ) /
PowerCorRatio; // tu jest zawarty stosunek mocy
}
}
else
Ft = 0; // jak nastawnik na zero, to sila tez zero
@@ -4506,32 +4498,40 @@ double TMoverParameters::TractionForce(double dt)
Im = DElist[MainCtrlPos].Imax;
}
if (Im > 0) // jak pod obciazeniem
if (Flat) // ograniczenie napiecia w pradnicy - plaszczak u gory
Voltage = 1000.0 * tmp / abs(Im);
else // charakterystyka pradnicy obcowzbudnej (elipsa) - twierdzenie Pitagorasa
{
Voltage = sqrt(abs(square(DElist[MainCtrlPos].Umax) -
square(DElist[MainCtrlPos].Umax * Im /
DElist[MainCtrlPos].Imax))) *
(MainCtrlPos - 1) +
(1.0 - Im / DElist[MainCtrlPos].Imax) * DElist[MainCtrlPos].Umax *
(MainCtrlPosNo - MainCtrlPos);
Voltage = Voltage / (MainCtrlPosNo - 1);
Voltage = Min0R(Voltage, (1000.0 * tmp / abs(Im)));
if (Voltage < (Im * 0.05))
Voltage = Im * 0.05;
if( Im > 0 ) {
// jak pod obciazeniem
if( true == Flat ) {
// ograniczenie napiecia w pradnicy - plaszczak u gory
Voltage = 1000.0 * tmp / std::abs( Im );
}
if ((Voltage > DElist[MainCtrlPos].Umax) ||
(Im == 0)) // gdy wychodzi za duze napiecie
Voltage = DElist[MainCtrlPos].Umax *
int(ConverterFlag); // albo przy biegu jalowym (jest cos takiego?)
else {
// charakterystyka pradnicy obcowzbudnej (elipsa) - twierdzenie Pitagorasa
Voltage =
std::sqrt(
std::abs(
square( DElist[ MainCtrlPos ].Umax )
- square( DElist[ MainCtrlPos ].Umax * Im / DElist[ MainCtrlPos ].Imax ) ) )
* ( MainCtrlPos - 1 )
+ ( 1.0 - Im / DElist[ MainCtrlPos ].Imax ) * DElist[ MainCtrlPos ].Umax * ( MainCtrlPosNo - MainCtrlPos );
Voltage /= ( MainCtrlPosNo - 1 );
Voltage = clamp(
Voltage,
Im * 0.05, ( 1000.0 * tmp / std::abs( Im ) ) );
}
}
if( ( Voltage > DElist[ MainCtrlPos ].Umax )
|| ( Im == 0 ) ) {
// gdy wychodzi za duze napiecie albo przy biegu jalowym (jest cos takiego?)
Voltage = DElist[ MainCtrlPos ].Umax * ( ConverterFlag ? 1 : 0 );
}
EnginePower = Voltage * Im / 1000.0;
/*
// NOTE: this part is experimentally disabled, as it generated early traction force drop for undetermined purpose
if ((tmpV > 2) && (EnginePower < tmp))
Ft = Ft * EnginePower / tmp;
*/
}
if ((Imax > 1) && (Im > Imax))
@@ -4705,8 +4705,7 @@ double TMoverParameters::TractionForce(double dt)
MainSwitch( false, ( TrainType == dt_EZT ? range::unit : range::local ) ); // TODO: check whether we need to send this EMU-wide
}
}
if ((Mains))
{
if( true == Mains ) {
dtrans = Hamulec->GetEDBCP();
if (((DoorLeftOpened) || (DoorRightOpened)))
@@ -4874,35 +4873,56 @@ double TMoverParameters::TractionForce(double dt)
Itot = eimv[eimv_Ipoj] * (0.01 + Min0R(0.99, 0.99 - Vadd));
EnginePower = abs(eimv[eimv_Ic] * eimv[eimv_U] * NPoweredAxles) / 1000;
// power inverters
auto const tmpV { std::abs( eimv[ eimv_fp ] ) };
if( ( RlistSize > 0 )
&& ( ( std::abs( eimv[ eimv_If ] ) > 1.0 )
|| ( tmpV > 0.1 ) ) ) {
int i = 0;
while( ( i < RlistSize - 1 )
&& ( DElist[ i + 1 ].RPM < tmpV ) ) {
++i;
}
InverterFrequency =
( tmpV - DElist[ i ].RPM )
/ std::max( 1.0, ( DElist[ i + 1 ].RPM - DElist[ i ].RPM ) )
* ( DElist[ i + 1 ].GenPower - DElist[ i ].GenPower )
+ DElist[ i ].GenPower;
}
else {
InverterFrequency = 0.0;
}
Mm = eimv[eimv_M] * DirAbsolute;
Mw = Mm * Transmision.Ratio;
Fw = Mw * 2.0 / WheelDiameter;
Ft = Fw * NPoweredAxles;
eimv[eimv_Fr] = DirAbsolute * Ft / 1000;
// RventRot;
}
} // mains
else
{
Im = 0;
Mm = 0;
Mw = 0;
Fw = 0;
Ft = 0;
Itot = 0;
dizel_fill = 0;
EnginePower = 0;
Im = 0.0;
Mm = 0.0;
Mw = 0.0;
Fw = 0.0;
Ft = 0.0;
Itot = 0.0;
dizel_fill = 0.0;
EnginePower = 0.0;
{
for (int i = 0; i < 21; ++i)
eimv[i] = 0;
eimv[i] = 0.0;
}
Hamulec->SetED(0);
RventRot = 0.0; //(Hamulec as TLSt).SetLBP(LocBrakePress);
Hamulec->SetED(0.0);
InverterFrequency = 0.0; //(Hamulec as TLSt).SetLBP(LocBrakePress);
}
break;
} // ElectricInductionMotor
case None:
{
default: {
break;
}
} // case EngineType

View File

@@ -375,6 +375,15 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
glm::length( glm::vec3( glm::column( matrix, 0 ) ) ),
glm::length( glm::vec3( glm::column( matrix, 1 ) ) ),
glm::length( glm::vec3( glm::column( matrix, 2 ) ) ) };
if( ( std::abs( scale.x - 1.0f ) > 0.01 )
|| ( std::abs( scale.y - 1.0f ) > 0.01 )
|| ( std::abs( scale.z - 1.0f ) > 0.01 ) ) {
ErrorLog( "Bad model: transformation matrix for sub-model \"" + pName + "\" imposes geometry scaling (factors: " + to_string( scale ) + ")", logtype::model );
m_normalizenormals = (
( ( std::abs( scale.x - scale.y ) < 0.01f ) && ( std::abs( scale.y - scale.z ) < 0.01f ) ) ?
rescale :
normalize );
}
}
if (eType < TP_ROTATOR)
{ // wczytywanie wierzchołków
@@ -455,7 +464,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
--facecount; // o jeden trójkąt mniej
iNumVerts -= 3; // czyli o 3 wierzchołki
i -= 3; // wczytanie kolejnego w to miejsce
WriteLog("Bad model: degenerated triangle ignored in: \"" + pName + "\", vertices " + std::to_string(rawvertexcount-2) + "-" + std::to_string(rawvertexcount));
WriteLog("Bad model: degenerated triangle ignored in: \"" + pName + "\", vertices " + std::to_string(rawvertexcount-2) + "-" + std::to_string(rawvertexcount), logtype::model );
}
if (i > 0) {
// jeśli pierwszy trójkąt będzie zdegenerowany, to zostanie usunięty i nie ma co sprawdzać
@@ -467,7 +476,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
--facecount; // o jeden trójkąt mniej
iNumVerts -= 3; // czyli o 3 wierzchołki
i -= 3; // wczytanie kolejnego w to miejsce
WriteLog( "Bad model: too large triangle ignored in: \"" + pName + "\"" );
WriteLog( "Bad model: too large triangle ignored in: \"" + pName + "\"", logtype::model );
}
}
}
@@ -506,14 +515,14 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
vertexnormal += facenormals[ adjacenvertextidx / 3 ];
}
else {
ErrorLog( "Bad model: opposite normals in the same smoothing group, check sub-model \"" + pName + "\" for two-sided faces and/or scaling" );
ErrorLog( "Bad model: opposite normals in the same smoothing group, check sub-model \"" + pName + "\" for two-sided faces and/or scaling", logtype::model );
}
// i szukanie od kolejnego trójkąta
adjacenvertextidx = SeekFaceNormal(sg, adjacenvertextidx / 3 + 1, sg[faceidx], Vertices[vertexidx].position, Vertices);
}
// Ra 15-01: należało by jeszcze uwzględnić skalowanie wprowadzane przez transformy, aby normalne po przeskalowaniu były jednostkowe
if( glm::length2( vertexnormal ) == 0.0f ) {
WriteLog( "Bad model: zero lenght normal vector generated for sub-model \"" + pName + "\"" );
WriteLog( "Bad model: zero lenght normal vector generated for sub-model \"" + pName + "\"", logtype::model );
}
Vertices[ vertexidx ].normal = (
glm::length2( vertexnormal ) > 0.0f ?
@@ -1167,7 +1176,7 @@ TSubModel::offset( float const Geometrytestoffsetthreshold ) const {
auto offset { glm::vec3 { glm::make_mat4( parentmatrix.readArray() ) * glm::vec4 { 0, 0, 0, 1 } } };
if( glm::length2( offset ) < Geometrytestoffsetthreshold ) {
if( glm::length( offset ) < Geometrytestoffsetthreshold ) {
// offset of zero generally means the submodel has optimized identity matrix
// for such cases we resort to an estimate from submodel geometry
// TODO: do proper bounding area calculation for submodel when loading mesh and grab the centre point from it here
@@ -1235,7 +1244,7 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic)
Root ? (iSubModelsCount > 0) : false; // brak pliku albo problem z wczytaniem
if (false == result)
{
ErrorLog("Failed to load 3d model \"" + FileName + "\"");
ErrorLog("Bad model: failed to load 3d model \"" + FileName + "\"");
}
return result;
};
@@ -1518,6 +1527,11 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
if( submodel.eType < TP_ROTATOR ) {
// normal vectors debug routine
auto normallength = glm::length2( vertex.normal );
if( ( false == submodel.m_normalizenormals )
&& ( std::abs( normallength - 1.0f ) > 0.01f ) ) {
submodel.m_normalizenormals = TSubModel::normalize; // we don't know if uniform scaling would suffice
WriteLog( "Bad model: non-unit normal vector(s) encountered during sub-model geometry deserialization", logtype::model );
}
}
}
// remap geometry type for custom type submodels
@@ -1642,7 +1656,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector<std::string> *t,
}
}
else {
ErrorLog( "Bad model: reference to nonexistent texture index in sub-model" + ( pName.empty() ? "" : " \"" + pName + "\"" ) );
ErrorLog( "Bad model: reference to nonexistent texture index in sub-model" + ( pName.empty() ? "" : " \"" + pName + "\"" ), logtype::model );
m_material = null_handle;
}
}
@@ -1679,12 +1693,21 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector<std::string> *t,
glm::length( glm::vec3( glm::column( matrix, 0 ) ) ),
glm::length( glm::vec3( glm::column( matrix, 1 ) ) ),
glm::length( glm::vec3( glm::column( matrix, 2 ) ) ) };
if( ( std::abs( scale.x - 1.0f ) > 0.01 )
|| ( std::abs( scale.y - 1.0f ) > 0.01 )
|| ( std::abs( scale.z - 1.0f ) > 0.01 ) ) {
ErrorLog( "Bad model: transformation matrix for sub-model \"" + pName + "\" imposes geometry scaling (factors: " + to_string( scale ) + ")", logtype::model );
m_normalizenormals = (
( ( std::abs( scale.x - scale.y ) < 0.01f ) && ( std::abs( scale.y - scale.z ) < 0.01f ) ) ?
rescale :
normalize );
}
}
};
void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic)
{ // wczytanie modelu z pliku binarnego
WriteLog("Loading binary format 3d model data from \"" + FileName + "\"...");
WriteLog( "Loading binary format 3d model data from \"" + FileName + "\"...", logtype::model );
std::string fn = FileName;
std::replace(fn.begin(), fn.end(), '\\', '/');
@@ -1699,12 +1722,12 @@ void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic)
deserialize(file, size, dynamic);
file.close();
WriteLog("Finished loading 3d model data from \"" + FileName + "\"");
WriteLog( "Finished loading 3d model data from \"" + FileName + "\"", logtype::model );
};
void TModel3d::LoadFromTextFile(std::string const &FileName, bool dynamic)
{ // wczytanie submodelu z pliku tekstowego
WriteLog("Loading text format 3d model data from \"" + FileName + "\"...");
WriteLog( "Loading text format 3d model data from \"" + FileName + "\"...", logtype::model );
iFlags |= 0x0200; // wczytano z pliku tekstowego (właścicielami tablic są submodle)
cParser parser(FileName, cParser::buffer_FILE); // Ra: tu powinno być "models\\"...
TSubModel *SubModel;

View File

@@ -40,7 +40,7 @@ opengl_texture::load() {
if( name.size() < 3 ) { goto fail; }
WriteLog( "Loading texture data from \"" + name + "\"" );
WriteLog( "Loading texture data from \"" + name + "\"", logtype::texture );
data_state = resource_state::loading;
{
@@ -69,7 +69,7 @@ opengl_texture::load() {
fail:
data_state = resource_state::failed;
ErrorLog( "Failed to load texture \"" + name + "\"" );
ErrorLog( "Bad texture: failed to load texture \"" + name + "\"" );
// NOTE: temporary workaround for texture assignment errors
id = 0;
return;
@@ -138,7 +138,7 @@ opengl_texture::load_BMP() {
BITMAPINFO info;
unsigned int infosize = header.bfOffBits - sizeof( BITMAPFILEHEADER );
if( infosize > sizeof( info ) ) {
WriteLog( "Warning - BMP header is larger than expected, possible format difference." );
WriteLog( "Warning - BMP header is larger than expected, possible format difference.", logtype::texture );
}
file.read( (char *)&info, std::min( (size_t)infosize, sizeof( info ) ) );
@@ -147,7 +147,7 @@ opengl_texture::load_BMP() {
if( info.bmiHeader.biCompression != BI_RGB ) {
ErrorLog( "Compressed BMP textures aren't supported." );
ErrorLog( "Bad texture: compressed BMP textures aren't supported.", logtype::texture );
data_state = resource_state::failed;
return;
}
@@ -336,7 +336,7 @@ opengl_texture::load_DDS() {
*/
if( datasize == 0 ) {
// catch malformed .dds files
WriteLog( "File \"" + name + "\" is malformed and holds no texture data." );
WriteLog( "Bad texture: file \"" + name + "\" is malformed and holds no texture data.", logtype::texture );
data_state = resource_state::failed;
return;
}
@@ -377,7 +377,7 @@ opengl_texture::load_TEX() {
hasalpha = true;
}
else {
ErrorLog( "Unrecognized TEX texture sub-format: " + std::string(head) );
ErrorLog( "Bad texture: unrecognized TEX texture sub-format: " + std::string(head), logtype::texture );
data_state = resource_state::failed;
return;
};
@@ -636,10 +636,12 @@ opengl_texture::create() {
}
}
// TBD, TODO: keep the texture data if we start doing some gpu data cleaning down the road
data.clear();
data.shrink_to_fit();
data_state = resource_state::none;
if( ( true == Global::ResourceMove )
|| ( false == Global::ResourceSweep ) ) {
// if garbage collection is disabled we don't expect having to upload the texture more than once
data = std::vector<char>();
data_state = resource_state::none;
}
is_ready = true;
}
@@ -648,19 +650,35 @@ opengl_texture::create() {
// releases resources allocated on the opengl end, storing local copy if requested
void
opengl_texture::release( bool const Backup ) {
opengl_texture::release() {
if( id == -1 ) { return; }
if( true == Backup ) {
// query texture details needed to perform the backup...
if( true == Global::ResourceMove ) {
// if resource move is enabled we don't keep a cpu side copy after upload
// so need to re-acquire the data before release
// TBD, TODO: instead of vram-ram transfer fetch the data 'normally' from the disk using worker thread
::glBindTexture( GL_TEXTURE_2D, id );
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (GLint *)&data_format );
GLint datasize;
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint *)&datasize );
data.resize( datasize );
// ...fetch the data...
::glGetCompressedTexImage( GL_TEXTURE_2D, 0, &data[ 0 ] );
GLint datasize {};
GLint iscompressed {};
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &iscompressed );
if( iscompressed == GL_TRUE ) {
// texture is compressed on the gpu side
// query texture details needed to perform the backup...
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &data_format );
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &datasize );
data.resize( datasize );
// ...fetch the data...
::glGetCompressedTexImage( GL_TEXTURE_2D, 0, &data[ 0 ] );
}
else {
// for whatever reason texture didn't get compressed during upload
// fallback on plain rgba storage...
data_format = GL_RGBA;
data.resize( data_width * data_height * 4 );
// ...fetch the data...
::glGetTexImage( GL_TEXTURE_2D, 0, data_format, GL_UNSIGNED_BYTE, &data[ 0 ] );
}
// ...and update texture object state
data_mapcount = 1; // we keep copy of only top mipmap level
data_state = resource_state::good;
@@ -816,7 +834,7 @@ texture_manager::create( std::string Filename, bool const Loadnow ) {
if( true == filename.empty() ) {
// there's nothing matching in the databank nor on the disk, report failure
ErrorLog( "Texture file missing: \"" + Filename + "\"" );
ErrorLog( "Bad file: failed do locate texture file \"" + Filename + "\"", logtype::file );
return npos;
}
@@ -831,7 +849,7 @@ texture_manager::create( std::string Filename, bool const Loadnow ) {
m_textures.emplace_back( texture, std::chrono::steady_clock::time_point() );
m_texturemappings.emplace( filename, textureindex );
WriteLog( "Created texture object for \"" + filename + "\"" );
WriteLog( "Created texture object for \"" + filename + "\"", logtype::texture );
if( true == Loadnow ) {

View File

@@ -30,7 +30,7 @@ struct opengl_texture {
create();
// releases resources allocated on the opengl end, storing local copy if requested
void
release( bool const Backup = true );
release();
inline
int
width() const {
@@ -63,7 +63,7 @@ private:
int data_width{ 0 },
data_height{ 0 },
data_mapcount{ 0 };
GLuint data_format{ 0 },
GLint data_format{ 0 },
data_components{ 0 };
/*
std::atomic<bool> is_loaded{ false }; // indicates the texture data was loaded and can be processed

204
Train.cpp
View File

@@ -322,7 +322,6 @@ TTrain::TTrain() {
pMechOffset = vector3(0, 0, 0);
fBlinkTimer = 0;
fHaslerTimer = 0;
keybrakecount = 0;
DynamicSet(NULL); // ustawia wszystkie mv*
iCabLightFlag = 0;
// hunter-091012
@@ -470,6 +469,7 @@ PyObject *TTrain::GetTrainState() {
PyDict_SetItemString( dict, "shp", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ) );
PyDict_SetItemString( dict, "pantpress", PyGetFloat( mvControlled->PantPress ) );
PyDict_SetItemString( dict, "universal3", PyGetBool( InstrumentLightActive ) );
PyDict_SetItemString( dict, "radio_channel", PyGetInt( iRadioChannel ) );
// movement data
PyDict_SetItemString( dict, "velocity", PyGetFloat( mover->Vel ) );
PyDict_SetItemString( dict, "tractionforce", PyGetFloat( mover->Ft ) );
@@ -551,6 +551,24 @@ bool TTrain::is_eztoer() const {
&& ( mvControlled->ActiveDir != 0 ) ); // od yB
}
// moves train brake lever to specified position, potentially emits switch sound if conditions are met
void TTrain::set_train_brake( double const Position ) {
auto const originalbrakeposition { static_cast<int>( 100.0 * mvOccupied->fBrakeCtrlPos ) };
mvOccupied->BrakeLevelSet( Position );
if( static_cast<int>( 100.0 * mvOccupied->fBrakeCtrlPos ) == originalbrakeposition ) { return; }
if( ( true == is_eztoer() )
&& ( false == (
( ( originalbrakeposition / 100 == 0 ) || ( originalbrakeposition / 100 >= 5 ) )
&& ( ( mvOccupied->BrakeCtrlPos == 0 ) || ( mvOccupied->BrakeCtrlPos >= 5 ) ) ) ) ) {
// sound feedback if the lever movement activates one of the switches
dsbPneumaticSwitch.play();
}
}
// locates nearest vehicle belonging to the consist
TDynamicObject *
TTrain::find_nearest_consist_vehicle() const {
@@ -799,14 +817,7 @@ void TTrain::OnCommand_trainbrakeincrease( TTrain *Train, command_data const &Co
Train->mvOccupied->BrakeLevelAdd( Global::fBrakeStep * Command.time_delta );
}
else {
if( Train->mvOccupied->BrakeLevelAdd( Global::fBrakeStep * Command.time_delta ) ) {
// nieodpowiedni warunek; true, jeśli można dalej kręcić
Train->keybrakecount = 0;
if( ( Train->is_eztoer() ) && ( Train->mvOccupied->BrakeCtrlPos < 3 ) ) {
// Ra: uzależnić dźwięk od zmiany stanu EP, nie od klawisza
Train->dsbPneumaticSwitch.play();
}
}
Train->set_train_brake( Train->mvOccupied->fBrakeCtrlPos + Global::fBrakeStep * Command.time_delta );
}
}
}
@@ -819,21 +830,7 @@ void TTrain::OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Co
Train->mvOccupied->BrakeLevelAdd( -Global::fBrakeStep * Command.time_delta );
}
else {
// nową wersję dostarczył ZiomalCl ("fixed looped sound in ezt when using NUM_9 key")
if( ( Train->mvOccupied->BrakeCtrlPos > -1 )
|| ( Train->keybrakecount > 1 ) ) {
if( ( Train->is_eztoer() )
&& ( Train->mvControlled->Mains )
&& ( Train->mvOccupied->BrakeCtrlPos != -1 ) ) {
// Ra: uzależnić dźwięk od zmiany stanu EP, nie od klawisza
Train->dsbPneumaticSwitch.play();
}
Train->mvOccupied->BrakeLevelAdd( -Global::fBrakeStep * Command.time_delta );
}
else
Train->keybrakecount += 1;
// koniec wersji dostarczonej przez ZiomalCl
Train->set_train_brake( Train->mvOccupied->BrakeCtrlPos - Global::fBrakeStep * Command.time_delta );
}
}
else if (Command.action == GLFW_RELEASE) {
@@ -841,15 +838,9 @@ void TTrain::OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Co
if( ( Train->mvOccupied->BrakeCtrlPos == -1 )
&& ( Train->mvOccupied->BrakeHandle == FVel6 )
&& ( Train->DynamicObject->Controller != AIdriver )
&& ( Global::iFeedbackMode != 4 ) ) {
&& ( Global::iFeedbackMode < 3 ) ) {
// Odskakiwanie hamulce EP
Train->mvOccupied->BrakeLevelSet( Train->mvOccupied->BrakeCtrlPos + 1 );
Train->keybrakecount = 0;
if( ( Train->mvOccupied->TrainType == dt_EZT )
&& ( Train->mvControlled->Mains )
&& ( Train->mvControlled->ActiveDir != 0 ) ) {
Train->dsbPneumaticSwitch.play();
}
Train->set_train_brake( 0 );
}
}
}
@@ -858,29 +849,16 @@ void TTrain::OnCommand_trainbrakecharging( TTrain *Train, command_data const &Co
if( Command.action != GLFW_RELEASE ) {
// press or hold
// sound feedback
if( ( Train->is_eztoer() )
&& ( Train->mvControlled->Mains )
&& ( Train->mvOccupied->BrakeCtrlPos != -1 ) ) {
Train->dsbPneumaticSwitch.play();
}
Train->mvOccupied->BrakeLevelSet( -1 );
Train->set_train_brake( -1 );
}
else {
// release
if( ( Train->mvOccupied->BrakeCtrlPos == -1 )
&& ( Train->mvOccupied->BrakeHandle == FVel6 )
&& ( Train->DynamicObject->Controller != AIdriver )
&& ( Global::iFeedbackMode != 4 ) ) {
&& ( Global::iFeedbackMode < 3 ) ) {
// Odskakiwanie hamulce EP
Train->mvOccupied->BrakeLevelSet( Train->mvOccupied->BrakeCtrlPos + 1 );
Train->keybrakecount = 0;
if( ( Train->mvOccupied->TrainType == dt_EZT )
&& ( Train->mvControlled->Mains )
&& ( Train->mvControlled->ActiveDir != 0 ) ) {
Train->dsbPneumaticSwitch.play();
}
Train->set_train_brake( 0 );
}
}
}
@@ -889,14 +867,7 @@ void TTrain::OnCommand_trainbrakerelease( TTrain *Train, command_data const &Com
if( Command.action == GLFW_PRESS ) {
// sound feedback
if( ( Train->is_eztoer() )
&& ( ( Train->mvOccupied->BrakeCtrlPos == 1 )
|| ( Train->mvOccupied->BrakeCtrlPos == -1 ) ) ) {
Train->dsbPneumaticSwitch.play();
}
Train->mvOccupied->BrakeLevelSet( 0 );
Train->set_train_brake( 0 );
}
}
@@ -904,14 +875,7 @@ void TTrain::OnCommand_trainbrakefirstservice( TTrain *Train, command_data const
if( Command.action == GLFW_PRESS ) {
// sound feedback
if( ( Train->is_eztoer() )
&& ( Train->mvControlled->Mains )
&& ( Train->mvOccupied->BrakeCtrlPos != 1 ) ) {
Train->dsbPneumaticSwitch.play();
}
Train->mvOccupied->BrakeLevelSet( 1 );
Train->set_train_brake( 1 );
}
}
@@ -919,19 +883,11 @@ void TTrain::OnCommand_trainbrakeservice( TTrain *Train, command_data const &Com
if( Command.action == GLFW_PRESS ) {
// sound feedback
if( ( Train->is_eztoer() )
&& ( Train->mvControlled->Mains )
&& ( ( Train->mvOccupied->BrakeCtrlPos == 1 )
|| ( Train->mvOccupied->BrakeCtrlPos == -1 ) ) ) {
Train->dsbPneumaticSwitch.play();
}
Train->mvOccupied->BrakeLevelSet(
Train->set_train_brake( (
Train->mvOccupied->BrakeCtrlPosNo / 2
+ ( Train->mvOccupied->BrakeHandle == FV4a ?
1 :
0 ) );
1 :
0 ) ) );
}
}
@@ -939,14 +895,7 @@ void TTrain::OnCommand_trainbrakefullservice( TTrain *Train, command_data const
if( Command.action == GLFW_PRESS ) {
// sound feedback
if( ( Train->is_eztoer() )
&& ( Train->mvControlled->Mains )
&& ( ( Train->mvOccupied->BrakeCtrlPos == 1 )
|| ( Train->mvOccupied->BrakeCtrlPos == -1 ) ) ) {
Train->dsbPneumaticSwitch.play();
}
Train->mvOccupied->BrakeLevelSet( Train->mvOccupied->BrakeCtrlPosNo - 1 );
Train->set_train_brake( Train->mvOccupied->BrakeCtrlPosNo - 1 );
}
}
@@ -954,7 +903,7 @@ void TTrain::OnCommand_trainbrakehandleoff( TTrain *Train, command_data const &C
if( Command.action == GLFW_PRESS ) {
Train->mvOccupied->BrakeLevelSet( Train->mvOccupied->Handle->GetPos( bh_NP ) );
Train->set_train_brake( Train->mvOccupied->Handle->GetPos( bh_NP ) );
}
}
@@ -962,7 +911,7 @@ void TTrain::OnCommand_trainbrakeemergency( TTrain *Train, command_data const &C
if( Command.action == GLFW_PRESS ) {
Train->mvOccupied->BrakeLevelSet( Train->mvOccupied->Handle->GetPos( bh_EB ) );
Train->set_train_brake( Train->mvOccupied->Handle->GetPos( bh_EB ) );
/*
if( Train->mvOccupied->BrakeCtrlPosNo <= 0.1 ) {
// hamulec bezpieczeństwa dla wagonów
@@ -3213,6 +3162,13 @@ void TTrain::OnCommand_radiochannelincrease( TTrain *Train, command_data const &
if( Command.action == GLFW_PRESS ) {
Train->iRadioChannel = clamp( Train->iRadioChannel + 1, 1, 10 );
// visual feedback
Train->ggRadioChannelSelector.UpdateValue( Train->iRadioChannel - 1 );
Train->ggRadioChannelNext.UpdateValue( 1.0 );
}
else if( Command.action == GLFW_RELEASE ) {
// visual feedback
Train->ggRadioChannelNext.UpdateValue( 0.0 );
}
}
@@ -3220,6 +3176,13 @@ void TTrain::OnCommand_radiochanneldecrease( TTrain *Train, command_data const &
if( Command.action == GLFW_PRESS ) {
Train->iRadioChannel = clamp( Train->iRadioChannel - 1, 1, 10 );
// visual feedback
Train->ggRadioChannelSelector.UpdateValue( Train->iRadioChannel - 1 );
Train->ggRadioChannelPrevious.UpdateValue( 1.0 );
}
else if( Command.action == GLFW_RELEASE ) {
// visual feedback
Train->ggRadioChannelPrevious.UpdateValue( 0.0 );
}
}
@@ -3417,9 +3380,7 @@ bool TTrain::Update( double const Deltatime )
}
if (DynamicObject->mdKabina)
{ // Ra: TODO: odczyty klawiatury/pulpitu nie
// powinny być uzależnione od istnienia modelu
// kabiny
{ // Ra: TODO: odczyty klawiatury/pulpitu nie powinny być uzależnione od istnienia modelu kabiny
tor = DynamicObject->GetTrack(); // McZapkie-180203
// McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol
float maxtacho = 3;
@@ -3441,9 +3402,10 @@ bool TTrain::Update( double const Deltatime )
if (fTachoCount < maxtacho)
fTachoCount += Deltatime * 3; // szybciej zacznij stukac
}
else if (fTachoCount > 0)
fTachoCount -= Deltatime * 0.66; // schodz powoli - niektore haslery to ze 4
// sekundy potrafia stukac
else if( fTachoCount > 0 ) {
// schodz powoli - niektore haslery to ze 4 sekundy potrafia stukac
fTachoCount -= Deltatime * 0.66;
}
// Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są ewentualnie na PoKeys
if ((mvControlled->EngineType != DieselElectric)
@@ -4056,6 +4018,9 @@ bool TTrain::Update( double const Deltatime )
btLampkaForward.Turn(mvControlled->ActiveDir > 0); // jazda do przodu
btLampkaBackward.Turn(mvControlled->ActiveDir < 0); // jazda do tyłu
btLampkaED.Turn(mvControlled->DynamicBrakeFlag); // hamulec ED
btLampkaBrakeProfileG.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_G ) );
btLampkaBrakeProfileP.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_P ) );
btLampkaBrakeProfileR.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_R ) );
// light indicators
// NOTE: sides are hardcoded to deal with setups where single cab is equipped with all indicators
btLampkaUpperLight.Turn( ( mvOccupied->iLights[ side::front ] & light::headlight_upper ) != 0 );
@@ -4073,6 +4038,9 @@ bool TTrain::Update( double const Deltatime )
{ // gdy bateria wyłączona
btLampkaHamienie.Turn( false );
btLampkaBrakingOff.Turn( false );
btLampkaBrakeProfileG.Turn( false );
btLampkaBrakeProfileP.Turn( false );
btLampkaBrakeProfileR.Turn( false );
btLampkaMaxSila.Turn( false );
btLampkaPrzekrMaxSila.Turn( false );
btLampkaRadio.Turn( false );
@@ -4246,7 +4214,7 @@ bool TTrain::Update( double const Deltatime )
else // wylaczone
{
btLampkaCzuwaka.Turn( false );
btLampkaSHP.Turn( true );
btLampkaSHP.Turn( false );
}
// przelaczniki
// ABu030405 obsluga lampki uniwersalnej:
@@ -4280,6 +4248,9 @@ bool TTrain::Update( double const Deltatime )
ggConverterFuseButton.Update();
ggStLinOffButton.Update();
ggRadioButton.Update();
ggRadioChannelSelector.Update();
ggRadioChannelPrevious.Update();
ggRadioChannelNext.Update();
ggDepartureSignalButton.Update();
ggPantFrontButton.Update();
@@ -4582,12 +4553,27 @@ TTrain::update_sounds( double const Deltatime ) {
&& ( false == Global::CabWindowOpen )
&& ( DynamicObject->GetVelocity() > 0.5 ) ) {
volume = rsRunningNoise.m_amplitudeoffset + rsRunningNoise.m_amplitudefactor * mvOccupied->Vel;
auto frequency { rsRunningNoise.m_frequencyoffset + rsRunningNoise.m_frequencyfactor * mvOccupied->Vel };
// frequency calculation
auto const normalizer { (
true == rsRunningNoise.is_combined() ?
mvOccupied->Vmax * 0.01f :
1.f ) };
auto const frequency {
rsRunningNoise.m_frequencyoffset
+ rsRunningNoise.m_frequencyfactor * mvOccupied->Vel * normalizer };
// volume calculation
volume =
rsRunningNoise.m_amplitudeoffset
+ rsRunningNoise.m_amplitudefactor * mvOccupied->Vel;
if( std::abs( mvOccupied->nrot ) > 0.01 ) {
// hamulce wzmagaja halas
volume *= 1 + 0.25 * ( mvOccupied->UnitBrakeForce / ( 1 + mvOccupied->MaxBrakeForce ) );
auto const brakeforceratio { (
clamp(
mvOccupied->UnitBrakeForce / std::max( 1.0, mvOccupied->BrakeForceR( 1.0, mvOccupied->Vel ) / ( mvOccupied->NAxles * std::max( 1, mvOccupied->NBpA ) ) ),
0.0, 1.0 ) ) };
volume *= 1 + 0.125 * brakeforceratio;
}
// scale volume by track quality
volume *= ( 20.0 + DynamicObject->MyTrack->iDamageFlag ) / 21;
@@ -4599,10 +4585,16 @@ TTrain::update_sounds( double const Deltatime ) {
clamp(
mvOccupied->Vel / 40.0,
0.0, 1.0 ) );
rsRunningNoise
.pitch( frequency )
.gain( volume )
.play( sound_flags::exclusive | sound_flags::looping );
if( volume > 0.05 ) {
rsRunningNoise
.pitch( frequency )
.gain( volume )
.play( sound_flags::exclusive | sound_flags::looping );
}
else {
rsRunningNoise.stop();
}
}
else {
// don't play the optional ending sound if the listener switches views
@@ -5257,6 +5249,10 @@ void TTrain::clear_cab_controls()
ggFuseButton.Clear();
ggConverterFuseButton.Clear();
ggStLinOffButton.Clear();
ggRadioButton.Clear();
ggRadioChannelSelector.Clear();
ggRadioChannelPrevious.Clear();
ggRadioChannelNext.Clear();
ggDoorLeftButton.Clear();
ggDoorRightButton.Clear();
ggDepartureSignalButton.Clear();
@@ -5335,6 +5331,9 @@ void TTrain::clear_cab_controls()
btLampkaRadiotelefon.Clear();
btLampkaHamienie.Clear();
btLampkaBrakingOff.Clear();
btLampkaBrakeProfileG.Clear();
btLampkaBrakeProfileP.Clear();
btLampkaBrakeProfileR.Clear();
btLampkaSprezarka.Clear();
btLampkaSprezarkaB.Clear();
btLampkaSprezarkaOff.Clear();
@@ -5391,6 +5390,7 @@ void TTrain::set_cab_controls() {
if( true == mvOccupied->Radio ) {
ggRadioButton.PutValue( 1.0 );
}
ggRadioChannelSelector.PutValue( iRadioChannel - 1 );
// pantographs
if( mvOccupied->PantSwitchType != "impulse" ) {
ggPantFrontButton.PutValue(
@@ -5612,6 +5612,9 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co
{ "i-braking:", btLampkaHamienie },
{ "i-brakingoff:", btLampkaBrakingOff },
{ "i-dynamicbrake:", btLampkaED },
{ "i-brakeprofileg:", btLampkaBrakeProfileG },
{ "i-brakeprofilep:", btLampkaBrakeProfileP },
{ "i-brakeprofiler:", btLampkaBrakeProfileR },
{ "i-braking-ezt:", btLampkaHamowanie1zes },
{ "i-braking-ezt2:", btLampkaHamowanie2zes },
{ "i-compressor:", btLampkaSprezarka },
@@ -5719,6 +5722,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
{ "converteroff_sw:", ggConverterOffButton },
{ "main_sw:", ggMainButton },
{ "radio_sw:", ggRadioButton },
{ "radiochannel_sw:", ggRadioChannelSelector },
{ "radiochannelprev_sw:", ggRadioChannelPrevious },
{ "radiochannelnext_sw:", ggRadioChannelNext },
{ "pantfront_sw:", ggPantFrontButton },
{ "pantrear_sw:", ggPantRearButton },
{ "pantfrontoff_sw:", ggPantFrontButtonOff },

13
Train.h
View File

@@ -90,7 +90,6 @@ class TTrain
void UpdateMechPosition(double dt);
vector3 GetWorldMechPosition();
bool Update( double const Deltatime );
void update_sounds( double const Deltatime );
void MechStop();
void SetLights();
// McZapkie-310302: ladowanie parametrow z pliku
@@ -115,6 +114,10 @@ class TTrain
bool is_eztoer() const;
// locates nearest vehicle belonging to the consist
TDynamicObject *find_nearest_consist_vehicle() const;
// moves train brake lever to specified position, potentially emits switch sound if conditions are met
void set_train_brake( double const Position );
// update function subroutines
void update_sounds( double const Deltatime );
// command handlers
// NOTE: we're currently using universal handlers and static handler map but it may be beneficial to have these implemented on individual class instance basis
@@ -269,6 +272,9 @@ public: // reszta może by?publiczna
TGauge ggConverterFuseButton; // hunter-261211: przycisk odblokowania nadmiarowego przetwornic i ogrzewania
TGauge ggStLinOffButton;
TGauge ggRadioButton;
TGauge ggRadioChannelSelector;
TGauge ggRadioChannelPrevious;
TGauge ggRadioChannelNext;
TGauge ggUpperLightButton;
TGauge ggLeftLightButton;
TGauge ggRightLightButton;
@@ -378,6 +384,10 @@ public: // reszta może by?publiczna
TButton btLampkaHamienie;
TButton btLampkaBrakingOff;
TButton btLampkaED; // Stele 161228 hamowanie elektrodynamiczne
TButton btLampkaBrakeProfileG; // cargo train brake acting speed
TButton btLampkaBrakeProfileP; // passenger train brake acting speed
TButton btLampkaBrakeProfileR; // rapid brake acting speed
// KURS90
TButton btLampkaBoczniki;
TButton btLampkaMaxSila;
@@ -469,7 +479,6 @@ private:
double fPoslizgTimer;
TTrack *tor;
int keybrakecount;
// McZapkie-240302 - przyda sie do tachometru
float fTachoVelocity{ 0.0f };
float fTachoVelocityJump{ 0.0f }; // ze skakaniem

View File

@@ -1577,13 +1577,11 @@ TWorld::Update_UI() {
"vel: " + to_string( vehicle->GetVelocity(), 2 ) + "/" + to_string( vehicle->MoverParameters->nrot* M_PI * vehicle->MoverParameters->WheelDiameter * 3.6, 2 )
+ " km/h;" + ( vehicle->MoverParameters->SlippingWheels ? " (!)" : " " )
+ " dist: " + to_string( vehicle->MoverParameters->DistCounter, 2 ) + " km"
+ "; pos: ("
+ to_string( vehicle->GetPosition().x, 2 ) + ", "
+ to_string( vehicle->GetPosition().y, 2 ) + ", "
+ to_string( vehicle->GetPosition().z, 2 ) + "), PM="
+ to_string( vehicle->MoverParameters->WheelFlat, 1 ) + " mm; enrot="
+ to_string( vehicle->MoverParameters->enrot * 60, 0 ) + " tmrot="
+ to_string( std::abs( vehicle->MoverParameters->nrot ) * vehicle->MoverParameters->Transmision.Ratio * 60, 0 );
+ "; pos: [" + to_string( vehicle->GetPosition().x, 2 ) + ", " + to_string( vehicle->GetPosition().y, 2 ) + ", " + to_string( vehicle->GetPosition().z, 2 ) + "]"
+ ", PM=" + to_string( vehicle->MoverParameters->WheelFlat, 1 )
+ " mm; enrot=" + to_string( vehicle->MoverParameters->enrot * 60, 0 )
+ " tmrot=" + to_string( std::abs( vehicle->MoverParameters->nrot ) * vehicle->MoverParameters->Transmision.Ratio * 60, 0 )
+ "; ventrot=" + to_string( vehicle->MoverParameters->RventRot, 1 );
uitextline2 =
"HamZ=" + to_string( vehicle->MoverParameters->fBrakeCtrlPos, 2 )
@@ -2207,14 +2205,14 @@ world_environment::update() {
auto const skydomecolour = m_skydome.GetAverageColor();
auto const skydomehsv = RGBtoHSV( skydomecolour );
// sun strength is reduced by overcast level
keylightintensity *= ( 1.0f - Global::Overcast * 0.65f );
keylightintensity *= ( 1.0f - std::min( 1.f, Global::Overcast ) * 0.65f );
// intensity combines intensity of the sun and the light reflected by the sky dome
// it'd be more technically correct to have just the intensity of the sun here,
// but whether it'd _look_ better is something to be tested
auto const intensity = std::min( 1.15f * ( 0.05f + keylightintensity + skydomehsv.z ), 1.25f );
// the impact of sun component is reduced proportionally to overcast level, as overcast increases role of ambient light
auto const diffuselevel = interpolate( keylightintensity, intensity * ( 1.0f - twilightfactor ), 1.0f - Global::Overcast * 0.75f );
auto const diffuselevel = interpolate( keylightintensity, intensity * ( 1.0f - twilightfactor ), 1.0f - std::min( 1.f, Global::Overcast ) * 0.75f );
// ...update light colours and intensity.
keylightcolor = keylightcolor * diffuselevel;
Global::DayLight.diffuse = glm::vec4( keylightcolor, Global::DayLight.diffuse.a );

View File

@@ -342,6 +342,15 @@ mouse_input::default_bindings() {
{ "radio_sw:", {
user_command::radiotoggle,
user_command::none } },
{ "radiochannel_sw:", {
user_command::radiochannelincrease,
user_command::radiochanneldecrease } },
{ "radiochannelprev_sw:", {
user_command::radiochanneldecrease,
user_command::none } },
{ "radiochannelnext_sw:", {
user_command::radiochannelincrease,
user_command::none } },
{ "pantfront_sw:", {
user_command::pantographtogglefront,
user_command::none } },

View File

@@ -34,10 +34,6 @@ private:
user_command left;
user_command right;
mouse_commands( user_command const Left, user_command const Right ):
left(Left), right(Right)
{}
};
typedef std::unordered_map<std::string, mouse_commands> controlcommands_map;

View File

@@ -1325,6 +1325,10 @@ opengl_renderer::Render( world_environment *Environment ) {
// turn on moon shadows after nautical twilight, if the moon is actually up
m_shadowcolor = glm::vec4{ 0.5f, 0.5f, 0.5f, 1.f };
}
// soften shadows depending on sky overcast factor
m_shadowcolor = glm::min(
colors::white,
m_shadowcolor + glm::vec4{ glm::vec3{ 0.5f * Global::Overcast }, 1.f } );
if( Global::bWireFrame ) {
// bez nieba w trybie rysowania linii
@@ -1447,7 +1451,7 @@ opengl_renderer::Render( world_environment *Environment ) {
GL_LIGHT_MODEL_AMBIENT,
glm::value_ptr(
interpolate( Environment->m_skydome.GetAverageColor(), suncolor, duskfactor * 0.25f )
* ( 1.0f - Global::Overcast * 0.5f ) // overcast darkens the clouds
* interpolate( 1.f, 0.35f, Global::Overcast / 2.f ) // overcast darkens the clouds
* 2.5f // arbitrary adjustment factor
) );
// render
@@ -3129,11 +3133,17 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
static_cast<float>( TSubModel::fSquareDist / Submodel->fSquareMaxDist ) ); // pozycja punktu świecącego względem kamery
Submodel->fCosViewAngle = glm::dot( glm::normalize( modelview * glm::vec4( 0.f, 0.f, -1.f, 1.f ) - lightcenter ), glm::normalize( -lightcenter ) );
float glarelevel = 0.6f; // luminosity at night is at level of ~0.1, so the overall resulting transparency is ~0.5 at full 'brightness'
float glarelevel = 0.6f; // luminosity at night is at level of ~0.1, so the overall resulting transparency in clear conditions is ~0.5 at full 'brightness'
if( Submodel->fCosViewAngle > Submodel->fCosFalloffAngle ) {
// only bother if the viewer is inside the visibility cone
if( Global::Overcast > 1.0 ) {
// increase the glare in rainy/foggy conditions
glarelevel += std::max( 0.f, 0.5f * ( Global::Overcast - 1.f ) );
}
// scale it down based on view angle
glarelevel *= ( Submodel->fCosViewAngle - Submodel->fCosFalloffAngle ) / ( 1.0f - Submodel->fCosFalloffAngle );
glarelevel = std::max( 0.0f, glarelevel - static_cast<float>(Global::fLuminance) );
// reduce the glare in bright daylight
glarelevel = clamp( glarelevel - static_cast<float>(Global::fLuminance), 0.f, 1.f );
if( glarelevel > 0.0f ) {
// setup
@@ -3360,7 +3370,8 @@ opengl_renderer::Update( double const Deltatime ) {
::glEnable( GL_MULTISAMPLE );
}
if( true == World.InitPerformed() ) {
if( ( true == Global::ResourceSweep )
&& ( true == World.InitPerformed() ) ) {
// garbage collection
m_geometry.update();
m_textures.update();

View File

@@ -20,7 +20,7 @@ inline bool strcend(std::string const &value, std::string const &ending)
gl_shader::gl_shader(std::string filename)
{
WriteLog("loading shader " + filename + " ..", false);
WriteLog("loading shader " + filename + " ..");
std::stringstream stream;
std::ifstream f;

View File

@@ -166,7 +166,7 @@ state_manager::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad
std::string token { Input.getToken<std::string>() };
if( token != "endatmo" ) {
// optional overcast parameter
Global::Overcast = clamp( std::stof( token ), 0.f, 1.f );
Global::Overcast = clamp( std::stof( token ), 0.f, 2.f );
}
while( ( false == token.empty() )
&& ( token != "endatmo" ) ) {

View File

@@ -274,8 +274,8 @@ void CSkyDome::RebuildColors() {
float const y = PerezFunctionO2( perezy, icostheta, gamma, cosgamma2, zenithy );
// luminance(Y) for clear & overcast sky
float const yclear = PerezFunctionO2( perezluminance, icostheta, gamma, cosgamma2, zenithluminance );
float const yover = zenithluminance * ( 1.0f + 2.0f * vertex.y ) / 3.0f;
float const yclear = std::max( 0.01f, PerezFunctionO2( perezluminance, icostheta, gamma, cosgamma2, zenithluminance ) );
float const yover = std::max( 0.01f, zenithluminance * ( 1.0f + 2.0f * vertex.y ) / 3.0f );
float const Y = interpolate( yclear, yover, m_overcast );
float const X = (x / y) * Y;

View File

@@ -63,6 +63,9 @@ static std::unordered_map<std::string, std::string> m_cabcontrols = {
{ "converteroff_sw:", "converter" },
{ "main_sw:", "line breaker" },
{ "radio_sw:", "radio" },
{ "radiochannel_sw:", "radio channel" },
{ "radiochannelprev_sw:", "radio channel" },
{ "radiochannelnext_sw:", "radio channel" },
{ "pantfront_sw:", "pantograph A" },
{ "pantrear_sw:", "pantograph B" },
{ "pantfrontoff_sw:", "pantograph A" },

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 18
#define VERSION_MINOR 114
#define VERSION_MINOR 122
#define VERSION_REVISION 0