mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-23 06:19:18 +02:00
build 200124. scenario parameters control sliders, material reload support, material opacity driven translucent geometry alpha test, command keyboard mapping tooltip hints, camshaft logic tweak, motor connector logic tweak, ai power use logic tweak, ai pantograph control logic tweak, converter sound pitch fix. additional cab control localization
This commit is contained in:
52
Driver.cpp
52
Driver.cpp
@@ -2194,6 +2194,7 @@ bool TController::CheckVehicles(TOrders user)
|
||||
}
|
||||
// with the order established the virtual train manager can do their work
|
||||
p = pVehicles[0];
|
||||
ControlledEnginesCount = ( p->MoverParameters->Power > 1.0 ? 1 : 0 );
|
||||
while (p)
|
||||
{
|
||||
if( p != pVehicle ) {
|
||||
@@ -2207,6 +2208,11 @@ bool TController::CheckVehicles(TOrders user)
|
||||
p->MoverParameters->ConverterSwitch( true, range_t::local );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( p->MoverParameters->Power > 1.0 ) {
|
||||
++ControlledEnginesCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p->asDestination == "none")
|
||||
@@ -2537,9 +2543,6 @@ bool TController::PrepareEngine()
|
||||
}
|
||||
if (mvControlling->EnginePowerSource.SourceType == TPowerSource::CurrentCollector)
|
||||
{ // jeśli silnikowy jest pantografującym
|
||||
mvControlling->OperatePantographsValve( operation_t::enable );
|
||||
mvControlling->OperatePantographValve( end::front, operation_t::enable );
|
||||
mvControlling->OperatePantographValve( end::rear, operation_t::enable );
|
||||
if (mvControlling->PantPress < 4.2) {
|
||||
// załączenie małej sprężarki
|
||||
if( false == mvControlling->PantAutoValve ) {
|
||||
@@ -2550,11 +2553,15 @@ bool TController::PrepareEngine()
|
||||
}
|
||||
else {
|
||||
// jeżeli jest wystarczające ciśnienie w pantografach
|
||||
if ((!mvControlling->bPantKurek3) ||
|
||||
(mvControlling->PantPress <=
|
||||
mvControlling->ScndPipePress)) // kurek przełączony albo główna już pompuje
|
||||
if ((!mvControlling->bPantKurek3)
|
||||
|| (mvControlling->PantPress <= mvControlling->ScndPipePress)) // kurek przełączony albo główna już pompuje
|
||||
mvControlling->PantCompFlag = false; // sprężarkę pantografów można już wyłączyć
|
||||
}
|
||||
if( ( fOverhead2 == -1.0 ) && ( iOverheadDown == 0 ) ) {
|
||||
mvControlling->OperatePantographsValve( operation_t::enable );
|
||||
mvControlling->OperatePantographValve( end::front, operation_t::enable );
|
||||
mvControlling->OperatePantographValve( end::rear, operation_t::enable );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3163,7 +3170,7 @@ bool TController::IncSpeed()
|
||||
if( usefieldshunting ) {
|
||||
// to dać bocznik
|
||||
// engage the shuntfield only if there's sufficient power margin to draw from
|
||||
auto const sufficientpowermargin { fVoltage - useseriesmodevoltage > ( IsHeavyCargoTrain ? 100.0 : 75.0 ) };
|
||||
auto const sufficientpowermargin { fVoltage - useseriesmodevoltage > ( IsHeavyCargoTrain ? 100.0 : 75.0 ) * ControlledEnginesCount };
|
||||
|
||||
OK = (
|
||||
sufficientpowermargin ?
|
||||
@@ -3183,7 +3190,7 @@ bool TController::IncSpeed()
|
||||
mvControlling->RList[ std::min( mvControlling->MainCtrlPos + 1, mvControlling->MainCtrlPosNo ) ].Bn == 1 ?
|
||||
mvControlling->EnginePowerSource.CollectorParameters.MinV :
|
||||
useseriesmodevoltage )
|
||||
> ( IsHeavyCargoTrain ? 80.0 : 60.0 ) };
|
||||
> ( IsHeavyCargoTrain ? 80.0 : 60.0 ) * ControlledEnginesCount };
|
||||
|
||||
OK = (
|
||||
( sufficientpowermargin && ( false == mvControlling->DelayCtrlFlag ) ) ?
|
||||
@@ -3994,8 +4001,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
|
||||
if (NewCommand == "Overhead")
|
||||
{ // informacja o stanie sieci trakcyjnej
|
||||
fOverhead1 =
|
||||
NewValue1; // informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!)
|
||||
fOverhead1 = NewValue1; // informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!)
|
||||
fOverhead2 = NewValue2; // informacja o sposobie jazdy (-1=normalnie, 0=bez prądu, >0=z
|
||||
// opuszczonym i ograniczeniem prędkości)
|
||||
return true; // załatwione
|
||||
@@ -4700,8 +4706,12 @@ TController::UpdateSituation(double dt) {
|
||||
|
||||
if( ( fOverhead2 > 0.0 ) || iOverheadDown ) {
|
||||
// jazda z opuszczonymi pantografami
|
||||
mvControlling->OperatePantographValve( end::front, operation_t::disable );
|
||||
mvControlling->OperatePantographValve( end::rear, operation_t::disable );
|
||||
if( mvControlling->Pantographs[ end::front ].is_active ) {
|
||||
mvControlling->OperatePantographValve( end::front, operation_t::disable );
|
||||
}
|
||||
if( mvControlling->Pantographs[ end::rear ].is_active ) {
|
||||
mvControlling->OperatePantographValve( end::rear, operation_t::disable );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// jeśli nie trzeba opuszczać pantografów
|
||||
@@ -4779,15 +4789,17 @@ TController::UpdateSituation(double dt) {
|
||||
// NOTE: abs(stoptime) covers either at least 15 sec remaining for a scheduled stop, or 15+ secs spent at a basic stop
|
||||
&& ( std::abs( fStopTime ) > 15.0 ) ) {
|
||||
// spending a longer at a stop, raise also front pantograph
|
||||
if( ( iDirection >= 0 ) && ( useregularpantographlayout ) ) {
|
||||
// jak jedzie w kierunku sprzęgu 0
|
||||
if( mvControlling->PantFrontVolt == 0.0 ) {
|
||||
mvControlling->OperatePantographValve( end::front, operation_t::enable );
|
||||
if( mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > 1 ) {
|
||||
if( ( iDirection >= 0 ) && ( useregularpantographlayout ) ) {
|
||||
// jak jedzie w kierunku sprzęgu 0
|
||||
if( mvControlling->PantFrontVolt == 0.0 ) {
|
||||
mvControlling->OperatePantographValve( end::front, operation_t::enable );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( mvControlling->PantRearVolt == 0.0 ) {
|
||||
mvControlling->OperatePantographValve( end::rear, operation_t::enable );
|
||||
else {
|
||||
if( mvControlling->PantRearVolt == 0.0 ) {
|
||||
mvControlling->OperatePantographValve( end::rear, operation_t::enable );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1
Driver.h
1
Driver.h
@@ -459,6 +459,7 @@ private:
|
||||
double fMass = 0.0; // całkowita masa do liczenia stycznej składowej grawitacji
|
||||
double fAccGravity = 0.0; // przyspieszenie składowej stycznej grawitacji
|
||||
int iVehicles = 0; // ilość pojazdów w składzie
|
||||
int ControlledEnginesCount{ 0 }; // number of powered vehicles under driver's control
|
||||
bool iEngineActive{ false }; // ABu: Czy silnik byl juz zalaczony
|
||||
bool IsCargoTrain{ false };
|
||||
bool IsHeavyCargoTrain{ false };
|
||||
|
||||
38
DynObj.cpp
38
DynObj.cpp
@@ -3805,24 +3805,28 @@ void TDynamicObject::RenderSounds() {
|
||||
m_startjoltplayed = false;
|
||||
}
|
||||
|
||||
double const dt{ Timer::GetDeltaRenderTime() };
|
||||
double volume{ 0.0 };
|
||||
double frequency{ 1.0 };
|
||||
|
||||
auto const dt{ Timer::GetDeltaRenderTime() };
|
||||
m_powertrainsounds.render( *MoverParameters, dt );
|
||||
|
||||
auto volume{ 0.0 };
|
||||
auto frequency{ 1.0 };
|
||||
|
||||
// NBMX dzwiek przetwornicy
|
||||
if( MoverParameters->ConverterFlag ) {
|
||||
frequency = (
|
||||
MoverParameters->EngineType != TEngineType::ElectricSeriesMotor ?
|
||||
1.0 :
|
||||
MoverParameters->PantographVoltage > 0.0 ?
|
||||
MoverParameters->PantographVoltage / ( MoverParameters->NominalVoltage * MoverParameters->RList[ MoverParameters->RlistSize ].Mn ) :
|
||||
1.0 );
|
||||
frequency = sConverter.m_frequencyoffset + sConverter.m_frequencyfactor * frequency;
|
||||
sConverter
|
||||
.pitch( clamp( frequency, 0.75, 1.25 ) ) // arbitrary limits )
|
||||
.play( sound_flags::exclusive | sound_flags::looping );
|
||||
if( MoverParameters->EngineType == TEngineType::ElectricSeriesMotor ) {
|
||||
auto const voltage { std::max( MoverParameters->GetAnyTrainsetVoltage(), MoverParameters->PantographVoltage ) };
|
||||
if( voltage > 0.0 ) {
|
||||
// NOTE: we do sound modulation here to avoid sudden jump on voltage loss
|
||||
frequency = ( voltage / ( MoverParameters->NominalVoltage * MoverParameters->RList[ MoverParameters->RlistSize ].Mn ) );
|
||||
frequency *= sConverter.m_frequencyfactor + sConverter.m_frequencyoffset;
|
||||
sConverter.pitch( clamp( frequency, 0.75, 1.25 ) ); // arbitrary limits )
|
||||
}
|
||||
}
|
||||
else {
|
||||
frequency = sConverter.m_frequencyoffset + sConverter.m_frequencyfactor * frequency;
|
||||
sConverter.pitch( clamp( frequency, 0.75, 1.25 ) ); // arbitrary limits )
|
||||
}
|
||||
sConverter.play( sound_flags::exclusive | sound_flags::looping );
|
||||
}
|
||||
else {
|
||||
sConverter.stop();
|
||||
@@ -6522,14 +6526,12 @@ void TDynamicObject::OverheadTrack(float o)
|
||||
}
|
||||
else if (o > 0.0)
|
||||
{ // opuszczenie pantografów
|
||||
ctOwner->iOverheadZero |=
|
||||
iOverheadMask; // ustawienie bitu - ma jechać bez pobierania prądu
|
||||
ctOwner->iOverheadZero |= iOverheadMask; // ustawienie bitu - ma jechać bez pobierania prądu
|
||||
ctOwner->iOverheadDown |= iOverheadMask; // ustawienie bitu - ma opuścić pantograf
|
||||
}
|
||||
else
|
||||
{ // jazda bezprądowa z podniesionym pantografem
|
||||
ctOwner->iOverheadZero |=
|
||||
iOverheadMask; // ustawienie bitu - ma jechać bez pobierania prądu
|
||||
ctOwner->iOverheadZero |= iOverheadMask; // ustawienie bitu - ma jechać bez pobierania prądu
|
||||
ctOwner->iOverheadDown &= ~iOverheadMask; // zerowanie bitu - może podnieść pantograf
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ struct global_settings {
|
||||
std::string Weather{ "cloudy:" }; // current weather
|
||||
bool FullPhysics{ true }; // full calculations performed for each simulation step
|
||||
bool bnewAirCouplers{ true };
|
||||
double fMoveLight{ -1 }; // numer dnia w roku albo -1
|
||||
float fMoveLight{ -1.f }; // numer dnia w roku albo -1
|
||||
bool FakeLight{ false }; // toggle between fixed and dynamic daylight
|
||||
double fTimeSpeed{ 1.0 }; // przyspieszenie czasu, zmienna do testów
|
||||
double fLatitudeDeg{ 52.0 }; // szerokość geograficzna
|
||||
|
||||
@@ -170,13 +170,13 @@ enum class range_t {
|
||||
};
|
||||
// possible settings of enable/disable input pair; exclusive
|
||||
enum class operation_t {
|
||||
enable_on = 1,
|
||||
enable_off = -1,
|
||||
disable_on = 2,
|
||||
disable_off = -2,
|
||||
none = 0,
|
||||
enable,
|
||||
disable,
|
||||
enable_on,
|
||||
enable_off,
|
||||
disable_on,
|
||||
disable_off,
|
||||
};
|
||||
// start method for devices; exclusive
|
||||
enum class start_t {
|
||||
@@ -1380,6 +1380,7 @@ public:
|
||||
bool Mains = false; /*polozenie glownego wylacznika*/
|
||||
double MainsInitTime{ 0.0 }; // config, initialization time (in seconds) of the main circuit after it receives power, before it can be closed
|
||||
double MainsInitTimeCountdown{ 0.0 }; // current state of main circuit initialization, remaining time (in seconds) until it's ready
|
||||
bool LineBreakerClosesAtNoPowerPosOnly{ false };
|
||||
int MainCtrlPos = 0; /*polozenie glownego nastawnika*/
|
||||
int ScndCtrlPos = 0; /*polozenie dodatkowego nastawnika*/
|
||||
int LightsPos = 0; /*polozenie przelacznika wielopozycyjnego swiatel*/
|
||||
|
||||
@@ -3193,6 +3193,7 @@ void TMoverParameters::MainSwitch_( bool const State ) {
|
||||
&& ( true == NoVoltRelay )
|
||||
&& ( true == OvervoltageRelay )
|
||||
&& ( LastSwitchingTime > CtrlDelay )
|
||||
&& ( HasCamshaft ? IsMainCtrlActualNoPowerPos() : ( LineBreakerClosesAtNoPowerPosOnly ? IsMainCtrlNoPowerPos() : true ) )
|
||||
&& ( false == TestFlag( DamageFlag, dtrain_out ) )
|
||||
&& ( false == TestFlag( EngDmgFlag, 1 ) ) ) ) {
|
||||
|
||||
@@ -5086,8 +5087,12 @@ double TMoverParameters::TractionForce( double dt ) {
|
||||
|
||||
case TEngineType::DieselElectric: {
|
||||
// TODO: move this to the auto relay check when the electric engine code paths are unified
|
||||
StLinFlag = MotorConnectorsCheck();
|
||||
StLinFlag &= IsMainCtrlNoPowerPos();
|
||||
StLinFlag &= MotorConnectorsCheck();
|
||||
StLinFlag |= (
|
||||
( MainCtrlActualPos == 0 )
|
||||
&& ( TrainType != dt_EZT ?
|
||||
MainCtrlPowerPos() == 1 :
|
||||
MainCtrlPowerPos() > 0 ) );
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -6145,12 +6150,14 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
bool OK = false; // b:int;
|
||||
bool ARC = false;
|
||||
|
||||
auto const motorconnectors { MotorConnectorsCheck() };
|
||||
auto const motorconnectorsoff { false == MotorConnectorsCheck() };
|
||||
|
||||
// Ra 2014-06: dla SN61 nie działa prawidłowo
|
||||
// yBARC - rozlaczenie stycznikow liniowych
|
||||
if( ( false == motorconnectors )
|
||||
|| ( HasCamshaft ? IsMainCtrlActualNoPowerPos() : IsMainCtrlNoPowerPos() ) ) {
|
||||
if( ( motorconnectorsoff )
|
||||
|| ( HasCamshaft ?
|
||||
IsMainCtrlActualNoPowerPos() :
|
||||
IsMainCtrlNoPowerPos() ) ) {
|
||||
StLinFlag = false;
|
||||
OK = false;
|
||||
if( false == DynamicBrakeFlag ) {
|
||||
@@ -6329,7 +6336,12 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
{
|
||||
OK = false;
|
||||
// ybARC - zalaczenie stycznikow liniowych
|
||||
if( true == motorconnectors ) {
|
||||
if( ( false == motorconnectorsoff )
|
||||
&& ( MainCtrlActualPos == 0 )
|
||||
&& ( ( TrainType == dt_EZT || HasCamshaft ) ?
|
||||
MainCtrlPowerPos() > 0 :
|
||||
MainCtrlPowerPos() == 1 ) ) {
|
||||
|
||||
DelayCtrlFlag = true;
|
||||
if( LastRelayTime >= InitialCtrlDelay ) {
|
||||
StLinFlag = true;
|
||||
@@ -6339,14 +6351,15 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
OK = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
DelayCtrlFlag = false;
|
||||
}
|
||||
|
||||
if( ( false == StLinFlag )
|
||||
&& ( ( MainCtrlActualPos > 0 )
|
||||
|| ( ScndCtrlActualPos > 0 ) ) ) {
|
||||
|
||||
if( CoupledCtrl ) {
|
||||
if( CoupledCtrl || HasCamshaft ) {
|
||||
|
||||
if( TrainType == dt_EZT ) {
|
||||
// EN57 wal jednokierunkowy calosciowy
|
||||
@@ -6380,7 +6393,8 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
else {
|
||||
// wal kulakowy dwukierunkowy
|
||||
if( LastRelayTime > CtrlDownDelay ) {
|
||||
if( ScndCtrlActualPos > 0 ) {
|
||||
if( ( CoupledCtrl )
|
||||
&& ( ScndCtrlActualPos > 0 ) ) {
|
||||
--ScndCtrlActualPos;
|
||||
SetFlag( SoundFlag, sound::shuntfield );
|
||||
}
|
||||
@@ -6421,16 +6435,7 @@ bool TMoverParameters::MotorConnectorsCheck() {
|
||||
|| ( true == StLinSwitchOff )
|
||||
|| ( DirActive == 0 ) };
|
||||
|
||||
if( connectorsoff ) { return false; }
|
||||
|
||||
auto const connectorson {
|
||||
( true == StLinFlag )
|
||||
|| ( ( MainCtrlActualPos == 0 )
|
||||
&& ( ( TrainType != dt_EZT ?
|
||||
MainCtrlPowerPos() == 1 :
|
||||
MainCtrlPowerPos() > 0 ) ) ) };
|
||||
|
||||
return connectorson;
|
||||
return ( false == connectorsoff );
|
||||
}
|
||||
|
||||
bool TMoverParameters::OperatePantographsValve( operation_t const State, range_t const Notify ) {
|
||||
@@ -6439,8 +6444,15 @@ bool TMoverParameters::OperatePantographsValve( operation_t const State, range_t
|
||||
|
||||
auto &valve { PantsValve };
|
||||
|
||||
valve.is_enabled = ( State == operation_t::enable );
|
||||
valve.is_disabled = ( State == operation_t::disable );
|
||||
switch( State ) {
|
||||
case operation_t::none: { valve.is_enabled = false; valve.is_disabled = false; break; }
|
||||
case operation_t::enable: { valve.is_enabled = true; valve.is_disabled = false; break; }
|
||||
case operation_t::disable: { valve.is_enabled = false; valve.is_disabled = true; break; }
|
||||
case operation_t::enable_on: { valve.is_enabled = true; break; }
|
||||
case operation_t::enable_off: { valve.is_enabled = false; break; }
|
||||
case operation_t::disable_on: { valve.is_disabled = true; break; }
|
||||
case operation_t::disable_off: { valve.is_disabled = false; break; }
|
||||
}
|
||||
|
||||
if( Notify != range_t::local ) {
|
||||
SendCtrlToNext(
|
||||
@@ -6459,8 +6471,15 @@ bool TMoverParameters::OperatePantographValve( end const End, operation_t const
|
||||
|
||||
auto &valve { Pantographs[ End ].valve };
|
||||
|
||||
valve.is_enabled = ( State == operation_t::enable );
|
||||
valve.is_disabled = ( State == operation_t::disable );
|
||||
switch( State ) {
|
||||
case operation_t::none: { valve.is_enabled = false; valve.is_disabled = false; break; }
|
||||
case operation_t::enable: { valve.is_enabled = true; valve.is_disabled = false; break; }
|
||||
case operation_t::disable: { valve.is_enabled = false; valve.is_disabled = true; break; }
|
||||
case operation_t::enable_on: { valve.is_enabled = true; break; }
|
||||
case operation_t::enable_off: { valve.is_enabled = false; break; }
|
||||
case operation_t::disable_on: { valve.is_disabled = true; break; }
|
||||
case operation_t::disable_off: { valve.is_disabled = false; break; }
|
||||
}
|
||||
|
||||
if( Notify != range_t::local ) {
|
||||
SendCtrlToNext(
|
||||
|
||||
@@ -353,6 +353,9 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
|
||||
if( Opacity > 1.f ) {
|
||||
Opacity = std::min( 1.f, Opacity * 0.01f );
|
||||
}
|
||||
if( Opacity < -1.f ) {
|
||||
Opacity = std::max( -1.f, Opacity * 0.01f );
|
||||
}
|
||||
|
||||
if (!parser.expectToken("map:"))
|
||||
Error("Model map parse failure!");
|
||||
|
||||
@@ -1284,7 +1284,7 @@ texture_manager::info() const {
|
||||
}
|
||||
|
||||
return
|
||||
"; textures: "
|
||||
"textures: "
|
||||
#ifdef EU07_DEFERRED_TEXTURE_UPLOAD
|
||||
+ std::to_string( readytexturecount )
|
||||
+ " ("
|
||||
|
||||
117
Train.cpp
117
Train.cpp
@@ -39,11 +39,19 @@ extern user_command command;
|
||||
|
||||
}
|
||||
*/
|
||||
void
|
||||
control_mapper::clear() {
|
||||
|
||||
*this = control_mapper();
|
||||
}
|
||||
|
||||
void
|
||||
control_mapper::insert( TGauge const &Gauge, std::string const &Label ) {
|
||||
|
||||
if( Gauge.SubModel != nullptr ) { m_controlnames.emplace( Gauge.SubModel, Label ); }
|
||||
if( Gauge.SubModelOn != nullptr ) { m_controlnames.emplace( Gauge.SubModelOn, Label ); }
|
||||
|
||||
m_names.emplace( Label );
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -58,6 +66,12 @@ control_mapper::find( TSubModel const *Control ) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
control_mapper::contains( std::string const Control ) const {
|
||||
|
||||
return ( m_names.find( Control ) != m_names.end() );
|
||||
}
|
||||
|
||||
void TCab::Load(cParser &Parser)
|
||||
{
|
||||
// NOTE: clearing control tables here is bit of a crutch, imposed by current scheme of loading compartments anew on each cab change
|
||||
@@ -2075,10 +2089,16 @@ void TTrain::OnCommand_pantographraisefront( TTrain *Train, command_data const &
|
||||
|
||||
// HACK: presence of pantograph selector prevents manual operation of the individual valves
|
||||
if( Train->ggPantSelectButton.SubModel ) { return; }
|
||||
// prevent operation without submodel outside of engine compartment
|
||||
if( ( Train->iCabn != 0 )
|
||||
&& ( false == Train->m_controlmapper.contains( "pantfront_sw:" ) ) ) { return; }
|
||||
|
||||
if( Command.action == GLFW_PRESS ) {
|
||||
// only reacting to press, so the switch doesn't flip back and forth if key is held down
|
||||
Train->mvControlled->OperatePantographValve( end::front, operation_t::enable );
|
||||
Train->mvControlled->OperatePantographValve( end::front,
|
||||
Train->mvOccupied->PantSwitchType == "impulse" ?
|
||||
operation_t::enable_on :
|
||||
operation_t::enable );
|
||||
}
|
||||
else if( Command.action == GLFW_RELEASE ) {
|
||||
// NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch
|
||||
@@ -2090,11 +2110,17 @@ void TTrain::OnCommand_pantographraiserear( TTrain *Train, command_data const &C
|
||||
|
||||
// HACK: presence of pantograph selector prevents manual operation of the individual valves
|
||||
if( Train->ggPantSelectButton.SubModel ) { return; }
|
||||
// prevent operation without submodel outside of engine compartment
|
||||
if( ( Train->iCabn != 0 )
|
||||
&& ( false == Train->m_controlmapper.contains( "pantrear_sw:" ) ) ) { return; }
|
||||
|
||||
if( Command.action == GLFW_PRESS ) {
|
||||
// only reacting to press, so the switch doesn't flip back and forth if key is held down
|
||||
Train->mvControlled->OperatePantographValve( end::rear, operation_t::enable );
|
||||
}
|
||||
Train->mvControlled->OperatePantographValve( end::rear,
|
||||
Train->mvOccupied->PantSwitchType == "impulse" ?
|
||||
operation_t::enable_on :
|
||||
operation_t::enable );
|
||||
}
|
||||
else if( Command.action == GLFW_RELEASE ) {
|
||||
// NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch
|
||||
OnCommand_pantographtogglerear( Train, Command );
|
||||
@@ -2105,10 +2131,21 @@ void TTrain::OnCommand_pantographlowerfront( TTrain *Train, command_data const &
|
||||
|
||||
// HACK: presence of pantograph selector prevents manual operation of the individual valves
|
||||
if( Train->ggPantSelectButton.SubModel ) { return; }
|
||||
// prevent operation without submodel outside of engine compartment
|
||||
if( ( Train->iCabn != 0 )
|
||||
&& ( false == Train->m_controlmapper.contains(
|
||||
Train->mvOccupied->PantSwitchType == "impulse" ?
|
||||
"pantfrontoff_sw:" :
|
||||
"pantfront_sw:" ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( Command.action == GLFW_PRESS ) {
|
||||
// only reacting to press, so the switch doesn't flip back and forth if key is held down
|
||||
Train->mvControlled->OperatePantographValve( end::front, operation_t::disable );
|
||||
Train->mvControlled->OperatePantographValve( end::front,
|
||||
Train->mvOccupied->PantSwitchType == "impulse" ?
|
||||
operation_t::disable_on :
|
||||
operation_t::disable );
|
||||
}
|
||||
else if( Command.action == GLFW_RELEASE ) {
|
||||
// NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch
|
||||
@@ -2120,14 +2157,24 @@ void TTrain::OnCommand_pantographlowerrear( TTrain *Train, command_data const &C
|
||||
|
||||
// HACK: presence of pantograph selector prevents manual operation of the individual valves
|
||||
if( Train->ggPantSelectButton.SubModel ) { return; }
|
||||
if( ( Train->iCabn != 0 )
|
||||
&& ( false == Train->m_controlmapper.contains(
|
||||
Train->mvOccupied->PantSwitchType == "impulse" ?
|
||||
"pantrearoff_sw:" :
|
||||
"pantrear_sw:" ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( Command.action == GLFW_PRESS ) {
|
||||
// only reacting to press, so the switch doesn't flip back and forth if key is held down
|
||||
Train->mvControlled->OperatePantographValve( end::rear, operation_t::disable );
|
||||
Train->mvControlled->OperatePantographValve( end::rear,
|
||||
Train->mvOccupied->PantSwitchType == "impulse" ?
|
||||
operation_t::disable_on :
|
||||
operation_t::disable );
|
||||
}
|
||||
else if( Command.action == GLFW_RELEASE ) {
|
||||
// NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch
|
||||
OnCommand_pantographtogglefront( Train, Command );
|
||||
OnCommand_pantographtogglerear( Train, Command );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6150,9 +6197,9 @@ bool TTrain::Update( double const Deltatime )
|
||||
|| ( mvControlled->MainCtrlActualPos == 0 ) ); // do EU04
|
||||
|
||||
btLampkaStyczn.Turn(
|
||||
mvControlled->StLinFlag ?
|
||||
( ( mvOccupied->StLinFlag ) /* || ( mvOccupied->BrakePress > 2.0 ) || ( mvOccupied->PipePress < 3.6 ) */ ) ?
|
||||
false :
|
||||
mvOccupied->BrakePress < 1.0 ); // mozna prowadzic rozruch
|
||||
( mvOccupied->BrakePress < 1.0 ) ); // mozna prowadzic rozruch
|
||||
|
||||
if( ( ( mvControlled->CabOccupied == 1 ) && ( TestFlag( mvControlled->Couplers[ end::rear ].CouplingFlag, coupling::control ) ) )
|
||||
|| ( ( mvControlled->CabOccupied == -1 ) && ( TestFlag( mvControlled->Couplers[ end::front ].CouplingFlag, coupling::control ) ) ) ) {
|
||||
@@ -6380,7 +6427,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
|
||||
if( ( mover->StLinFlag )
|
||||
|| ( mover->BrakePress > 2.0 )
|
||||
|| ( mover->PipePress < 0.36 ) ) {
|
||||
|| ( mover->PipePress < 3.6 ) ) {
|
||||
btLampkaStycznB.Turn( false );
|
||||
}
|
||||
else if( mover->BrakePress < 1.0 ) {
|
||||
@@ -6760,57 +6807,6 @@ bool TTrain::Update( double const Deltatime )
|
||||
mvControlled->AntiSlippingBrake();
|
||||
}
|
||||
}
|
||||
/*
|
||||
// NOTE: crude way to have the pantographs go back up if they're dropped due to insufficient pressure etc
|
||||
// TODO: rework it into something more elegant, when redoing the whole consist/unit/cab etc arrangement
|
||||
if( ( DynamicObject->Mechanik == nullptr )
|
||||
|| ( false == DynamicObject->Mechanik->AIControllFlag ) ) {
|
||||
// don't mess with the ai driving, at least not while switches don't follow ai-set vehicle state
|
||||
if( ( mvControlled->Battery )
|
||||
|| ( mvControlled->ConverterFlag ) ) {
|
||||
if( ggPantAllDownButton.GetDesiredValue() < 0.05 ) {
|
||||
// the 'lower all' button overrides state of switches, while active itself
|
||||
if( ( false == mvControlled->PantFrontUp )
|
||||
&& ( ggPantFrontButton.GetDesiredValue() >= 0.95 ) ) {
|
||||
mvControlled->PantFront( true );
|
||||
}
|
||||
if( ( false == mvControlled->PantRearUp )
|
||||
&& ( ggPantRearButton.GetDesiredValue() >= 0.95 ) ) {
|
||||
mvControlled->PantRear( true );
|
||||
}
|
||||
}
|
||||
if( ggPantSelectButton.SubModel ) {
|
||||
if( ggPantSelectedButton.SubModel ) {
|
||||
if( ( ggPantSelectedButton.type() == TGaugeType::toggle )
|
||||
&& ( ggPantSelectedButton.GetDesiredValue() >= 0.95 ) ) {
|
||||
change_pantograph_selection_state( true );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// HACK: force pantographs into currently selected state
|
||||
change_pantograph_selection( 0, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
// check whether we should raise the pantographs, based on volume in pantograph tank
|
||||
// NOTE: disabled while switch state isn't preserved while moving between compartments
|
||||
if( mvControlled->PantPress > (
|
||||
mvControlled->TrainType == dt_EZT ?
|
||||
2.4 :
|
||||
3.5 ) ) {
|
||||
if( ( false == mvControlled->PantFrontUp )
|
||||
&& ( ggPantFrontButton.GetValue() > 0.95 ) ) {
|
||||
mvControlled->PantFront( true );
|
||||
}
|
||||
if( ( false == mvControlled->PantRearUp )
|
||||
&& ( ggPantRearButton.GetValue() > 0.95 ) ) {
|
||||
mvControlled->PantRear( true );
|
||||
}
|
||||
}
|
||||
*/
|
||||
// screens
|
||||
fScreenTimer += Deltatime;
|
||||
if( ( fScreenTimer > Global.PythonScreenUpdateRate * 0.001f )
|
||||
@@ -7718,6 +7714,7 @@ Math3D::vector3 TTrain::MirrorPosition(bool lewe)
|
||||
1.5 + Cabine[iCabn].CabPos1.y,
|
||||
Cabine[iCabn].CabPos1.z);
|
||||
case 1: // przednia (1)
|
||||
[[fallthrough]];
|
||||
default:
|
||||
return DynamicObject->mMatrix *
|
||||
Math3D::vector3(
|
||||
|
||||
6
Train.h
6
Train.h
@@ -59,13 +59,17 @@ private:
|
||||
class control_mapper {
|
||||
typedef std::unordered_map< TSubModel const *, std::string> submodelstring_map;
|
||||
submodelstring_map m_controlnames;
|
||||
using stringset = std::unordered_set<std::string>;
|
||||
stringset m_names; // names of registered controls
|
||||
public:
|
||||
void
|
||||
clear() { m_controlnames.clear(); }
|
||||
clear();
|
||||
void
|
||||
insert( TGauge const &Gauge, std::string const &Label );
|
||||
std::string
|
||||
find( TSubModel const *Control ) const;
|
||||
bool
|
||||
contains( std::string const Control ) const;
|
||||
};
|
||||
|
||||
class TTrain {
|
||||
|
||||
@@ -39,6 +39,11 @@ public:
|
||||
set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f ) {
|
||||
if( m_userinterface != nullptr ) {
|
||||
m_userinterface->set_progress( Progress, Subtaskprogress ); } }
|
||||
inline
|
||||
void
|
||||
set_tooltip( std::string const &Tooltip ) {
|
||||
if( m_userinterface != nullptr ) {
|
||||
m_userinterface->set_tooltip( Tooltip ); } }
|
||||
// maintenance method, called when the mode is activated
|
||||
virtual
|
||||
void
|
||||
|
||||
@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "Globals.h"
|
||||
#include "application.h"
|
||||
#include "translation.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "simulationenvironment.h"
|
||||
@@ -80,6 +81,50 @@ driver_mode::drivermode_input::init() {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string
|
||||
driver_mode::drivermode_input::command_hints( std::pair<user_command, user_command> const &Commands ) const {
|
||||
|
||||
auto const inputhintleft { keyboard.mapping( Commands.first ) };
|
||||
auto const inputhintright { keyboard.mapping( Commands.second ) };
|
||||
std::string inputhints =
|
||||
inputhintleft
|
||||
+ ( inputhintright.empty() ? "" :
|
||||
inputhintleft.empty() ?
|
||||
inputhintright :
|
||||
"] [" + inputhintright );
|
||||
|
||||
return inputhints;
|
||||
}
|
||||
|
||||
std::unordered_map<user_command, std::pair<user_command, user_command>> commandfallbacks = {
|
||||
{ user_command::mastercontrollerset, { user_command::mastercontrollerincrease, user_command::mastercontrollerdecrease } },
|
||||
{ user_command::secondcontrollerset, { user_command::secondcontrollerincrease, user_command::secondcontrollerdecrease } },
|
||||
{ user_command::trainbrakeset, { user_command::trainbrakeincrease, user_command::trainbrakedecrease } },
|
||||
{ user_command::independentbrakeset, { user_command::independentbrakeincrease, user_command::independentbrakedecrease } },
|
||||
{ user_command::linebreakeropen, { user_command::linebreakertoggle, user_command::none } },
|
||||
{ user_command::linebreakerclose, { user_command::linebreakertoggle, user_command::none } },
|
||||
{ user_command::pantographlowerfront, { user_command::pantographtogglefront, user_command::none } },
|
||||
{ user_command::pantographlowerrear, { user_command::pantographtogglerear, user_command::none } },
|
||||
};
|
||||
|
||||
std::pair<user_command, user_command>
|
||||
driver_mode::drivermode_input::command_fallback( user_command const Command ) const {
|
||||
|
||||
if( Command == user_command::none ) {
|
||||
return { user_command::none, user_command::none };
|
||||
}
|
||||
|
||||
auto const lookup { commandfallbacks.find( Command ) };
|
||||
|
||||
if( lookup == commandfallbacks.end() ) {
|
||||
return { user_command::none, user_command::none };
|
||||
}
|
||||
|
||||
return lookup->second;
|
||||
}
|
||||
|
||||
|
||||
|
||||
driver_mode::driver_mode() {
|
||||
|
||||
m_userinterface = std::make_shared<driver_ui>();
|
||||
@@ -217,6 +262,7 @@ driver_mode::update() {
|
||||
// fixed step render time routines
|
||||
|
||||
fTime50Hz += deltarealtime; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek
|
||||
bool runonce { false };
|
||||
while( fTime50Hz >= 1.0 / 50.0 ) {
|
||||
Console::Update(); // to i tak trzeba wywoływać
|
||||
ui::Transcripts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie
|
||||
@@ -232,6 +278,52 @@ driver_mode::update() {
|
||||
if( std::abs( DebugCamera.Velocity.y ) < 0.01 ) { DebugCamera.Velocity.y = 0.0; }
|
||||
if( std::abs( DebugCamera.Velocity.z ) < 0.01 ) { DebugCamera.Velocity.z = 0.0; }
|
||||
|
||||
if( false == runonce ) {
|
||||
// tooltip update
|
||||
set_tooltip( "" );
|
||||
auto const *train{ simulation::Train };
|
||||
if( ( train != nullptr ) && ( false == FreeFlyModeFlag ) ) {
|
||||
if( false == DebugModeFlag ) {
|
||||
// in regular mode show control functions, for defined controls
|
||||
auto const controlname { train->GetLabel( GfxRenderer->Pick_Control() ) };
|
||||
if( false == controlname.empty() ) {
|
||||
auto const bindings { m_input.mouse.bindings( controlname ) };
|
||||
auto inputhints { m_input.command_hints( bindings ) };
|
||||
// if the commands bound with the control don't have any assigned keys try potential fallbacks
|
||||
if( inputhints.empty() ) {
|
||||
inputhints = m_input.command_hints( m_input.command_fallback( bindings.first ) );
|
||||
}
|
||||
if( inputhints.empty() ) {
|
||||
inputhints = m_input.command_hints( m_input.command_fallback( bindings.second ) );
|
||||
}
|
||||
// ready or not, here we go
|
||||
if( inputhints.empty() ) {
|
||||
set_tooltip( locale::label_cab_control( controlname ) );
|
||||
}
|
||||
else {
|
||||
set_tooltip(
|
||||
locale::label_cab_control( controlname )
|
||||
+ " [" + inputhints + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// in debug mode show names of submodels, to help with cab setup and/or debugging
|
||||
auto const cabcontrol = GfxRenderer->Pick_Control();
|
||||
set_tooltip( ( cabcontrol ? cabcontrol->pName : "" ) );
|
||||
}
|
||||
}
|
||||
if( ( true == Global.ControlPicking ) && ( true == FreeFlyModeFlag ) && ( true == DebugModeFlag ) ) {
|
||||
auto const scenerynode = GfxRenderer->Pick_Node();
|
||||
set_tooltip(
|
||||
( scenerynode ?
|
||||
scenerynode->name() :
|
||||
"" ) );
|
||||
}
|
||||
|
||||
runonce = true;
|
||||
}
|
||||
|
||||
fTime50Hz -= 1.0 / 50.0;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,10 @@ private:
|
||||
|
||||
bool init();
|
||||
void poll();
|
||||
std::string
|
||||
command_hints( std::pair<user_command, user_command> const &Commands ) const;
|
||||
std::pair<user_command, user_command>
|
||||
command_fallback( user_command const Command ) const;
|
||||
};
|
||||
|
||||
// methods
|
||||
|
||||
@@ -372,70 +372,70 @@ drivermouse_input::button( int const Button, int const Action ) {
|
||||
bool pickwaiting = m_pickwaiting;
|
||||
m_pickwaiting = false;
|
||||
|
||||
auto const lookup = m_buttonbindings.find( simulation::Train->GetLabel( control ) );
|
||||
if( lookup != m_buttonbindings.end() ) {
|
||||
// if the recognized element under the cursor has a command associated with the pressed button, notify the recipient
|
||||
mousecommand = (
|
||||
Button == GLFW_MOUSE_BUTTON_LEFT ?
|
||||
lookup->second.left :
|
||||
lookup->second.right
|
||||
);
|
||||
if( mousecommand == user_command::none ) { return; }
|
||||
// check manually for commands which have 'fast' variants launched with shift modifier
|
||||
if( Global.shiftState ) {
|
||||
switch( mousecommand ) {
|
||||
case user_command::mastercontrollerincrease: { mousecommand = user_command::mastercontrollerincreasefast; break; }
|
||||
case user_command::mastercontrollerdecrease: { mousecommand = user_command::mastercontrollerdecreasefast; break; }
|
||||
case user_command::secondcontrollerincrease: { mousecommand = user_command::secondcontrollerincreasefast; break; }
|
||||
case user_command::secondcontrollerdecrease: { mousecommand = user_command::secondcontrollerdecreasefast; break; }
|
||||
case user_command::independentbrakeincrease: { mousecommand = user_command::independentbrakeincreasefast; break; }
|
||||
case user_command::independentbrakedecrease: { mousecommand = user_command::independentbrakedecreasefast; break; }
|
||||
default: { break; }
|
||||
}
|
||||
auto const controlbindings { bindings( simulation::Train->GetLabel( control ) ) };
|
||||
// if the recognized element under the cursor has a command associated with the pressed button, notify the recipient
|
||||
mousecommand = (
|
||||
Button == GLFW_MOUSE_BUTTON_LEFT ?
|
||||
controlbindings.first :
|
||||
controlbindings.second
|
||||
);
|
||||
|
||||
if( mousecommand == user_command::none ) {
|
||||
// if we don't have any recognized element under the cursor and the right button was pressed, enter view panning mode
|
||||
if( Button == GLFW_MOUSE_BUTTON_RIGHT ) {
|
||||
m_pickmodepanning = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// check manually for commands which have 'fast' variants launched with shift modifier
|
||||
if( Global.shiftState ) {
|
||||
switch( mousecommand ) {
|
||||
case user_command::mastercontrollerincrease: { mousecommand = user_command::mastercontrollerincreasefast; break; }
|
||||
case user_command::mastercontrollerdecrease: { mousecommand = user_command::mastercontrollerdecreasefast; break; }
|
||||
case user_command::secondcontrollerincrease: { mousecommand = user_command::secondcontrollerincreasefast; break; }
|
||||
case user_command::secondcontrollerdecrease: { mousecommand = user_command::secondcontrollerdecreasefast; break; }
|
||||
case user_command::independentbrakeincrease: { mousecommand = user_command::independentbrakeincreasefast; break; }
|
||||
case user_command::independentbrakedecrease: { mousecommand = user_command::independentbrakedecreasefast; break; }
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
|
||||
switch( mousecommand ) {
|
||||
case user_command::mastercontrollerincrease:
|
||||
case user_command::mastercontrollerdecrease:
|
||||
case user_command::secondcontrollerincrease:
|
||||
case user_command::secondcontrollerdecrease:
|
||||
case user_command::trainbrakeincrease:
|
||||
case user_command::trainbrakedecrease:
|
||||
case user_command::independentbrakeincrease:
|
||||
case user_command::independentbrakedecrease: {
|
||||
// these commands trigger varying repeat rate mode,
|
||||
// which scales the rate based on the distance of the cursor from its point when the command was first issued
|
||||
m_varyingpollrateorigin = m_cursorposition;
|
||||
m_varyingpollrate = true;
|
||||
break;
|
||||
}
|
||||
case user_command::jointcontrollerset:
|
||||
case user_command::mastercontrollerset:
|
||||
case user_command::secondcontrollerset:
|
||||
case user_command::trainbrakeset:
|
||||
case user_command::independentbrakeset: {
|
||||
m_slider.bind( mousecommand );
|
||||
mousecommand = user_command::none;
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
switch( mousecommand ) {
|
||||
case user_command::mastercontrollerincrease:
|
||||
case user_command::mastercontrollerdecrease:
|
||||
case user_command::secondcontrollerincrease:
|
||||
case user_command::secondcontrollerdecrease:
|
||||
case user_command::trainbrakeincrease:
|
||||
case user_command::trainbrakedecrease:
|
||||
case user_command::independentbrakeincrease:
|
||||
case user_command::independentbrakedecrease: {
|
||||
// these commands trigger varying repeat rate mode,
|
||||
// which scales the rate based on the distance of the cursor from its point when the command was first issued
|
||||
m_varyingpollrateorigin = m_cursorposition;
|
||||
m_varyingpollrate = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// NOTE: basic keyboard controls don't have any parameters
|
||||
// NOTE: as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
m_relay.post( mousecommand, 0, 0, Action, 0 );
|
||||
if (!pickwaiting) // already depressed
|
||||
m_relay.post( mousecommand, 0, 0, GLFW_RELEASE, 0 );
|
||||
m_updateaccumulator = -0.25; // prevent potential command repeat right after issuing one
|
||||
}
|
||||
else {
|
||||
// if we don't have any recognized element under the cursor and the right button was pressed, enter view panning mode
|
||||
if( Button == GLFW_MOUSE_BUTTON_RIGHT ) {
|
||||
m_pickmodepanning = true;
|
||||
} } } );
|
||||
case user_command::jointcontrollerset:
|
||||
case user_command::mastercontrollerset:
|
||||
case user_command::secondcontrollerset:
|
||||
case user_command::trainbrakeset:
|
||||
case user_command::independentbrakeset: {
|
||||
m_slider.bind( mousecommand );
|
||||
mousecommand = user_command::none;
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// NOTE: basic keyboard controls don't have any parameters
|
||||
// NOTE: as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
m_relay.post( mousecommand, 0, 0, Action, 0 );
|
||||
if (!pickwaiting) // already depressed
|
||||
m_relay.post( mousecommand, 0, 0, GLFW_RELEASE, 0 );
|
||||
m_updateaccumulator = -0.25; // prevent potential command repeat right after issuing one
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -495,6 +495,19 @@ drivermouse_input::command() const {
|
||||
m_mousecommandright );
|
||||
}
|
||||
|
||||
// returns pair of bindings associated with specified cab control
|
||||
std::pair<user_command, user_command>
|
||||
drivermouse_input::bindings( std::string const &Control ) const {
|
||||
|
||||
auto const lookup{ m_buttonbindings.find( Control ) };
|
||||
|
||||
if( lookup != m_buttonbindings.end() )
|
||||
return { lookup->second.left, lookup->second.right };
|
||||
else {
|
||||
return { user_command::none, user_command::none };
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
drivermouse_input::default_bindings() {
|
||||
|
||||
|
||||
@@ -66,6 +66,9 @@ public:
|
||||
poll();
|
||||
user_command
|
||||
command() const;
|
||||
// returns pair of bindings associated with specified cab control
|
||||
std::pair<user_command, user_command>
|
||||
bindings( std::string const &Control ) const;
|
||||
|
||||
private:
|
||||
// types
|
||||
|
||||
@@ -164,29 +164,6 @@ driver_ui::update() {
|
||||
}
|
||||
m_paused = ispaused;
|
||||
|
||||
set_tooltip( "" );
|
||||
|
||||
auto const *train { simulation::Train };
|
||||
|
||||
if( ( train != nullptr ) && ( false == FreeFlyModeFlag ) ) {
|
||||
if( false == DebugModeFlag ) {
|
||||
// in regular mode show control functions, for defined controls
|
||||
set_tooltip( locale::label_cab_control( train->GetLabel( GfxRenderer->Pick_Control() ) ) );
|
||||
}
|
||||
else {
|
||||
// in debug mode show names of submodels, to help with cab setup and/or debugging
|
||||
auto const cabcontrol = GfxRenderer->Pick_Control();
|
||||
set_tooltip( ( cabcontrol ? cabcontrol->pName : "" ) );
|
||||
}
|
||||
}
|
||||
if( ( true == Global.ControlPicking ) && ( true == FreeFlyModeFlag ) && ( true == DebugModeFlag ) ) {
|
||||
auto const scenerynode = GfxRenderer->Pick_Node();
|
||||
set_tooltip(
|
||||
( scenerynode ?
|
||||
scenerynode->name() :
|
||||
"" ) );
|
||||
}
|
||||
|
||||
ui_layer::update();
|
||||
}
|
||||
|
||||
|
||||
@@ -542,7 +542,25 @@ debug_panel::render() {
|
||||
render_section( "Vehicle Engine", m_enginelines );
|
||||
render_section( "Vehicle AI", m_ailines );
|
||||
render_section( "Vehicle Scan Table", m_scantablelines );
|
||||
render_section( "Scenario", m_scenariolines );
|
||||
if( true == render_section( "Scenario", m_scenariolines ) ) {
|
||||
// cloud cover slider
|
||||
if( ImGui::SliderFloat(
|
||||
( to_string(Global.Overcast, 2 ) + " (" + Global.Weather + ")###overcast" ).c_str(), &Global.Overcast, 0.0f, 2.0f, "Cloud cover" ) ) {
|
||||
Global.Overcast = clamp( Global.Overcast, 0.0f, 2.0f );
|
||||
simulation::Environment.compute_weather();
|
||||
}
|
||||
// day of year slider
|
||||
if( ImGui::SliderFloat( ( to_string( Global.fMoveLight, 0, 4 ) + " (" + Global.Season + ")###movelight" ).c_str(), &Global.fMoveLight, 0.0f, 355.0f, "Day of year" ) ) {
|
||||
Global.fMoveLight = clamp( Global.fMoveLight, 0.0f, 355.0f );
|
||||
auto const weather { Global.Weather };
|
||||
simulation::Environment.compute_season( Global.fMoveLight );
|
||||
simulation::Time.init();
|
||||
if( weather != Global.Weather ) {
|
||||
// HACK: force re-calculation of precipitation
|
||||
Global.Overcast = clamp( Global.Overcast - 0.0001f, 0.0f, 2.0f );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( true == render_section( "Scenario Event Queue", m_eventqueuelines ) ) {
|
||||
// event queue filter
|
||||
ImGui::Checkbox( "By This Vehicle Only", &m_eventqueueactivevehicleonly );
|
||||
@@ -597,8 +615,8 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
|
||||
( mover.Mains ? 'M' : '.' ),
|
||||
( mover.FuseFlag ? '!' : '.' ),
|
||||
( mover.PantsValve.is_active ? '+' : '.' ),
|
||||
( mover.Pantographs[ end::rear ].valve.is_enabled ? ( mover.Pantographs[ end::rear ].valve.is_active ? 'O' : 'o' ) : '.' ),
|
||||
( mover.Pantographs[end::front].valve.is_enabled ? ( mover.Pantographs[ end::front ].valve.is_active ? 'P' : 'p' ) : '.' ),
|
||||
( mover.Pantographs[ end::rear ].valve.is_active ? 'O' : ( mover.Pantographs[ end::rear ].valve.is_enabled ? 'o' : '.' ) ),
|
||||
( mover.Pantographs[ end::front ].valve.is_active ? 'P' : ( mover.Pantographs[ end::front ].valve.is_enabled ? 'p' : '.' ) ),
|
||||
( mover.PantPressLockActive ? '!' : ( mover.PantPressSwitchActive ? '*' : '.' ) ),
|
||||
( mover.WaterPump.is_active ? 'W' : ( false == mover.WaterPump.breaker ? '-' : ( mover.WaterPump.is_enabled ? 'w' : '.' ) ) ),
|
||||
( true == mover.WaterHeater.is_damaged ? '!' : ( mover.WaterHeater.is_active ? 'H' : ( false == mover.WaterHeater.breaker ? '-' : ( mover.WaterHeater.is_enabled ? 'h' : '.' ) ) ) ),
|
||||
@@ -987,8 +1005,7 @@ debug_panel::update_section_scenario( std::vector<text_line> &Output ) {
|
||||
|
||||
Output.emplace_back( textline, Global.UITextColor );
|
||||
// current luminance level
|
||||
textline = "Cloud cover: " + to_string( Global.Overcast, 3 );
|
||||
textline += "\nLight level: " + to_string( Global.fLuminance, 3 );
|
||||
textline = "Light level: " + to_string( Global.fLuminance, 3 ) + ( Global.FakeLight ? "(*)" : "" );
|
||||
if( Global.FakeLight ) { textline += "(*)"; }
|
||||
textline +=
|
||||
"\nWind: azimuth "
|
||||
|
||||
@@ -159,8 +159,8 @@ keyboard_input::key( int const Key, int const Action ) {
|
||||
| ( modifier ? 0 : ( input::key_shift ? keymodifier::shift : 0 ) )
|
||||
| ( modifier ? 0 : ( input::key_ctrl ? keymodifier::control : 0 ) );
|
||||
|
||||
auto const lookup = m_bindings.find( key );
|
||||
if( lookup == m_bindings.end() ) {
|
||||
auto const lookup = m_commands.find( key );
|
||||
if( lookup == m_commands.end() ) {
|
||||
// no binding for this key
|
||||
return false;
|
||||
}
|
||||
@@ -187,7 +187,8 @@ keyboard_input::bind() {
|
||||
|
||||
for( auto const &bindingsetup : m_bindingsetups ) {
|
||||
|
||||
m_bindings[ bindingsetup.binding ] = bindingsetup.command;
|
||||
m_commands[ bindingsetup.binding ] = bindingsetup.command;
|
||||
m_bindings[ bindingsetup.command ] = bindingsetup.binding;
|
||||
}
|
||||
// cache movement key bindings
|
||||
m_bindingscache.forward = binding( user_command::moveforward );
|
||||
@@ -201,12 +202,11 @@ keyboard_input::bind() {
|
||||
int
|
||||
keyboard_input::binding( user_command const Command ) const {
|
||||
|
||||
for( auto const &binding : m_bindings ) {
|
||||
if( binding.second == Command ) {
|
||||
return binding.first;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
auto const lookup{ m_bindings.find( Command ) };
|
||||
return (
|
||||
lookup != m_bindings.end() ?
|
||||
lookup->second :
|
||||
-1 );
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -274,4 +274,50 @@ keyboard_input::poll() {
|
||||
m_movementvertical = movementvertical;
|
||||
}
|
||||
|
||||
std::unordered_map<int, std::string> keytonamemap = {
|
||||
{ GLFW_KEY_0, "0" }, { GLFW_KEY_1, "1" }, { GLFW_KEY_2, "2" }, { GLFW_KEY_3, "3" }, { GLFW_KEY_4, "4" },
|
||||
{ GLFW_KEY_5, "5" }, { GLFW_KEY_6, "6" }, { GLFW_KEY_7, "7" }, { GLFW_KEY_8, "8" }, { GLFW_KEY_9, "9" },
|
||||
{ GLFW_KEY_MINUS, "-" }, { GLFW_KEY_EQUAL, "=" },
|
||||
{ GLFW_KEY_A, "A" }, { GLFW_KEY_B, "B" }, { GLFW_KEY_C, "C" }, { GLFW_KEY_D, "D" }, { GLFW_KEY_E, "E" },
|
||||
{ GLFW_KEY_F, "F" }, { GLFW_KEY_G, "G" }, { GLFW_KEY_H, "H" }, { GLFW_KEY_I, "I" }, { GLFW_KEY_J, "J" },
|
||||
{ GLFW_KEY_K, "K" }, { GLFW_KEY_L, "L" }, { GLFW_KEY_M, "M" }, { GLFW_KEY_N, "N" }, { GLFW_KEY_O, "O" },
|
||||
{ GLFW_KEY_P, "P" }, { GLFW_KEY_Q, "Q" }, { GLFW_KEY_R, "R" }, { GLFW_KEY_S, "S" }, { GLFW_KEY_T, "T" },
|
||||
{ GLFW_KEY_U, "U" }, { GLFW_KEY_V, "V" }, { GLFW_KEY_W, "W" }, { GLFW_KEY_X, "X" }, { GLFW_KEY_Y, "Y" }, { GLFW_KEY_Z, "Z" },
|
||||
{ GLFW_KEY_BACKSPACE, "BACKSPACE" },
|
||||
{ GLFW_KEY_LEFT_BRACKET, "[" }, { GLFW_KEY_RIGHT_BRACKET, "]" }, { GLFW_KEY_BACKSLASH, "\\" },
|
||||
{ GLFW_KEY_SEMICOLON, ";" }, { GLFW_KEY_APOSTROPHE, "'" }, { GLFW_KEY_ENTER, "ENTER" },
|
||||
{ GLFW_KEY_COMMA, "<" }, { GLFW_KEY_PERIOD, ">" }, { GLFW_KEY_SLASH, "/" },
|
||||
{ GLFW_KEY_SPACE, "SPACE" },
|
||||
{ GLFW_KEY_PAUSE, "PAUSE" }, { GLFW_KEY_INSERT, "INSERT" }, { GLFW_KEY_DELETE, "DELETE" }, { GLFW_KEY_HOME, "HOME" }, { GLFW_KEY_END, "END" },
|
||||
// numpad block
|
||||
{ GLFW_KEY_KP_DIVIDE, "NUM /" }, { GLFW_KEY_KP_MULTIPLY, "NUM *" }, { GLFW_KEY_KP_SUBTRACT, "NUM -" },
|
||||
{ GLFW_KEY_KP_7, "NUM 7" }, { GLFW_KEY_KP_8, "NUM 8" }, { GLFW_KEY_KP_9, "NUM 9" }, { GLFW_KEY_KP_ADD, "NUM +" },
|
||||
{ GLFW_KEY_KP_4, "NUM 4" }, { GLFW_KEY_KP_5, "NUM 5" }, { GLFW_KEY_KP_6, "NUM 6" },
|
||||
{ GLFW_KEY_KP_1, "NUM 1" }, { GLFW_KEY_KP_2, "NUM 2" }, { GLFW_KEY_KP_3, "NUM 3" }, { GLFW_KEY_KP_ENTER, "NUM ENTER" },
|
||||
{ GLFW_KEY_KP_0, "NUM 0" }, { GLFW_KEY_KP_DECIMAL, "NUM ." }
|
||||
};
|
||||
|
||||
std::string
|
||||
keyboard_input::mapping( user_command const Command ) const {
|
||||
|
||||
if( Command == user_command::none ) { return ""; }
|
||||
|
||||
auto const binding { this->binding( Command ) };
|
||||
if( binding == -1 ) { return ""; }
|
||||
|
||||
auto const lookup { keytonamemap.find( binding & 0xffff ) };
|
||||
if( lookup == keytonamemap.end() ) { return ""; }
|
||||
|
||||
std::string mapping;
|
||||
if( ( binding & keymodifier::shift ) != 0 ) {
|
||||
mapping += "SHIFT ";
|
||||
}
|
||||
if( ( binding & keymodifier::control ) != 0 ) {
|
||||
mapping += "CTRL ";
|
||||
}
|
||||
mapping += lookup->second;
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -45,6 +45,8 @@ public:
|
||||
user_command const
|
||||
command() const {
|
||||
return m_command; }
|
||||
std::string
|
||||
mapping( user_command const Command ) const;
|
||||
|
||||
protected:
|
||||
// types
|
||||
@@ -77,6 +79,7 @@ protected:
|
||||
private:
|
||||
// types
|
||||
using usercommand_map = std::unordered_map<int, user_command>;
|
||||
using binding_map = std::unordered_map<user_command, int>;
|
||||
|
||||
struct bindings_cache {
|
||||
|
||||
@@ -96,7 +99,8 @@ private:
|
||||
|
||||
// members
|
||||
user_command m_command { user_command::none }; // last, if any, issued command
|
||||
usercommand_map m_bindings;
|
||||
usercommand_map m_commands;
|
||||
binding_map m_bindings;
|
||||
command_relay m_relay;
|
||||
bindings_cache m_bindingscache;
|
||||
glm::vec2 m_movementhorizontal { 0.f };
|
||||
|
||||
101
material.cpp
101
material.cpp
@@ -17,6 +17,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
|
||||
opengl_material::path_data opengl_material::paths;
|
||||
|
||||
opengl_material::opengl_material()
|
||||
{
|
||||
for (size_t i = 0; i < params.size(); i++)
|
||||
@@ -32,6 +34,21 @@ opengl_material::deserialize( cParser &Input, bool const Loadnow ) {
|
||||
result = true; // once would suffice but, eh
|
||||
}
|
||||
|
||||
if( ( path == -1 )
|
||||
&& ( update_on_weather_change || update_on_season_change ) ) {
|
||||
// record current texture path in the material, potentially needed when material is reloaded on environment change
|
||||
// NOTE: we're storing this only for textures that can actually change, to keep the size of path database modest
|
||||
auto const lookup{ paths.index_map.find( Global.asCurrentTexturePath ) };
|
||||
if( lookup != paths.index_map.end() ) {
|
||||
path = lookup->second;
|
||||
}
|
||||
else {
|
||||
path = paths.data.size();
|
||||
paths.data.emplace_back( Global.asCurrentTexturePath );
|
||||
paths.index_map.emplace( Global.asCurrentTexturePath, path );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -94,19 +111,20 @@ void opengl_material::finalize(bool Loadnow)
|
||||
|
||||
if (!shader)
|
||||
{
|
||||
// TODO: add error severity to logging, re-enable these errors as low severity messages
|
||||
if (textures[0] == null_handle)
|
||||
{
|
||||
log_error("shader not specified, assuming \"default_0\"");
|
||||
// log_error("shader not specified, assuming \"default_0\"");
|
||||
shader = GfxRenderer->Fetch_Shader("default_0");
|
||||
}
|
||||
else if (textures[1] == null_handle)
|
||||
{
|
||||
log_error("shader not specified, assuming \"default_1\"");
|
||||
// log_error("shader not specified, assuming \"default_1\"");
|
||||
shader = GfxRenderer->Fetch_Shader("default_1");
|
||||
}
|
||||
else if (textures[2] == null_handle)
|
||||
{
|
||||
log_error("shader not specified, assuming \"default_2\"");
|
||||
// log_error("shader not specified, assuming \"default_2\"");
|
||||
shader = GfxRenderer->Fetch_Shader("default_2");
|
||||
}
|
||||
}
|
||||
@@ -198,6 +216,55 @@ void opengl_material::finalize(bool Loadnow)
|
||||
}
|
||||
}
|
||||
|
||||
bool opengl_material::update() {
|
||||
|
||||
auto const texturepathbackup { Global.asCurrentTexturePath };
|
||||
auto const namebackup { name };
|
||||
auto const pathbackup { path };
|
||||
cParser materialparser( name + ".mat", cParser::buffer_FILE ); // fairly safe to presume .mat is present for branching materials
|
||||
|
||||
// temporarily set texture path to state recorded in the material
|
||||
Global.asCurrentTexturePath = paths.data[ path ];
|
||||
|
||||
// clean material slate, restore relevant members
|
||||
*this = opengl_material();
|
||||
name = namebackup;
|
||||
path = pathbackup;
|
||||
|
||||
auto result { false };
|
||||
|
||||
if( true == deserialize( materialparser, true ) ) {
|
||||
try {
|
||||
finalize( true );
|
||||
result = true;
|
||||
}
|
||||
catch( gl::shader_exception const &e ) {
|
||||
ErrorLog( "invalid shader: " + std::string( e.what() ) );
|
||||
}
|
||||
}
|
||||
// restore texture path
|
||||
Global.asCurrentTexturePath = texturepathbackup;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> seasons = {
|
||||
"winter:", "spring:", "summer:", "autumn:"
|
||||
};
|
||||
|
||||
bool is_season( std::string const &String ) {
|
||||
|
||||
return ( seasons.find( String ) != seasons.end() );
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> weather = {
|
||||
"clear:", "cloudy:", "rain:", "snow:" };
|
||||
|
||||
bool is_weather( std::string const &String ) {
|
||||
|
||||
return ( weather.find( String ) != weather.end() );
|
||||
}
|
||||
|
||||
// imports member data pair from the config file
|
||||
bool
|
||||
opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool const Loadnow ) {
|
||||
@@ -209,6 +276,11 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c
|
||||
|
||||
if( Priority != -1 ) {
|
||||
// regular attribute processing mode
|
||||
|
||||
// mark potential material change
|
||||
update_on_weather_change |= is_weather( key );
|
||||
update_on_season_change |= is_season( key );
|
||||
|
||||
if( key == Global.Weather ) {
|
||||
// weather textures override generic (pri 0) and seasonal (pri 1) textures
|
||||
// seasonal weather textures (pri 1+2=3) override generic weather (pri 2) textures
|
||||
@@ -433,14 +505,13 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
|
||||
|
||||
if( false == material.name.empty() ) {
|
||||
// if we have material name and shader it means resource was processed succesfully
|
||||
try {
|
||||
materialhandle = m_materials.size();
|
||||
m_materialmappings.emplace( material.name, materialhandle );
|
||||
try {
|
||||
material.finalize(Loadnow);
|
||||
materialhandle = m_materials.size();
|
||||
m_materialmappings.emplace( material.name, materialhandle );
|
||||
m_materials.emplace_back( std::move(material) );
|
||||
} catch (gl::shader_exception const &e) {
|
||||
ErrorLog("invalid shader: " + std::string(e.what()));
|
||||
m_materialmappings.emplace( filename, materialhandle );
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -451,6 +522,22 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
|
||||
return materialhandle;
|
||||
};
|
||||
|
||||
void
|
||||
material_manager::on_weather_change() {
|
||||
|
||||
for( auto &material : m_materials ) {
|
||||
if( material.update_on_weather_change ) { material.update(); }
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
material_manager::on_season_change() {
|
||||
|
||||
for( auto &material : m_materials ) {
|
||||
if( material.update_on_season_change ) { material.update(); }
|
||||
}
|
||||
}
|
||||
|
||||
// checks whether specified material is in the material bank. returns handle to the material, or a null handle
|
||||
material_handle
|
||||
material_manager::find_in_databank( std::string const &Materialname ) const {
|
||||
|
||||
17
material.h
17
material.h
@@ -38,10 +38,18 @@ struct opengl_material {
|
||||
bool
|
||||
deserialize( cParser &Input, bool const Loadnow );
|
||||
void finalize(bool Loadnow);
|
||||
bool update();
|
||||
float get_or_guess_opacity() const;
|
||||
bool is_translucent() const;
|
||||
// members
|
||||
static struct path_data {
|
||||
std::unordered_map<std::string, int> index_map;
|
||||
std::vector<std::string> data;
|
||||
} paths;
|
||||
bool is_good { false }; // indicates material was compiled without failure
|
||||
int path{ -1 }; // index to material path
|
||||
bool update_on_weather_change{ false };
|
||||
bool update_on_season_change{ false };
|
||||
|
||||
private:
|
||||
// methods
|
||||
@@ -49,9 +57,6 @@ private:
|
||||
bool
|
||||
deserialize_mapping( cParser &Input, int const Priority, bool const Loadnow );
|
||||
void log_error(const std::string &str);
|
||||
// extracts name of the sound file from provided data stream
|
||||
std::string
|
||||
deserialize_filename( cParser &Input );
|
||||
|
||||
// members
|
||||
// priorities for textures, shader, opacity
|
||||
@@ -89,6 +94,12 @@ public:
|
||||
material( material_handle const Material ) const { return m_materials[ Material ]; }
|
||||
opengl_material &
|
||||
material( material_handle const Material ) { return m_materials[ Material ]; }
|
||||
// material updates executed when environment changes
|
||||
// TODO: registerable callbacks in environment manager
|
||||
void
|
||||
on_weather_change();
|
||||
void
|
||||
on_season_change();
|
||||
|
||||
private:
|
||||
// types
|
||||
|
||||
@@ -113,7 +113,7 @@ OnCommandGet(multiplayer::DaneRozkaz *pRozkaz)
|
||||
if (*pRozkaz->iPar == 0) // sprawdzenie czasu
|
||||
if (*pRozkaz->iPar & 1) // ustawienie czasu
|
||||
{
|
||||
double t = pRozkaz->fPar[1];
|
||||
auto t = pRozkaz->fPar[1];
|
||||
simulation::Time.data().wDay = std::floor(t); // niby nie powinno być dnia, ale...
|
||||
if (Global.fMoveLight >= 0)
|
||||
Global.fMoveLight = t; // trzeba by deklinację Słońca przeliczyć
|
||||
|
||||
@@ -1597,9 +1597,14 @@ bool opengl33_renderer::Render(world_environment *Environment)
|
||||
if (Environment->m_clouds.mdCloud)
|
||||
{
|
||||
// setup
|
||||
glm::vec3 color = interpolate(Environment->m_skydome.GetAverageColor(), suncolor, duskfactor * 0.25f) * interpolate(1.f, 0.35f, Global.Overcast / 2.f) // overcast darkens the clouds
|
||||
* 0.5f;
|
||||
|
||||
glm::vec3 color =
|
||||
interpolate(
|
||||
Environment->m_skydome.GetAverageColor(), suncolor,
|
||||
duskfactor * 0.25f)
|
||||
* interpolate(
|
||||
1.f, 0.35f,
|
||||
Global.Overcast / 2.f) // overcast darkens the clouds
|
||||
* 0.5f;
|
||||
// write cloud color into material
|
||||
TSubModel *mdl = Environment->m_clouds.mdCloud->Root;
|
||||
if (mdl->m_material != null_handle)
|
||||
@@ -1751,17 +1756,18 @@ void opengl33_renderer::Bind_Material(material_handle const Material, TSubModel
|
||||
model_ubs.param[entry.location][entry.offset + j] = src[j];
|
||||
}
|
||||
|
||||
if (m_blendingenabled)
|
||||
{
|
||||
model_ubs.opacity = -1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!std::isnan(material.opacity))
|
||||
model_ubs.opacity = material.opacity;
|
||||
else
|
||||
model_ubs.opacity = 0.5f;
|
||||
}
|
||||
if( !std::isnan( material.opacity ) ) {
|
||||
model_ubs.opacity = (
|
||||
m_blendingenabled ?
|
||||
-material.opacity :
|
||||
material.opacity );
|
||||
}
|
||||
else {
|
||||
model_ubs.opacity = (
|
||||
m_blendingenabled ?
|
||||
0.0f :
|
||||
0.5f );
|
||||
}
|
||||
|
||||
if (sm)
|
||||
model_ubs.alpha_mult = sm->fVisible;
|
||||
@@ -3926,6 +3932,19 @@ void opengl33_renderer::Update(double const Deltatime)
|
||||
}
|
||||
}
|
||||
|
||||
// update resources if there was environmental change
|
||||
simulation_state simulationstate {
|
||||
Global.Weather,
|
||||
Global.Season
|
||||
};
|
||||
std::swap( m_simulationstate, simulationstate );
|
||||
if( ( m_simulationstate.season != simulationstate.season ) && ( false == simulationstate.season.empty() ) ) {
|
||||
m_materials.on_season_change();
|
||||
}
|
||||
if( ( m_simulationstate.weather != simulationstate.weather ) && ( false == simulationstate.weather.empty() ) ) {
|
||||
m_materials.on_weather_change();
|
||||
}
|
||||
|
||||
if ((true == Global.ResourceSweep) && (true == simulation::is_ready))
|
||||
{
|
||||
// garbage collection
|
||||
|
||||
@@ -300,6 +300,10 @@ class opengl33_renderer : public gfx_renderer {
|
||||
std::string m_pickdebuginfo;
|
||||
//debug_stats m_debugstats;
|
||||
std::string m_debugstatstext;
|
||||
struct simulation_state {
|
||||
std::string weather;
|
||||
std::string season;
|
||||
} m_simulationstate;
|
||||
|
||||
glm::vec4 m_baseambient{0.0f, 0.0f, 0.0f, 1.0f};
|
||||
glm::vec4 m_shadowcolor{colors::shadow};
|
||||
|
||||
@@ -3601,14 +3601,14 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
||||
#endif
|
||||
// material configuration:
|
||||
// textures...
|
||||
if( Submodel->m_material < 0 ) { // zmienialne skóry
|
||||
Bind_Material( Submodel->ReplacableSkinId[ -Submodel->m_material ] );
|
||||
}
|
||||
else {
|
||||
// również 0
|
||||
Bind_Material( Submodel->m_material );
|
||||
}
|
||||
// ...colors...
|
||||
auto const material { (
|
||||
Submodel->m_material < 0 ?
|
||||
Submodel->ReplacableSkinId[ -Submodel->m_material ] : // zmienialne skóry
|
||||
Submodel->m_material ) }; // również 0
|
||||
// textures...
|
||||
Bind_Material( material );
|
||||
// ...colors and opacity...
|
||||
auto const opacity { clamp( Material( material ).get_or_guess_opacity(), 0.f, 1.f ) };
|
||||
if( Submodel->fVisible < 1.f ) {
|
||||
::glColor4f(
|
||||
Submodel->f4Diffuse.r,
|
||||
@@ -3619,6 +3619,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
||||
else {
|
||||
::glColor3fv( glm::value_ptr( Submodel->f4Diffuse ) ); // McZapkie-240702: zamiast ub
|
||||
}
|
||||
if( opacity != 0.f ) {
|
||||
// discard fragments with opacity exceeding the threshold
|
||||
::glAlphaFunc( GL_LEQUAL, opacity );
|
||||
}
|
||||
if( ( true == m_renderspecular ) && ( m_sunlight.specular.a > 0.01f ) ) {
|
||||
::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( Submodel->f4Specular * m_sunlight.specular.a * m_speculartranslucentscalefactor ) );
|
||||
}
|
||||
@@ -3639,6 +3643,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
||||
m_geometry.draw( Submodel->m_geometry );
|
||||
|
||||
// post-draw reset
|
||||
if( opacity != 0.f ) {
|
||||
// discard fragments with opacity exceeding the threshold
|
||||
::glAlphaFunc( GL_GREATER, 0.0f );
|
||||
}
|
||||
if( ( true == m_renderspecular ) && ( m_sunlight.specular.a > 0.01f ) ) {
|
||||
::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( colors::none ) );
|
||||
}
|
||||
@@ -4032,6 +4040,19 @@ opengl_renderer::Update( double const Deltatime ) {
|
||||
}
|
||||
}
|
||||
|
||||
// update resources if there was environmental change
|
||||
simulation_state simulationstate {
|
||||
Global.Weather,
|
||||
Global.Season
|
||||
};
|
||||
std::swap( m_simulationstate, simulationstate );
|
||||
if( ( m_simulationstate.season != simulationstate.season ) && ( false == simulationstate.season.empty() ) ) {
|
||||
m_materials.on_season_change();
|
||||
}
|
||||
if( ( m_simulationstate.weather != simulationstate.weather ) && ( false == simulationstate.weather.empty() ) ) {
|
||||
m_materials.on_weather_change();
|
||||
}
|
||||
|
||||
if( ( true == Global.ResourceSweep )
|
||||
&& ( true == simulation::is_ready ) ) {
|
||||
// garbage collection
|
||||
|
||||
@@ -320,6 +320,10 @@ private:
|
||||
std::string m_debugtimestext;
|
||||
std::string m_pickdebuginfo;
|
||||
std::string m_debugstatstext;
|
||||
struct simulation_state {
|
||||
std::string weather;
|
||||
std::string season;
|
||||
} m_simulationstate;
|
||||
|
||||
glm::vec4 m_baseambient { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
glm::vec4 m_shadowcolor { colors::shadow };
|
||||
|
||||
@@ -169,15 +169,16 @@ world_environment::update() {
|
||||
Global.FogColor = m_skydome.GetAverageHorizonColor();
|
||||
|
||||
// weather-related simulation factors
|
||||
// TODO: dynamic change of air temperature and overcast levels
|
||||
Global.FrictionWeatherFactor = (
|
||||
Global.Weather == "rain:" ? 0.85f :
|
||||
Global.Weather == "snow:" ? 0.75f :
|
||||
1.0f );
|
||||
|
||||
if( Global.Weather == "rain:" ) {
|
||||
// reduce friction in rain
|
||||
Global.FrictionWeatherFactor = 0.85f;
|
||||
m_precipitationsound.play( sound_flags::exclusive | sound_flags::looping );
|
||||
}
|
||||
else if( Global.Weather == "snow:" ) {
|
||||
// reduce friction due to snow
|
||||
Global.FrictionWeatherFactor = 0.75f;
|
||||
else {
|
||||
m_precipitationsound.stop();
|
||||
}
|
||||
|
||||
update_wind();
|
||||
|
||||
@@ -34,7 +34,7 @@ scenario_time::init() {
|
||||
// cache requested elements, if any
|
||||
::GetLocalTime( &m_time );
|
||||
|
||||
if( Global.fMoveLight > 0.0 ) {
|
||||
if( Global.fMoveLight > 0.f ) {
|
||||
// day and month of the year can be overriden by scenario setup
|
||||
daymonth( m_time.wDay, m_time.wMonth, m_time.wYear, static_cast<WORD>( Global.fMoveLight ) );
|
||||
}
|
||||
|
||||
23
sound.cpp
23
sound.cpp
@@ -117,20 +117,23 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons
|
||||
}
|
||||
|
||||
if( Legacyparameters & sound_parameters::range ) {
|
||||
Input.getTokens( 1, false );
|
||||
Input >> m_range;
|
||||
if( Input.getTokens( 1, false ) ) {
|
||||
Input >> m_range;
|
||||
}
|
||||
}
|
||||
if( Legacyparameters & sound_parameters::amplitude ) {
|
||||
Input.getTokens( 2, false );
|
||||
Input
|
||||
>> m_amplitudefactor
|
||||
>> m_amplitudeoffset;
|
||||
if( Input.getTokens( 2, false ) ) {
|
||||
Input
|
||||
>> m_amplitudefactor
|
||||
>> m_amplitudeoffset;
|
||||
}
|
||||
}
|
||||
if( Legacyparameters & sound_parameters::frequency ) {
|
||||
Input.getTokens( 2, false );
|
||||
Input
|
||||
>> m_frequencyfactor
|
||||
>> m_frequencyoffset;
|
||||
if( Input.getTokens( 2, false ) ) {
|
||||
Input
|
||||
>> m_frequencyfactor
|
||||
>> m_frequencyoffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
// restore parser behaviour
|
||||
|
||||
@@ -85,6 +85,20 @@ init() {
|
||||
"second controller",
|
||||
"shunt mode power",
|
||||
"tempomat",
|
||||
"tempomat (speed)",
|
||||
"tempomat (speed)",
|
||||
"tempomat (power)",
|
||||
"tempomat (power)",
|
||||
"tempomat (speed)",
|
||||
"tempomat (speed)",
|
||||
"tempomat (speed)",
|
||||
"tempomat (speed)",
|
||||
"tempomat (speed)",
|
||||
"tempomat (speed)",
|
||||
"tempomat (speed)",
|
||||
"tempomat (speed)",
|
||||
"tempomat (speed)",
|
||||
"tempomat (speed)",
|
||||
"distance counter",
|
||||
"reverser",
|
||||
"train brake",
|
||||
@@ -114,6 +128,9 @@ init() {
|
||||
"spring brake",
|
||||
"spring brake",
|
||||
"spring brake",
|
||||
"train brake",
|
||||
"train brake",
|
||||
"train brake",
|
||||
"electro-pneumatic brake",
|
||||
"sandbox",
|
||||
"wheelspin brake",
|
||||
@@ -163,6 +180,9 @@ init() {
|
||||
"radiostop test",
|
||||
"radiostop",
|
||||
"radio call 3",
|
||||
"radio volume",
|
||||
"radio volume",
|
||||
"radio volume",
|
||||
"pantograph A",
|
||||
"pantograph B",
|
||||
"pantograph A",
|
||||
@@ -260,6 +280,20 @@ init() {
|
||||
"nastawnik dodatkowy",
|
||||
"sterowanie analogowe",
|
||||
"tempomat",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (moc)",
|
||||
"tempomat (moc)",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (predkosc)",
|
||||
"tempomat (predkosc)",
|
||||
"miernik odleglosci",
|
||||
"nastawnik kierunku",
|
||||
"hamulec zespolony",
|
||||
@@ -289,6 +323,9 @@ init() {
|
||||
"hamulec sprezynowy",
|
||||
"hamulec sprezynowy",
|
||||
"hamulec sprezynowy",
|
||||
"hamulec zespolony",
|
||||
"hamulec zespolony",
|
||||
"hamulec zespolony",
|
||||
"hamulec elektropneumatyczny",
|
||||
"piasecznica",
|
||||
"hamulec przeciwposlizgowy",
|
||||
@@ -338,6 +375,9 @@ init() {
|
||||
"test radiostopu",
|
||||
"radiostop",
|
||||
"zew 3",
|
||||
"glosnosc radia",
|
||||
"glosnosc radia",
|
||||
"glosnosc radia",
|
||||
"pantograf A",
|
||||
"pantograf B",
|
||||
"pantograf A",
|
||||
@@ -388,6 +428,20 @@ init() {
|
||||
"scndctrl:",
|
||||
"shuntmodepower:",
|
||||
"tempomat_sw:",
|
||||
"speedinc_bt:",
|
||||
"speeddec_bt:",
|
||||
"speedctrlpowerinc_bt:",
|
||||
"speedctrlpowerdec_bt:",
|
||||
"speedbutton0:",
|
||||
"speedbutton1:",
|
||||
"speedbutton2:",
|
||||
"speedbutton3:",
|
||||
"speedbutton4:",
|
||||
"speedbutton5:",
|
||||
"speedbutton6:",
|
||||
"speedbutton7:",
|
||||
"speedbutton8:",
|
||||
"speedbutton9:",
|
||||
"distancecounter_sw:",
|
||||
"dirkey:",
|
||||
"brakectrl:",
|
||||
@@ -417,6 +471,9 @@ init() {
|
||||
"springbraketoggle_bt:",
|
||||
"springbrakeon_bt:",
|
||||
"springbrakeoff_bt:",
|
||||
"universalbrake1_bt:",
|
||||
"universalbrake2_bt:",
|
||||
"universalbrake3_bt:",
|
||||
"epbrake_bt:",
|
||||
"sand_bt:",
|
||||
"antislip_bt:",
|
||||
@@ -466,6 +523,9 @@ init() {
|
||||
"radiotest_sw:",
|
||||
"radiostop_sw:",
|
||||
"radiocall3_sw:",
|
||||
"radiovolume_sw:",
|
||||
"radiovolumeprev_sw:",
|
||||
"radiovolumenext_sw:",
|
||||
"pantfront_sw:",
|
||||
"pantrear_sw:",
|
||||
"pantfrontoff_sw:",
|
||||
|
||||
@@ -74,6 +74,20 @@ enum string {
|
||||
cab_scndctrl,
|
||||
cab_shuntmodepower,
|
||||
cab_tempomat,
|
||||
cab_speedinc,
|
||||
cab_speeddec,
|
||||
cab_speedctrlpowerinc,
|
||||
cab_speedctrlpowerdec,
|
||||
cab_speedbutton0,
|
||||
cab_speedbutton1,
|
||||
cab_speedbutton2,
|
||||
cab_speedbutton3,
|
||||
cab_speedbutton4,
|
||||
cab_speedbutton5,
|
||||
cab_speedbutton6,
|
||||
cab_speedbutton7,
|
||||
cab_speedbutton8,
|
||||
cab_speedbutton9,
|
||||
cab_distancecounter,
|
||||
cab_dirkey,
|
||||
cab_brakectrl,
|
||||
@@ -103,6 +117,9 @@ enum string {
|
||||
cab_springbrake_bt,
|
||||
cab_springbrakeon_bt,
|
||||
cab_springbrakeoff_bt,
|
||||
cab_universalbrake1_bt,
|
||||
cab_universalbrake2_bt,
|
||||
cab_universalbrake3_bt,
|
||||
cab_epbrake_bt,
|
||||
cab_sand_bt,
|
||||
cab_antislip_bt,
|
||||
@@ -152,6 +169,9 @@ enum string {
|
||||
cab_radiotest_sw,
|
||||
cab_radiostop_sw,
|
||||
cab_radiocall3_sw,
|
||||
cab_radiovolume_sw,
|
||||
cab_radiovolumeprev_sw,
|
||||
cab_radiovolumenext_sw,
|
||||
cab_pantfront_sw,
|
||||
cab_pantrear_sw,
|
||||
cab_pantfrontoff_sw,
|
||||
|
||||
Reference in New Issue
Block a user