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

build 200322. coupler adapter, automatic coupling vehicle setting, parked vehicle manual brake activation, ai braking logic enhancement, opengl 3.3 renderer diffuse color visualization fix, minor cab control logic bug fixes

This commit is contained in:
tmj-fstate
2020-03-24 16:12:25 +01:00
parent e0c1f41474
commit c22f4c900f
17 changed files with 431 additions and 93 deletions

View File

@@ -1988,6 +1988,8 @@ void TController::AutoRewident()
break; break;
} }
} }
// potentially release manual brake
d->MoverParameters->DecManualBrakeLevel( ManualBrakePosNo );
} }
d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła)
} }
@@ -2347,6 +2349,10 @@ bool TController::CheckVehicles(TOrders user)
break; break;
} }
} // switch } // switch
if( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) ) {
// nastawianie hamulca do jazdy pociągowej
AutoRewident();
}
} }
// Ra 2014-09: tymczasowo prymitywne ustawienie warunku pod kątem SN61 // Ra 2014-09: tymczasowo prymitywne ustawienie warunku pod kątem SN61
if( ( mvOccupied->TrainType == dt_EZT ) if( ( mvOccupied->TrainType == dt_EZT )
@@ -2767,7 +2773,14 @@ bool TController::ReleaseEngine() {
} }
// gasimy światła // gasimy światła
Lights( 0, 0 ); Lights( 0, 0 );
// activate parking brake
// TBD: do it earlier?
mvOccupied->SpringBrakeActivate(true); mvOccupied->SpringBrakeActivate(true);
if( ( mvOccupied->LocalBrake == TLocalBrake::ManualBrake )
|| ( mvOccupied->MBrake == true ) ) {
mvOccupied->IncManualBrakeLevel( ManualBrakePosNo );
}
// switch off remaining power
mvOccupied->BatterySwitch( false ); mvOccupied->BatterySwitch( false );
} }
} }
@@ -2959,7 +2972,14 @@ bool TController::IncBrakeEIM()
switch (mvOccupied->EIMCtrlType) switch (mvOccupied->EIMCtrlType)
{ {
case 0: { case 0: {
if( mvOccupied->MED_amax != 9.81 ) {
auto const brakeposition{ clamp( -1.0 * mvOccupied->AIHintLocalBrakeAccFactor * AccDesired / mvOccupied->MED_amax, 0.0, 1.0 ) };
OK = ( brakeposition != mvOccupied->LocalBrakePosA );
mvOccupied->LocalBrakePosA = brakeposition;
}
else {
OK = mvOccupied->IncLocalBrakeLevel( 1 ); OK = mvOccupied->IncLocalBrakeLevel( 1 );
}
break; break;
} }
case 1: { case 1: {
@@ -3067,25 +3087,36 @@ bool TController::DecBrakeEIM()
bool OK = false; bool OK = false;
switch (mvOccupied->EIMCtrlType) switch (mvOccupied->EIMCtrlType)
{ {
case 0: case 0: {
OK = mvOccupied->DecLocalBrakeLevel(1); if( mvOccupied->MED_amax != 9.81 ) {
auto const brakeposition { clamp( -1.0 * mvOccupied->AIHintLocalBrakeAccFactor * AccDesired / mvOccupied->MED_amax, 0.0, 1.0 ) };
OK = ( brakeposition != mvOccupied->LocalBrakePosA );
mvOccupied->LocalBrakePosA = brakeposition;
}
else {
OK = mvOccupied->DecLocalBrakeLevel( 1 );
}
break; break;
case 1: }
case 1: {
OK = mvOccupied->MainCtrlPos < 2; OK = mvOccupied->MainCtrlPos < 2;
if (OK) if( OK )
mvOccupied->MainCtrlPos = 2; mvOccupied->MainCtrlPos = 2;
break; break;
case 2: }
case 2: {
OK = mvOccupied->MainCtrlPos < 3; OK = mvOccupied->MainCtrlPos < 3;
if (OK) if( OK )
mvOccupied->MainCtrlPos = 3; mvOccupied->MainCtrlPos = 3;
break; break;
case 3: }
case 3: {
OK = mvOccupied->MainCtrlPos < mvOccupied->MainCtrlMaxDirChangePos; OK = mvOccupied->MainCtrlPos < mvOccupied->MainCtrlMaxDirChangePos;
if( OK ) if( OK )
mvOccupied->MainCtrlPos = mvOccupied->MainCtrlMaxDirChangePos; mvOccupied->MainCtrlPos = mvOccupied->MainCtrlMaxDirChangePos;
break; break;
} }
}
return OK; return OK;
} }
@@ -4468,6 +4499,7 @@ void TController::PhysicsLog()
void void
TController::UpdateSituation(double dt) { TController::UpdateSituation(double dt) {
// uruchamiać przynajmniej raz na sekundę // uruchamiać przynajmniej raz na sekundę
if( false == simulation::is_ready ) { return; }
if( ( iDrivigFlags & movePrimary ) == 0 ) { return; } // pasywny nic nie robi if( ( iDrivigFlags & movePrimary ) == 0 ) { return; } // pasywny nic nie robi
// update timers // update timers
@@ -5068,6 +5100,16 @@ TController::UpdateSituation(double dt) {
int const end { ( vehicle->DirectionGet() > 0 ? end::front : end::rear ) }; int const end { ( vehicle->DirectionGet() > 0 ? end::front : end::rear ) };
auto const &neighbour { vehicleparameters->Neighbours[ end ] }; auto const &neighbour { vehicleparameters->Neighbours[ end ] };
if( neighbour.vehicle != nullptr ) { if( neighbour.vehicle != nullptr ) {
if( neighbour.distance < 10 ) {
// check whether we don't need to attach coupler adapter
auto &coupler{ vehicleparameters->Couplers[ end ] };
if( coupler.type() != TCouplerType::Automatic ) {
auto &othercoupler = neighbour.vehicle->MoverParameters->Couplers[ ( neighbour.vehicle_end != 2 ? neighbour.vehicle_end : coupler.ConnectedNr ) ];
if( othercoupler.type() == TCouplerType::Automatic ) {
vehicle->attach_coupler_adapter( end );
}
}
if( neighbour.distance < 2 ) {
// próba podczepienia // próba podczepienia
vehicleparameters->Attach( vehicleparameters->Attach(
end, neighbour.vehicle_end, end, neighbour.vehicle_end,
@@ -5082,6 +5124,8 @@ TController::UpdateSituation(double dt) {
JumpToNextOrder(); // wykonanie następnej komendy JumpToNextOrder(); // wykonanie następnej komendy
} }
} }
}
}
} // if (AIControllFlag) //koniec zblokowania, bo była zmienna lokalna } // if (AIControllFlag) //koniec zblokowania, bo była zmienna lokalna
} }
else { else {
@@ -5463,7 +5507,12 @@ TController::UpdateSituation(double dt) {
// tylko jeśli odepnie // tylko jeśli odepnie
WriteLog( mvOccupied->Name + " odczepiony." ); WriteLog( mvOccupied->Name + " odczepiony." );
iVehicleCount = -2; iVehicleCount = -2;
CheckVehicles( Disconnect ); // update trainset state // potentially remove coupler adapter
if( p->MoverParameters->Couplers[ d ].has_adapter() ) {
p->remove_coupler_adapter( d );
}
// update trainset state
CheckVehicles( Disconnect );
} // a jak nie, to dociskać dalej } // a jak nie, to dociskać dalej
} }
if ((mvOccupied->Vel < 0.01) && !(iDrivigFlags & movePress)) if ((mvOccupied->Vel < 0.01) && !(iDrivigFlags & movePress))

View File

@@ -747,14 +747,16 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
// ABu-240105: Dodatkowy warunek: if (...).Render, zeby rysowal tylko // ABu-240105: Dodatkowy warunek: if (...).Render, zeby rysowal tylko
// jeden // jeden
// z polaczonych sprzegow // z polaczonych sprzegow
if ((TestFlag(MoverParameters->Couplers[end::front].CouplingFlag, ctrain_coupler)) && if ((false == MoverParameters->Couplers[ end::front ].has_adapter()) &&
(TestFlag(MoverParameters->Couplers[end::front].CouplingFlag, ctrain_coupler)) &&
(MoverParameters->Couplers[end::front].Render)) (MoverParameters->Couplers[end::front].Render))
{ {
btCoupler1.Turn( true ); btCoupler1.Turn( true );
btnOn = true; btnOn = true;
} }
// else btCoupler1.TurnOff(); // else btCoupler1.TurnOff();
if ((TestFlag(MoverParameters->Couplers[end::rear].CouplingFlag, ctrain_coupler)) && if ((false == MoverParameters->Couplers[ end::rear ].has_adapter()) &&
(TestFlag(MoverParameters->Couplers[end::rear].CouplingFlag, ctrain_coupler)) &&
(MoverParameters->Couplers[end::rear].Render)) (MoverParameters->Couplers[end::rear].Render))
{ {
btCoupler2.Turn( true ); btCoupler2.Turn( true );
@@ -903,6 +905,12 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
// uginanie zderzakow // uginanie zderzakow
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
if( MoverParameters->Couplers[ i ].has_adapter() ) {
// HACK: if there's coupler adapter on this side, we presume there's additional distance put between vehicles
// which prevents buffers from clashing against each other (or the other vehicle doesn't have buffers to begin with)
continue;
}
auto const dist { clamp( MoverParameters->Couplers[ i ].Dist / 2.0, -MoverParameters->Couplers[ i ].DmaxB, 0.0 ) }; auto const dist { clamp( MoverParameters->Couplers[ i ].Dist / 2.0, -MoverParameters->Couplers[ i ].DmaxB, 0.0 ) };
if( dist >= 0.0 ) { continue; } if( dist >= 0.0 ) { continue; }
@@ -1539,6 +1547,64 @@ TDynamicObject::uncouple( int const Side ) {
return couplingflag; return couplingflag;
} }
bool
TDynamicObject::attach_coupler_adapter( int const Side ) {
auto &coupler { MoverParameters->Couplers[ Side ] };
// sanity check(s)
if( coupler.type() == TCouplerType::Automatic ) { return false; }
auto const *neighbour { MoverParameters->Neighbours[ Side ].vehicle };
if( ( neighbour == nullptr )
|| ( MoverParameters->Neighbours[ Side ].distance > 25.0 ) ) {
// can only acquire the adapter from a nearby enough vehicle
return false;
}
// TBD: empty struct instead of fallback defaults, to allow vehicles without adapter?
auto adapterdata {
coupleradapter_data {
{ 0.085f, 0.95f },
"tabor/polsprzeg" } };
if( false == neighbour->m_coupleradapter.model.empty() ) {
// explicit coupler adapter definition overrides default parameters
adapterdata = neighbour->m_coupleradapter;
}
if( MoverParameters->Neighbours[ Side ].distance - adapterdata.position.x < 0.5 ) {
// arbitrary amount of free room required to install the adapter
// NOTE: this also covers cases with established physical connection
return false;
}
coupler.adapter_type = TCouplerType::Automatic;
coupler.adapter_length = adapterdata.position.x;
coupler.adapter_height = adapterdata.position.y;
// audio flag, visuals update
coupler.sounds |= sound::attachadapter;
m_coupleradapters[ Side ] = TModelsManager::GetModel( adapterdata.model );
return true;
}
bool
TDynamicObject::remove_coupler_adapter( int const Side ) {
auto &coupler{ MoverParameters->Couplers[ Side ] };
if( coupler.adapter_type == TCouplerType::NoCoupler ) { return false; }
// TODO: sanity check(s)
if( coupler.Connected != nullptr ) {
// TBD: disallow instead adapter removal if it's coupled with another vehicle?
uncouple( Side );
}
coupler.adapter_type = TCouplerType::NoCoupler;
coupler.adapter_length = 0.0;
coupler.adapter_height = 0.0;
// audio flag, visuals update
coupler.sounds |= sound::removeadapter;
m_coupleradapters[ Side ] = nullptr;
return true;
}
TDynamicObject::TDynamicObject() { TDynamicObject::TDynamicObject() {
modelShake = Math3D::vector3(0, 0, 0); modelShake = Math3D::vector3(0, 0, 0);
// fTrackBlock = 10000.0; // brak przeszkody na drodze // fTrackBlock = 10000.0; // brak przeszkody na drodze
@@ -3367,7 +3433,7 @@ bool TDynamicObject::Update(double dt, double dt1)
double fCurrent = ( double fCurrent = (
( MoverParameters->DynamicBrakeFlag && MoverParameters->ResistorsFlag ) ? ( MoverParameters->DynamicBrakeFlag && MoverParameters->ResistorsFlag ) ?
0 : 0 :
std::abs( MoverParameters->Itot ) ) std::abs( MoverParameters->Itot ) * MoverParameters->IsVehicleEIMBrakingFactor() )
+ MoverParameters->TotalCurrent; // prąd pobierany przez pojazd - bez sensu z tym (TotalCurrent) + MoverParameters->TotalCurrent; // prąd pobierany przez pojazd - bez sensu z tym (TotalCurrent)
// TotalCurrent to bedzie prad nietrakcyjny (niezwiazany z napedem) // TotalCurrent to bedzie prad nietrakcyjny (niezwiazany z napedem)
// fCurrent+=fabs(MoverParameters->Voltage)*1e-6; //prąd płynący przez woltomierz, rozładowuje kondensator orgromowy 4µF // fCurrent+=fabs(MoverParameters->Voltage)*1e-6; //prąd płynący przez woltomierz, rozładowuje kondensator orgromowy 4µF
@@ -4394,6 +4460,12 @@ void TDynamicObject::RenderSounds() {
m_couplersounds[ couplerindex ].dsbCouplerAttach.play(); m_couplersounds[ couplerindex ].dsbCouplerAttach.play();
m_couplersounds[ couplerindex ].dsbCouplerDetach.play(); m_couplersounds[ couplerindex ].dsbCouplerDetach.play();
} }
if( true == TestFlag( coupler.sounds, sound::attachadapter ) ) {
m_couplersounds[ couplerindex ].dsbAdapterAttach.play();
}
if( true == TestFlag( coupler.sounds, sound::removeadapter ) ) {
m_couplersounds[ couplerindex ].dsbAdapterRemove.play();
}
++couplerindex; ++couplerindex;
coupler.sounds = 0; coupler.sounds = 0;
@@ -4566,6 +4638,17 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
mdLowPolyInt = TModelsManager::GetModel(asModel, true); mdLowPolyInt = TModelsManager::GetModel(asModel, true);
} }
else if(token == "coupleradapter:") {
// coupling adapter data
parser.getTokens( 3 );
parser
>> m_coupleradapter.model
>> m_coupleradapter.position.x
>> m_coupleradapter.position.y;
replace_slashes( m_coupleradapter.model );
erase_leading_slashes( m_coupleradapter.model );
}
else if(token == "attachments:") { else if(token == "attachments:") {
// additional 3d models attached to main body // additional 3d models attached to main body
// content provided as a series of values together enclosed in "{}" // content provided as a series of values together enclosed in "{}"
@@ -5784,6 +5867,24 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
couplersounds.dsbBufferClamp_loud = bufferclash; couplersounds.dsbBufferClamp_loud = bufferclash;
} }
} }
else if( token == "coupleradapterattach:" ) {
// laczenie:
sound_source adapterattach { sound_placement::external };
adapterattach.deserialize( parser, sound_type::single );
adapterattach.owner( this );
for( auto &couplersounds : m_couplersounds ) {
couplersounds.dsbAdapterAttach = adapterattach;
}
}
else if( token == "coupleradapterremove:" ) {
// rozlaczanie:
sound_source adapterremove { sound_placement::external };
adapterremove.deserialize( parser, sound_type::single );
adapterremove.owner( this );
for( auto &couplersounds : m_couplersounds ) {
couplersounds.dsbAdapterRemove = adapterremove;
}
}
else if( token == "startjolt:" ) { else if( token == "startjolt:" ) {
// movement start jolt // movement start jolt
m_startjolt.deserialize( parser, sound_type::single ); m_startjolt.deserialize( parser, sound_type::single );
@@ -5972,6 +6073,8 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
m_couplersounds[ end::front ].dsbCouplerStretch_loud.offset( frontcoupleroffset ); m_couplersounds[ end::front ].dsbCouplerStretch_loud.offset( frontcoupleroffset );
m_couplersounds[ end::front ].dsbBufferClamp.offset( frontcoupleroffset ); m_couplersounds[ end::front ].dsbBufferClamp.offset( frontcoupleroffset );
m_couplersounds[ end::front ].dsbBufferClamp_loud.offset( frontcoupleroffset ); m_couplersounds[ end::front ].dsbBufferClamp_loud.offset( frontcoupleroffset );
m_couplersounds[ end::front ].dsbAdapterAttach.offset( frontcoupleroffset );
m_couplersounds[ end::front ].dsbAdapterRemove.offset( frontcoupleroffset );
auto const rearcoupleroffset { glm::vec3{ 0.f, 1.f, MoverParameters->Dim.L * -0.5f } }; auto const rearcoupleroffset { glm::vec3{ 0.f, 1.f, MoverParameters->Dim.L * -0.5f } };
m_couplersounds[ end::rear ].dsbCouplerAttach.offset( rearcoupleroffset ); m_couplersounds[ end::rear ].dsbCouplerAttach.offset( rearcoupleroffset );
m_couplersounds[ end::rear ].dsbCouplerDetach.offset( rearcoupleroffset ); m_couplersounds[ end::rear ].dsbCouplerDetach.offset( rearcoupleroffset );
@@ -5979,6 +6082,8 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
m_couplersounds[ end::rear ].dsbCouplerStretch_loud.offset( rearcoupleroffset ); m_couplersounds[ end::rear ].dsbCouplerStretch_loud.offset( rearcoupleroffset );
m_couplersounds[ end::rear ].dsbBufferClamp.offset( rearcoupleroffset ); m_couplersounds[ end::rear ].dsbBufferClamp.offset( rearcoupleroffset );
m_couplersounds[ end::rear ].dsbBufferClamp_loud.offset( rearcoupleroffset ); m_couplersounds[ end::rear ].dsbBufferClamp_loud.offset( rearcoupleroffset );
m_couplersounds[ end::rear ].dsbAdapterAttach.offset( rearcoupleroffset );
m_couplersounds[ end::rear ].dsbAdapterRemove.offset( rearcoupleroffset );
} }
TModel3d * TModel3d *
@@ -6258,6 +6363,10 @@ TDynamicObject::update_neighbours() {
// neighbour.vehicle = coupler.Connected; // neighbour.vehicle = coupler.Connected;
// neighbour.vehicle_end = coupler.ConnectedNr; // neighbour.vehicle_end = coupler.ConnectedNr;
neighbour.distance = TMoverParameters::CouplerDist( MoverParameters, coupler.Connected ); neighbour.distance = TMoverParameters::CouplerDist( MoverParameters, coupler.Connected );
// take into account potential adapters attached to the couplers
auto const &othercoupler { neighbour.vehicle->MoverParameters->Couplers[ neighbour.vehicle_end ] };
neighbour.distance -= coupler.adapter_length;
neighbour.distance -= othercoupler.adapter_length;
} }
else { else {
// if there's no connected vehicle check for potential collision sources in the vicinity // if there's no connected vehicle check for potential collision sources in the vicinity
@@ -6276,6 +6385,10 @@ TDynamicObject::update_neighbours() {
if( neighbour.distance < ( neighbour.vehicle->MoverParameters->CategoryFlag == 2 ? 50 : 100 ) ) { if( neighbour.distance < ( neighbour.vehicle->MoverParameters->CategoryFlag == 2 ? 50 : 100 ) ) {
// at short distances (re)calculate range between couplers directly // at short distances (re)calculate range between couplers directly
neighbour.distance = TMoverParameters::CouplerDist( MoverParameters, neighbour.vehicle->MoverParameters ); neighbour.distance = TMoverParameters::CouplerDist( MoverParameters, neighbour.vehicle->MoverParameters );
// take into account potential adapters attached to the couplers
auto const &othercoupler { neighbour.vehicle->MoverParameters->Couplers[ neighbour.vehicle_end ] };
neighbour.distance -= coupler.adapter_length;
neighbour.distance -= othercoupler.adapter_length;
} }
} }
} }

