From 642b8fb623362d12e312982c7ca5a36eca6fa9b1 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 1 Mar 2020 03:09:55 +0100 Subject: [PATCH] compartment lighting vehicle subsystem, submodel diffuse impact on ambient lighting, minor gfx renderer bug fixes, minor ai logic tweaks --- Driver.cpp | 103 +++++++++++++++-------- Driver.h | 1 + DynObj.cpp | 40 +++++---- DynObj.h | 2 +- Gauge.h | 8 +- McZapkie/MOVER.h | 21 +++-- McZapkie/Mover.cpp | 105 +++++++++++++++++++++++ Model3d.cpp | 17 ++++ Model3d.h | 2 + PyInt.cpp | 2 +- Train.cpp | 172 ++++++++++++++++++++++++++++++-------- Train.h | 10 ++- command.cpp | 3 + command.h | 3 + driverkeyboardinput.cpp | 3 + drivermode.cpp | 4 + drivermouseinput.cpp | 9 ++ maszyna.vcxproj | 8 +- opengl33renderer.cpp | 65 +++++++++----- opengl33renderer.h | 2 +- openglrenderer.cpp | 14 +++- openglrenderer.h | 2 +- renderer.h | 4 +- shaders/light_common.glsl | 3 + translation.cpp | 9 ++ translation.h | 3 + 26 files changed, 485 insertions(+), 130 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 0e6d1192..8b660a27 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1721,7 +1721,7 @@ TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, } // HACK: give the simulation a small window to potentially replace the AI with a human driver - fActionTime = -2.0; + fActionTime = -5.0; }; void TController::CloseLog() @@ -2229,6 +2229,11 @@ bool TController::CheckVehicles(TOrders user) || ( pVehicle->NextC( coupling::control ) != nullptr ) ) { sync_consist_reversers(); } + // potentially sync compartment lighting state for the newly connected vehicles + if( mvOccupied->CompartmentLights.start_type == start_t::manual ) { + mvOccupied->CompartmentLightsSwitchOff( mvOccupied->CompartmentLights.is_disabled ); + mvOccupied->CompartmentLightsSwitch( mvOccupied->CompartmentLights.is_enabled ); + } } if (AIControllFlag) @@ -2515,7 +2520,7 @@ void TController::SetDriverPsyche() bool TController::PrepareEngine() { // odpalanie silnika // HACK: don't immediately activate inert vehicle in case the simulation is about to replace us with human driver - if( /* ( mvOccupied->Vel < 1.0 ) && */ ( fActionTime < 0.0 ) ) { return false; } + if( ( mvOccupied->Vel < 1.0 ) && ( fActionTime < 0.0 ) ) { return false; } bool OK = false, voltfront = false, @@ -4525,6 +4530,7 @@ TController::UpdateSituation(double dt) { double dy; // składowa styczna grawitacji, w przedziale <0,1> double AbsAccS = 0; IsAnyDoorOpen[ side::right ] = IsAnyDoorOpen[ side::left ] = false; + ConsistShade = 0.0; TDynamicObject *p = pVehicles[0]; // pojazd na czole składu while (p) { // sprawdzenie odhamowania wszystkich połączonych pojazdów @@ -4573,9 +4579,13 @@ TController::UpdateSituation(double dt) { IsAnyDoorOpen[ side::left ] = IsAnyDoorOpen[ side::left ] || ( false == vehicle->Doors.instances[ ( switchsides ? side::right : side::left ) ].is_closed ); - + // measure lighting level + // TBD: apply weight (multiplier) to partially lit vehicles? + ConsistShade += ( p->fShade > 0.0 ? p->fShade : 1.0 ); p = p->Next(); // pojazd podłączony z tyłu (patrząc od czoła) } + // calculate average amount of received sunlight + ConsistShade /= iVehicles; // test state of main switch in all powered vehicles under control IsLineBreakerClosed = ( mvOccupied->Power > 0.01 ? mvOccupied->Mains : true ); @@ -4720,32 +4730,35 @@ TController::UpdateSituation(double dt) { } else { // jeśli nie trzeba opuszczać pantografów - if( mvOccupied->AIHintPantstate == 0 ) { - // jazda na tylnym - if( ( iDirection >= 0 ) && ( useregularpantographlayout ) ) { - // jak jedzie w kierunku sprzęgu 0 - if( ( mvControlling->PantRearVolt == 0.0 ) - // filter out cases with single _other_ working pantograph so we don't try to raise something we can't - && ( ( mvControlling->PantographVoltage == 0.0 ) - || ( mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > 1 ) ) ) { - mvControlling->OperatePantographValve( end::rear, operation_t::enable ); + if( fActionTime > 0.0 ) { + if( mvOccupied->AIHintPantstate == 0 ) { + // jazda na tylnym + if( ( iDirection >= 0 ) && ( useregularpantographlayout ) ) { + // jak jedzie w kierunku sprzęgu 0 + if( ( mvControlling->PantRearVolt == 0.0 ) + // filter out cases with single _other_ working pantograph so we don't try to raise something we can't + && ( ( mvControlling->PantographVoltage == 0.0 ) + || ( mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > 1 ) ) ) { + mvControlling->OperatePantographValve( end::rear, operation_t::enable ); + } } - } - else { - // jak jedzie w kierunku sprzęgu 0 - if( ( mvControlling->PantFrontVolt == 0.0 ) - // filter out cases with single _other_ working pantograph so we don't try to raise something we can't - && ( ( mvControlling->PantographVoltage == 0.0 ) - || ( mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > 1 ) ) ) { - mvControlling->OperatePantographValve( end::front, operation_t::enable ); + else { + // jak jedzie w kierunku sprzęgu 0 + if( ( mvControlling->PantFrontVolt == 0.0 ) + // filter out cases with single _other_ working pantograph so we don't try to raise something we can't + && ( ( mvControlling->PantographVoltage == 0.0 ) + || ( mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > 1 ) ) ) { + mvControlling->OperatePantographValve( end::front, operation_t::enable ); + } } } } } if( mvOccupied->Vel > 5 ) { - if( mvOccupied->AIHintPantstate != 0 ) { - // use suggested pantograph setup - auto const pantographsetup { mvOccupied->AIHintPantstate }; + if( fActionTime > 0.0 ) { + if( mvOccupied->AIHintPantstate != 0 ) { + // use suggested pantograph setup + auto const pantographsetup{ mvOccupied->AIHintPantstate }; mvControlling->OperatePantographValve( end::front, ( pantographsetup & ( 1 << 0 ) ? @@ -4756,21 +4769,22 @@ TController::UpdateSituation(double dt) { ( pantographsetup & ( 1 << 1 ) ? operation_t::enable : operation_t::disable ) ); - } - else { - // opuszczenie przedniego po rozpędzeniu się o ile jest więcej niż jeden - if( mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > 1 ) { - if( ( iDirection >= 0 ) && ( useregularpantographlayout ) ) // jak jedzie w kierunku sprzęgu 0 - { // poczekać na podniesienie tylnego - if( ( mvControlling->PantFrontVolt != 0.0 ) - && ( mvControlling->PantRearVolt != 0.0 ) ) { // czy jest napięcie zasilające na tylnym? - mvControlling->OperatePantographValve( end::front, operation_t::disable ); // opuszcza od sprzęgu 0 + } + else { + // opuszczenie przedniego po rozpędzeniu się o ile jest więcej niż jeden + if( mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > 1 ) { + if( ( iDirection >= 0 ) && ( useregularpantographlayout ) ) // jak jedzie w kierunku sprzęgu 0 + { // poczekać na podniesienie tylnego + if( ( mvControlling->PantFrontVolt != 0.0 ) + && ( mvControlling->PantRearVolt != 0.0 ) ) { // czy jest napięcie zasilające na tylnym? + mvControlling->OperatePantographValve( end::front, operation_t::disable ); // opuszcza od sprzęgu 0 + } } - } - else { // poczekać na podniesienie przedniego - if( ( mvControlling->PantRearVolt != 0.0 ) - && ( mvControlling->PantFrontVolt != 0.0 ) ) { // czy jest napięcie zasilające na przednim? - mvControlling->OperatePantographValve( end::rear, operation_t::disable ); // opuszcza od sprzęgu 1 + else { // poczekać na podniesienie przedniego + if( ( mvControlling->PantRearVolt != 0.0 ) + && ( mvControlling->PantFrontVolt != 0.0 ) ) { // czy jest napięcie zasilające na przednim? + mvControlling->OperatePantographValve( end::rear, operation_t::disable ); // opuszcza od sprzęgu 1 + } } } } @@ -4860,6 +4874,21 @@ TController::UpdateSituation(double dt) { if (AIControllFlag) { CheckTimeControllers(); + + // low priority operations + // compartment lights + if( mvOccupied->CompartmentLights.start_type == start_t::manual ) { + auto const currentlightstate { mvOccupied->CompartmentLights.is_enabled }; + auto const lightlevel { Global.fLuminance * ConsistShade }; + auto const desiredlightstate { ( + currentlightstate ? + lightlevel < 0.40 : // turn off if lighting level goes above 0.4 + lightlevel < 0.35 ) }; // turn on if lighting level goes below 0.35 + if( desiredlightstate != currentlightstate ) { + mvOccupied->CompartmentLightsSwitch( desiredlightstate ); + mvOccupied->CompartmentLightsSwitchOff( !desiredlightstate ); + } + } } LastReactionTime -= reactiontime; diff --git a/Driver.h b/Driver.h index 9ccfab6a..c3349d8c 100644 --- a/Driver.h +++ b/Driver.h @@ -466,6 +466,7 @@ private: bool IsLineBreakerClosed{ false }; // state of line breaker in all powered vehicles under control double fReady = 0.0; // poziom odhamowania wagonów bool Ready = false; // ABu: stan gotowosci do odjazdu - sprawdzenie odhamowania wagonow + double ConsistShade{ 1.0 }; // averaged amount of sunlight received by the consist TDynamicObject *pVehicles[ 2 ]; // skrajne pojazdy w składzie (niekoniecznie bezpośrednio sterowane) bool IsAnyDoorOpen[ 2 ]; // state of door in the consist diff --git a/DynObj.cpp b/DynObj.cpp index 23dda44b..ff28fd81 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -664,13 +664,7 @@ TDynamicObject::toggle_lights() { if( true == SectionLightsActive ) { // switch all lights off... - for( auto §ion : Sections ) { - // ... but skip cab sections, their lighting ignores battery state - auto const sectionname { section.compartment->pName }; - if( sectionname.find( "cab" ) == 0 ) { continue; } - - section.light_level = 0.0f; - } + MoverParameters->BatterySwitch( false ); SectionLightsActive = false; } else { @@ -690,6 +684,7 @@ TDynamicObject::toggle_lights() { section.light_level = ( Random() < 0.75 ? 0.75f : 0.15f ); } } + MoverParameters->BatterySwitch( true ); SectionLightsActive = true; } } @@ -1092,15 +1087,20 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) } // interior light levels auto sectionlightcolor { glm::vec4( 1.f ) }; + bool cabsection{ true }; for( auto const §ion : Sections ) { - /* - sectionlightcolor = glm::vec4( InteriorLight, section.light_level ); - */ + if( cabsection ) { + // check whether we're still processing cab sections + auto const §ionname { section.compartment->pName }; + cabsection &= ( ( sectionname.size() >= 4 ) && ( sectionname.substr( 0, 3 ) == "cab" ) ); + } + // TODO: add cablight devices + auto const sectionlightlevel { section.light_level * ( cabsection ? 1.0f : MoverParameters->CompartmentLights.intensity ) }; sectionlightcolor = glm::vec4( - ( ( ( section.light_level == 0.f ) || ( Global.fLuminance > section.compartment->fLight ) ) ? + ( ( ( sectionlightlevel == 0.f ) || ( Global.fLuminance > section.compartment->fLight ) ) ? glm::vec3( 240.f / 255.f ) : // TBD: save and restore initial submodel diffuse instead of enforcing one? InteriorLight ), // TODO: per-compartment (type) light color - section.light_level ); + sectionlightlevel ); section.compartment->SetLightLevel( sectionlightcolor, true ); if( section.load != nullptr ) { section.load->SetLightLevel( sectionlightcolor, true ); @@ -2069,7 +2069,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" // passenger car compartments std::vector nameprefixes = { "corridor", "korytarz", "compartment", "przedzial" }; for( auto const &nameprefix : nameprefixes ) { - init_sections( mdLowPolyInt, nameprefix ); + init_sections( mdLowPolyInt, nameprefix, MoverParameters->CompartmentLights.start_type == start_t::manual ); } } // destination sign @@ -2078,7 +2078,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" } // 'external_load' is an optional special section in the main model, pointing to submodel of external load if( mdModel ) { - init_sections( mdModel, "external_load" ); + init_sections( mdModel, "external_load", false ); } update_load_sections(); update_load_visibility(); @@ -2176,7 +2176,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" } int -TDynamicObject::init_sections( TModel3d const *Model, std::string const &Nameprefix ) { +TDynamicObject::init_sections( TModel3d const *Model, std::string const &Nameprefix, bool const Overrideselfillum ) { auto sectioncount = 0; auto sectionindex = 0; @@ -2192,6 +2192,10 @@ TDynamicObject::init_sections( TModel3d const *Model, std::string const &Namepre sectionsubmodel = Model->GetFromName( Nameprefix + "0" + sectionindexname ); } if( sectionsubmodel != nullptr ) { + // HACK: disable automatic self-illumination threshold, at least until 3d model update + if( Overrideselfillum ) { + sectionsubmodel->SetSelfIllum( 2.0f, true, true ); + } Sections.push_back( { sectionsubmodel, nullptr, // pointers to load sections are generated afterwards @@ -2609,6 +2613,10 @@ TDynamicObject::update_load_sections() { if( ( section.load != nullptr ) && ( section.load->count_children() > 0 ) ) { SectionLoadVisibility.push_back( { section.load, false } ); + // HACK: disable automatic self-illumination threshold, at least until 3d model update + if( MoverParameters->CompartmentLights.start_type == start_t::manual ) { + section.load->SetSelfIllum( 2.0f, true, true ); + } } } shuffle_load_sections(); @@ -3690,7 +3698,7 @@ bool TDynamicObject::Update(double dt, double dt1) // if the vehicle has a controller, we base the light state on state of the controller otherwise we check the vehicle itself if( ( ctOwner != nullptr ? ctOwner->Controlling()->Battery != SectionLightsActive : - SectionLightsActive == true ) ) { // without controller lights are off. NOTE: this likely mess up the EMU + MoverParameters->CompartmentLights.is_active == true ) ) { // without controller lights are off. NOTE: this likely mess up the EMU toggle_lights(); } diff --git a/DynObj.h b/DynObj.h index efb3dac1..8319fad2 100644 --- a/DynObj.h +++ b/DynObj.h @@ -550,7 +550,7 @@ private: std::string Name, std::string BaseDir, std::string asReplacableSkin, std::string Type_Name, TTrack *Track, double fDist, std::string DriverType, double fVel, std::string TrainName, float Load, std::string LoadType, bool Reversed, std::string); - int init_sections( TModel3d const *Model, std::string const &Nameprefix ); + int init_sections( TModel3d const *Model, std::string const &Nameprefix, bool const Overrideselfillum ); bool init_destination( TModel3d *Model ); void create_controller( std::string const Type, bool const Trainset ); void AttachPrev(TDynamicObject *Object, int iType = 1); diff --git a/Gauge.h b/Gauge.h index 86b65120..86b08c97 100644 --- a/Gauge.h +++ b/Gauge.h @@ -22,10 +22,12 @@ enum class TGaugeAnimation { }; enum class TGaugeType : int { - toggle = 1, - push = 2, + toggle = 1 << 0, + push = 1 << 1, + delayed = 1 << 2, pushtoggle = ( toggle | push ), - push_delayed + push_delayed = ( push | delayed ), + pushtoggle_delayed = ( toggle | push | delayed ) }; // animowany wskaźnik, mogący przyjmować wiele stanów pośrednich diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index b9a25bef..9394e8fc 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -756,6 +756,13 @@ private: bool is_active { false }; // device is working }; + struct basic_light : public basic_device { + // config + float dimming { 1.0f }; // light strength multiplier + // ld outputs + float intensity { 0.0f }; // current light strength + }; + struct cooling_fan : public basic_device { // config float speed { 0.f }; // cooling fan rpm; either fraction of parent rpm, or absolute value if negative @@ -1315,6 +1322,11 @@ public: bool CompressorTankValve{ false }; // indicates excessive pressure is vented from compressor tank directly and instantly start_t CompressorStart{ start_t::manual }; // whether the compressor is started manually, or another way start_t PantographCompressorStart{ start_t::manual }; + basic_valve PantsValve; + std::array Pantographs; + bool PantAllDown { false }; + double PantFrontVolt = 0.0; //pantograf pod napieciem? 'Winger 160404 + double PantRearVolt = 0.0; // TODO converter parameters, for when we start cleaning up mover parameters start_t ConverterStart{ start_t::manual }; // whether converter is started manually, or by other means float ConverterStartDelay{ 0.0f }; // delay (in seconds) before the converter is started, once its activation conditions are met @@ -1506,11 +1518,6 @@ public: bool DoorRightOpened = false; double DoorRightOpenTimer{ -1.0 }; // right door closing timer for automatic door type #endif - basic_valve PantsValve; - std::array Pantographs; - bool PantAllDown { false }; - double PantFrontVolt = 0.0; //pantograf pod napieciem? 'Winger 160404 - double PantRearVolt = 0.0; // TODO: move these switch types where they belong, cabin definition std::string PantSwitchType; std::string ConvSwitchType; @@ -1519,6 +1526,7 @@ public: bool Heating = false; //ogrzewanie 'Winger 020304 bool HeatingAllow { false }; // heating switch // TODO: wrap heating in a basic device int DoubleTr = 1; //trakcja ukrotniona - przedni pojazd 'Winger 160304 + basic_light CompartmentLights; bool PhysicActivation = true; @@ -1674,6 +1682,8 @@ public: bool OilPumpSwitchOff( bool State, range_t const Notify = range_t::consist ); // oil pump state toggle bool MotorBlowersSwitch( bool State, end const Side, range_t const Notify = range_t::consist ); // traction motor fan state toggle bool MotorBlowersSwitchOff( bool State, end const Side, range_t const Notify = range_t::consist ); // traction motor fan state toggle + bool CompartmentLightsSwitch( bool State, range_t const Notify = range_t::consist ); // compartment lights state toggle + bool CompartmentLightsSwitchOff( bool State, range_t const Notify = range_t::consist ); // compartment lights state toggle bool MainSwitch( bool const State, range_t const Notify = range_t::consist );/*! wylacznik glowny*/ void MainSwitch_( bool const State ); bool ConverterSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl przetwornicy*/ @@ -1691,6 +1701,7 @@ public: void OilPumpCheck( double const Timestep ); void MotorBlowersCheck( double const Timestep ); void PantographsCheck( double const Timestep ); + void LightsCheck( double const Timestep ); bool FuseOn(void); //bezpiecznik nadamiary bool FuseFlagCheck(void) const; // sprawdzanie flagi nadmiarowego void FuseOff(void); // wylaczenie nadmiarowego diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index b02a8238..da8f4e47 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1439,6 +1439,8 @@ void TMoverParameters::compute_movement_( double const Deltatime ) { } // heating HeatingCheck( Deltatime ); + // lighting + LightsCheck( Deltatime ); UpdateBrakePressure(Deltatime); UpdatePipePressure(Deltatime); @@ -1902,6 +1904,35 @@ void TMoverParameters::PantographsCheck( double const Timestep ) { } } +void TMoverParameters::LightsCheck( double const Timestep ) { + + auto const lowvoltagepower { ( + ( ConverterFlag ) + || ( ( ( Couplers[ end::front ].CouplingFlag & coupling::permanent ) != 0 ) && ( Couplers[ end::front ].Connected->ConverterFlag ) ) + || ( ( ( Couplers[ end::rear ].CouplingFlag & coupling::permanent ) != 0 ) && ( Couplers[ end::rear ].Connected->ConverterFlag ) ) ) }; + + auto &light { CompartmentLights }; + + light.is_active = ( + // TODO: bind properly power source when ld is in place + ( Battery || lowvoltagepower ) // power source + && ( false == light.is_disabled ) + && ( ( true == light.is_active ) + || ( light.start_type == start_t::manual ? + light.is_enabled : + true ) ) ); + + light.intensity = + ( light.is_active ? + 1.0f : + 0.0f ) + // TODO: bind properly power source when ld is in place + * ( lowvoltagepower ? 1.0f : + Battery ? 0.5f : + 0.0f ) + * light.dimming; +} + double TMoverParameters::ShowCurrent(int AmpN) const { // Odczyt poboru prądu na podanym amperomierzu switch (EngineType) @@ -3151,6 +3182,55 @@ bool TMoverParameters::MotorBlowersSwitchOff( bool State, end const Side, range_ return ( fan.is_disabled != initialstate ); } +bool TMoverParameters::CompartmentLightsSwitch( bool State, range_t const Notify ) { + + if( CompartmentLights.start_type == start_t::automatic ) { + // automatic lights ignore 'manual' state commands + return false; + } + + bool const initialstate { CompartmentLights.is_enabled }; + + CompartmentLights.is_enabled = State; + + if( Notify != range_t::local ) { + SendCtrlToNext( + "CompartmentLightsSwitch", + ( CompartmentLights.is_enabled ? 1 : 0 ), + CabActive, + ( Notify == range_t::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + return ( CompartmentLights.is_enabled != initialstate ); +} + +// water pump state toggle +bool TMoverParameters::CompartmentLightsSwitchOff( bool State, range_t const Notify ) { + + if( CompartmentLights.start_type == start_t::automatic ) { + // automatic lights ignore 'manual' state commands + return false; + } + + bool const initialstate { CompartmentLights.is_disabled }; + + CompartmentLights.is_disabled = State; + + if( Notify != range_t::local ) { + SendCtrlToNext( + "CompartmentLightsSwitchOff", + ( CompartmentLights.is_disabled ? 1 : 0 ), + CabActive, + ( Notify == range_t::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + return ( CompartmentLights.is_disabled != initialstate ); +} + // ************************************************************************************************* // Q: 20160713 // włączenie / wyłączenie obwodu głownego @@ -9758,6 +9838,15 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { lookup->second : start_t::manual; } + // compartment lights + { + auto lookup = starts.find( extract_value( "CompartmentLightsStart", line ) ); + CompartmentLights.start_type = + lookup != starts.end() ? + lookup->second : + start_t::automatic; + } + } void TMoverParameters::LoadFIZ_Blending(std::string const &line) { @@ -11042,6 +11131,22 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C } OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } + else if( Command == "CompartmentLightsSwitch" ) { + + if( CompartmentLights.start_type != start_t::automatic ) { + // automatic lights ignore 'manual' state commands + CompartmentLights.is_enabled = ( CValue1 == 1 ); + } + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } + else if( Command == "CompartmentLightsSwitchOff" ) { + + if( CompartmentLights.start_type != start_t::automatic ) { + // automatic lights ignore 'manual' state commands + CompartmentLights.is_disabled = ( CValue1 == 1 ); + } + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } else if (Command == "MainSwitch") { MainSwitch_( CValue1 > 0.0 ); diff --git a/Model3d.cpp b/Model3d.cpp index e9cc722a..b04b7fa4 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -151,6 +151,23 @@ TSubModel::SetLightLevel( glm::vec4 const &Level, bool const Includechildren, bo } } +// sets activation threshold of self-illumination to specitied value +void TSubModel::SetSelfIllum( float const Threshold, bool const Includechildren, bool const Includesiblings ) { + + fLight = Threshold; + if( true == Includesiblings ) { + auto sibling { this }; + while( ( sibling = sibling->Next ) != nullptr ) { + sibling->SetSelfIllum( Threshold, Includechildren, false ); // no need for all siblings to duplicate the work + } + } + if( ( true == Includechildren ) + && ( Child != nullptr ) ) { + Child->SetSelfIllum( Threshold, Includechildren, true ); // node's children include child's siblings and children + } +} + + int TSubModel::SeekFaceNormal(std::vector const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, gfx::vertex_array const &Vertices) { // szukanie punktu stycznego do (pt), zwraca numer wierzchołka, a nie trójkąta int facecount = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkąt diff --git a/Model3d.h b/Model3d.h index d4a8ecea..25f3cb01 100644 --- a/Model3d.h +++ b/Model3d.h @@ -214,6 +214,8 @@ public: void SetVisibilityLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false ); // sets light level (alpha component of illumination color) to specified value void SetLightLevel( glm::vec4 const &Level, bool const Includechildren = false, bool const Includesiblings = false ); + // sets activation threshold of self-illumination to specitied value + void SetSelfIllum( float const Threshold, bool const Includechildren = false, bool const Includesiblings = false ); inline float3 Translation1Get() { return fMatrix ? *(fMatrix->TranslationGet()) + v_TransVector : v_TransVector; } inline float3 Translation2Get() { diff --git a/PyInt.cpp b/PyInt.cpp index cb9cfe8d..e527a86f 100644 --- a/PyInt.cpp +++ b/PyInt.cpp @@ -76,7 +76,7 @@ void render_task::run() { if (!Global.gfx_usegles) { int size = width * height * 3; - format = GL_SRGB8; + format = ( Global.GfxFramebufferSRGB ? GL_SRGB8 : GL_RGBA8 ); components = GL_RGB; m_target->image = new unsigned char[size]; memcpy(m_target->image, image, size); diff --git a/Train.cpp b/Train.cpp index a68b313f..e153da9b 100644 --- a/Train.cpp +++ b/Train.cpp @@ -335,6 +335,9 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::interiorlightdimtoggle, &TTrain::OnCommand_interiorlightdimtoggle }, { user_command::interiorlightdimenable, &TTrain::OnCommand_interiorlightdimenable }, { user_command::interiorlightdimdisable, &TTrain::OnCommand_interiorlightdimdisable }, + { user_command::compartmentlightstoggle, &TTrain::OnCommand_compartmentlightstoggle }, + { user_command::compartmentlightsenable, &TTrain::OnCommand_compartmentlightsenable }, + { user_command::compartmentlightsdisable, &TTrain::OnCommand_compartmentlightsdisable }, { user_command::instrumentlighttoggle, &TTrain::OnCommand_instrumentlighttoggle }, { user_command::instrumentlightenable, &TTrain::OnCommand_instrumentlightenable }, { user_command::instrumentlightdisable, &TTrain::OnCommand_instrumentlightdisable }, @@ -536,6 +539,7 @@ dictionary_source *TTrain::GetTrainState() { dict->insert( "pant_compressor", mvControlled->PantCompFlag ); dict->insert( "lights_front", mvOccupied->iLights[ end::front ] ); dict->insert( "lights_rear", mvOccupied->iLights[ end::rear ] ); + dict->insert( "lights_compartments", mvOccupied->CompartmentLights.is_active || mvOccupied->CompartmentLights.is_disabled ); // reverser dict->insert( "direction", mvOccupied->DirActive ); // throttle @@ -757,8 +761,8 @@ void TTrain::zero_charging_train_brake() { && ( DynamicObject->Controller != AIdriver ) && ( Global.iFeedbackMode < 3 ) && ( ( mvOccupied->BrakeHandle == TBrakeHandle::FVel6 ) - || (mvOccupied->BrakeHandle == TBrakeHandle::MHZ_EN57) - || (mvOccupied->BrakeHandle == TBrakeHandle::MHZ_K8P)) ) { + || ( mvOccupied->BrakeHandle == TBrakeHandle::MHZ_EN57 ) + || ( mvOccupied->BrakeHandle == TBrakeHandle::MHZ_K8P ) ) ) { // Odskakiwanie hamulce EP set_train_brake( 0 ); } @@ -2466,14 +2470,16 @@ void TTrain::OnCommand_linebreakeropen( TTrain *Train, command_data const &Comma if( Command.action == GLFW_PRESS ) { // visual feedback - if( Train->m_controlmapper.contains( "main_off_bt:" ) ) { + if( Train->ggMainOffButton.SubModel != nullptr ) { Train->ggMainOffButton.UpdateValue( 1.0, Train->dsbSwitch ); } - else if( Train->m_controlmapper.contains( "main_sw:" ) ) { + else if( Train->ggMainButton.SubModel != nullptr ) { Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch ); } - else { - // there's no switch capable of doing the job + else if( Train->ggMainOnButton.SubModel != nullptr ) { + // NOTE: legacy behaviour, for vehicles equipped only with impulse close switch + // it doesn't make any real sense to animate this one, but some people can't get over how there's no visual reaction to their keypress + Train->ggMainOnButton.UpdateValue( 1.0, Train->dsbSwitch ); return; } // play sound immediately when the switch is hit, not after release @@ -2514,10 +2520,14 @@ void TTrain::OnCommand_linebreakerclose( TTrain *Train, command_data const &Comm // two separate switches to close and break the circuit Train->ggMainOnButton.UpdateValue( 1.0, Train->dsbSwitch ); } - else { + else if( Train->ggMainButton.SubModel != nullptr ) { // single two-state switch Train->ggMainButton.UpdateValue( 1.0, Train->dsbSwitch ); } + else { + // no switch capable of doing the job + return; + } // the actual closing of the line breaker is handled in the train update routine } else if( Command.action == GLFW_RELEASE ) { @@ -2526,7 +2536,7 @@ void TTrain::OnCommand_linebreakerclose( TTrain *Train, command_data const &Comm // setup with two separate switches Train->ggMainOnButton.UpdateValue( 0.0, Train->dsbSwitch ); } - else { + else if( Train->ggMainButton.SubModel != nullptr ) { if( Train->ggMainButton.type() != TGaugeType::toggle ) { Train->ggMainButton.UpdateValue( 0.5, Train->dsbSwitch ); } @@ -2536,8 +2546,9 @@ void TTrain::OnCommand_linebreakerclose( TTrain *Train, command_data const &Comm if( Train->m_linebreakerstate == 2 ) { // we don't need to start the diesel twice, but the other types (with impulse switch setup) still need to be launched - if( ( Train->mvControlled->EngineType != TEngineType::DieselEngine ) - && ( Train->mvControlled->EngineType != TEngineType::DieselElectric ) ) { + // NOTE: this behaviour should depend on MainOnButton presence and type_delayed + // TODO: change it when/if vehicle definition files get their proper switch types + if( Train->mvControlled->EngineType == TEngineType::ElectricSeriesMotor ) { // try to finalize state change of the line breaker, set the state based on the outcome Train->m_linebreakerstate = ( Train->mvControlled->MainSwitch( true ) ? @@ -4356,6 +4367,79 @@ void TTrain::OnCommand_interiorlightdimdisable( TTrain *Train, command_data cons } } +void TTrain::OnCommand_compartmentlightstoggle( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_REPEAT ) { return; } + + // keep the switch from flipping back and forth if key is held down + if( ( false == Train->mvOccupied->CompartmentLights.is_active ) + && ( false == Train->mvOccupied->CompartmentLights.is_enabled ) ) { + // turn on + OnCommand_compartmentlightsenable( Train, Command ); + } + else { + //turn off + OnCommand_compartmentlightsdisable( Train, Command ); + } +} + +void TTrain::OnCommand_compartmentlightsenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + Train->mvOccupied->CompartmentLightsSwitch( true ); + // visual feedback + if( Train->m_controlmapper.contains( "compartmentlights_sw:" ) ) { + Train->ggCompartmentLightsButton.UpdateValue( 1.0f, Train->dsbSwitch ); + } + if( Train->m_controlmapper.contains( "compartmentlightson_sw:" ) ) { + Train->ggCompartmentLightsOnButton.UpdateValue( 1.0f, Train->dsbSwitch ); + } + } + else if( Command.action == GLFW_RELEASE ) { + if( Train->m_controlmapper.contains( "compartmentlights_sw:" ) ) { + if( Train->ggCompartmentLightsButton.type() == TGaugeType::push ) { + // return the switch to neutral position + Train->mvOccupied->CompartmentLightsSwitch( false ); + Train->mvOccupied->CompartmentLightsSwitchOff( false ); + Train->ggCompartmentLightsButton.UpdateValue( 0.5f ); + } + } + if( Train->m_controlmapper.contains( "compartmentlightson_sw:" ) ) { + Train->mvOccupied->CompartmentLightsSwitch( false ); + Train->ggCompartmentLightsOnButton.UpdateValue( 0.0f, Train->dsbSwitch ); + } + } +} + +void TTrain::OnCommand_compartmentlightsdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + if( Train->m_controlmapper.contains( "compartmentlights_sw:" ) ) { + Train->ggCompartmentLightsButton.UpdateValue( 0.0f, Train->dsbSwitch ); + } + if( Train->m_controlmapper.contains( "compartmentlightsoff_sw:" ) ) { + Train->ggCompartmentLightsOffButton.UpdateValue( 1.0f, Train->dsbSwitch ); + } + + Train->mvOccupied->CompartmentLightsSwitchOff( true ); + } + else if( Command.action == GLFW_RELEASE ) { + if( Train->m_controlmapper.contains( "compartmentlights_sw:" ) ) { + if( Train->ggCompartmentLightsButton.type() == TGaugeType::push ) { + // return the switch to neutral position + Train->mvOccupied->CompartmentLightsSwitch( false ); + Train->mvOccupied->CompartmentLightsSwitchOff( false ); + Train->ggCompartmentLightsButton.UpdateValue( 0.5f ); + } + } + if( Train->m_controlmapper.contains( "compartmentlightsoff_sw:" ) ) { + Train->mvOccupied->CompartmentLightsSwitchOff( false ); + Train->ggCompartmentLightsOffButton.UpdateValue( 0.0f, Train->dsbSwitch ); + } + } +} + void TTrain::OnCommand_instrumentlighttoggle( TTrain *Train, command_data const &Command ) { if( Command.action == GLFW_PRESS ) { @@ -5709,8 +5793,8 @@ bool TTrain::Update( double const Deltatime ) } } - if( ( ggMainButton.GetDesiredValue() > 0.95 ) - || ( ggMainOnButton.GetDesiredValue() > 0.95 ) ) { + if( ( ( ggMainButton.SubModel != nullptr ) && ( ggMainButton.GetDesiredValue() > 0.95 ) ) + || ( ( ggMainOnButton.SubModel != nullptr ) && ( ggMainOnButton.GetDesiredValue() > 0.95 ) ) ) { // keep track of period the line breaker button is held down, to determine when/if circuit closes if( ( mvControlled->MainsInitTimeCountdown <= 0.0 ) && ( ( fHVoltage > 0.5 * mvControlled->EnginePowerSource.MaxVoltage ) @@ -5733,15 +5817,15 @@ bool TTrain::Update( double const Deltatime ) if( m_linebreakerstate == 0 ) { if( fMainRelayTimer > mvControlled->InitialCtrlDelay ) { // wlaczanie WSa z opoznieniem - // mark the line breaker as ready to close; for electric vehicles with impulse switch the setup is completed on button release + // mark the line breaker as ready to close; for electric series vehicles with impulse switch the setup is completed on button release m_linebreakerstate = 2; } } if( m_linebreakerstate == 2 ) { // for diesels and/or vehicles with toggle switch setup we complete the engine start here + // TODO: make it a test for main_on_bt of type push_delayed instead if( ( ggMainOnButton.SubModel == nullptr ) - || ( ( mvControlled->EngineType == TEngineType::DieselEngine ) - || ( mvControlled->EngineType == TEngineType::DieselElectric ) ) ) { + || ( mvControlled->EngineType != TEngineType::ElectricSeriesMotor ) ) { // try to finalize state change of the line breaker, set the state based on the outcome m_linebreakerstate = ( mvControlled->MainSwitch( true ) ? @@ -5749,6 +5833,8 @@ bool TTrain::Update( double const Deltatime ) 0 ); } } + // helper variables + m_doors = ( DynamicObject->Mechanik->IsAnyDoorOpen[ side::right ] || DynamicObject->Mechanik->IsAnyDoorOpen[ side::left ] ); // check for received user commands // NOTE: this is a temporary arrangement, for the transition period from old command setup to the new one @@ -6204,8 +6290,8 @@ bool TTrain::Update( double const Deltatime ) ( mvControlled->Mains ) || ( mvControlled->dizel_startup ) || ( fMainRelayTimer > 0.f ) - || ( ggMainButton.GetDesiredValue() > 0.95 ) - || ( ggMainOnButton.GetDesiredValue() > 0.95 ) ); + || ( ( ggMainButton.SubModel != nullptr ) && ( ggMainButton.GetDesiredValue() > 0.95 ) ) + || ( ( ggMainOnButton.SubModel != nullptr ) && ( ggMainOnButton.GetDesiredValue() > 0.95 ) ) ); ggIgnitionKey.Update(); } } @@ -6395,7 +6481,6 @@ bool TTrain::Update( double const Deltatime ) // NBMX wrzesien 2003 - drzwi oraz sygnał odjazdu btLampkaDoorLeft.Turn( DynamicObject->Mechanik->IsAnyDoorOpen[ ( cab_to_end() == end::front ? side::left : side::right ) ] ); btLampkaDoorRight.Turn( DynamicObject->Mechanik->IsAnyDoorOpen[ ( cab_to_end() == end::front ? side::right : side::left ) ] ); - btLampkaDoors.Turn( DynamicObject->Mechanik->IsAnyDoorOpen[ side::right ] || DynamicObject->Mechanik->IsAnyDoorOpen[ side::left ] ); btLampkaBlokadaDrzwi.Turn( mvOccupied->Doors.is_locked ); btLampkaDoorLockOff.Turn( false == mvOccupied->Doors.lock_enabled ); btLampkaDepartureSignal.Turn( mvControlled->DepartureSignal ); @@ -6467,7 +6552,6 @@ bool TTrain::Update( double const Deltatime ) btLampkaHamulecReczny.Turn( false ); btLampkaDoorLeft.Turn( false ); btLampkaDoorRight.Turn( false ); - btLampkaDoors.Turn( false ); btLampkaBlokadaDrzwi.Turn( false ); btLampkaDoorLockOff.Turn( false ); btLampkaDepartureSignal.Turn( false ); @@ -6850,6 +6934,9 @@ bool TTrain::Update( double const Deltatime ) ggTimetableLightButton.Update(); ggCabLightButton.Update(); ggCabLightDimButton.Update(); + ggCompartmentLightsButton.Update(); + ggCompartmentLightsOnButton.Update(); + ggCompartmentLightsOffButton.Update(); ggBatteryButton.Update(); ggBatteryOnButton.Update(); ggBatteryOffButton.Update(); @@ -7942,13 +8029,14 @@ TTrain::MoveToVehicle(TDynamicObject *target) { target_train->Dynamic()->ABuSetModelShake( {} ); } - target_train->Dynamic()->bDisplayCab = true; target_train->Dynamic()->ABuSetModelShake( {} ); // zerowanie przesunięcia przed powrotem? // potentially move player if (simulation::Train == this) { simulation::Train = target_train; - } + // our local driver may potentially be in external view mode, in which case we shouldn't activate cab visualization + target_train->Dynamic()->bDisplayCab |= !FreeFlyModeFlag; + } // delete this TTrain pending_delete = true; @@ -7982,7 +8070,7 @@ TTrain::MoveToVehicle(TDynamicObject *target) { Occupied()->LimPipePress = Occupied()->PipePress; Occupied()->CabActivisation( true ); // załączenie rozrządu (wirtualne kabiny) Dynamic()->MechInside = true; - Dynamic()->Controller = ( Dynamic()->Mechanik ? !Dynamic()->Mechanik->AIControllFlag : Humandriver ); + Dynamic()->Controller = ( Dynamic()->Mechanik ? Dynamic()->Mechanik->AIControllFlag : Humandriver ); } else { Dynamic()->bDisplayCab = false; Dynamic()->ABuSetModelShake( {} ); @@ -7994,9 +8082,13 @@ TTrain::MoveToVehicle(TDynamicObject *target) { Occupied()->CabActive, Dynamic()->asBaseDir + Occupied()->TypeName + ".mmd" ); - Dynamic()->bDisplayCab = true; Dynamic()->ABuSetModelShake( {} ); // zerowanie przesunięcia przed powrotem? + if( simulation::Train == this ) { + // our local driver may potentially be in external view mode, in which case we shouldn't activate cab visualization + Dynamic()->bDisplayCab |= !FreeFlyModeFlag; + } + // add it back with updated dynamic name simulation::Trains.insert(this); } @@ -8157,6 +8249,9 @@ void TTrain::clear_cab_controls() // hunter-091012 ggCabLightButton.Clear(); ggCabLightDimButton.Clear(); + ggCompartmentLightsButton.Clear(); + ggCompartmentLightsOnButton.Clear(); + ggCompartmentLightsOffButton.Clear(); ggBatteryButton.Clear(); ggBatteryOnButton.Clear(); ggBatteryOffButton.Clear(); @@ -8262,7 +8357,6 @@ void TTrain::clear_cab_controls() btLampkaWentZaluzje.Clear(); btLampkaDoorLeft.Clear(); btLampkaDoorRight.Clear(); - btLampkaDoors.Clear(); btLampkaDepartureSignal.Clear(); btLampkaRezerwa.Clear(); btLampkaBoczniki.Clear(); @@ -8337,10 +8431,12 @@ void TTrain::set_cab_controls( int const Cab ) { mvOccupied->Battery ? 1.f : 0.f ) ); // line breaker - ggMainButton.PutValue( - ( ggMainButton.type() == TGaugeType::push ? 0.5f : - m_linebreakerstate > 0 ? 1.f : - 0.f ) ); + if( ggMainButton.SubModel != nullptr ) { // instead of single main button there can be on/off pair + ggMainButton.PutValue( + ( ggMainButton.type() == TGaugeType::push ? 0.5f : + m_linebreakerstate > 0 ? 1.f : + 0.f ) ); + } // motor connectors ggStLinOffButton.PutValue( ( mvControlled->StLinSwitchOff ? @@ -8487,7 +8583,12 @@ void TTrain::set_cab_controls( int const Cab ) { if( true == Cabine[Cab].bLightDim ) { ggCabLightDimButton.PutValue( 1.f ); } - + // compartment lights + ggCompartmentLightsButton.PutValue( + ( ggCompartmentLightsButton.type() == TGaugeType::push ? 0.5f : + mvOccupied->CompartmentLights.is_enabled ? 1.f : + 0.f ) ); + // instrument lights ggInstrumentLightButton.PutValue( ( InstrumentLightActive ? 1.f : @@ -8687,7 +8788,6 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-security_cabsignal:", btLampkaSHP }, { "i-door_left:", btLampkaDoorLeft }, { "i-door_right:", btLampkaDoorRight }, - { "i-doors:", btLampkaDoors }, { "i-departure_signal:", btLampkaDepartureSignal }, { "i-reserve:", btLampkaRezerwa }, { "i-scnd:", btLampkaBoczniki }, @@ -8752,6 +8852,7 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co } // TODO: move viable dedicated lights to the automatic light array std::unordered_map const autolights = { + { "i-doors:", &m_doors }, { "i-doorpermit_left:", &mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::left : side::right ) ].open_permit }, { "i-doorpermit_right:", &mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::right : side::left ) ].open_permit }, { "i-doorstep:", &mvOccupied->Doors.step_enabled }, @@ -8844,8 +8945,6 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "fuse_bt:", ggFuseButton }, { "converterfuse_bt:", ggConverterFuseButton }, { "stlinoff_bt:", ggStLinOffButton }, - { "doorleftpermit_sw:", ggDoorLeftPermitButton }, - { "doorrightpermit_sw:", ggDoorRightPermitButton }, { "doorpermitpreset_sw:", ggDoorPermitPresetButton }, { "door_left_sw:", ggDoorLeftButton }, { "door_right_sw:", ggDoorRightButton }, @@ -8854,7 +8953,6 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "doorleftoff_sw:", ggDoorLeftOffButton }, { "doorrightoff_sw:", ggDoorRightOffButton }, { "doorallon_sw:", ggDoorAllOnButton }, - { "dooralloff_sw:", ggDoorAllOffButton }, { "departure_signal_bt:", ggDepartureSignalButton }, { "upperlight_sw:", ggUpperLightButton }, { "leftlight_sw:", ggLeftLightButton }, @@ -8918,6 +9016,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "timetablelight_sw:", ggTimetableLightButton }, { "cablight_sw:", ggCabLightButton }, { "cablightdim_sw:", ggCabLightDimButton }, + { "compartmentlights_sw:", ggCompartmentLightsButton }, + { "compartmentlightson_sw:", ggCompartmentLightsOnButton }, + { "compartmentlightsoff_sw:", ggCompartmentLightsOffButton }, { "battery_sw:", ggBatteryButton }, { "batteryon_sw:", ggBatteryOnButton }, { "batteryoff_sw:", ggBatteryOffButton }, @@ -8957,7 +9058,10 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "speedbutton6:", { ggSpeedCtrlButtons[ 6 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, { "speedbutton7:", { ggSpeedCtrlButtons[ 7 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, { "speedbutton8:", { ggSpeedCtrlButtons[ 8 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton9:", { ggSpeedCtrlButtons[ 9 ], &mvOccupied->SpeedCtrlUnit.IsActive } } + { "speedbutton9:", { ggSpeedCtrlButtons[ 9 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, + { "doorleftpermit_sw:", { ggDoorLeftPermitButton, &mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::left : side::right ) ].open_permit } }, + { "doorrightpermit_sw:", { ggDoorRightPermitButton, &mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::right : side::left ) ].open_permit } }, + { "dooralloff_sw:", { ggDoorAllOffButton, &m_doors } }, }; { auto const lookup { stategauges.find( Label ) }; diff --git a/Train.h b/Train.h index c3d4f6e7..6a1b4cb1 100644 --- a/Train.h +++ b/Train.h @@ -361,6 +361,9 @@ class TTrain { static void OnCommand_interiorlightdimtoggle( TTrain *Train, command_data const &Command ); static void OnCommand_interiorlightdimenable( TTrain *Train, command_data const &Command ); static void OnCommand_interiorlightdimdisable( TTrain *Train, command_data const &Command ); + static void OnCommand_compartmentlightstoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_compartmentlightsenable( TTrain *Train, command_data const &Command ); + static void OnCommand_compartmentlightsdisable( TTrain *Train, command_data const &Command ); static void OnCommand_instrumentlighttoggle( TTrain *Train, command_data const &Command ); static void OnCommand_instrumentlightenable( TTrain *Train, command_data const &Command ); static void OnCommand_instrumentlightdisable( TTrain *Train, command_data const &Command ); @@ -539,10 +542,13 @@ public: // reszta może by?publiczna TGauge ggTimetableLightButton; TGauge ggCabLightButton; // hunter-091012: przelacznik oswietlania kabiny TGauge ggCabLightDimButton; // hunter-091012: przelacznik przyciemnienia + // oswietlenia kabiny + TGauge ggCompartmentLightsButton; + TGauge ggCompartmentLightsOnButton; + TGauge ggCompartmentLightsOffButton; TGauge ggBatteryButton; // Stele 161228 hebelek baterii TGauge ggBatteryOnButton; TGauge ggBatteryOffButton; - // oswietlenia kabiny // NBMX wrzesien 2003 - obsluga drzwi TGauge ggDoorLeftPermitButton; @@ -661,7 +667,6 @@ public: // reszta może by?publiczna TButton btLampkaPrzekrMaxSila; TButton btLampkaDoorLeft; TButton btLampkaDoorRight; - TButton btLampkaDoors; TButton btLampkaDepartureSignal; TButton btLampkaBlokadaDrzwi; TButton btLampkaDoorLockOff; @@ -776,6 +781,7 @@ private: float m_distancecounter { -1.f }; // distance traveled since meter was activated or -1 if inactive double m_brakehandlecp{ 0.0 }; int m_pantselection{ 0 }; + bool m_doors{ false }; // helper, true if any door is open public: float fPress[20][3]; // cisnienia dla wszystkich czlonow diff --git a/command.cpp b/command.cpp index 241d05ce..d4ea7974 100644 --- a/command.cpp +++ b/command.cpp @@ -224,6 +224,9 @@ commanddescription_sequence Commands_descriptions = { { "interiorlightdimtoggle", command_target::vehicle }, { "interiorlightdimenable", command_target::vehicle }, { "interiorlightdimdisable", command_target::vehicle }, + { "compartmentlightstoggle", command_target::vehicle }, + { "compartmentlightsenable", command_target::vehicle }, + { "compartmentlightsdisable", command_target::vehicle }, { "instrumentlighttoggle", command_target::vehicle }, { "instrumentlightenable", command_target::vehicle }, { "instrumentlightdisable", command_target::vehicle }, diff --git a/command.h b/command.h index 1073cbb2..0987a421 100644 --- a/command.h +++ b/command.h @@ -215,6 +215,9 @@ enum class user_command { interiorlightdimtoggle, interiorlightdimenable, interiorlightdimdisable, + compartmentlightstoggle, + compartmentlightsenable, + compartmentlightsdisable, instrumentlighttoggle, instrumentlightenable, instrumentlightdisable, diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp index cf461660..3ba33ddd 100644 --- a/driverkeyboardinput.cpp +++ b/driverkeyboardinput.cpp @@ -224,6 +224,9 @@ driverkeyboard_input::default_bindings() { { user_command::interiorlightdimtoggle, GLFW_KEY_APOSTROPHE | keymodifier::control }, // interiorlightdimenable, // interiorlightdimdisable, + // compartmentlightstoggle, + // compartmentlightsenable, + // compartmentlightsdisable, { user_command::instrumentlighttoggle, GLFW_KEY_SEMICOLON }, // instrumentlightenable, // instrumentlightdisable, diff --git a/drivermode.cpp b/drivermode.cpp index 6b14af91..fffa5e64 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -106,6 +106,10 @@ std::unordered_map> commandf { 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 } }, + { user_command::compartmentlightsenable, { user_command::compartmentlightstoggle, user_command::none } }, + { user_command::compartmentlightsdisable, { user_command::compartmentlightstoggle, user_command::none } }, + { user_command::batteryenable, { user_command::batterytoggle, user_command::none } }, + { user_command::batterydisable, { user_command::batterytoggle, user_command::none } }, }; std::pair diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index 65f8ca09..60b9bc4c 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -837,6 +837,15 @@ drivermouse_input::default_bindings() { { "cablightdim_sw:", { user_command::interiorlightdimtoggle, user_command::none } }, + { "compartmentlights_sw:", { + user_command::compartmentlightstoggle, + user_command::none } }, + { "compartmentlightson_sw:", { + user_command::compartmentlightsenable, + user_command::none } }, + { "compartmentlightsoff_sw:", { + user_command::compartmentlightsdisable, + user_command::none } }, { "battery_sw:", { user_command::batterytoggle, user_command::none } }, diff --git a/maszyna.vcxproj b/maszyna.vcxproj index ff54530e..612613da 100644 --- a/maszyna.vcxproj +++ b/maszyna.vcxproj @@ -97,7 +97,7 @@ true - $(DXSKD_DIR)lib/$(PlatformShortName);$(SolutionDir)ref/glew/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/glfw/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/openal/lib/$(PlatformShortName);$(SolutionDir)ref/python/lib/$(PlatformShortName);$(SolutionDir)ref/libserialport/lib/$(PlatformShortName);%(AdditionalLibraryDirectories) + $(DXSKD_DIR)lib/$(PlatformShortName);$(SolutionDir)ref/glfw/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/openal/lib/$(PlatformShortName);$(SolutionDir)ref/python/lib/$(PlatformShortName);$(SolutionDir)ref/libserialport/lib/$(PlatformShortName);%(AdditionalLibraryDirectories) Windows @@ -120,7 +120,7 @@ true - $(DXSKD_DIR)lib/$(PlatformShortName);$(SolutionDir)ref/glew/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/glfw/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/openal/lib/$(PlatformShortName);$(SolutionDir)ref/python/lib/$(PlatformShortName);$(SolutionDir)ref/libserialport/lib/$(PlatformShortName);%(AdditionalLibraryDirectories) + $(DXSKD_DIR)lib/$(PlatformShortName);$(SolutionDir)ref/glfw/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/openal/lib/$(PlatformShortName);$(SolutionDir)ref/python/lib/$(PlatformShortName);$(SolutionDir)ref/libserialport/lib/$(PlatformShortName);%(AdditionalLibraryDirectories) Windows @@ -142,7 +142,7 @@ true true true - $(DXSKD_DIR)lib/$(PlatformShortName);$(SolutionDir)ref/glew/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/glfw/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/openal/lib/$(PlatformShortName);$(SolutionDir)ref/python/lib/$(PlatformShortName);$(SolutionDir)ref/libserialport/lib/$(PlatformShortName);%(AdditionalLibraryDirectories) + $(DXSKD_DIR)lib/$(PlatformShortName);$(SolutionDir)ref/glfw/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/openal/lib/$(PlatformShortName);$(SolutionDir)ref/python/lib/$(PlatformShortName);$(SolutionDir)ref/libserialport/lib/$(PlatformShortName);%(AdditionalLibraryDirectories) Windows libcmt.lib true @@ -166,7 +166,7 @@ true true true - $(DXSKD_DIR)lib/$(PlatformShortName);$(SolutionDir)ref/glew/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/glfw/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/openal/lib/$(PlatformShortName);$(SolutionDir)ref/python/lib/$(PlatformShortName);$(SolutionDir)ref/libserialport/lib/$(PlatformShortName);%(AdditionalLibraryDirectories) + $(DXSKD_DIR)lib/$(PlatformShortName);$(SolutionDir)ref/glfw/lib/msvc-$(MSBuildToolsVersion)/$(PlatformShortName);$(SolutionDir)ref/openal/lib/$(PlatformShortName);$(SolutionDir)ref/python/lib/$(PlatformShortName);$(SolutionDir)ref/libserialport/lib/$(PlatformShortName);%(AdditionalLibraryDirectories) Windows libcmt.lib UseLinkTimeCodeGeneration diff --git a/opengl33renderer.cpp b/opengl33renderer.cpp index 8f1d6b09..008b1eab 100644 --- a/opengl33renderer.cpp +++ b/opengl33renderer.cpp @@ -713,11 +713,10 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode) setup_shadow_color( glm::min( colors::white, m_shadowcolor + glm::vec4( vehicle->InteriorLight * vehicle->InteriorLightLevel, 1.f ) ) ); } Render_cab( vehicle, vehicle->InteriorLightLevel, false ); - if( vehicle->InteriorLightLevel > 0.f ) { - setup_shadow_color( m_shadowcolor ); - } } + setup_shadow_color( m_shadowcolor ); + glDebug("render opaque region"); model_ubs.future = future; @@ -755,9 +754,9 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode) } glDebug( "render translucent cab" ); Render_cab(vehicle, vehicle->InteriorLightLevel, true); - if( vehicle->InteriorLightLevel > 0.f ) { - setup_shadow_color( m_shadowcolor ); - } + + setup_shadow_color( m_shadowcolor ); + if( Global.Overcast > 1.0f ) { // with the cab in place we can (finally) safely draw translucent part of the occupied vehicle Render_Alpha( vehicle ); @@ -1023,7 +1022,19 @@ bool opengl33_renderer::Render_lowpoly( TDynamicObject *Dynamic, float const Squ } // HACK: reduce light level for vehicle interior if there's strong global lighting source if( false == Alpha ) { - auto const luminance{ static_cast( 0.5 * ( std::max( 0.3, Global.fLuminance - Global.Overcast ) ) ) }; +/* + auto const luminance { static_cast( std::min( + ( Dynamic->fShade > 0.0 ? Dynamic->fShade * Global.fLuminance : Global.fLuminance ), + Global.fLuminance - 0.5 * ( std::max( 0.3, Global.fLuminance - Global.Overcast ) ) ) ) }; +*/ + auto const luminance{ static_cast( + 0.5 + * ( std::max( + 0.3, + ( Global.fLuminance - Global.Overcast ) + * ( Dynamic->fShade > 0.0 ? + Dynamic->fShade : + 1.0 ) ) ) ) }; setup_sunlight_intensity( clamp( ( Dynamic->fShade > 0.f ? @@ -1729,7 +1740,7 @@ std::shared_ptr opengl33_renderer::Fetch_Shader(const std::string & return m_shaders[name]; } -void opengl33_renderer::Bind_Material(material_handle const Material, TSubModel *sm) +void opengl33_renderer::Bind_Material( material_handle const Material, TSubModel const *sm, lighting_data const *lighting ) { if (Material != null_handle) { @@ -1773,6 +1784,26 @@ void opengl33_renderer::Bind_Material(material_handle const Material, TSubModel } } } + if( lighting ) + { + switch( entry.defaultparam ) { + case gl::shader::defaultparam_e::ambient: { + src = lighting->ambient; + break; + } + case gl::shader::defaultparam_e::diffuse: { + src = lighting->diffuse; + break; + } + case gl::shader::defaultparam_e::specular: { + src = lighting->specular; + break; + } + default: { + break; + } + } + } // material-based parameters switch( entry.defaultparam ) { case gl::shader::defaultparam_e::glossiness: { @@ -2280,7 +2311,7 @@ void opengl33_renderer::Render(scene::shape_node const &Shape, bool const Ignore { case rendermode::color: case rendermode::reflections: - Bind_Material(data.material); + Bind_Material(data.material, nullptr, &Shape.data().lighting ); break; case rendermode::shadows: Bind_Material_Shadow(data.material); @@ -2546,9 +2577,10 @@ bool opengl33_renderer::Render_cab(TDynamicObject const *Dynamic, float const Li } auto const old_ambient { light_ubs.ambient }; + auto const luminance { Global.fLuminance * ( Dynamic->fShade > 0.0f ? Dynamic->fShade : 1.0f ) }; if( Lightlevel > 0.f ) { // crude way to light the cabin, until we have something more complete in place - light_ubs.ambient += ( Dynamic->InteriorLight * Lightlevel ) * static_cast( clamp( 1.25 - Global.fLuminance, 0.0, 1.0 ) ); + light_ubs.ambient += ( Dynamic->InteriorLight * Lightlevel ) * static_cast( clamp( 1.25 - luminance, 0.0, 1.0 ) ); light_ubo->update( light_ubs ); } @@ -2564,17 +2596,8 @@ bool opengl33_renderer::Render_cab(TDynamicObject const *Dynamic, float const Li Render(Dynamic->mdKabina, Dynamic->Material(), 0.0); } // post-render restore - if (Dynamic->fShade > 0.0f) - { - // change light level based on light level of the occupied track - setup_sunlight_intensity(); - } - - // restore ambient - if( Lightlevel > 0.f ) { - light_ubs.ambient = old_ambient; - light_ubo->update( light_ubs ); - } + light_ubs.ambient = old_ambient; + setup_sunlight_intensity(); break; } diff --git a/opengl33renderer.h b/opengl33renderer.h index 04ef0433..15649e18 100644 --- a/opengl33renderer.h +++ b/opengl33renderer.h @@ -73,7 +73,7 @@ class opengl33_renderer : public gfx_renderer { material_handle Fetch_Material( std::string const &Filename, bool const Loadnow = true ) override; void - Bind_Material( material_handle const Material, TSubModel *sm = nullptr ) override; + Bind_Material( material_handle const Material, TSubModel const *sm = nullptr, lighting_data const *lighting = nullptr ) override; opengl_material const & Material( material_handle const Material ) const override; // shader methods diff --git a/openglrenderer.cpp b/openglrenderer.cpp index 27b6bf0a..3bf399dc 100644 --- a/openglrenderer.cpp +++ b/openglrenderer.cpp @@ -797,7 +797,14 @@ bool opengl_renderer::Render_lowpoly( TDynamicObject *Dynamic, float const Squar } // HACK: reduce light level for vehicle interior if there's strong global lighting source if( false == Alpha ) { - auto const luminance{ static_cast( 0.5 * ( std::max( 0.3, Global.fLuminance - Global.Overcast ) ) ) }; + auto const luminance{ static_cast( + 0.5 + * ( std::max( + 0.3, + ( Global.fLuminance - Global.Overcast ) + * ( Dynamic->fShade > 0.0 ? + Dynamic->fShade : + 1.0 ) ) ) ) }; m_sunlight.apply_intensity( clamp( ( Dynamic->fShade > 0.f ? @@ -1677,7 +1684,7 @@ opengl_renderer::Fetch_Material( std::string const &Filename, bool const Loadnow } void -opengl_renderer::Bind_Material( material_handle const Material, TSubModel *sm ) { +opengl_renderer::Bind_Material( material_handle const Material, TSubModel const *sm, lighting_data const *lighting ) { auto const &material = m_materials.material( Material ); if( false == Global.BasicRenderer ) { @@ -2403,11 +2410,12 @@ opengl_renderer::Render_cab( TDynamicObject const *Dynamic, float const Lightlev } if( Lightlevel > 0.f ) { // crude way to light the cabin, until we have something more complete in place + auto const luminance { Global.fLuminance * ( Dynamic->fShade > 0.0f ? Dynamic->fShade : 1.0f ) }; ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr( glm::vec3( m_baseambient ) - + ( Dynamic->InteriorLight * Lightlevel ) * static_cast( clamp( 1.25 - Global.fLuminance, 0.0, 1.0 ) ) ) ); + + ( Dynamic->InteriorLight * Lightlevel ) * static_cast( clamp( 1.25 - luminance, 0.0, 1.0 ) ) ) ); } // render if( true == Alpha ) { diff --git a/openglrenderer.h b/openglrenderer.h index afb375a0..d80c7793 100644 --- a/openglrenderer.h +++ b/openglrenderer.h @@ -67,7 +67,7 @@ public: material_handle Fetch_Material( std::string const &Filename, bool const Loadnow = true ) override; void - Bind_Material( material_handle const Material, TSubModel *sm = nullptr ) override; + Bind_Material( material_handle const Material, TSubModel const *sm = nullptr, lighting_data const *lighting = nullptr ) override; opengl_material const & Material( material_handle const Material ) const override; // shader methods diff --git a/renderer.h b/renderer.h index 4e08ffac..f8c0c71b 100644 --- a/renderer.h +++ b/renderer.h @@ -12,6 +12,8 @@ http://mozilla.org/MPL/2.0/. #include "geometrybank.h" #include "material.h" +class lighting_data; + class gfx_renderer { public: @@ -38,7 +40,7 @@ public: virtual auto Vertices( gfx::geometry_handle const &Geometry ) const ->gfx::vertex_array const & = 0; // material methods virtual auto Fetch_Material( std::string const &Filename, bool const Loadnow = true ) -> material_handle = 0; - virtual void Bind_Material( material_handle const Material, TSubModel *sm = nullptr ) = 0; + virtual void Bind_Material( material_handle const Material, TSubModel const *sm = nullptr, lighting_data const *lighting = nullptr ) = 0; virtual auto Material( material_handle const Material ) const -> opengl_material const & = 0; // shader methods virtual auto Fetch_Shader( std::string const &name ) -> std::shared_ptr = 0; diff --git a/shaders/light_common.glsl b/shaders/light_common.glsl index 0d26e1e2..335d1ff0 100644 --- a/shaders/light_common.glsl +++ b/shaders/light_common.glsl @@ -108,12 +108,15 @@ vec2 calc_headlights(light_s light, vec3 fragnormal) vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone) { + fragcolor *= param[1].x; + vec3 emissioncolor = param[0].rgb * emission; vec3 envcolor = envmap_color(fragnormal); if(lights_count == 0U) return (fragcolor + emissioncolor + envcolor * reflectivity) * texturecolor; +// fragcolor *= lights[0].intensity; vec2 sunlight = calc_dir_light(lights[0], fragnormal); float diffuseamount = (sunlight.x * param[1].x) * lights[0].intensity; diff --git a/translation.cpp b/translation.cpp index b6f8aef9..f5cbc4c7 100644 --- a/translation.cpp +++ b/translation.cpp @@ -202,6 +202,9 @@ init() { "timetable light", "interior light", "interior light dimmer", + "compartment lights", + "compartment lights", + "compartment lights", "battery", "battery", "battery", @@ -397,6 +400,9 @@ init() { "oswietlenie rozkladu jazdy", "oswietlenie kabiny", "przyciemnienie oswietlenia kabiny", + "oswietlenie przedzialow", + "oswietlenie przedzialow", + "oswietlenie przedzialow", "bateria", "bateria", "bateria", @@ -545,6 +551,9 @@ init() { "timetablelight_sw:", "cablight_sw:", "cablightdim_sw:", + "compartmentlights_sw:", + "compartmentlightson_sw:", + "compartmentlightsoff_sw:", "battery_sw:", "batteryon_sw:", "batteryoff_sw:", diff --git a/translation.h b/translation.h index ed48552b..def285d0 100644 --- a/translation.h +++ b/translation.h @@ -191,6 +191,9 @@ enum string { cab_timetablelight_sw, cab_cablight_sw, cab_cablightdim_sw, + cab_compartmentlights_sw, + cab_compartmentlightson_sw, + cab_compartmentlightsoff_sw, cab_battery_sw, cab_batteryon_sw, cab_batteryoff_sw,