17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-25 02:07:37 +02:00

Merge branch 'master' of https://github.com/tmj-fstate/maszyna into tmj-master

This commit is contained in:
stele
2020-03-25 20:41:20 +01:00
19 changed files with 459 additions and 123 deletions

View File

@@ -1988,6 +1988,8 @@ void TController::AutoRewident()
break;
}
}
// potentially release manual brake
d->MoverParameters->DecManualBrakeLevel( ManualBrakePosNo );
}
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;
}
} // 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
if( ( mvOccupied->TrainType == dt_EZT )
@@ -2767,7 +2773,14 @@ bool TController::ReleaseEngine() {
}
// gasimy światła
Lights( 0, 0 );
// activate parking brake
// TBD: do it earlier?
mvOccupied->SpringBrakeActivate(true);
if( ( mvOccupied->LocalBrake == TLocalBrake::ManualBrake )
|| ( mvOccupied->MBrake == true ) ) {
mvOccupied->IncManualBrakeLevel( ManualBrakePosNo );
}
// switch off remaining power
mvOccupied->BatterySwitch( false );
}
}
@@ -2959,7 +2972,14 @@ bool TController::IncBrakeEIM()
switch (mvOccupied->EIMCtrlType)
{
case 0: {
OK = mvOccupied->IncLocalBrakeLevel( 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->IncLocalBrakeLevel( 1 );
}
break;
}
case 1: {
@@ -3067,24 +3087,35 @@ bool TController::DecBrakeEIM()
bool OK = false;
switch (mvOccupied->EIMCtrlType)
{
case 0:
OK = mvOccupied->DecLocalBrakeLevel(1);
break;
case 1:
OK = mvOccupied->MainCtrlPos < 2;
if (OK)
mvOccupied->MainCtrlPos = 2;
break;
case 2:
OK = mvOccupied->MainCtrlPos < 3;
if (OK)
mvOccupied->MainCtrlPos = 3;
break;
case 3:
OK = mvOccupied->MainCtrlPos < mvOccupied->MainCtrlMaxDirChangePos;
if( OK )
mvOccupied->MainCtrlPos = mvOccupied->MainCtrlMaxDirChangePos;
break;
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->DecLocalBrakeLevel( 1 );
}
break;
}
case 1: {
OK = mvOccupied->MainCtrlPos < 2;
if( OK )
mvOccupied->MainCtrlPos = 2;
break;
}
case 2: {
OK = mvOccupied->MainCtrlPos < 3;
if( OK )
mvOccupied->MainCtrlPos = 3;
break;
}
case 3: {
OK = mvOccupied->MainCtrlPos < mvOccupied->MainCtrlMaxDirChangePos;
if( OK )
mvOccupied->MainCtrlPos = mvOccupied->MainCtrlMaxDirChangePos;
break;
}
}
return OK;
}
@@ -4468,6 +4499,7 @@ void TController::PhysicsLog()
void
TController::UpdateSituation(double dt) {
// uruchamiać przynajmniej raz na sekundę
if( false == simulation::is_ready ) { return; }
if( ( iDrivigFlags & movePrimary ) == 0 ) { return; } // pasywny nic nie robi
// update timers
@@ -5068,18 +5100,30 @@ TController::UpdateSituation(double dt) {
int const end { ( vehicle->DirectionGet() > 0 ? end::front : end::rear ) };
auto const &neighbour { vehicleparameters->Neighbours[ end ] };
if( neighbour.vehicle != nullptr ) {
// próba podczepienia
vehicleparameters->Attach(
end, neighbour.vehicle_end,
neighbour.vehicle->MoverParameters,
iCoupler );
if( vehicleparameters->Couplers[ end ].CouplingFlag == iCoupler ) {
// jeżeli został podłączony
iCoupler = 0; // dalsza jazda manewrowa już bez łączenia
iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania
SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie
CheckVehicles( Connect ); // sprawdzić światła nowego składu
JumpToNextOrder(); // wykonanie następnej komendy
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
vehicleparameters->Attach(
end, neighbour.vehicle_end,
neighbour.vehicle->MoverParameters,
iCoupler );
if( vehicleparameters->Couplers[ end ].CouplingFlag == iCoupler ) {
// jeżeli został podłączony
iCoupler = 0; // dalsza jazda manewrowa już bez łączenia
iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania
SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie
CheckVehicles( Connect ); // sprawdzić światła nowego składu
JumpToNextOrder(); // wykonanie następnej komendy
}
}
}
}
} // if (AIControllFlag) //koniec zblokowania, bo była zmienna lokalna
@@ -5463,7 +5507,12 @@ TController::UpdateSituation(double dt) {
// tylko jeśli odepnie
WriteLog( mvOccupied->Name + " odczepiony." );
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
}
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
// jeden
// 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))
{
btCoupler1.Turn( true );
btnOn = true;
}
// 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))
{
btCoupler2.Turn( true );
@@ -903,6 +905,12 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
// uginanie zderzakow
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 ) };
if( dist >= 0.0 ) { continue; }
@@ -1539,6 +1547,64 @@ TDynamicObject::uncouple( int const Side ) {
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() {
modelShake = Math3D::vector3(0, 0, 0);
// fTrackBlock = 10000.0; // brak przeszkody na drodze
@@ -3367,7 +3433,7 @@ bool TDynamicObject::Update(double dt, double dt1)
double fCurrent = (
( MoverParameters->DynamicBrakeFlag && MoverParameters->ResistorsFlag ) ?
0 :
std::abs( MoverParameters->Itot ) )
std::abs( MoverParameters->Itot ) * MoverParameters->IsVehicleEIMBrakingFactor() )
+ MoverParameters->TotalCurrent; // prąd pobierany przez pojazd - bez sensu z tym (TotalCurrent)
// 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
@@ -4394,6 +4460,12 @@ void TDynamicObject::RenderSounds() {
m_couplersounds[ couplerindex ].dsbCouplerAttach.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;
coupler.sounds = 0;
@@ -4566,6 +4638,17 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
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:") {
// additional 3d models attached to main body
// 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;
}
}
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:" ) {
// movement start jolt
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 ].dsbBufferClamp.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 } };
m_couplersounds[ end::rear ].dsbCouplerAttach.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 ].dsbBufferClamp.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 *
@@ -6258,6 +6363,10 @@ TDynamicObject::update_neighbours() {
// neighbour.vehicle = coupler.Connected;
// neighbour.vehicle_end = coupler.ConnectedNr;
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 {
// 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 ) ) {
// at short distances (re)calculate range between couplers directly
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
};
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 {
sound_source dsbCouplerAttach { 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 dsbBufferClamp { sound_placement::external }; // moved from cab
sound_source dsbBufferClamp_loud { sound_placement::external };
sound_source dsbAdapterAttach { sound_placement::external };
sound_source dsbAdapterRemove { sound_placement::external };
};
struct pantograph_sounds {
@@ -394,6 +401,7 @@ private:
// members
TButton btCoupler1; // sprzegi
TButton btCoupler2;
std::array<TModel3d *, 2> m_coupleradapters = { nullptr, nullptr };
TAirCoupler btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
TAirCoupler btCPneumatic2;
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 };
#endif
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
exchange_data m_exchange; // state of active load exchange procedure, if any
exchange_sounds m_exchangesounds; // sounds associated with the load exchange
coupleradapter_data m_coupleradapter;
bool renderme; // yB - czy renderowac
float ModCamRot;
int iInventory[ 2 ] { 0, 0 }; // flagi bitowe posiadanych submodeli (np. świateł)
@@ -583,6 +593,8 @@ private:
// pobranie współrzędnych tyłu
inline Math3D::vector3 RearPosition() {
return vCoulpler[iDirection]; };
inline Math3D::vector3 CouplerPosition( end const End ) const {
return vCoulpler[ End ]; }
inline Math3D::vector3 AxlePositionGet() {
return iAxleFirst ?
Axle1.pPosition :
@@ -647,6 +659,8 @@ private:
void couple( 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 Damage(char flag);
void RaLightsSet(int head, int rear);

View File

@@ -193,7 +193,7 @@ basic_event::event_conditions::deserialize( cParser &Input ) {
flags |= flags::text;
}
Input.getTokens();
if( Input.peek() != "*" ) //"*" - nie brac val1 pod uwage
if( Input.peek() != "*" ) //"*" - nie brac pod uwage
{ // two tokens, operator followed by comparison value
std::string operatorstring;
Input >> operatorstring;
@@ -203,13 +203,14 @@ basic_event::event_conditions::deserialize( cParser &Input ) {
flags |= flags::value1;
}
Input.getTokens();
if( Input.peek() != "*" ) //"*" - nie brac pod uwage
{ // two tokens, operator followed by comparison value
std::string operatorstring;
Input >> operatorstring;
memcompare_value2_operator = comparison_operator_from_string( operatorstring );
Input.getTokens();
Input >> memcompare_value2;
flags |= flags::value1;
flags |= flags::value2;
}
}
}

View File

@@ -240,7 +240,9 @@ enum sound {
attachmainhose = 1 << 10,
attachcontrol = 1 << 11,
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
@@ -673,7 +675,8 @@ struct TCoupling {
double FmaxC = 1000.0;
double beta = 0.0;
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*/
int CouplingFlag = 0; /*0 - wirtualnie, 1 - sprzegi, 2 - pneumatycznie, 4 - sterowanie, 8 - kabel mocy*/
class TMoverParameters *Connected = nullptr; /*co jest podlaczone*/
@@ -682,12 +685,26 @@ struct TCoupling {
double Dist = 0.0; /*strzalka ugiecia zderzaków*/
bool CheckCollision = false; /*czy sprawdzac sile czy pedy*/
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_low; // TODO: implement this
int sounds { 0 }; // sounds emitted by the coupling devices
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 {
@@ -1543,6 +1560,7 @@ public:
int iLights[2]; // bity zapalonych świateł tutaj, żeby dało się liczyć pobór prądu
int AIHintPantstate{ 0 }; // suggested pantograph setup
double AIHintLocalBrakeAccFactor{ 1.05 }; // suggested acceleration weight for local brake operation
public:
TMoverParameters(double VelInitial, std::string TypeNameInit, std::string NameInit, int Cab);
@@ -1557,6 +1575,8 @@ public:
bool DirectionForward();
bool DirectionBackward( void );/*! kierunek ruchu*/
bool EIMDirectionChangeAllow( void ) const;
inline double IsVehicleEIMBrakingFactor() {
return eimv[ eimv_Ipoj ] < 0 ? -1.0 : 1.0; }
void BrakeLevelSet(double b);
bool BrakeLevelAdd(double b);
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ć.
// 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
int ConversionError = 0;
@@ -438,13 +438,13 @@ bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *
auto &coupler { Couplers[ ConnectNo ] };
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 {
( Forced )
|| ( ( distance <= dEpsilon )
&& ( coupler.CouplerType != TCouplerType::NoCoupler )
&& ( coupler.CouplerType == othercoupler.CouplerType ) ) };
&& ( coupler.type() != TCouplerType::NoCoupler )
&& ( coupler.type() == othercoupler.type() ) ) };
if( false == couplercheck ) { return false; }
@@ -495,7 +495,7 @@ int TMoverParameters::DettachStatus(int ConnectNo)
if (TestFlag(DamageFlag, dtrain_coupling))
return -Couplers[ConnectNo].CouplingFlag; // hak urwany - rozłączanie jest OK
// 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 (Neighbours[ConnectNo].distance > 0.2) ? -Couplers[ConnectNo].CouplingFlag :
Couplers[ConnectNo].CouplingFlag;
@@ -1102,7 +1102,7 @@ TMoverParameters::damage_coupler( int const 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 ) )
EventFlag = true;
@@ -1595,7 +1595,7 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) {
// bez napiecia...
if( couplervoltage != 0.0 ) {
// ...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 ) {
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
if( ( newdistance < 0.0 )
&& ( 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
SetFlag(
coupler.sounds,
@@ -4866,7 +4867,7 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
if( ( coupler.CouplingFlag != coupling::faux )
|| ( 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 Fmax = 0;
@@ -4923,16 +4924,19 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
- Fmax * dV * BetaAvg;
}
// 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
coupler.CheckCollision = true;
if( ( coupler.CouplerType == TCouplerType::Automatic )
&& ( coupler.CouplerType == othercoupler.CouplerType )
if( ( coupler.type() == TCouplerType::Automatic )
&& ( coupler.type() == othercoupler.type() )
&& ( coupler.CouplingFlag == coupling::faux ) ) {
// sprzeganie wagonow z samoczynnymi sprzegami
// EN57
// TBD, TODO: configurable flag for automatic coupling
coupler.CouplingFlag = coupling::coupler /*| coupling::brakehose | coupling::mainhose | coupling::control*/;
coupler.CouplingFlag = ( coupler.AutomaticCouplingFlag & othercoupler.AutomaticCouplingFlag );
SetFlag( coupler.sounds, sound::attachcoupler );
}
}
@@ -5898,10 +5902,10 @@ double TMoverParameters::TractionForce( double dt ) {
else if ((std::abs(EngineVoltage) < EnginePowerSource.CollectorParameters.MaxV))
Vadd *= (1.0 - dt);
else
Vadd = Max0R(
Vadd = std::max(
Vadd * (1.0 - 0.2 * dt),
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;
// power inverters
@@ -9498,8 +9502,8 @@ void TMoverParameters::LoadFIZ_BuffCoupl( std::string const &line, int const Ind
auto lookup = couplertypes.find( extract_value( "CType", line ) );
coupler->CouplerType = (
lookup != couplertypes.end() ?
lookup->second :
TCouplerType::NoCoupler );
lookup->second :
TCouplerType::NoCoupler );
extract_value( coupler->SpringKC, "kC", line, "" );
extract_value( coupler->DmaxC, "DmaxC", line, "" );
@@ -9508,6 +9512,7 @@ void TMoverParameters::LoadFIZ_BuffCoupl( std::string const &line, int const Ind
extract_value( coupler->DmaxB, "DmaxB", line, "" );
extract_value( coupler->FmaxB, "FmaxB", line, "" );
extract_value( coupler->beta, "beta", line, "" );
extract_value( coupler->AutomaticCouplingFlag, "AutomaticFlag", line, "" );
extract_value( coupler->AllowedFlag, "AllowedFlag", line, "" );
if( coupler->AllowedFlag < 0 ) {
@@ -10255,6 +10260,8 @@ void TMoverParameters::LoadFIZ_Circuit( std::string const &Input ) {
void TMoverParameters::LoadFIZ_AI( std::string const &Input ) {
extract_value( AIHintPantstate, "Pantstate", Input, "" );
extract_value( AIHintLocalBrakeAccFactor, "LocalBrakeAccFactor", Input, "" );
}
void TMoverParameters::LoadFIZ_RList( std::string const &Input ) {
@@ -10763,6 +10770,13 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir)
LocalBrakePosA = 0.0;
BrakeCtrlPos = static_cast<int>( Handle->GetPos( bh_NP ) );
LimPipePress = LowPipePress;
if( ( LocalBrake == TLocalBrake::ManualBrake )
|| ( MBrake == true ) ) {
IncManualBrakeLevel( ManualBrakePosNo );
}
if( SpringBrake.MaxBrakeForce > 0.0 ) {
SpringBrake.Activate = true;
}
}
ActFlowSpeed = 0.0;

View File

@@ -157,12 +157,12 @@ bool TMemCell::Compare( std::string const &szTestText, double const fTestValue1,
checkfailed |= ( !result );
}
if( TestFlag( CheckMask, basic_event::flags::value1 ) ) {
auto const result { compare( fValue1, fTestValue1, TextOperator ) };
auto const result { compare( fValue1, fTestValue1, Value1Operator ) };
checkpassed |= result;
checkfailed |= ( !result );
}
if( TestFlag( CheckMask, basic_event::flags::value2 ) ) {
auto const result { compare( fValue2, fTestValue2, TextOperator ) };
auto const result { compare( fValue2, fTestValue2, Value2Operator ) };
checkpassed |= result;
checkfailed |= ( !result );
}

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
// 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 { (
/*
false == std::isnan( mat.opacity ) ?
mat.opacity :
*/
Opacity ) };
iFlags &= ~0x30;
iFlags |= (

103
Train.cpp
View File

@@ -360,6 +360,8 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = {
{ user_command::doormodetoggle, &TTrain::OnCommand_doormodetoggle },
{ user_command::carcouplingincrease, &TTrain::OnCommand_carcouplingincrease },
{ 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::hornlowactivate, &TTrain::OnCommand_hornlowactivate },
{ user_command::hornhighactivate, &TTrain::OnCommand_hornhighactivate },
@@ -2430,22 +2432,20 @@ void TTrain::OnCommand_pantographcompressoractivate( TTrain *Train, command_data
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 ) {
// press or hold to activate
Train->mvControlled->PantCompFlag = true;
// visual feedback:
if( ( Train->mvControlled->PantPress < 4.8 )
&& ( true == Train->mvControlled->Battery ) ) {
// needs live power source and low enough pressure to work
Train->mvControlled->PantCompFlag = true;
}
// visual feedback
Train->ggPantCompressorButton.UpdateValue( 1.0 );
}
else {
// release to disable
Train->mvControlled->PantCompFlag = false;
// visual feedback:
// visual feedback
Train->ggPantCompressorButton.UpdateValue( 0.0 );
}
}
@@ -2480,6 +2480,8 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com
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 {
// 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;
}
// the actual closing of the line breaker is handled in the train update routine
@@ -4271,14 +4275,11 @@ void TTrain::OnCommand_interiorlightenable( TTrain *Train, command_data const &C
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( Train->ggCabLightButton.SubModel == nullptr ) {
if( false == Train->m_controlmapper.contains( "cablight_sw:" ) ) {
// TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels
WriteLog( "Interior Light switch is missing, or wasn't defined" );
return;
}
// visual feedback
Train->ggCabLightButton.UpdateValue( 1.0, Train->dsbSwitch );
Train->btCabLight.Turn( true );
// store lighting switch states
if( false == Train->DynamicObject->JointCabs ) {
// vehicles with separate cabs get separate lighting switch states
@@ -4297,14 +4298,11 @@ void TTrain::OnCommand_interiorlightdisable( TTrain *Train, command_data const &
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( Train->ggCabLightButton.SubModel == nullptr ) {
if( false == Train->m_controlmapper.contains( "cablight_sw:" ) ) {
// TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels
WriteLog( "Interior Light switch is missing, or wasn't defined" );
return;
}
// visual feedback
Train->ggCabLightButton.UpdateValue( 0.0, Train->dsbSwitch );
Train->btCabLight.Turn( false );
// store lighting switch states
if( false == Train->DynamicObject->JointCabs ) {
// vehicles with separate cabs get separate lighting switch states
@@ -5406,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 ) {
if( Train->ggDepartureSignalButton.SubModel == nullptr ) {
@@ -5803,7 +5835,8 @@ bool TTrain::Update( double const Deltatime )
}
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
if( ( mvControlled->MainsInitTimeCountdown <= 0.0 )
&& ( ( fHVoltage > 0.5 * mvControlled->EnginePowerSource.MaxVoltage )
@@ -6800,10 +6833,6 @@ bool TTrain::Update( double const Deltatime )
}
ggLocalBrake.Update();
}
if (ggManualBrake.SubModel != nullptr) {
ggManualBrake.UpdateValue(double(mvOccupied->ManualBrakePos));
ggManualBrake.Update();
}
ggAlarmChain.Update();
ggBrakeProfileCtrl.Update();
ggBrakeProfileG.Update();
@@ -6940,7 +6969,6 @@ bool TTrain::Update( double const Deltatime )
ggInstrumentLightButton.Update();
ggDashboardLightButton.Update();
ggTimetableLightButton.Update();
ggCabLightButton.Update();
ggCabLightDimButton.Update();
ggCompartmentLightsButton.Update();
ggCompartmentLightsOnButton.Update();
@@ -7617,6 +7645,8 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
cabindex = 0;
break;
}
iCabn = cabindex;
std::string cabstr("cab" + std::to_string(cabindex) + "definition:");
cParser parser(asFileName, cParser::buffer_FILE);
@@ -8212,7 +8242,6 @@ void TTrain::clear_cab_controls()
ggDirKey.Clear();
ggBrakeCtrl.Clear();
ggLocalBrake.Clear();
ggManualBrake.Clear();
ggAlarmChain.Clear();
ggBrakeProfileCtrl.Clear();
ggBrakeProfileG.Clear();
@@ -8253,7 +8282,6 @@ void TTrain::clear_cab_controls()
ggDashboardLightButton.Clear();
ggTimetableLightButton.Clear();
// hunter-091012
ggCabLightButton.Clear();
ggCabLightDimButton.Clear();
ggCompartmentLightsButton.Clear();
ggCompartmentLightsOnButton.Clear();
@@ -8403,7 +8431,6 @@ void TTrain::clear_cab_controls()
btLampkaRearRightLight.Clear();
btLampkaRearLeftEndLight.Clear();
btLampkaRearRightEndLight.Clear();
btCabLight.Clear(); // hunter-171012
// others
btLampkaMalfunction.Clear();
btLampkaMalfunctionB.Clear();
@@ -8579,9 +8606,6 @@ void TTrain::set_cab_controls( int const Cab ) {
ggDimHeadlightsButton.PutValue( 1.f );
}
// cab lights
if( true == Cabine[Cab].bLight ) {
ggCabLightButton.PutValue( 1.f );
}
if( true == Cabine[Cab].bLightDim ) {
ggCabLightDimButton.PutValue( 1.f );
}
@@ -8833,7 +8857,6 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co
{ "i-rearrightend:", btLampkaRearRightEndLight },
{ "i-dashboardlight:", btDashboardLight },
{ "i-timetablelight:", btTimetableLight },
{ "i-cablight:", btCabLight },
{ "i-universal0:", btUniversals[ 0 ] },
{ "i-universal1:", btUniversals[ 1 ] },
{ "i-universal2:", btUniversals[ 2 ] },
@@ -8859,7 +8882,8 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co
{ "i-doorpermit_right:", &mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::right : side::left ) ].open_permit },
{ "i-doorstep:", &mvOccupied->Doors.step_enabled },
{ "i-mainpipelock:", &mvOccupied->LockPipe },
{ "i-battery:", &mvOccupied->Battery }
{ "i-battery:", &mvOccupied->Battery },
{ "i-cablight:", &Cabine[ iCabn ].bLight },
};
{
auto lookup = autolights.find( Label );
@@ -8918,7 +8942,6 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
{ "dirkey:" , ggDirKey },
{ "brakectrl:", ggBrakeCtrl },
{ "localbrake:", ggLocalBrake },
{ "manualbrake:", ggManualBrake },
{ "alarmchain:", ggAlarmChain },
{ "brakeprofile_sw:", ggBrakeProfileCtrl },
{ "brakeprofileg_sw:", ggBrakeProfileG },
@@ -9015,7 +9038,6 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
{ "instrumentlight_sw:", ggInstrumentLightButton },
{ "dashboardlight_sw:", ggDashboardLightButton },
{ "timetablelight_sw:", ggTimetableLightButton },
{ "cablight_sw:", ggCabLightButton },
{ "cablightdim_sw:", ggCabLightDimButton },
{ "compartmentlights_sw:", ggCompartmentLightsButton },
{ "compartmentlightson_sw:", ggCompartmentLightsOnButton },
@@ -9084,6 +9106,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
{ "pantfrontoff_sw:", &mvControlled->Pantographs[end::front].valve.is_disabled },
{ "pantrearoff_sw:", &mvControlled->Pantographs[end::rear].valve.is_disabled },
{ "radio_sw:", &mvOccupied->Radio },
{ "cablight_sw:", &Cabine[ iCabn ].bLight },
};
{
auto lookup = autoboolgauges.find( Label );
@@ -9095,6 +9118,20 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
return true;
}
}
// TODO: move viable dedicated gauges to the automatic array
std::unordered_map<std::string, int *> const autointgauges = {
{ "manualbrake:", &mvOccupied->ManualBrakePos },
};
{
auto lookup = autointgauges.find( Label );
if( lookup != autointgauges.end() ) {
auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna lampka
gauge.Load( Parser, DynamicObject );
gauge.AssignInt( lookup->second );
m_controlmapper.insert( gauge, lookup->first );
return true;
}
}
// ABu 090305: uniwersalne przyciski lub inne rzeczy
if( Label == "mainctrlact:" ) {

View File

@@ -386,6 +386,8 @@ class TTrain {
static void OnCommand_doormodetoggle( 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_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_hornlowactivate( TTrain *Train, command_data const &Command );
static void OnCommand_hornhighactivate( TTrain *Train, command_data const &Command );
@@ -459,7 +461,6 @@ public: // reszta może by?publiczna
TGauge ggDirKey;
TGauge ggBrakeCtrl;
TGauge ggLocalBrake;
TGauge ggManualBrake;
TGauge ggAlarmChain;
TGauge ggBrakeProfileCtrl; // nastawiacz GPR - przelacznik obrotowy
TGauge ggBrakeProfileG; // nastawiacz GP - hebelek towarowy
@@ -539,7 +540,7 @@ public: // reszta może by?publiczna
TGauge ggInstrumentLightButton;
TGauge ggDashboardLightButton;
TGauge ggTimetableLightButton;
TGauge ggCabLightButton; // hunter-091012: przelacznik oswietlania kabiny
// TGauge ggCabLightButton; // hunter-091012: przelacznik oswietlania kabiny
TGauge ggCabLightDimButton; // hunter-091012: przelacznik przyciemnienia
// oswietlenia kabiny
TGauge ggCompartmentLightsButton;
@@ -691,7 +692,7 @@ public: // reszta może by?publiczna
TButton btLampkaTempomat;
TButton btLampkaDistanceCounter;
TButton btCabLight; // hunter-171012: lampa oswietlajaca kabine
// TButton btCabLight; // hunter-171012: lampa oswietlajaca kabine
// Ra 2013-12: wirtualne "lampki" do odbijania na haslerze w PoKeys
TButton btHaslerBrakes; // ciśnienie w cylindrach
TButton btHaslerCurrent; // prąd na silnikach

View File

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

View File

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

View File

@@ -155,6 +155,8 @@ driverkeyboard_input::default_bindings() {
{ user_command::movedown, GLFW_KEY_PAGE_DOWN },
{ user_command::carcouplingincrease, GLFW_KEY_INSERT },
{ 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::doortoggleright, GLFW_KEY_PERIOD },
{ 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
debug_panel::update_vehicle_coupler( int const Side ) {
// 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 const adapterstatus { ( mover.Couplers[ Side ].adapter_type == TCouplerType::NoCoupler ? "" : "[A]" ) };
auto const *connected { m_input.vehicle->MoverParameters->Neighbours[ Side ].vehicle };
if( connected == nullptr ) { return couplerstatus; }
auto const &mover { *( m_input.mover ) };
if( connected == nullptr ) {
return couplerstatus + " " + adapterstatus;
}
std::snprintf(
m_buffer.data(), m_buffer.size(),
"%s [%d] (%.1f m)",
"%s %s[%d] (%.1f m)",
connected->name().c_str(),
adapterstatus.c_str(),
mover.Couplers[ Side ].CouplingFlag,
mover.Neighbours[ Side ].distance );

View File

@@ -1083,6 +1083,30 @@ bool opengl33_renderer::Render_lowpoly( TDynamicObject *Dynamic, float const Squ
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
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
switch( entry.defaultparam ) {
case gl::shader::defaultparam_e::glossiness: {
src = glm::vec4( material.glossiness );
src = glm::vec4 { material.glossiness };
}
default: {
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++)
model_ubs.param[entry.location][entry.offset + j] = src[j];
}
@@ -2487,8 +2515,11 @@ bool opengl33_renderer::Render(TDynamicObject *Dynamic)
for( auto *attachment : Dynamic->mdAttachments ) {
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)
{
// restore regular light level
@@ -2510,6 +2541,9 @@ bool opengl33_renderer::Render(TDynamicObject *Dynamic)
for( auto *attachment : Dynamic->mdAttachments ) {
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 ) {
// renderowanie nieprzezroczystego ładunku
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))
{
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
glm::mat4 future_stack = model_ubs.future;
if (Submodel->iFlags & 0xC000)
@@ -2714,6 +2743,11 @@ void opengl33_renderer::Render(TSubModel *Submodel)
if (Submodel->iAlpha & Submodel->iFlags & 0x1F)
{
// rysuj gdy element nieprzezroczysty
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
switch (m_renderpass.draw_mode)
{
case rendermode::color:
@@ -3440,6 +3474,9 @@ bool opengl33_renderer::Render_Alpha(TDynamicObject *Dynamic)
for( auto *attachment : Dynamic->mdAttachments ) {
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 ) {
// renderowanie nieprzezroczystego ładunku
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
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;
if (Submodel->iFlags & 0xC000)
@@ -3538,7 +3570,12 @@ void opengl33_renderer::Render_Alpha(TSubModel *Submodel)
// renderowanie obiektów OpenGL
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)
{
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_interior( 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_particles();
void Render_precipitation();

View File

@@ -845,6 +845,27 @@ bool opengl_renderer::Render_lowpoly( TDynamicObject *Dynamic, float const Squar
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
bool
opengl_renderer::Render_reflections() {
@@ -2318,6 +2339,9 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
for( auto *attachment : Dynamic->mdAttachments ) {
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
m_renderspecular = false;
if( Dynamic->fShade > 0.0f ) {
@@ -2342,6 +2366,9 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
for( auto *attachment : Dynamic->mdAttachments ) {
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 ) {
// renderowanie nieprzezroczystego ładunku
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->fSquareMaxDist ) ) {
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
if( Submodel->iFlags & 0xC000 ) {
::glPushMatrix();
if( Submodel->fMatrix )
@@ -2540,6 +2563,11 @@ opengl_renderer::Render( TSubModel *Submodel ) {
// renderowanie obiektów OpenGL
if( Submodel->iAlpha & Submodel->iFlags & 0x1F ) {
// rysuj gdy element nieprzezroczysty
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
switch( m_renderpass.draw_mode ) {
case rendermode::color:
case rendermode::reflections: {
@@ -3491,6 +3519,9 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) {
for( auto *attachment : Dynamic->mdAttachments ) {
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 ) {
// renderowanie nieprzezroczystego ładunku
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->fSquareMaxDist ) ) {
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
if( Submodel->iFlags & 0xC000 ) {
::glPushMatrix();
if( Submodel->fMatrix )
@@ -3585,6 +3612,11 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
// renderowanie obiektów OpenGL
if( Submodel->iAlpha & Submodel->iFlags & 0x2F ) {
// rysuj gdy element przezroczysty
// debug data
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
switch( m_renderpass.draw_mode ) {
case rendermode::color: {

View File

@@ -223,6 +223,8 @@ private:
Render_interior( 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

View File

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