View File

@@ -311,6 +311,11 @@ private:
float time { 0.f }; // time spent on the operation float time { 0.f }; // time spent on the operation
}; };
struct coupleradapter_data {
glm::vec2 position; // adapter placement; offset from vehicle end and height
std::string model; // 3d model of the adapter
};
struct coupler_sounds { struct coupler_sounds {
sound_source dsbCouplerAttach { sound_placement::external }; // moved from cab sound_source dsbCouplerAttach { sound_placement::external }; // moved from cab
sound_source dsbCouplerDetach { sound_placement::external }; // moved from cab sound_source dsbCouplerDetach { sound_placement::external }; // moved from cab
@@ -318,6 +323,8 @@ private:
sound_source dsbCouplerStretch_loud { sound_placement::external }; sound_source dsbCouplerStretch_loud { sound_placement::external };
sound_source dsbBufferClamp { sound_placement::external }; // moved from cab sound_source dsbBufferClamp { sound_placement::external }; // moved from cab
sound_source dsbBufferClamp_loud { sound_placement::external }; sound_source dsbBufferClamp_loud { sound_placement::external };
sound_source dsbAdapterAttach { sound_placement::external };
sound_source dsbAdapterRemove { sound_placement::external };
}; };
struct pantograph_sounds { struct pantograph_sounds {
@@ -394,6 +401,7 @@ private:
// members // members
TButton btCoupler1; // sprzegi TButton btCoupler1; // sprzegi
TButton btCoupler2; TButton btCoupler2;
std::array<TModel3d *, 2> m_coupleradapters = { nullptr, nullptr };
TAirCoupler btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki TAirCoupler btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
TAirCoupler btCPneumatic2; TAirCoupler btCPneumatic2;
TAirCoupler btCPneumatic1r; // ABu: to zeby nie bylo problemow przy laczeniu wagonow, TAirCoupler btCPneumatic1r; // ABu: to zeby nie bylo problemow przy laczeniu wagonow,
@@ -469,12 +477,14 @@ private:
sound_source m_outernoise { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; sound_source m_outernoise { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
#endif #endif
sound_source m_wheelflat { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; sound_source m_wheelflat { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
sound_source rscurve { sound_placement::external, 2 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; // youBy sound_source rscurve { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; // youBy
sound_source rsDerailment { sound_placement::external, 2 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; // McZapkie-051202 sound_source rsDerailment { sound_placement::external, 2 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; // McZapkie-051202
exchange_data m_exchange; // state of active load exchange procedure, if any exchange_data m_exchange; // state of active load exchange procedure, if any
exchange_sounds m_exchangesounds; // sounds associated with the load exchange exchange_sounds m_exchangesounds; // sounds associated with the load exchange
coupleradapter_data m_coupleradapter;
bool renderme; // yB - czy renderowac bool renderme; // yB - czy renderowac
float ModCamRot; float ModCamRot;
int iInventory[ 2 ] { 0, 0 }; // flagi bitowe posiadanych submodeli (np. świateł) int iInventory[ 2 ] { 0, 0 }; // flagi bitowe posiadanych submodeli (np. świateł)
@@ -583,6 +593,8 @@ private:
// pobranie współrzędnych tyłu // pobranie współrzędnych tyłu
inline Math3D::vector3 RearPosition() { inline Math3D::vector3 RearPosition() {
return vCoulpler[iDirection]; }; return vCoulpler[iDirection]; };
inline Math3D::vector3 CouplerPosition( end const End ) const {
return vCoulpler[ End ]; }
inline Math3D::vector3 AxlePositionGet() { inline Math3D::vector3 AxlePositionGet() {
return iAxleFirst ? return iAxleFirst ?
Axle1.pPosition : Axle1.pPosition :
@@ -647,6 +659,8 @@ private:
void couple( int const Side ); void couple( int const Side );
int uncouple( int const Side ); int uncouple( int const Side );
bool attach_coupler_adapter( int const Side );
bool remove_coupler_adapter( int const Side );
void RadioStop(); void RadioStop();
void Damage(char flag); void Damage(char flag);
void RaLightsSet(int head, int rear); void RaLightsSet(int head, int rear);

View File

@@ -240,7 +240,9 @@ enum sound {
attachmainhose = 1 << 10, attachmainhose = 1 << 10,
attachcontrol = 1 << 11, attachcontrol = 1 << 11,
attachgangway = 1 << 12, attachgangway = 1 << 12,
attachheating = 1 << 13 attachheating = 1 << 13,
attachadapter = 1 << 14,
removeadapter = 1 << 15,
}; };
//szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType //szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType
@@ -673,7 +675,8 @@ struct TCoupling {
double FmaxC = 1000.0; double FmaxC = 1000.0;
double beta = 0.0; double beta = 0.0;
TCouplerType CouplerType = TCouplerType::NoCoupler; /*typ sprzegu*/ TCouplerType CouplerType = TCouplerType::NoCoupler; /*typ sprzegu*/
int AllowedFlag = 3; //Ra: maska dostępnych int AutomaticCouplingFlag = coupling::coupler;
int AllowedFlag = coupling::coupler | coupling::brakehose; //Ra: maska dostępnych
/*zmienne*/ /*zmienne*/
int CouplingFlag = 0; /*0 - wirtualnie, 1 - sprzegi, 2 - pneumatycznie, 4 - sterowanie, 8 - kabel mocy*/ int CouplingFlag = 0; /*0 - wirtualnie, 1 - sprzegi, 2 - pneumatycznie, 4 - sterowanie, 8 - kabel mocy*/
class TMoverParameters *Connected = nullptr; /*co jest podlaczone*/ class TMoverParameters *Connected = nullptr; /*co jest podlaczone*/
@@ -682,12 +685,26 @@ struct TCoupling {
double Dist = 0.0; /*strzalka ugiecia zderzaków*/ double Dist = 0.0; /*strzalka ugiecia zderzaków*/
bool CheckCollision = false; /*czy sprawdzac sile czy pedy*/ bool CheckCollision = false; /*czy sprawdzac sile czy pedy*/
float stretch_duration { 0.f }; // seconds, elapsed time with excessive force applied to the coupler float stretch_duration { 0.f }; // seconds, elapsed time with excessive force applied to the coupler
// optional adapter piece
double adapter_length { 0.0 }; // meters, value added on the given end to standard vehicle (half)length
double adapter_height { 0.0 }; // meters, distance from rail level
TCouplerType adapter_type = TCouplerType::NoCoupler; // CouplerType override if other than NoCoupler
power_coupling power_high; power_coupling power_high;
// power_coupling power_low; // TODO: implement this // power_coupling power_low; // TODO: implement this
int sounds { 0 }; // sounds emitted by the coupling devices int sounds { 0 }; // sounds emitted by the coupling devices
bool Render = false; /*ABu: czy rysowac jak zaczepiony sprzeg*/ bool Render = false; /*ABu: czy rysowac jak zaczepiony sprzeg*/
inline bool
has_adapter() const {
return ( adapter_type != TCouplerType::NoCoupler ); }
inline TCouplerType const
type() const {
return (
adapter_type == TCouplerType::NoCoupler ?
CouplerType :
adapter_type ); }
}; };
struct neighbour_data { struct neighbour_data {
@@ -1543,6 +1560,7 @@ public:
int iLights[2]; // bity zapalonych świateł tutaj, żeby dało się liczyć pobór prądu int iLights[2]; // bity zapalonych świateł tutaj, żeby dało się liczyć pobór prądu
int AIHintPantstate{ 0 }; // suggested pantograph setup int AIHintPantstate{ 0 }; // suggested pantograph setup
double AIHintLocalBrakeAccFactor{ 1.05 }; // suggested acceleration weight for local brake operation
public: public:
TMoverParameters(double VelInitial, std::string TypeNameInit, std::string NameInit, int Cab); TMoverParameters(double VelInitial, std::string TypeNameInit, std::string NameInit, int Cab);
@@ -1557,6 +1575,8 @@ public:
bool DirectionForward(); bool DirectionForward();
bool DirectionBackward( void );/*! kierunek ruchu*/ bool DirectionBackward( void );/*! kierunek ruchu*/
bool EIMDirectionChangeAllow( void ) const; bool EIMDirectionChangeAllow( void ) const;
inline double IsVehicleEIMBrakingFactor() {
return eimv[ eimv_Ipoj ] < 0 ? -1.0 : 1.0; }
void BrakeLevelSet(double b); void BrakeLevelSet(double b);
bool BrakeLevelAdd(double b); bool BrakeLevelAdd(double b);
bool IncBrakeLevel(); // wersja na użytek AI bool IncBrakeLevel(); // wersja na użytek AI

View File

@@ -22,7 +22,7 @@ http://mozilla.org/MPL/2.0/.
// Jeśli jakieś zmienne nie są używane w mover.pas, też można je przenosić. // Jeśli jakieś zmienne nie są używane w mover.pas, też można je przenosić.
// Przeniesienie wszystkiego na raz zrobiło by zbyt wielki chaos do ogarnięcia. // Przeniesienie wszystkiego na raz zrobiło by zbyt wielki chaos do ogarnięcia.
const double dEpsilon = 0.01; // 1cm (zależy od typu sprzęgu...) const double dEpsilon = 0.025; // 1cm (zależy od typu sprzęgu...)
const double CouplerTune = 0.1; // skalowanie tlumiennosci const double CouplerTune = 0.1; // skalowanie tlumiennosci
int ConversionError = 0; int ConversionError = 0;
@@ -438,13 +438,13 @@ bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *
auto &coupler { Couplers[ ConnectNo ] }; auto &coupler { Couplers[ ConnectNo ] };
auto &othercoupler = ConnectTo->Couplers[ ( ConnectToNr != 2 ? ConnectToNr : coupler.ConnectedNr ) ]; auto &othercoupler = ConnectTo->Couplers[ ( ConnectToNr != 2 ? ConnectToNr : coupler.ConnectedNr ) ];
auto const distance { CouplerDist( this, ConnectTo ) }; auto const distance { CouplerDist( this, ConnectTo ) - ( coupler.adapter_length + othercoupler.adapter_length ) };
auto const couplercheck { auto const couplercheck {
( Forced ) ( Forced )
|| ( ( distance <= dEpsilon ) || ( ( distance <= dEpsilon )
&& ( coupler.CouplerType != TCouplerType::NoCoupler ) && ( coupler.type() != TCouplerType::NoCoupler )
&& ( coupler.CouplerType == othercoupler.CouplerType ) ) }; && ( coupler.type() == othercoupler.type() ) ) };
if( false == couplercheck ) { return false; } if( false == couplercheck ) { return false; }
@@ -495,7 +495,7 @@ int TMoverParameters::DettachStatus(int ConnectNo)
if (TestFlag(DamageFlag, dtrain_coupling)) if (TestFlag(DamageFlag, dtrain_coupling))
return -Couplers[ConnectNo].CouplingFlag; // hak urwany - rozłączanie jest OK return -Couplers[ConnectNo].CouplingFlag; // hak urwany - rozłączanie jest OK
// CouplerDist(ConnectNo); // CouplerDist(ConnectNo);
if (Couplers[ConnectNo].CouplerType == TCouplerType::Screw ? Neighbours[ConnectNo].distance < 0.01 : true) if ( (Couplers[ConnectNo].type() != TCouplerType::Screw) || (Neighbours[ConnectNo].distance < 0.01) )
return -Couplers[ConnectNo].CouplingFlag; // można rozłączać, jeśli dociśnięty return -Couplers[ConnectNo].CouplingFlag; // można rozłączać, jeśli dociśnięty
return (Neighbours[ConnectNo].distance > 0.2) ? -Couplers[ConnectNo].CouplingFlag : return (Neighbours[ConnectNo].distance > 0.2) ? -Couplers[ConnectNo].CouplingFlag :
Couplers[ConnectNo].CouplingFlag; Couplers[ConnectNo].CouplingFlag;
@@ -1102,7 +1102,7 @@ TMoverParameters::damage_coupler( int const End ) {
auto &coupler{ Couplers[ End ] }; auto &coupler{ Couplers[ End ] };
if( coupler.CouplerType == TCouplerType::Articulated ) { return; } // HACK: don't break articulated couplings no matter what if( coupler.type() == TCouplerType::Articulated ) { return; } // HACK: don't break articulated couplings no matter what
if( SetFlag( DamageFlag, dtrain_coupling ) ) if( SetFlag( DamageFlag, dtrain_coupling ) )
EventFlag = true; EventFlag = true;
@@ -1595,7 +1595,7 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) {
// bez napiecia... // bez napiecia...
if( couplervoltage != 0.0 ) { if( couplervoltage != 0.0 ) {
// ...ale jest cos na sprzegach: // ...ale jest cos na sprzegach:
coupler.power_high.current = ( std::abs( Itot ) + TotalCurrent ) * coupler.power_high.voltage / couplervoltage; // obciążenie rozkladane stosownie do napiec coupler.power_high.current = ( std::abs( Itot ) * IsVehicleEIMBrakingFactor() + TotalCurrent ) * coupler.power_high.voltage / couplervoltage; // obciążenie rozkladane stosownie do napiec
if( true == coupler.power_high.is_live ) { if( true == coupler.power_high.is_live ) {
coupler.power_high.current += connectedothercoupler.power_high.current; coupler.power_high.current += connectedothercoupler.power_high.current;
} }
@@ -4837,7 +4837,8 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
// potentially generate sounds on clash or stretch // potentially generate sounds on clash or stretch
if( ( newdistance < 0.0 ) if( ( newdistance < 0.0 )
&& ( coupler.Dist > newdistance ) && ( coupler.Dist > newdistance )
&& ( dV < -0.1 ) ) { && ( dV < -0.1 )
&& ( false == coupler.has_adapter() ) ) { // HACK: with adapter present we presume buffers won't clash
// 090503: dzwieki pracy zderzakow // 090503: dzwieki pracy zderzakow
SetFlag( SetFlag(
coupler.sounds, coupler.sounds,
@@ -4866,7 +4867,7 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
if( ( coupler.CouplingFlag != coupling::faux ) if( ( coupler.CouplingFlag != coupling::faux )
|| ( initialdistance < 0 ) ) { || ( initialdistance < 0 ) ) {
coupler.Dist = clamp( newdistance, -coupler.DmaxB, coupler.DmaxC ); coupler.Dist = clamp( newdistance, ( coupler.has_adapter() ? 0 : -coupler.DmaxB ), coupler.DmaxC );
double BetaAvg = 0; double BetaAvg = 0;
double Fmax = 0; double Fmax = 0;
@@ -4923,16 +4924,19 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
- Fmax * dV * BetaAvg; - Fmax * dV * BetaAvg;
} }
// liczenie sily ze sprezystosci zderzaka // liczenie sily ze sprezystosci zderzaka
if( -newdistance > ( coupler.DmaxB + othercoupler.DmaxB ) ) { auto const collisiondistance { (
( coupler.has_adapter() || othercoupler.has_adapter() ) ?
std::min( coupler.DmaxB, othercoupler.DmaxB ) : // HACK: only take into account buffering ability of automatic coupler
coupler.DmaxB + othercoupler.DmaxB
) };
if( -newdistance > collisiondistance ) {
// zderzenie // zderzenie
coupler.CheckCollision = true; coupler.CheckCollision = true;
if( ( coupler.CouplerType == TCouplerType::Automatic ) if( ( coupler.type() == TCouplerType::Automatic )
&& ( coupler.CouplerType == othercoupler.CouplerType ) && ( coupler.type() == othercoupler.type() )
&& ( coupler.CouplingFlag == coupling::faux ) ) { && ( coupler.CouplingFlag == coupling::faux ) ) {
// sprzeganie wagonow z samoczynnymi sprzegami // sprzeganie wagonow z samoczynnymi sprzegami
// EN57 coupler.CouplingFlag = ( coupler.AutomaticCouplingFlag & othercoupler.AutomaticCouplingFlag );
// TBD, TODO: configurable flag for automatic coupling
coupler.CouplingFlag = coupling::coupler /*| coupling::brakehose | coupling::mainhose | coupling::control*/;
SetFlag( coupler.sounds, sound::attachcoupler ); SetFlag( coupler.sounds, sound::attachcoupler );
} }
} }
@@ -5898,10 +5902,10 @@ double TMoverParameters::TractionForce( double dt ) {
else if ((std::abs(EngineVoltage) < EnginePowerSource.CollectorParameters.MaxV)) else if ((std::abs(EngineVoltage) < EnginePowerSource.CollectorParameters.MaxV))
Vadd *= (1.0 - dt); Vadd *= (1.0 - dt);
else else
Vadd = Max0R( Vadd = std::max(
Vadd * (1.0 - 0.2 * dt), Vadd * (1.0 - 0.2 * dt),
0.007 * (std::abs(EngineVoltage) - (EnginePowerSource.CollectorParameters.MaxV - 100))); 0.007 * (std::abs(EngineVoltage) - (EnginePowerSource.CollectorParameters.MaxV - 100)));
Itot = eimv[eimv_Ipoj] * (0.01 + Min0R(0.99, 0.99 - Vadd)); Itot = eimv[eimv_Ipoj] * (0.01 + std::min(0.99, 0.99 - Vadd));
EnginePower = abs(eimv[eimv_Ic] * eimv[eimv_U] * NPoweredAxles) / 1000; EnginePower = abs(eimv[eimv_Ic] * eimv[eimv_U] * NPoweredAxles) / 1000;
// power inverters // power inverters
@@ -9508,6 +9512,7 @@ void TMoverParameters::LoadFIZ_BuffCoupl( std::string const &line, int const Ind
extract_value( coupler->DmaxB, "DmaxB", line, "" ); extract_value( coupler->DmaxB, "DmaxB", line, "" );
extract_value( coupler->FmaxB, "FmaxB", line, "" ); extract_value( coupler->FmaxB, "FmaxB", line, "" );
extract_value( coupler->beta, "beta", line, "" ); extract_value( coupler->beta, "beta", line, "" );
extract_value( coupler->AutomaticCouplingFlag, "AutomaticFlag", line, "" );
extract_value( coupler->AllowedFlag, "AllowedFlag", line, "" ); extract_value( coupler->AllowedFlag, "AllowedFlag", line, "" );
if( coupler->AllowedFlag < 0 ) { if( coupler->AllowedFlag < 0 ) {
@@ -10255,6 +10260,8 @@ void TMoverParameters::LoadFIZ_Circuit( std::string const &Input ) {
void TMoverParameters::LoadFIZ_AI( std::string const &Input ) { void TMoverParameters::LoadFIZ_AI( std::string const &Input ) {
extract_value( AIHintPantstate, "Pantstate", Input, "" ); extract_value( AIHintPantstate, "Pantstate", Input, "" );
extract_value( AIHintLocalBrakeAccFactor, "LocalBrakeAccFactor", Input, "" );
} }
void TMoverParameters::LoadFIZ_RList( std::string const &Input ) { void TMoverParameters::LoadFIZ_RList( std::string const &Input ) {
@@ -10763,6 +10770,13 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir)
LocalBrakePosA = 0.0; LocalBrakePosA = 0.0;
BrakeCtrlPos = static_cast<int>( Handle->GetPos( bh_NP ) ); BrakeCtrlPos = static_cast<int>( Handle->GetPos( bh_NP ) );
LimPipePress = LowPipePress; LimPipePress = LowPipePress;
if( ( LocalBrake == TLocalBrake::ManualBrake )
|| ( MBrake == true ) ) {
IncManualBrakeLevel( ManualBrakePosNo );
}
if( SpringBrake.MaxBrakeForce > 0.0 ) {
SpringBrake.Activate = true;
}
} }
ActFlowSpeed = 0.0; ActFlowSpeed = 0.0;

View File

@@ -448,9 +448,13 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
*/ */
{ {
// if material has opacity set, replace submodel opacity with it // if material has opacity set, replace submodel opacity with it
// NOTE: reverted to use base opacity, this allows to define opacity threshold in material
// without it causing the translucent models to become opaque
auto const opacity { ( auto const opacity { (
/*
false == std::isnan( mat.opacity ) ? false == std::isnan( mat.opacity ) ?
mat.opacity : mat.opacity :
*/
Opacity ) }; Opacity ) };
iFlags &= ~0x30; iFlags &= ~0x30;
iFlags |= ( iFlags |= (

View File

@@ -360,6 +360,8 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = {
{ user_command::doormodetoggle, &TTrain::OnCommand_doormodetoggle }, { user_command::doormodetoggle, &TTrain::OnCommand_doormodetoggle },
{ user_command::carcouplingincrease, &TTrain::OnCommand_carcouplingincrease }, { user_command::carcouplingincrease, &TTrain::OnCommand_carcouplingincrease },
{ user_command::carcouplingdisconnect, &TTrain::OnCommand_carcouplingdisconnect }, { user_command::carcouplingdisconnect, &TTrain::OnCommand_carcouplingdisconnect },
{ user_command::carcoupleradapterattach, &TTrain::OnCommand_carcoupleradapterattach },
{ user_command::carcoupleradapterremove, &TTrain::OnCommand_carcoupleradapterremove },
{ user_command::departureannounce, &TTrain::OnCommand_departureannounce }, { user_command::departureannounce, &TTrain::OnCommand_departureannounce },
{ user_command::hornlowactivate, &TTrain::OnCommand_hornlowactivate }, { user_command::hornlowactivate, &TTrain::OnCommand_hornlowactivate },
{ user_command::hornhighactivate, &TTrain::OnCommand_hornhighactivate }, { user_command::hornhighactivate, &TTrain::OnCommand_hornhighactivate },
@@ -2430,22 +2432,20 @@ void TTrain::OnCommand_pantographcompressoractivate( TTrain *Train, command_data
return; return;
} }
if( ( Train->mvControlled->PantPress > 4.8 )
|| ( false == Train->mvControlled->Battery ) ) {
// needs live power source and low enough pressure to work
return;
}
if( Command.action != GLFW_RELEASE ) { if( Command.action != GLFW_RELEASE ) {
// press or hold to activate // press or hold to activate
if( ( Train->mvControlled->PantPress < 4.8 )
&& ( true == Train->mvControlled->Battery ) ) {
// needs live power source and low enough pressure to work
Train->mvControlled->PantCompFlag = true; Train->mvControlled->PantCompFlag = true;
// visual feedback: }
// visual feedback
Train->ggPantCompressorButton.UpdateValue( 1.0 ); Train->ggPantCompressorButton.UpdateValue( 1.0 );
} }
else { else {
// release to disable // release to disable
Train->mvControlled->PantCompFlag = false; Train->mvControlled->PantCompFlag = false;
// visual feedback: // visual feedback
Train->ggPantCompressorButton.UpdateValue( 0.0 ); Train->ggPantCompressorButton.UpdateValue( 0.0 );
} }
} }
@@ -2480,6 +2480,8 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com
OnCommand_linebreakerclose( Train, Command ); OnCommand_linebreakerclose( Train, Command );
} }
} }
// HACK: ignition key ignores lack of submodel, so we can start vehicles without any modeled controls
Train->ggIgnitionKey.UpdateValue( 0.0 );
} }
} }
@@ -2543,6 +2545,8 @@ void TTrain::OnCommand_linebreakerclose( TTrain *Train, command_data const &Comm
} }
else { else {
// no switch capable of doing the job // no switch capable of doing the job
// HACK: ignition key ignores lack of submodel, so we can start vehicles without any modeled controls
Train->ggIgnitionKey.UpdateValue( 1.0 );
return; return;
} }
// the actual closing of the line breaker is handled in the train update routine // the actual closing of the line breaker is handled in the train update routine
@@ -5400,6 +5404,40 @@ void TTrain::OnCommand_carcouplingdisconnect( TTrain *Train, command_data const
} }
} }
void TTrain::OnCommand_carcoupleradapterattach( TTrain *Train, command_data const &Command ) {
if( ( true == FreeFlyModeFlag )
&& ( Command.action == GLFW_PRESS ) ) {
// tryb freefly, press only
auto *vehicle { std::get<TDynamicObject *>( simulation::Region->find_vehicle( Command.location, 50, false, true ) ) };
if( vehicle == nullptr ) { return; }
auto const coupler = (
glm::length2( glm::vec3 { vehicle->CouplerPosition( end::front ) } - Command.location ) < glm::length2( glm::vec3 { vehicle->CouplerPosition( end::rear ) } - Command.location ) ?
end::front :
end::rear );
vehicle->attach_coupler_adapter( coupler );
}
}
void TTrain::OnCommand_carcoupleradapterremove( TTrain *Train, command_data const &Command ) {
if( ( true == FreeFlyModeFlag )
&& ( Command.action == GLFW_PRESS ) ) {
// tryb freefly, press only
auto *vehicle { std::get<TDynamicObject *>( simulation::Region->find_vehicle( Command.location, 50, false, true ) ) };
if( vehicle == nullptr ) { return; }
auto const coupler = (
glm::length2( glm::vec3 { vehicle->CouplerPosition( end::front ) } - Command.location ) < glm::length2( glm::vec3 { vehicle->CouplerPosition( end::rear ) } - Command.location ) ?
end::front :
end::rear );
vehicle->remove_coupler_adapter( coupler );
}
}
void TTrain::OnCommand_departureannounce( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_departureannounce( TTrain *Train, command_data const &Command ) {
if( Train->ggDepartureSignalButton.SubModel == nullptr ) { if( Train->ggDepartureSignalButton.SubModel == nullptr ) {
@@ -5797,7 +5835,8 @@ bool TTrain::Update( double const Deltatime )
} }
if( ( ( ggMainButton.SubModel != nullptr ) && ( ggMainButton.GetDesiredValue() > 0.95 ) ) if( ( ( ggMainButton.SubModel != nullptr ) && ( ggMainButton.GetDesiredValue() > 0.95 ) )
|| ( ( ggMainOnButton.SubModel != nullptr ) && ( ggMainOnButton.GetDesiredValue() > 0.95 ) ) ) { || ( ( ggMainOnButton.SubModel != nullptr ) && ( ggMainOnButton.GetDesiredValue() > 0.95 )
|| ( ggIgnitionKey.GetDesiredValue() > 0.95 ) ) ) { // HACK: fallback
// keep track of period the line breaker button is held down, to determine when/if circuit closes // keep track of period the line breaker button is held down, to determine when/if circuit closes
if( ( mvControlled->MainsInitTimeCountdown <= 0.0 ) if( ( mvControlled->MainsInitTimeCountdown <= 0.0 )
&& ( ( fHVoltage > 0.5 * mvControlled->EnginePowerSource.MaxVoltage ) && ( ( fHVoltage > 0.5 * mvControlled->EnginePowerSource.MaxVoltage )

View File

@@ -386,6 +386,8 @@ class TTrain {
static void OnCommand_doormodetoggle( TTrain *Train, command_data const &Command ); static void OnCommand_doormodetoggle( TTrain *Train, command_data const &Command );
static void OnCommand_carcouplingincrease( TTrain *Train, command_data const &Command ); static void OnCommand_carcouplingincrease( TTrain *Train, command_data const &Command );
static void OnCommand_carcouplingdisconnect( TTrain *Train, command_data const &Command ); static void OnCommand_carcouplingdisconnect( TTrain *Train, command_data const &Command );
static void OnCommand_carcoupleradapterattach( TTrain *Train, command_data const &Command );
static void OnCommand_carcoupleradapterremove( TTrain *Train, command_data const &Command );
static void OnCommand_departureannounce( TTrain *Train, command_data const &Command ); static void OnCommand_departureannounce( TTrain *Train, command_data const &Command );
static void OnCommand_hornlowactivate( TTrain *Train, command_data const &Command ); static void OnCommand_hornlowactivate( TTrain *Train, command_data const &Command );
static void OnCommand_hornhighactivate( TTrain *Train, command_data const &Command ); static void OnCommand_hornhighactivate( TTrain *Train, command_data const &Command );

View File

@@ -155,6 +155,8 @@ commanddescription_sequence Commands_descriptions = {
// TBD, TODO: make coupling controls entity-centric // TBD, TODO: make coupling controls entity-centric
{ "carcouplingincrease", command_target::vehicle }, { "carcouplingincrease", command_target::vehicle },
{ "carcouplingdisconnect", command_target::vehicle }, { "carcouplingdisconnect", command_target::vehicle },
{ "carcoupleradapterattach", command_target::vehicle },
{ "carcoupleradapterremove", command_target::vehicle },
{ "doortoggleleft", command_target::vehicle }, { "doortoggleleft", command_target::vehicle },
{ "doortoggleright", command_target::vehicle }, { "doortoggleright", command_target::vehicle },
{ "doorpermitleft", command_target::vehicle }, { "doorpermitleft", command_target::vehicle },

View File

@@ -146,6 +146,8 @@ enum class user_command {
carcouplingincrease, carcouplingincrease,
carcouplingdisconnect, carcouplingdisconnect,
carcoupleradapterattach,
carcoupleradapterremove,
doortoggleleft, doortoggleleft,
doortoggleright, doortoggleright,
doorpermitleft, doorpermitleft,

View File

@@ -155,6 +155,8 @@ driverkeyboard_input::default_bindings() {
{ user_command::movedown, GLFW_KEY_PAGE_DOWN }, { user_command::movedown, GLFW_KEY_PAGE_DOWN },
{ user_command::carcouplingincrease, GLFW_KEY_INSERT }, { user_command::carcouplingincrease, GLFW_KEY_INSERT },
{ user_command::carcouplingdisconnect, GLFW_KEY_DELETE }, { user_command::carcouplingdisconnect, GLFW_KEY_DELETE },
{ user_command::carcoupleradapterattach, GLFW_KEY_INSERT | keymodifier::control },
{ user_command::carcoupleradapterremove, GLFW_KEY_DELETE | keymodifier::control },
{ user_command::doortoggleleft, GLFW_KEY_COMMA }, { user_command::doortoggleleft, GLFW_KEY_COMMA },
{ user_command::doortoggleright, GLFW_KEY_PERIOD }, { user_command::doortoggleright, GLFW_KEY_PERIOD },
{ user_command::doorpermitleft, GLFW_KEY_COMMA | keymodifier::shift }, { user_command::doorpermitleft, GLFW_KEY_COMMA | keymodifier::shift },

View File

@@ -797,18 +797,23 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
std::string std::string
debug_panel::update_vehicle_coupler( int const Side ) { debug_panel::update_vehicle_coupler( int const Side ) {
// NOTE: mover and vehicle are guaranteed to be valid by the caller // NOTE: mover and vehicle are guaranteed to be valid by the caller
auto const &mover { *( m_input.mover ) };
std::string couplerstatus { locale::strings[ locale::string::debug_vehicle_none ] }; std::string couplerstatus { locale::strings[ locale::string::debug_vehicle_none ] };
std::string const adapterstatus { ( mover.Couplers[ Side ].adapter_type == TCouplerType::NoCoupler ? "" : "[A]" ) };
auto const *connected { m_input.vehicle->MoverParameters->Neighbours[ Side ].vehicle }; auto const *connected { m_input.vehicle->MoverParameters->Neighbours[ Side ].vehicle };
if( connected == nullptr ) { return couplerstatus; } if( connected == nullptr ) {
auto const &mover { *( m_input.mover ) }; return couplerstatus + " " + adapterstatus;
}
std::snprintf( std::snprintf(
m_buffer.data(), m_buffer.size(), m_buffer.data(), m_buffer.size(),
"%s [%d] (%.1f m)", "%s %s[%d] (%.1f m)",
connected->name().c_str(), connected->name().c_str(),
adapterstatus.c_str(),
mover.Couplers[ Side ].CouplingFlag, mover.Couplers[ Side ].CouplingFlag,
mover.Neighbours[ Side ].distance ); mover.Neighbours[ Side ].distance );

View File

@@ -1083,6 +1083,30 @@ bool opengl33_renderer::Render_lowpoly( TDynamicObject *Dynamic, float const Squ
return true; return true;
} }
bool opengl33_renderer::Render_coupler_adapter( TDynamicObject *Dynamic, float const Squaredistance, int const End, bool const Alpha ) {
if( Dynamic->m_coupleradapters[ End ] == nullptr ) { return false; }
auto const position { Math3D::vector3 {
0.f,
Dynamic->MoverParameters->Couplers[ End ].adapter_height,
( Dynamic->MoverParameters->Couplers[ End ].adapter_length + Dynamic->MoverParameters->Dim.L * 0.5 ) * ( End == end::front ? 1 : -1 ) } };
auto const angle { glm::vec3{
0,
( End == end::front ? 0 : 180 ),
0 } };
if( Alpha ) {
Render_Alpha( Dynamic->m_coupleradapters[ End ], Dynamic->Material(), Squaredistance, position, angle );
}
else {
Render( Dynamic->m_coupleradapters[ End ], Dynamic->Material(), Squaredistance, position, angle );
}
return true;
}
// creates dynamic environment cubemap // creates dynamic environment cubemap
bool opengl33_renderer::Render_reflections(viewport_config &vp) bool opengl33_renderer::Render_reflections(viewport_config &vp)
{ {
@@ -1813,13 +1837,17 @@ void opengl33_renderer::Bind_Material( material_handle const Material, TSubModel
// material-based parameters // material-based parameters
switch( entry.defaultparam ) { switch( entry.defaultparam ) {
case gl::shader::defaultparam_e::glossiness: { case gl::shader::defaultparam_e::glossiness: {
src = glm::vec4( material.glossiness ); src = glm::vec4 { material.glossiness };
} }
default: { default: {
break; break;
} }
} }
if( entry.size == 1 ) {
// HACK: convert color to luminosity, if it's passed as single value
src == glm::vec4 { colors::RGBtoHSV( glm::vec3 { src } ).s };
}
for (size_t j = 0; j < entry.size; j++) for (size_t j = 0; j < entry.size; j++)
model_ubs.param[entry.location][entry.offset + j] = src[j]; model_ubs.param[entry.location][entry.offset + j] = src[j];
} }
@@ -2487,6 +2515,9 @@ bool opengl33_renderer::Render(TDynamicObject *Dynamic)
for( auto *attachment : Dynamic->mdAttachments ) { for( auto *attachment : Dynamic->mdAttachments ) {
Render( attachment, Dynamic->Material(), squaredistance ); Render( attachment, Dynamic->Material(), squaredistance );
} }
// optional coupling adapters
Render_coupler_adapter( Dynamic, squaredistance, end::front );
Render_coupler_adapter( Dynamic, squaredistance, end::rear );
// post-render cleanup // post-render cleanup
if (Dynamic->fShade > 0.0f) if (Dynamic->fShade > 0.0f)
@@ -2510,6 +2541,9 @@ bool opengl33_renderer::Render(TDynamicObject *Dynamic)
for( auto *attachment : Dynamic->mdAttachments ) { for( auto *attachment : Dynamic->mdAttachments ) {
Render( attachment, Dynamic->Material(), squaredistance ); Render( attachment, Dynamic->Material(), squaredistance );
} }
// optional coupling adapters
Render_coupler_adapter( Dynamic, squaredistance, end::front );
Render_coupler_adapter( Dynamic, squaredistance, end::rear );
if( Dynamic->mdLoad ) { if( Dynamic->mdLoad ) {
// renderowanie nieprzezroczystego ładunku // renderowanie nieprzezroczystego ładunku
Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} ); Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
@@ -2687,11 +2721,6 @@ void opengl33_renderer::Render(TSubModel *Submodel)
if ((Submodel->iVisible) && (TSubModel::fSquareDist >= Submodel->fSquareMinDist) && (TSubModel::fSquareDist < Submodel->fSquareMaxDist)) if ((Submodel->iVisible) && (TSubModel::fSquareDist >= Submodel->fSquareMinDist) && (TSubModel::fSquareDist < Submodel->fSquareMaxDist))
{ {
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
glm::mat4 future_stack = model_ubs.future; glm::mat4 future_stack = model_ubs.future;
if (Submodel->iFlags & 0xC000) if (Submodel->iFlags & 0xC000)
@@ -2714,6 +2743,11 @@ void opengl33_renderer::Render(TSubModel *Submodel)
if (Submodel->iAlpha & Submodel->iFlags & 0x1F) if (Submodel->iAlpha & Submodel->iFlags & 0x1F)
{ {
// rysuj gdy element nieprzezroczysty // rysuj gdy element nieprzezroczysty
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
switch (m_renderpass.draw_mode) switch (m_renderpass.draw_mode)
{ {
case rendermode::color: case rendermode::color:
@@ -3440,6 +3474,9 @@ bool opengl33_renderer::Render_Alpha(TDynamicObject *Dynamic)
for( auto *attachment : Dynamic->mdAttachments ) { for( auto *attachment : Dynamic->mdAttachments ) {
Render_Alpha( attachment, Dynamic->Material(), squaredistance ); Render_Alpha( attachment, Dynamic->Material(), squaredistance );
} }
// optional coupling adapters
Render_coupler_adapter( Dynamic, squaredistance, end::front, true );
Render_coupler_adapter( Dynamic, squaredistance, end::rear, true );
if( Dynamic->mdLoad ) { if( Dynamic->mdLoad ) {
// renderowanie nieprzezroczystego ładunku // renderowanie nieprzezroczystego ładunku
Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} ); Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
@@ -3512,11 +3549,6 @@ void opengl33_renderer::Render_Alpha(TSubModel *Submodel)
// renderowanie przezroczystych przez DL // renderowanie przezroczystych przez DL
if ((Submodel->iVisible) && (TSubModel::fSquareDist >= Submodel->fSquareMinDist) && (TSubModel::fSquareDist < Submodel->fSquareMaxDist)) if ((Submodel->iVisible) && (TSubModel::fSquareDist >= Submodel->fSquareMinDist) && (TSubModel::fSquareDist < Submodel->fSquareMaxDist))
{ {
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
glm::mat4 future_stack = model_ubs.future; glm::mat4 future_stack = model_ubs.future;
if (Submodel->iFlags & 0xC000) if (Submodel->iFlags & 0xC000)
@@ -3539,6 +3571,11 @@ void opengl33_renderer::Render_Alpha(TSubModel *Submodel)
if (Submodel->iAlpha & Submodel->iFlags & 0x2F) if (Submodel->iAlpha & Submodel->iFlags & 0x2F)
{ {
// rysuj gdy element przezroczysty // rysuj gdy element przezroczysty
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
switch (m_renderpass.draw_mode) switch (m_renderpass.draw_mode)
{ {
case rendermode::color: case rendermode::color:

View File

@@ -242,6 +242,7 @@ class opengl33_renderer : public gfx_renderer {
bool Render_cab(TDynamicObject const *Dynamic, float const Lightlevel, bool const Alpha = false); bool Render_cab(TDynamicObject const *Dynamic, float const Lightlevel, bool const Alpha = false);
bool Render_interior( bool const Alpha = false ); bool Render_interior( bool const Alpha = false );
bool Render_lowpoly( TDynamicObject *Dynamic, float const Squaredistance, bool const Setup, bool const Alpha = false ); bool Render_lowpoly( TDynamicObject *Dynamic, float const Squaredistance, bool const Setup, bool const Alpha = false );
bool Render_coupler_adapter( TDynamicObject *Dynamic, float const Squaredistance, int const End, bool const Alpha = false );
void Render(TMemCell *Memcell); void Render(TMemCell *Memcell);
void Render_particles(); void Render_particles();
void Render_precipitation(); void Render_precipitation();

View File

@@ -845,6 +845,27 @@ bool opengl_renderer::Render_lowpoly( TDynamicObject *Dynamic, float const Squar
return true; return true;
} }
bool opengl_renderer::Render_coupler_adapter( TDynamicObject *Dynamic, float const Squaredistance, int const End, bool const Alpha ) {
if( Dynamic->m_coupleradapters[ End ] == nullptr ) { return false; }
auto const position { Math3D::vector3 {
0.f,
Dynamic->MoverParameters->Couplers[ End ].adapter_height,
( Dynamic->MoverParameters->Couplers[ End ].adapter_length + Dynamic->MoverParameters->Dim.L * 0.5 ) * ( End == end::front ? 1 : -1 ) } };
auto const angle{ glm::vec3{ 0, ( End == end::front ? 0 : 180 ), 0 } };
if( Alpha ) {
Render_Alpha( Dynamic->m_coupleradapters[ End ], Dynamic->Material(), Squaredistance, position, angle );
}
else {
Render( Dynamic->m_coupleradapters[ End ], Dynamic->Material(), Squaredistance, position, angle );
}
return true;
}
// creates dynamic environment cubemap // creates dynamic environment cubemap
bool bool
opengl_renderer::Render_reflections() { opengl_renderer::Render_reflections() {
@@ -2318,6 +2339,9 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
for( auto *attachment : Dynamic->mdAttachments ) { for( auto *attachment : Dynamic->mdAttachments ) {
Render( attachment, Dynamic->Material(), squaredistance ); Render( attachment, Dynamic->Material(), squaredistance );
} }
// optional coupling adapters
Render_coupler_adapter( Dynamic, squaredistance, end::front );
Render_coupler_adapter( Dynamic, squaredistance, end::rear );
// post-render cleanup // post-render cleanup
m_renderspecular = false; m_renderspecular = false;
if( Dynamic->fShade > 0.0f ) { if( Dynamic->fShade > 0.0f ) {
@@ -2342,6 +2366,9 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
for( auto *attachment : Dynamic->mdAttachments ) { for( auto *attachment : Dynamic->mdAttachments ) {
Render( attachment, Dynamic->Material(), squaredistance ); Render( attachment, Dynamic->Material(), squaredistance );
} }
// optional coupling adapters
Render_coupler_adapter( Dynamic, squaredistance, end::front );
Render_coupler_adapter( Dynamic, squaredistance, end::rear );
if( Dynamic->mdLoad ) { if( Dynamic->mdLoad ) {
// renderowanie nieprzezroczystego ładunku // renderowanie nieprzezroczystego ładunku
Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} ); Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
@@ -2524,10 +2551,6 @@ opengl_renderer::Render( TSubModel *Submodel ) {
&& ( TSubModel::fSquareDist >= Submodel->fSquareMinDist ) && ( TSubModel::fSquareDist >= Submodel->fSquareMinDist )
&& ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) { && ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) {
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
if( Submodel->iFlags & 0xC000 ) { if( Submodel->iFlags & 0xC000 ) {
::glPushMatrix(); ::glPushMatrix();
if( Submodel->fMatrix ) if( Submodel->fMatrix )
@@ -2540,6 +2563,11 @@ opengl_renderer::Render( TSubModel *Submodel ) {
// renderowanie obiektów OpenGL // renderowanie obiektów OpenGL
if( Submodel->iAlpha & Submodel->iFlags & 0x1F ) { if( Submodel->iAlpha & Submodel->iFlags & 0x1F ) {
// rysuj gdy element nieprzezroczysty // rysuj gdy element nieprzezroczysty
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
switch( m_renderpass.draw_mode ) { switch( m_renderpass.draw_mode ) {
case rendermode::color: case rendermode::color:
case rendermode::reflections: { case rendermode::reflections: {
@@ -3491,6 +3519,9 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) {
for( auto *attachment : Dynamic->mdAttachments ) { for( auto *attachment : Dynamic->mdAttachments ) {
Render_Alpha( attachment, Dynamic->Material(), squaredistance ); Render_Alpha( attachment, Dynamic->Material(), squaredistance );
} }
// optional coupling adapters
Render_coupler_adapter( Dynamic, squaredistance, end::front, true );
Render_coupler_adapter( Dynamic, squaredistance, end::rear, true );
if( Dynamic->mdLoad ) { if( Dynamic->mdLoad ) {
// renderowanie nieprzezroczystego ładunku // renderowanie nieprzezroczystego ładunku
Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} ); Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
@@ -3569,10 +3600,6 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
&& ( TSubModel::fSquareDist >= Submodel->fSquareMinDist ) && ( TSubModel::fSquareDist >= Submodel->fSquareMinDist )
&& ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) { && ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) {
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
if( Submodel->iFlags & 0xC000 ) { if( Submodel->iFlags & 0xC000 ) {
::glPushMatrix(); ::glPushMatrix();
if( Submodel->fMatrix ) if( Submodel->fMatrix )
@@ -3585,6 +3612,11 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
// renderowanie obiektów OpenGL // renderowanie obiektów OpenGL
if( Submodel->iAlpha & Submodel->iFlags & 0x2F ) { if( Submodel->iAlpha & Submodel->iFlags & 0x2F ) {
// rysuj gdy element przezroczysty // rysuj gdy element przezroczysty
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
switch( m_renderpass.draw_mode ) { switch( m_renderpass.draw_mode ) {
case rendermode::color: { case rendermode::color: {

View File

@@ -223,6 +223,8 @@ private:
Render_interior( bool const Alpha = false ); Render_interior( bool const Alpha = false );
bool bool
Render_lowpoly( TDynamicObject *Dynamic, float const Squaredistance, bool const Setup, bool const Alpha = false ); Render_lowpoly( TDynamicObject *Dynamic, float const Squaredistance, bool const Setup, bool const Alpha = false );
bool
Render_coupler_adapter( TDynamicObject *Dynamic, float const Squaredistance, int const End, bool const Alpha = false );
void void
Render( TMemCell *Memcell ); Render( TMemCell *Memcell );
void void

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#define VERSION_MAJOR 20 #define VERSION_MAJOR 20
#define VERSION_MINOR 222 #define VERSION_MINOR 322
#define VERSION_REVISION 0 #define VERSION_REVISION 0