mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 19:49:19 +02:00
Merge branch 'milek-dev' into gfx-work
This commit is contained in:
26
Driver.cpp
26
Driver.cpp
@@ -503,7 +503,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
|
||||
VelSignalLast = -1.0;
|
||||
}
|
||||
iTableDirection = iDirection; // ustalenie w jakim kierunku jest wypełniana tabelka względem pojazdu
|
||||
pTrack = pVehicle->RaTrackGet(); // odcinek, na którym stoi
|
||||
pTrack = pVehicle->GetTrack(); // odcinek, na którym stoi
|
||||
fTrackLength = pVehicle->RaTranslationGet(); // pozycja na tym torze (odległość od Point1)
|
||||
fLastDir = pVehicle->DirectionGet() * pVehicle->RaDirectionGet(); // ustalenie kierunku skanowania na torze
|
||||
if( fLastDir < 0.0 ) {
|
||||
@@ -1136,6 +1136,17 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
if( sSpeedTable[ i ].fDist > 0.0 ) {
|
||||
// check signals ahead
|
||||
if( sSpeedTable[ i ].IsProperSemaphor( OrderCurrentGet() ) ) {
|
||||
|
||||
if( ( mvOccupied->CategoryFlag & 2 )
|
||||
&& ( sSpeedTable[ i ].fVelNext != -1.0 )
|
||||
&& ( sSpeedTable[ i ].fVelNext < 1.0 )
|
||||
&& ( sSpeedTable[ i ].fDist < -0.5 + std::min( fBrakeDist * 0.2, mvOccupied->Vel * 0.2 ) ) ) {
|
||||
// special rule for cars: ignore stop signals at distance too short to come to a stop
|
||||
// as trying to stop in such situation is likely to place the car on train tracks
|
||||
sSpeedTable[ i ].iFlags &= ~spEnabled;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( SemNextIndex == -1 ) {
|
||||
// jeśli jest mienięty poprzedni semafor a wcześniej
|
||||
// byl nowy to go dorzucamy do zmiennej, żeby cały czas widział najbliższy
|
||||
@@ -2124,22 +2135,19 @@ bool TController::CheckVehicles(TOrders user)
|
||||
p = pVehicles[0];
|
||||
while (p)
|
||||
{
|
||||
// HACK: wagony muszą mieć baterię załączoną do otwarcia drzwi...
|
||||
if( p != pVehicle ) {
|
||||
if( ( ( p->MoverParameters->Couplers[ end::front ].CouplingFlag & ( coupling::control ) ) == 0 )
|
||||
&& ( ( p->MoverParameters->Couplers[ end::rear ].CouplingFlag & ( coupling::control ) ) == 0 ) ) {
|
||||
// NOTE: don't set battery in the occupied vehicle, let the user/ai do it explicitly
|
||||
// NOTE: don't set battery in controllable vehicles, let the user/ai do it explicitly
|
||||
// HACK: wagony muszą mieć baterię załączoną do otwarcia drzwi...
|
||||
p->MoverParameters->BatterySwitch( true );
|
||||
}
|
||||
}
|
||||
// enable heating and converter in carriages with can be heated
|
||||
// NOTE: don't touch the controlled vehicle, let the user/ai handle it explicitly
|
||||
if( p->MoverParameters != mvControlling ) {
|
||||
if( p->MoverParameters->HeatingPower > 0 ) {
|
||||
p->MoverParameters->HeatingAllow = true;
|
||||
p->MoverParameters->ConverterSwitch( true, range_t::local );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p->asDestination == "none")
|
||||
p->DestinationSet(TrainParams->Relation2, TrainParams->TrainName); // relacja docelowa, jeśli nie było
|
||||
@@ -5904,7 +5912,7 @@ TController::UpdateSituation(double dt) {
|
||||
/* mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_FS ) ); GBH */
|
||||
BrakeLevelSet( gbh_FS );
|
||||
// don't charge the brakes too often, or we risk overcharging
|
||||
BrakeChargingCooldown = -120.0;
|
||||
BrakeChargingCooldown = -1 * clamp( iVehicleCount * 3, 30, 90 );
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -6557,7 +6565,7 @@ TCommandType TController::BackwardScan()
|
||||
double scandist = scanmax; // zmodyfikuje na rzeczywiście przeskanowane
|
||||
basic_event *e = NULL; // event potencjalnie od semafora
|
||||
// opcjonalnie może być skanowanie od "wskaźnika" z przodu, np. W5, Tm=Ms1, koniec toru wg drugiej osi w kierunku ruchu
|
||||
TTrack *scantrack = BackwardTraceRoute(scandist, scandir, pVehicles[0]->RaTrackGet(), e);
|
||||
TTrack *scantrack = BackwardTraceRoute(scandist, scandir, pVehicles[0]->GetTrack(), e);
|
||||
auto const dir = startdir * pVehicles[0]->VectorFront(); // wektor w kierunku jazdy/szukania
|
||||
if( !scantrack ) {
|
||||
// jeśli wstecz wykryto koniec toru to raczej nic się nie da w takiej sytuacji zrobić
|
||||
|
||||
70
DynObj.cpp
70
DynObj.cpp
@@ -848,16 +848,19 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
|
||||
//*************************************************************/// koniec
|
||||
// wezykow
|
||||
// uginanie zderzakow
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
double dist = MoverParameters->Couplers[i].Dist / 2.0;
|
||||
if (smBuforLewy[i])
|
||||
if (dist < 0)
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
|
||||
auto const dist { clamp( MoverParameters->Couplers[ i ].Dist / 2.0, -MoverParameters->Couplers[ i ].DmaxB, 0.0 ) };
|
||||
|
||||
if( dist >= 0.0 ) { continue; }
|
||||
|
||||
if( smBuforLewy[ i ] ) {
|
||||
smBuforLewy[ i ]->SetTranslate( Math3D::vector3( dist, 0, 0 ) );
|
||||
if (smBuforPrawy[i])
|
||||
if (dist < 0)
|
||||
}
|
||||
if( smBuforPrawy[ i ] ) {
|
||||
smBuforPrawy[ i ]->SetTranslate( Math3D::vector3( dist, 0, 0 ) );
|
||||
}
|
||||
}
|
||||
} // vehicle within 50m
|
||||
|
||||
// Winger 160204 - podnoszenie pantografow
|
||||
@@ -1614,6 +1617,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
}
|
||||
// load the cargo now that we know whether the vehicle will allow it
|
||||
MoverParameters->AssignLoad( LoadType, Load );
|
||||
MoverParameters->ComputeMass();
|
||||
|
||||
bool driveractive = (fVel != 0.0); // jeśli prędkość niezerowa, to aktywujemy ruch
|
||||
if (!MoverParameters->CheckLocomotiveParameters(
|
||||
@@ -2190,12 +2194,9 @@ void TDynamicObject::Move(double fDistance)
|
||||
// Ra 2F1J: to nie jest stabilne (powoduje rzucanie taborem) i wymaga
|
||||
// dopracowania
|
||||
fAdjustment = vFront.Length() - fAxleDist; // na łuku będzie ujemny
|
||||
// if (fabs(fAdjustment)>0.02) //jeśli jest zbyt dużo, to rozłożyć na kilka
|
||||
// przeliczeń
|
||||
// (wygasza drgania?)
|
||||
// if (fabs(fAdjustment)>0.02) //jeśli jest zbyt dużo, to rozłożyć na kilka przeliczeń (wygasza drgania?)
|
||||
//{//parę centymetrów trzeba by już skorygować; te błędy mogą się też
|
||||
// generować na ostrych
|
||||
//łukach
|
||||
// generować na ostrych łukach
|
||||
// fAdjustment*=0.5; //w jednym kroku korygowany jest ułamek błędu
|
||||
//}
|
||||
// else
|
||||
@@ -2418,6 +2419,7 @@ void TDynamicObject::update_exchange( double const Deltatime ) {
|
||||
m_exchange.unload_count -= exchangesize;
|
||||
MoverParameters->LoadStatus = 1;
|
||||
MoverParameters->LoadAmount = std::max( 0.f, MoverParameters->LoadAmount - exchangesize );
|
||||
MoverParameters->ComputeMass();
|
||||
update_load_visibility();
|
||||
}
|
||||
if( m_exchange.unload_count < 0.01 ) {
|
||||
@@ -2432,6 +2434,7 @@ void TDynamicObject::update_exchange( double const Deltatime ) {
|
||||
m_exchange.load_count -= exchangesize;
|
||||
MoverParameters->LoadStatus = 2;
|
||||
MoverParameters->LoadAmount = std::min( MoverParameters->MaxLoad, MoverParameters->LoadAmount + exchangesize ); // std::max not strictly needed but, eh
|
||||
MoverParameters->ComputeMass();
|
||||
update_load_visibility();
|
||||
}
|
||||
}
|
||||
@@ -2768,8 +2771,8 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
auto Frj { 0.0 };
|
||||
auto osie { 0 };
|
||||
// 0a. ustal aktualna nastawe zadania sily napedowej i hamowania
|
||||
if (MoverParameters->Power < 1)
|
||||
{
|
||||
if( ( MoverParameters->Power < 1 )
|
||||
&& ( ctOwner != nullptr ) ) {
|
||||
MoverParameters->MainCtrlPos = ctOwner->Controlling()->MainCtrlPos*MoverParameters->MainCtrlPosNo / std::max(1, ctOwner->Controlling()->MainCtrlPosNo);
|
||||
MoverParameters->ScndCtrlActualPos = ctOwner->Controlling()->ScndCtrlActualPos;
|
||||
}
|
||||
@@ -3110,7 +3113,10 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
-vPosition.x,
|
||||
vPosition.z,
|
||||
vPosition.y };
|
||||
TRotation r { 0.0, 0.0, 0.0 };
|
||||
TRotation const r {
|
||||
0.0,
|
||||
0.0,
|
||||
modelRot.z };
|
||||
// McZapkie-260202 - dMoveLen przyda sie przy stukocie kol
|
||||
dDOMoveLen = GetdMoveLen() + MoverParameters->ComputeMovement(dt, dt1, ts, tp, tmpTraction, l, r);
|
||||
if( Mechanik )
|
||||
@@ -3620,7 +3626,10 @@ bool TDynamicObject::FastUpdate(double dt)
|
||||
-vPosition.x,
|
||||
vPosition.z,
|
||||
vPosition.y };
|
||||
TRotation r { 0.0, 0.0, 0.0 };
|
||||
TRotation const r {
|
||||
0.0,
|
||||
0.0,
|
||||
modelRot.z };
|
||||
// McZapkie: parametry powinny byc pobierane z toru
|
||||
// ts.R=MyTrack->fRadius;
|
||||
// ts.Len= Max0R(MoverParameters->BDist,MoverParameters->ADist);
|
||||
@@ -3904,7 +3913,7 @@ void TDynamicObject::RenderSounds() {
|
||||
}
|
||||
// NBMX sygnal odjazdu
|
||||
if( MoverParameters->Doors.has_warning ) {
|
||||
for( auto &door : m_doorsounds ) {
|
||||
for( auto &departuresignalsound : m_departuresignalsounds ) {
|
||||
// TBD, TODO: per-location door state triggers?
|
||||
if( ( MoverParameters->DepartureSignal )
|
||||
/*
|
||||
@@ -3915,10 +3924,10 @@ void TDynamicObject::RenderSounds() {
|
||||
) {
|
||||
// for the autonomous doors play the warning automatically whenever a door is closing
|
||||
// MC: pod warunkiem ze jest zdefiniowane w chk
|
||||
door.sDepartureSignal.play( sound_flags::exclusive | sound_flags::looping );
|
||||
departuresignalsound.play( sound_flags::exclusive | sound_flags::looping );
|
||||
}
|
||||
else {
|
||||
door.sDepartureSignal.stop();
|
||||
departuresignalsound.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4227,12 +4236,7 @@ void TDynamicObject::RenderSounds() {
|
||||
if( MoverParameters->EventFlag ) {
|
||||
// McZapkie: w razie wykolejenia
|
||||
if( true == TestFlag( MoverParameters->DamageFlag, dtrain_out ) ) {
|
||||
if( GetVelocity() > 0 ) {
|
||||
rsDerailment.play();
|
||||
}
|
||||
else {
|
||||
rsDerailment.stop();
|
||||
}
|
||||
rsDerailment.play( sound_flags::exclusive );
|
||||
}
|
||||
|
||||
MoverParameters->EventFlag = false;
|
||||
@@ -5235,11 +5239,11 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
sound_source soundtemplate { sound_placement::general, 25.f };
|
||||
soundtemplate.deserialize( parser, sound_type::multipart, sound_parameters::range );
|
||||
soundtemplate.owner( this );
|
||||
for( auto &door : m_doorsounds ) {
|
||||
for( auto &departuresignalsound : m_departuresignalsounds ) {
|
||||
// apply configuration to all defined doors, but preserve their individual offsets
|
||||
auto const dooroffset { door.lock.offset() };
|
||||
door.sDepartureSignal = soundtemplate;
|
||||
door.sDepartureSignal.offset( dooroffset );
|
||||
auto const soundoffset { departuresignalsound.offset() };
|
||||
departuresignalsound = soundtemplate;
|
||||
departuresignalsound.offset( soundoffset );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5393,7 +5397,6 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
// left...
|
||||
auto const location { glm::vec3 { MoverParameters->Dim.W * 0.5f, MoverParameters->Dim.H * 0.5f, offset } };
|
||||
door.placement = side::left;
|
||||
door.sDepartureSignal.offset( location );
|
||||
door.rsDoorClose.offset( location );
|
||||
door.rsDoorOpen.offset( location );
|
||||
door.lock.offset( location );
|
||||
@@ -5405,9 +5408,8 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
if( ( sides == "both" )
|
||||
|| ( sides == "right" ) ) {
|
||||
// ...and right
|
||||
auto const location { glm::vec3 { MoverParameters->Dim.W * -0.5f, MoverParameters->Dim.H * 0.5f, offset } };
|
||||
auto const location { glm::vec3 { MoverParameters->Dim.W * -0.5f, 2.f, offset } };
|
||||
door.placement = side::right;
|
||||
door.sDepartureSignal.offset( location );
|
||||
door.rsDoorClose.offset( location );
|
||||
door.rsDoorOpen.offset( location );
|
||||
door.lock.offset( location );
|
||||
@@ -5416,6 +5418,10 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
door.step_open.offset( location );
|
||||
m_doorsounds.emplace_back( door );
|
||||
}
|
||||
// potential departure sound, one per door (pair) on vehicle centreline
|
||||
sound_source departuresignalsound { sound_placement::general, 25.f };
|
||||
departuresignalsound.offset( glm::vec3{ 0.f, 3.f, offset } );
|
||||
m_departuresignalsounds.emplace_back( departuresignalsound );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
DynObj.h
4
DynObj.h
@@ -322,7 +322,6 @@ private:
|
||||
};
|
||||
|
||||
struct door_sounds {
|
||||
sound_source sDepartureSignal { sound_placement::general };
|
||||
sound_source rsDoorOpen { sound_placement::general }; // Ra: przeniesione z kabiny
|
||||
sound_source rsDoorClose { sound_placement::general };
|
||||
sound_source lock { sound_placement::general };
|
||||
@@ -449,6 +448,7 @@ private:
|
||||
std::array<coupler_sounds, 2> m_couplersounds; // always front and rear
|
||||
std::vector<pantograph_sounds> m_pantographsounds; // typically 2 but can be less (or more?)
|
||||
std::vector<door_sounds> m_doorsounds; // can expect symmetrical arrangement, but don't count on it
|
||||
std::vector<sound_source> m_departuresignalsounds; // single source per door (pair) on the centreline
|
||||
bool m_doorlocks { false }; // sound helper, current state of door locks
|
||||
sound_source sHorn1 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
sound_source sHorn2 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
@@ -620,7 +620,7 @@ private:
|
||||
Axle1.GetTranslation() :
|
||||
Axle0.GetTranslation(); };
|
||||
// zwraca tor z aktywną osią
|
||||
inline TTrack * RaTrackGet() const {
|
||||
inline TTrack const * RaTrackGet() const {
|
||||
return iAxleFirst ?
|
||||
Axle1.GetTrack() :
|
||||
Axle0.GetTrack(); };
|
||||
|
||||
24
Globals.cpp
24
Globals.cpp
@@ -185,12 +185,6 @@ global_settings::ConfigParse(cParser &Parser) {
|
||||
Parser.getTokens();
|
||||
Parser >> DisabledLogTypes;
|
||||
}
|
||||
else if( token == "adjustscreenfreq" )
|
||||
{
|
||||
// McZapkie-240403 - czestotliwosc odswiezania ekranu
|
||||
Parser.getTokens();
|
||||
Parser >> bAdjustScreenFreq;
|
||||
}
|
||||
else if (token == "mousescale")
|
||||
{
|
||||
// McZapkie-060503 - czulosc ruchu myszy (krecenia glowa)
|
||||
@@ -364,6 +358,18 @@ global_settings::ConfigParse(cParser &Parser) {
|
||||
>> shadowtune.depth
|
||||
>> shadowtune.distance;
|
||||
}
|
||||
else if( token == "gfx.smoke" ) {
|
||||
// smoke visualization toggle
|
||||
Parser.getTokens();
|
||||
Parser >> Smoke;
|
||||
}
|
||||
else if( token == "gfx.smoke.fidelity" ) {
|
||||
// smoke visualization fidelity
|
||||
float smokefidelity;
|
||||
Parser.getTokens();
|
||||
Parser >> smokefidelity;
|
||||
SmokeFidelity = clamp( smokefidelity, 1.f, 4.f );
|
||||
}
|
||||
else if( token == "splinefidelity" ) {
|
||||
// segment size during spline->geometry conversion
|
||||
float splinefidelity;
|
||||
@@ -660,7 +666,7 @@ global_settings::ConfigParse(cParser &Parser) {
|
||||
>> uart_conf.updatetime;
|
||||
}
|
||||
else if( token == "uarttune" ) {
|
||||
Parser.getTokens( 14 );
|
||||
Parser.getTokens( 16 );
|
||||
Parser
|
||||
>> uart_conf.mainbrakemin
|
||||
>> uart_conf.mainbrakemax
|
||||
@@ -675,7 +681,9 @@ global_settings::ConfigParse(cParser &Parser) {
|
||||
>> uart_conf.hvmax
|
||||
>> uart_conf.hvuart
|
||||
>> uart_conf.currentmax
|
||||
>> uart_conf.currentuart;
|
||||
>> uart_conf.currentuart
|
||||
>> uart_conf.lvmax
|
||||
>> uart_conf.lvuart;
|
||||
}
|
||||
else if( token == "uartfeature" ) {
|
||||
Parser.getTokens( 4 );
|
||||
|
||||
@@ -126,6 +126,8 @@ struct global_settings {
|
||||
GLint iMaxTextureSize{ 4096 }; // maksymalny rozmiar tekstury
|
||||
int iMultisampling{ 2 }; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px
|
||||
float SplineFidelity{ 1.f }; // determines segment size during conversion of splines to geometry
|
||||
bool Smoke{ true }; // toggles smoke simulation and visualization
|
||||
float SmokeFidelity{ 1.f }; // determines amount of generated smoke particles
|
||||
bool ResourceSweep{ true }; // gfx resource garbage collection
|
||||
bool ResourceMove{ false }; // gfx resources are moved between cpu and gpu side instead of sending a copy
|
||||
bool compress_tex{ true }; // all textures are compressed on gpu side
|
||||
|
||||
@@ -657,6 +657,7 @@ struct TCoupling {
|
||||
double CForce = 0.0; /*sila z jaka dzialal*/
|
||||
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
|
||||
|
||||
power_coupling power_high;
|
||||
// power_coupling power_low; // TODO: implement this
|
||||
@@ -1143,6 +1144,7 @@ public:
|
||||
/*--opis konkretnego egzemplarza taboru*/
|
||||
TLocation Loc { 0.0, 0.0, 0.0 }; //pozycja pojazdów do wyznaczenia odległości pomiędzy sprzęgami
|
||||
TRotation Rot { 0.0, 0.0, 0.0 };
|
||||
glm::vec3 Front{};
|
||||
std::string Name; /*nazwa wlasna*/
|
||||
TCoupling Couplers[2]; //urzadzenia zderzno-sprzegowe, polaczenia miedzy wagonami
|
||||
std::array<neighbour_data, 2> Neighbours; // potential collision sources
|
||||
@@ -1408,6 +1410,8 @@ public:
|
||||
bool Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false, bool Audible = true);
|
||||
int DettachStatus(int ConnectNo);
|
||||
bool Dettach(int ConnectNo);
|
||||
void damage_coupler( int const End );
|
||||
void derail( int const Reason );
|
||||
bool DirectionForward();
|
||||
bool DirectionBackward( void );/*! kierunek ruchu*/
|
||||
void BrakeLevelSet(double b);
|
||||
@@ -1417,8 +1421,8 @@ public:
|
||||
bool ChangeCab(int direction);
|
||||
bool CurrentSwitch(bool const State);
|
||||
void UpdateBatteryVoltage(double dt);
|
||||
double ComputeMovement(double dt, double dt1, const TTrackShape &Shape, TTrackParam &Track, TTractionParam &ElectricTraction, const TLocation &NewLoc, TRotation &NewRot); //oblicza przesuniecie pojazdu
|
||||
double FastComputeMovement(double dt, const TTrackShape &Shape, TTrackParam &Track, const TLocation &NewLoc, TRotation &NewRot); //oblicza przesuniecie pojazdu - wersja zoptymalizowana
|
||||
double ComputeMovement(double dt, double dt1, const TTrackShape &Shape, TTrackParam &Track, TTractionParam &ElectricTraction, TLocation const &NewLoc, TRotation const &NewRot); //oblicza przesuniecie pojazdu
|
||||
double FastComputeMovement(double dt, const TTrackShape &Shape, TTrackParam &Track, TLocation const &NewLoc, TRotation const &NewRot); //oblicza przesuniecie pojazdu - wersja zoptymalizowana
|
||||
void compute_movement_( double const Deltatime );
|
||||
double ShowEngineRotation(int VehN);
|
||||
|
||||
@@ -1498,7 +1502,7 @@ public:
|
||||
|
||||
/*funkcje obliczajace sily*/
|
||||
void ComputeConstans(void);//ABu: wczesniejsze wyznaczenie stalych dla liczenia sil
|
||||
double ComputeMass(void);
|
||||
void ComputeMass(void);
|
||||
void ComputeTotalForce(double dt);
|
||||
double Adhesive(double staticfriction) const;
|
||||
double TractionForce(double dt);
|
||||
@@ -1507,7 +1511,7 @@ public:
|
||||
double BrakeForceP(double press, double velocity);
|
||||
double BrakeForce(const TTrackParam &Track);
|
||||
double CouplerForce(int const End, double dt);
|
||||
void CollisionDetect(int CouplerN, double dt);
|
||||
void CollisionDetect(int const End, double const dt);
|
||||
/*obrot kol uwzgledniajacy poslizg*/
|
||||
double ComputeRotatingWheel(double WForce, double dt, double n) const;
|
||||
|
||||
@@ -1646,3 +1650,11 @@ private:
|
||||
};
|
||||
|
||||
//double Distance(TLocation Loc1, TLocation Loc2, TDimension Dim1, TDimension Dim2);
|
||||
|
||||
namespace simulation {
|
||||
|
||||
using weights_table = std::unordered_map<std::string, float>;
|
||||
|
||||
extern weights_table Weights;
|
||||
|
||||
} // simulation
|
||||
|
||||
@@ -995,68 +995,140 @@ double TMoverParameters::PipeRatio(void)
|
||||
// Q: 20160716
|
||||
// Wykrywanie kolizji
|
||||
// *************************************************************************************************
|
||||
void TMoverParameters::CollisionDetect(int CouplerN, double dt)
|
||||
void TMoverParameters::CollisionDetect(int const End, double const dt)
|
||||
{
|
||||
double CCF, Vprev, VprevC;
|
||||
bool VirtualCoupling;
|
||||
if( Neighbours[ End ].vehicle == nullptr ) { return; } // shouldn't normally happen but, eh
|
||||
|
||||
CCF = 0;
|
||||
// with Couplers[CouplerN] do
|
||||
auto &coupler = Couplers[ CouplerN ];
|
||||
auto &coupler { Couplers[ End ] };
|
||||
auto *othervehicle { Neighbours[ End ].vehicle->MoverParameters };
|
||||
auto const otherend { Neighbours[ End ].vehicle_end };
|
||||
auto &othercoupler { othervehicle->Couplers[ otherend ] };
|
||||
|
||||
if (coupler.Connected != nullptr)
|
||||
{
|
||||
VirtualCoupling = (coupler.CouplingFlag == ctrain_virtual);
|
||||
Vprev = V;
|
||||
VprevC = coupler.Connected->V;
|
||||
switch (CouplerN)
|
||||
{
|
||||
case 0:
|
||||
auto velocity { V };
|
||||
auto othervehiclevelocity { othervehicle->V };
|
||||
// calculate collision force and new velocities for involved vehicles
|
||||
auto const VirtualCoupling { ( coupler.CouplingFlag == coupling::faux ) };
|
||||
auto CCF { 0.0 };
|
||||
|
||||
switch( End ) {
|
||||
case 0: {
|
||||
CCF =
|
||||
ComputeCollision(
|
||||
V,
|
||||
coupler.Connected->V,
|
||||
TotalMass,
|
||||
coupler.Connected->TotalMass,
|
||||
(coupler.beta + coupler.Connected->Couplers[coupler.ConnectedNr].beta) / 2.0,
|
||||
velocity, othervehiclevelocity,
|
||||
TotalMass, othervehicle->TotalMass,
|
||||
( coupler.beta + othercoupler.beta ) / 2.0,
|
||||
VirtualCoupling )
|
||||
/ ( dt );
|
||||
break; // yB: ej ej ej, a po
|
||||
case 1:
|
||||
}
|
||||
case 1: {
|
||||
CCF =
|
||||
ComputeCollision(
|
||||
coupler.Connected->V,
|
||||
V,
|
||||
coupler.Connected->TotalMass,
|
||||
TotalMass,
|
||||
(coupler.beta + coupler.Connected->Couplers[coupler.ConnectedNr].beta) / 2.0,
|
||||
othervehiclevelocity, velocity,
|
||||
othervehicle->TotalMass, TotalMass,
|
||||
( coupler.beta + othercoupler.beta ) / 2.0,
|
||||
VirtualCoupling )
|
||||
/ ( dt );
|
||||
break; // czemu tu jest +0.01??
|
||||
break;
|
||||
}
|
||||
AccS = AccS + (V - Vprev) / dt; // korekta przyspieszenia o siły wynikające ze zderzeń?
|
||||
coupler.Connected->AccS += (coupler.Connected->V - VprevC) / dt;
|
||||
if ((coupler.Dist > 0) && (!VirtualCoupling))
|
||||
if (FuzzyLogic(abs(CCF), 5.0 * (coupler.FmaxC + 1.0), p_coupldmg))
|
||||
{ //! zerwanie sprzegu
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( ( coupler.Dist < 0 )
|
||||
&& ( FuzzyLogic( std::abs( CCF ), 5.0 * ( coupler.FmaxC + 1.0 ), p_coupldmg ) ) ) {
|
||||
// small chance to smash the coupler if it's hit with excessive force
|
||||
damage_coupler( End );
|
||||
}
|
||||
|
||||
auto const safevelocitylimit { 15.0 };
|
||||
auto const velocitydifference {
|
||||
glm::length(
|
||||
glm::angleAxis( Rot.Rz, glm::dvec3{ 0, 1, 0 } ) * V
|
||||
- glm::angleAxis( othervehicle->Rot.Rz, glm::dvec3{ 0, 1, 0 } ) * othervehicle->V )
|
||||
* 3.6 }; // m/s -> km/h
|
||||
|
||||
if( velocitydifference > safevelocitylimit ) {
|
||||
// HACK: crude estimation for potential derail, will take place with velocity difference > 15 km/h adjusted for vehicle mass ratio
|
||||
WriteLog( "Bad driving: " + Name + " and " + othervehicle->Name + " collided with velocity " + to_string( velocitydifference, 0 ) + " km/h" );
|
||||
|
||||
if( velocitydifference > safevelocitylimit * ( TotalMass / othervehicle->TotalMass ) ) {
|
||||
derail( 5 );
|
||||
}
|
||||
if( velocitydifference > safevelocitylimit * ( othervehicle->TotalMass / TotalMass ) ) {
|
||||
othervehicle->derail( 5 );
|
||||
}
|
||||
}
|
||||
|
||||
// adjust velocity and acceleration of affected vehicles
|
||||
if( false == TestFlag( DamageFlag, dtrain_out ) ) {
|
||||
auto const accelerationchange{ ( velocity - V ) / dt };
|
||||
// if( accelerationchange / AccS < 1.0 ) {
|
||||
// HACK: prevent excessive vehicle pinball cases
|
||||
AccS += accelerationchange;
|
||||
// AccS = clamp( AccS, -2.0, 2.0 );
|
||||
V = velocity;
|
||||
// }
|
||||
}
|
||||
if( false == TestFlag( othervehicle->DamageFlag, dtrain_out ) ) {
|
||||
auto const othervehicleaccelerationchange{ ( othervehiclevelocity - othervehicle->V ) / dt };
|
||||
// if( othervehicleaccelerationchange / othervehicle->AccS < 1.0 ) {
|
||||
// HACK: prevent excessive vehicle pinball cases
|
||||
othervehicle->AccS += othervehicleaccelerationchange;
|
||||
othervehicle->V = othervehiclevelocity;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TMoverParameters::damage_coupler( int const End ) {
|
||||
|
||||
if( SetFlag( DamageFlag, dtrain_coupling ) )
|
||||
EventFlag = true;
|
||||
|
||||
if ((coupler.CouplingFlag & ctrain_pneumatic) == ctrain_pneumatic)
|
||||
AlarmChainFlag = true; // hamowanie nagle - zerwanie przewodow hamulcowych
|
||||
auto &coupler { Couplers[ End ] };
|
||||
|
||||
if( ( coupler.CouplingFlag & ctrain_pneumatic ) == ctrain_pneumatic ) {
|
||||
// hamowanie nagle - zerwanie przewodow hamulcowych
|
||||
AlarmChainFlag = true;
|
||||
}
|
||||
|
||||
coupler.CouplingFlag = 0;
|
||||
|
||||
switch (CouplerN) // wyzerowanie flag podlaczenia ale ciagle sa wirtualnie polaczone
|
||||
{
|
||||
case 0:
|
||||
coupler.Connected->Couplers[1].CouplingFlag = 0;
|
||||
break;
|
||||
case 1:
|
||||
coupler.Connected->Couplers[0].CouplingFlag = 0;
|
||||
if( coupler.Connected != nullptr ) {
|
||||
switch( End ) {
|
||||
// break connection with other vehicle, if there's any
|
||||
case 0: {
|
||||
coupler.Connected->Couplers[ end::rear ].CouplingFlag = 0;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
coupler.Connected->Couplers[ end::front ].CouplingFlag = 0;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WriteLog( "Bad driving: " + Name + " broke a coupler" );
|
||||
}
|
||||
|
||||
void
|
||||
TMoverParameters::derail( int const Reason ) {
|
||||
|
||||
if( SetFlag( DamageFlag, dtrain_out ) ) {
|
||||
|
||||
DerailReason = Reason; // TODO: enum derail causes
|
||||
EventFlag = true;
|
||||
MainSwitch( false, range_t::local );
|
||||
|
||||
AccS *= 0.65;
|
||||
V *= 0.65;
|
||||
|
||||
WriteLog( "Bad driving: " + Name + " derailed" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1065,7 +1137,7 @@ void TMoverParameters::CollisionDetect(int CouplerN, double dt)
|
||||
// *************************************************************************************************
|
||||
double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShape &Shape,
|
||||
TTrackParam &Track, TTractionParam &ElectricTraction,
|
||||
const TLocation &NewLoc, TRotation &NewRot)
|
||||
TLocation const &NewLoc, TRotation const &NewRot)
|
||||
{
|
||||
const double Vepsilon = 1e-5;
|
||||
const double Aepsilon = 1e-3; // ASBSpeed=0.8;
|
||||
@@ -1099,9 +1171,6 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
|
||||
// TODO: investigate, seems supplied NewRot is always 0 although the code here suggests some actual values are expected
|
||||
Loc = NewLoc;
|
||||
Rot = NewRot;
|
||||
NewRot.Rx = 0;
|
||||
NewRot.Ry = 0;
|
||||
NewRot.Rz = 0;
|
||||
|
||||
if (dL == 0) // oblicz przesuniecie}
|
||||
{
|
||||
@@ -1230,17 +1299,14 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
|
||||
// *************************************************************************************************
|
||||
|
||||
double TMoverParameters::FastComputeMovement(double dt, const TTrackShape &Shape,
|
||||
TTrackParam &Track, const TLocation &NewLoc,
|
||||
TRotation &NewRot)
|
||||
TTrackParam &Track, TLocation const &NewLoc,
|
||||
TRotation const &NewRot)
|
||||
{
|
||||
int b;
|
||||
// T_MoverParameters::FastComputeMovement(dt, Shape, Track, NewLoc, NewRot);
|
||||
|
||||
Loc = NewLoc;
|
||||
Rot = NewRot;
|
||||
NewRot.Rx = 0.0;
|
||||
NewRot.Ry = 0.0;
|
||||
NewRot.Rz = 0.0;
|
||||
|
||||
if (dL == 0) // oblicz przesuniecie
|
||||
{
|
||||
@@ -1410,7 +1476,13 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) {
|
||||
break;
|
||||
}
|
||||
case TPowerSource::Main: {
|
||||
localvoltage = ( true == Mains ? Voltage : 0.0 );
|
||||
// HACK: main circuit can be fed through couplers, so we explicitly check pantograph supply here
|
||||
localvoltage = (
|
||||
true == Mains ?
|
||||
std::max(
|
||||
PantFrontVolt,
|
||||
PantRearVolt ) :
|
||||
0.0 );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -1710,7 +1782,7 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) {
|
||||
OilPump.pressure =
|
||||
std::max<float>(
|
||||
OilPump.pressure_target,
|
||||
OilPump.pressure - 0.01 * Timestep );
|
||||
OilPump.pressure - ( enrot > 5.0 ? 0.05 : 0.035 ) * 0.5 * Timestep );
|
||||
}
|
||||
OilPump.pressure = clamp( OilPump.pressure, 0.f, 1.5f );
|
||||
}
|
||||
@@ -4020,7 +4092,6 @@ void TMoverParameters::ComputeConstans(void)
|
||||
double BearingF, RollF, HideModifier;
|
||||
double Curvature; // Ra 2014-07: odwrotność promienia
|
||||
|
||||
TotalMass = ComputeMass();
|
||||
TotalMassxg = TotalMass * g; // TotalMass*g
|
||||
BearingF = 2.0 * (DamageFlag && dtrain_bearing);
|
||||
|
||||
@@ -4071,29 +4142,28 @@ void TMoverParameters::ComputeConstans(void)
|
||||
// Q: 20160713
|
||||
// Oblicza masę ładunku
|
||||
// *************************************************************************************************
|
||||
double TMoverParameters::ComputeMass(void)
|
||||
void TMoverParameters::ComputeMass()
|
||||
{
|
||||
double M { 0.0 };
|
||||
// TODO: unit weight table, pulled from external data file
|
||||
if( LoadAmount > 0 ) {
|
||||
|
||||
if (ToLower(LoadQuantity) == "tonns")
|
||||
M = LoadAmount * 1000;
|
||||
else if (LoadType.name == "passengers")
|
||||
M = LoadAmount * 80;
|
||||
else if (LoadType.name == "luggage")
|
||||
M = LoadAmount * 100;
|
||||
else if (LoadType.name == "cars")
|
||||
M = LoadAmount * 1200; // 800 kilo to miał maluch
|
||||
else if (LoadType.name == "containers")
|
||||
M = LoadAmount * 8000;
|
||||
else if (LoadType.name == "transformers")
|
||||
M = LoadAmount * 50000;
|
||||
else
|
||||
M = LoadAmount * 1000;
|
||||
}
|
||||
// Ra: na razie tak, ale nie wszędzie masy wirujące się wliczają
|
||||
return Mass + M + Mred;
|
||||
TotalMass = Mass + Mred;
|
||||
|
||||
if( LoadAmount == 0 ) { return; }
|
||||
|
||||
// include weight of carried load
|
||||
auto loadtypeunitweight { 0.f };
|
||||
|
||||
if( ToLower( LoadQuantity ) == "tonns" ) {
|
||||
loadtypeunitweight = 1000;
|
||||
}
|
||||
else {
|
||||
auto const lookup { simulation::Weights.find( LoadType.name ) };
|
||||
loadtypeunitweight = (
|
||||
lookup != simulation::Weights.end() ?
|
||||
lookup->second :
|
||||
1000.f ); // legacy default unit weight value
|
||||
}
|
||||
|
||||
TotalMass += LoadAmount * loadtypeunitweight;
|
||||
}
|
||||
|
||||
// *************************************************************************************************
|
||||
@@ -4135,6 +4205,11 @@ void TMoverParameters::ComputeTotalForce(double dt) {
|
||||
|
||||
// juz zoptymalizowane:
|
||||
FStand = FrictionForce(RunningShape.R, RunningTrack.DamageFlag); // siła oporów ruchu
|
||||
if( true == TestFlag( DamageFlag, dtrain_out ) ) {
|
||||
// HACK: crude way to reduce speed after derailment
|
||||
// TBD, TODO: more accurate approach?
|
||||
FStand *= 1e20;
|
||||
}
|
||||
double old_nrot = abs(nrot);
|
||||
nrot = v2n(); // przeliczenie prędkości liniowej na obrotową
|
||||
|
||||
@@ -4424,15 +4499,13 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
|
||||
auto &othercoupler { othervehicle->Couplers[ otherend ] };
|
||||
|
||||
auto const othervehiclemove { ( othervehicle->dMoveLen * DirPatch( End, otherend ) ) };
|
||||
auto const initialdistance { Neighbours[ End ].distance }; // odległość od sprzęgu sąsiada
|
||||
auto const distancedelta { (
|
||||
End == end::front ?
|
||||
othervehiclemove - dMoveLen :
|
||||
dMoveLen - othervehiclemove ) };
|
||||
auto const initialdistance { Neighbours[ End ].distance }; // odległość od sprzęgu sąsiada
|
||||
|
||||
auto const newdistance =
|
||||
initialdistance
|
||||
+ 10.0 * distancedelta;
|
||||
auto const newdistance { initialdistance + 10.0 * distancedelta };
|
||||
|
||||
auto const dV { V - ( othervehicle->V * DirPatch( End, otherend ) ) };
|
||||
auto const absdV { std::abs( dV ) };
|
||||
@@ -4462,11 +4535,15 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
|
||||
}
|
||||
|
||||
coupler.CheckCollision = false;
|
||||
coupler.Dist = 0.0;
|
||||
|
||||
double CF { 0.0 };
|
||||
|
||||
if( ( coupler.CouplingFlag != coupling::faux )
|
||||
|| ( initialdistance < 0 ) ) {
|
||||
|
||||
coupler.Dist = clamp( newdistance, -coupler.DmaxB, coupler.DmaxC );
|
||||
|
||||
double BetaAvg = 0;
|
||||
double Fmax = 0;
|
||||
|
||||
@@ -4481,8 +4558,8 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
|
||||
Fmax = 0.5 * ( coupler.FmaxC + coupler.FmaxB + othercoupler.FmaxC + othercoupler.FmaxB ) * CouplerTune;
|
||||
}
|
||||
auto const distDelta { std::abs( newdistance ) - std::abs( coupler.Dist ) }; // McZapkie-191103: poprawka na histereze
|
||||
coupler.Dist = newdistance;
|
||||
if (coupler.Dist > 0) {
|
||||
|
||||
if (newdistance > 0) {
|
||||
|
||||
if( distDelta > 0 ) {
|
||||
CF = ( -( coupler.SpringKC + othercoupler.SpringKC ) * coupler.Dist / 2.0 ) * DirF( End )
|
||||
@@ -4493,12 +4570,25 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
|
||||
- Fmax * dV * BetaAvg;
|
||||
}
|
||||
// liczenie sily ze sprezystosci sprzegu
|
||||
if( coupler.Dist > ( coupler.DmaxC + othercoupler.DmaxC ) ) {
|
||||
if( newdistance > ( coupler.DmaxC + othercoupler.DmaxC ) ) {
|
||||
// zderzenie
|
||||
coupler.CheckCollision = true;
|
||||
}
|
||||
if( std::abs( CF ) > coupler.FmaxC ) {
|
||||
// coupler is stretched with excessive force, may break
|
||||
coupler.stretch_duration += dt;
|
||||
// give coupler 1 sec of leeway to account for simulation glitches, before checking whether it breaks
|
||||
// (arbitrary) chance to break grows from 10-100% over 10 sec period
|
||||
if( ( coupler.stretch_duration > 1.f )
|
||||
&& ( Random() < ( coupler.stretch_duration * 0.1f * dt ) ) ) {
|
||||
damage_coupler( End );
|
||||
}
|
||||
if( coupler.Dist < 0 ) {
|
||||
}
|
||||
else {
|
||||
coupler.stretch_duration = 0.f;
|
||||
}
|
||||
}
|
||||
if( newdistance < 0 ) {
|
||||
|
||||
if( distDelta > 0 ) {
|
||||
CF = ( -( coupler.SpringKB + othercoupler.SpringKB ) * coupler.Dist / 2.0 ) * DirF( End )
|
||||
@@ -4509,7 +4599,7 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
|
||||
- Fmax * dV * BetaAvg;
|
||||
}
|
||||
// liczenie sily ze sprezystosci zderzaka
|
||||
if( -coupler.Dist > ( coupler.DmaxB + othercoupler.DmaxB ) ) {
|
||||
if( -newdistance > ( coupler.DmaxB + othercoupler.DmaxB ) ) {
|
||||
// zderzenie
|
||||
coupler.CheckCollision = true;
|
||||
if( ( coupler.CouplerType == TCouplerType::Automatic )
|
||||
@@ -5408,25 +5498,19 @@ double TMoverParameters::TractionForce( double dt ) {
|
||||
|
||||
eimv[eimv_ks] = eimv[eimv_Fr] / eimv[eimv_FMAXMAX];
|
||||
eimv[eimv_df] = eimv[eimv_ks] * eimc[eimc_s_dfmax];
|
||||
eimv[eimv_fp] = DirAbsolute * enrot * eimc[eimc_s_p] +
|
||||
eimv[eimv_df]; // do przemyslenia dzialanie pp z tmpV
|
||||
eimv[eimv_fp] = DirAbsolute * enrot * eimc[eimc_s_p] + eimv[eimv_df]; // do przemyslenia dzialanie pp z tmpV
|
||||
// eimv[eimv_U]:=Max0R(eimv[eimv_Uzsmax],Min0R(eimc[eimc_f_cfu]*eimv[eimv_fp],eimv[eimv_Uzsmax]));
|
||||
// eimv[eimv_pole]:=eimv[eimv_U]/(eimv[eimv_fp]*eimc[eimc_s_cfu]);
|
||||
if ((abs(eimv[eimv_fp]) <= eimv[eimv_fkr]))
|
||||
eimv[eimv_pole] = eimc[eimc_f_cfu] / eimc[eimc_s_cfu];
|
||||
else
|
||||
eimv[eimv_pole] =
|
||||
eimv[eimv_Uzsmax] / eimc[eimc_s_cfu] / abs(eimv[eimv_fp]);
|
||||
eimv[eimv_pole] = eimv[eimv_Uzsmax] / eimc[eimc_s_cfu] / abs(eimv[eimv_fp]);
|
||||
eimv[eimv_U] = eimv[eimv_pole] * eimv[eimv_fp] * eimc[eimc_s_cfu];
|
||||
eimv[eimv_Ic] = (eimv[eimv_fp] - DirAbsolute * enrot * eimc[eimc_s_p]) *
|
||||
eimc[eimc_s_dfic] * eimv[eimv_pole];
|
||||
eimv[eimv_Ic] = (eimv[eimv_fp] - DirAbsolute * enrot * eimc[eimc_s_p]) * eimc[eimc_s_dfic] * eimv[eimv_pole];
|
||||
eimv[eimv_If] = eimv[eimv_Ic] * eimc[eimc_s_icif];
|
||||
eimv[eimv_M] = eimv[eimv_pole] * eimv[eimv_Ic] * eimc[eimc_s_cim];
|
||||
eimv[eimv_Ipoj] = (eimv[eimv_Ic] * NPoweredAxles * eimv[eimv_U]) /
|
||||
(Voltage - eimc[eimc_f_DU]) +
|
||||
eimc[eimc_f_I0];
|
||||
eimv[eimv_Pm] =
|
||||
ActiveDir * eimv[eimv_M] * NPoweredAxles * enrot * Pirazy2 / 1000;
|
||||
eimv[eimv_Ipoj] = (eimv[eimv_Ic] * NPoweredAxles * eimv[eimv_U]) / (Voltage - eimc[eimc_f_DU]) + eimc[eimc_f_I0];
|
||||
eimv[eimv_Pm] = ActiveDir * eimv[eimv_M] * NPoweredAxles * enrot * Pirazy2 / 1000;
|
||||
eimv[eimv_Pe] = eimv[eimv_Ipoj] * Voltage / 1000;
|
||||
eimv[eimv_eta] = eimv[eimv_Pm] / eimv[eimv_Pe];
|
||||
|
||||
@@ -5447,7 +5531,7 @@ double TMoverParameters::TractionForce( double dt ) {
|
||||
|
||||
if( ( RlistSize > 0 )
|
||||
&& ( ( std::abs( eimv[ eimv_If ] ) > 1.0 )
|
||||
|| ( tmpV > 0.1 ) ) ) {
|
||||
&& ( tmpV > 0.1 ) ) ) {
|
||||
|
||||
int i = 0;
|
||||
while( ( i < RlistSize - 1 )
|
||||
@@ -7079,6 +7163,7 @@ TMoverParameters::AssignLoad( std::string const &Name, float const Amount ) {
|
||||
if( Name == loadattributes.name ) {
|
||||
LoadType = loadattributes;
|
||||
LoadAmount = clamp( Amount, 0.f, MaxLoad ) ;
|
||||
ComputeMass();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -7121,6 +7206,7 @@ bool TMoverParameters::LoadingDone(double const LSpeed, std::string const &Loadn
|
||||
if( LoadAmount == 0.f ) {
|
||||
AssignLoad(""); // jak nic nie ma, to nie ma też nazwy
|
||||
}
|
||||
ComputeMass();
|
||||
}
|
||||
}
|
||||
else if( LSpeed > 0 ) {
|
||||
@@ -7135,6 +7221,7 @@ bool TMoverParameters::LoadingDone(double const LSpeed, std::string const &Loadn
|
||||
LoadStatus = 4; // skończony załadunek
|
||||
LoadAmount = std::min<float>( MaxLoad * ( 1.0 + OverLoadFactor ), LoadAmount );
|
||||
}
|
||||
ComputeMass();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10681,3 +10768,9 @@ double TMoverParameters::ShowCurrentP(int AmpN) const
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
namespace simulation {
|
||||
|
||||
weights_table Weights;
|
||||
|
||||
} // simulation
|
||||
2
Names.h
2
Names.h
@@ -35,7 +35,7 @@ public:
|
||||
if( true == mapping.second ) {
|
||||
return true;
|
||||
}
|
||||
// cell with this name already exists; update mapping to point to the new one, for backward compatibility
|
||||
// item with this name already exists; update mapping to point to the new one, for backward compatibility
|
||||
mapping.first->second = itemhandle;
|
||||
return false; }
|
||||
bool insert (Type_ *Item)
|
||||
|
||||
36
Train.cpp
36
Train.cpp
@@ -509,7 +509,7 @@ dictionary_source *TTrain::GetTrainState() {
|
||||
// induction motor state data
|
||||
char const *TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" };
|
||||
char const *TXTC[ 10 ] = { "fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv" };
|
||||
char const *TXTD[ 10 ] = { "enrot", "nrot", "fill_des", "fill_real", "clutch_des", "clutch_real", "water_temp", "oil_press", "res1", "res2" };
|
||||
char const *TXTD[ 10 ] = { "enrot", "nrot", "fill_des", "fill_real", "clutch_des", "clutch_real", "water_temp", "oil_press", "engine_temp", "res1" };
|
||||
char const *TXTP[ 3 ] = { "bc", "bp", "sp" };
|
||||
for( int j = 0; j < 10; ++j )
|
||||
dict->insert( ( "eimp_t_" + std::string( TXTT[ j ] ) ), fEIMParams[ 0 ][ j ] );
|
||||
@@ -597,6 +597,7 @@ TTrain::get_state() const {
|
||||
btLampkaNadmWent.GetValue(),
|
||||
btLampkaWysRozr.GetValue(),
|
||||
btLampkaOgrzewanieSkladu.GetValue(),
|
||||
static_cast<std::uint8_t>( iCabn ),
|
||||
btHaslerBrakes.GetValue(),
|
||||
btHaslerCurrent.GetValue(),
|
||||
( TestFlag( mvOccupied->SecuritySystem.Status, s_CAalarm ) || TestFlag( mvOccupied->SecuritySystem.Status, s_SHPalarm ) ),
|
||||
@@ -606,7 +607,8 @@ TTrain::get_state() const {
|
||||
static_cast<float>( mvOccupied->PipePress ),
|
||||
static_cast<float>( mvOccupied->BrakePress ),
|
||||
fHVoltage,
|
||||
{ fHCurrent[ ( mvControlled->TrainType & dt_EZT ) ? 0 : 1 ], fHCurrent[ 2 ], fHCurrent[ 3 ] }
|
||||
{ fHCurrent[ ( mvControlled->TrainType & dt_EZT ) ? 0 : 1 ], fHCurrent[ 2 ], fHCurrent[ 3 ] },
|
||||
ggLVoltage.GetValue()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4261,9 +4263,8 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman
|
||||
if( Command.action == GLFW_PRESS ) {
|
||||
// NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors
|
||||
if( false == (
|
||||
Train->mvOccupied->ActiveCab == 1 ?
|
||||
Train->mvOccupied->Doors.instances[side::left].is_opening || Train->mvOccupied->Doors.instances[ side::left ].is_open :
|
||||
Train->mvOccupied->Doors.instances[side::right].is_opening || Train->mvOccupied->Doors.instances[ side::right ].is_open ) ) {
|
||||
( Train->ggDoorLeftButton.GetDesiredValue() > 0.5 )
|
||||
|| ( Train->ggDoorLeftOnButton.GetDesiredValue() > 0.5 ) ) ) {
|
||||
// open
|
||||
OnCommand_dooropenleft( Train, Command );
|
||||
}
|
||||
@@ -4283,9 +4284,8 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman
|
||||
else if( Command.action == GLFW_RELEASE ) {
|
||||
|
||||
if( true == (
|
||||
Train->mvOccupied->ActiveCab == 1 ?
|
||||
Train->mvOccupied->Doors.instances[side::left].is_opening || Train->mvOccupied->Doors.instances[ side::left ].is_open :
|
||||
Train->mvOccupied->Doors.instances[side::right].is_opening || Train->mvOccupied->Doors.instances[ side::right ].is_open ) ) {
|
||||
( Train->ggDoorLeftButton.GetDesiredValue() > 0.5 )
|
||||
|| ( Train->ggDoorLeftOnButton.GetDesiredValue() > 0.5 ) ) ) {
|
||||
// open
|
||||
if( ( Train->mvOccupied->Doors.has_autowarning )
|
||||
&& ( Train->mvOccupied->DepartureSignal ) ) {
|
||||
@@ -4345,7 +4345,7 @@ void TTrain::OnCommand_doorpermitleft( TTrain *Train, command_data const &Comman
|
||||
}
|
||||
else {
|
||||
// two-state switch
|
||||
auto const newstate { !( Train->mvOccupied->Doors.instances[ side ].open_permit ) };
|
||||
auto const newstate { !( Train->ggDoorLeftPermitButton.GetDesiredValue() > 0.5 ) };
|
||||
|
||||
Train->mvOccupied->PermitDoors( side, newstate );
|
||||
// visual feedback
|
||||
@@ -4381,7 +4381,7 @@ void TTrain::OnCommand_doorpermitright( TTrain *Train, command_data const &Comma
|
||||
}
|
||||
else {
|
||||
// two-state switch
|
||||
auto const newstate { !( Train->mvOccupied->Doors.instances[ side ].open_permit ) };
|
||||
auto const newstate { !( Train->ggDoorRightPermitButton.GetDesiredValue() > 0.5 ) };
|
||||
|
||||
Train->mvOccupied->PermitDoors( side, newstate );
|
||||
// visual feedback
|
||||
@@ -4520,9 +4520,8 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma
|
||||
if( Command.action == GLFW_PRESS ) {
|
||||
// NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors
|
||||
if( false == (
|
||||
Train->mvOccupied->ActiveCab == 1 ?
|
||||
Train->mvOccupied->Doors.instances[side::right].is_opening || Train->mvOccupied->Doors.instances[ side::right ].is_open :
|
||||
Train->mvOccupied->Doors.instances[side::left].is_opening || Train->mvOccupied->Doors.instances[ side::left ].is_open ) ) {
|
||||
( Train->ggDoorRightButton.GetDesiredValue() > 0.5 )
|
||||
|| ( Train->ggDoorRightOnButton.GetDesiredValue() > 0.5 ) ) ) {
|
||||
// open
|
||||
OnCommand_dooropenright( Train, Command );
|
||||
}
|
||||
@@ -4542,9 +4541,8 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma
|
||||
else if( Command.action == GLFW_RELEASE ) {
|
||||
|
||||
if( true == (
|
||||
Train->mvOccupied->ActiveCab == 1 ?
|
||||
Train->mvOccupied->Doors.instances[side::right].is_opening || Train->mvOccupied->Doors.instances[ side::right ].is_open :
|
||||
Train->mvOccupied->Doors.instances[side::left].is_opening || Train->mvOccupied->Doors.instances[ side::left ].is_open ) ) {
|
||||
( Train->ggDoorRightButton.GetDesiredValue() > 0.5 )
|
||||
|| ( Train->ggDoorRightOnButton.GetDesiredValue() > 0.5 ) ) ) {
|
||||
// open
|
||||
if( ( Train->mvOccupied->Doors.has_autowarning )
|
||||
&& ( Train->mvOccupied->DepartureSignal ) ) {
|
||||
@@ -5416,7 +5414,9 @@ bool TTrain::Update( double const Deltatime )
|
||||
in++;
|
||||
iPowerNo = in;
|
||||
}
|
||||
if ((in < 8) && (p->MoverParameters->EngineType==TEngineType::DieselEngine))
|
||||
if ((in < 8)
|
||||
&& ((p->MoverParameters->EngineType==TEngineType::DieselEngine)
|
||||
||(p->MoverParameters->EngineType==TEngineType::DieselElectric)))
|
||||
{
|
||||
fDieselParams[1 + in][0] = p->MoverParameters->enrot*60;
|
||||
fDieselParams[1 + in][1] = p->MoverParameters->nrot;
|
||||
@@ -5426,7 +5426,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
fDieselParams[1 + in][5] = p->MoverParameters->dizel_engage;
|
||||
fDieselParams[1 + in][6] = p->MoverParameters->dizel_heat.Twy;
|
||||
fDieselParams[1 + in][7] = p->MoverParameters->OilPump.pressure;
|
||||
//fDieselParams[1 + in][8] = p->MoverParameters->
|
||||
fDieselParams[1 + in][8] = p->MoverParameters->dizel_heat.Ts;
|
||||
//fDieselParams[1 + in][9] = p->MoverParameters->
|
||||
bMains[in] = p->MoverParameters->Mains;
|
||||
fCntVol[in] = p->MoverParameters->BatteryVoltage;
|
||||
|
||||
10
Train.h
10
Train.h
@@ -70,8 +70,10 @@ public:
|
||||
find( TSubModel const *Control ) const;
|
||||
};
|
||||
|
||||
class TTrain
|
||||
{
|
||||
class TTrain {
|
||||
|
||||
friend class drivingaid_panel;
|
||||
|
||||
public:
|
||||
// types
|
||||
struct state_t {
|
||||
@@ -89,6 +91,7 @@ class TTrain
|
||||
std::uint8_t ventilator_overload;
|
||||
std::uint8_t motor_overload_threshold;
|
||||
std::uint8_t train_heating;
|
||||
std::uint8_t cab;
|
||||
std::uint8_t recorder_braking;
|
||||
std::uint8_t recorder_power;
|
||||
std::uint8_t alerter_sound;
|
||||
@@ -99,6 +102,7 @@ class TTrain
|
||||
float brake_pressure;
|
||||
float hv_voltage;
|
||||
std::array<float, 3> hv_current;
|
||||
float lv_voltage;
|
||||
};
|
||||
|
||||
// methods
|
||||
@@ -632,7 +636,7 @@ public: // reszta może by?publiczna
|
||||
*/
|
||||
// McZapkie: opis kabiny - obszar poruszania sie mechanika oraz zajetosc
|
||||
std::array<TCab, maxcab + 1> Cabine; // przedzial maszynowy, kabina 1 (A), kabina 2 (B)
|
||||
int iCabn { 0 };
|
||||
int iCabn { 0 }; // 0: mid, 1: front, 2: rear
|
||||
// McZapkie: do poruszania sie po kabinie
|
||||
Math3D::vector3 pMechSittingPosition; // ABu 180404
|
||||
Math3D::vector3 MirrorPosition( bool lewe );
|
||||
|
||||
@@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Globals.h"
|
||||
#include "simulation.h"
|
||||
#include "Train.h"
|
||||
#include "dictionary.h"
|
||||
#include "sceneeditor.h"
|
||||
#include "renderer.h"
|
||||
#include "uilayer.h"
|
||||
@@ -129,6 +130,9 @@ eu07_application::init( int Argc, char *Argv[] ) {
|
||||
if( ( result = init_audio() ) != 0 ) {
|
||||
return result;
|
||||
}
|
||||
if( ( result = init_data() ) != 0 ) {
|
||||
return result;
|
||||
}
|
||||
m_taskqueue.init();
|
||||
if( ( result = init_modes() ) != 0 ) {
|
||||
return result;
|
||||
@@ -752,6 +756,23 @@ eu07_application::init_audio() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
eu07_application::init_data() {
|
||||
|
||||
// HACK: grab content of the first {} block in load_unit_weights using temporary parser, then parse it normally. on any error our weight list will be empty string
|
||||
auto loadweights { cParser( cParser( "data/load_weights.txt", cParser::buffer_FILE ).getToken<std::string>( true, "{}" ), cParser::buffer_TEXT ) };
|
||||
while( true == loadweights.getTokens( 2 ) ) {
|
||||
std::pair<std::string, float> weightpair;
|
||||
loadweights
|
||||
>> weightpair.first
|
||||
>> weightpair.second;
|
||||
weightpair.first.erase( weightpair.first.end() - 1 ); // trim trailing ':' from the key
|
||||
simulation::Weights.emplace( weightpair.first, weightpair.second );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
eu07_application::init_modes() {
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ private:
|
||||
void init_callbacks();
|
||||
int init_gfx();
|
||||
int init_audio();
|
||||
int init_data();
|
||||
int init_modes();
|
||||
bool init_network();
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ openal_source::sync_with( sound_properties const &State ) {
|
||||
|| ( false == is_in_range ) ) {
|
||||
// if the emitter is outside of its nominal hearing range or was outside of it during last check
|
||||
// adjust the volume to a suitable fraction of nominal value
|
||||
auto const fadedistance { sound_range * 0.75 };
|
||||
auto const fadedistance { sound_range * 0.75f };
|
||||
auto const rangefactor {
|
||||
interpolate(
|
||||
1.f, 0.f,
|
||||
|
||||
@@ -136,7 +136,7 @@ drivingaid_panel::update() {
|
||||
}
|
||||
}
|
||||
std::string textline =
|
||||
( true == TestFlag( mover->SecuritySystem.Status, s_aware ) ?
|
||||
( (true == TestFlag( mover->SecuritySystem.Status, s_aware ) && train != nullptr && train->fBlinkTimer > 0) ?
|
||||
locale::strings[ locale::string::driver_aid_alerter ] :
|
||||
" " );
|
||||
textline +=
|
||||
@@ -958,6 +958,14 @@ debug_panel::update_section_scenario( std::vector<text_line> &Output ) {
|
||||
textline = "Cloud cover: " + to_string( Global.Overcast, 3 );
|
||||
textline += "\nLight level: " + to_string( Global.fLuminance, 3 );
|
||||
if( Global.FakeLight ) { textline += "(*)"; }
|
||||
textline +=
|
||||
"\nWind: azimuth "
|
||||
+ to_string( simulation::Environment.wind_azimuth(), 0 ) // ma być azymut, czyli 0 na północy i rośnie na wschód
|
||||
+ " "
|
||||
+ std::string( "N NEE SES SWW NW" )
|
||||
.substr( 0 + 2 * std::floor( std::fmod( 8 + ( glm::radians( simulation::Environment.wind_azimuth() ) + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 )
|
||||
+ ", " + to_string( glm::length( simulation::Environment.wind() ), 1 ) + " m/s";
|
||||
|
||||
textline += "\nAir temperature: " + to_string( Global.AirTemperature, 1 ) + " deg C";
|
||||
|
||||
Output.emplace_back( textline, Global.UITextColor );
|
||||
|
||||
@@ -35,12 +35,24 @@ smoke_source::particle_emitter::deserialize( cParser &Input ) {
|
||||
while( ( false == ( ( key = Input.getToken<std::string>( true, "\n\r\t ,;[]" ) ).empty() ) )
|
||||
&& ( key != "}" ) ) {
|
||||
|
||||
if( key == "color:" ) {
|
||||
// special case, vec3 attribute type
|
||||
// TODO: variable table, if amount of vector attributes increases
|
||||
color = Input.getToken<glm::vec3>( true, "\n\r\t ,;[]" );
|
||||
color =
|
||||
glm::clamp(
|
||||
color / 255.f,
|
||||
glm::vec3{ 0.f }, glm::vec3{ 1.f } );
|
||||
}
|
||||
else {
|
||||
// float type attributes
|
||||
auto const lookup { variablemap.find( key ) };
|
||||
if( lookup == variablemap.end() ) { continue; }
|
||||
|
||||
if( lookup != variablemap.end() ) {
|
||||
lookup->second = Input.getToken<float>( true, "\n\r\t ,;[]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
smoke_source::particle_emitter::initialize( smoke_particle &Particle ) {
|
||||
@@ -49,16 +61,16 @@ smoke_source::particle_emitter::initialize( smoke_particle &Particle ) {
|
||||
auto const azimuthalangle { glm::radians( Random( -180, 180 ) ) }; // phi
|
||||
// convert spherical coordinates to opengl coordinates
|
||||
auto const launchvector { glm::vec3(
|
||||
std::sin( polarangle ) * std::sin( azimuthalangle ),
|
||||
std::sin( polarangle ) * std::sin( azimuthalangle ) * -1,
|
||||
std::cos( polarangle ),
|
||||
std::sin( polarangle ) * std::cos( azimuthalangle ) * -1 ) };
|
||||
std::sin( polarangle ) * std::cos( azimuthalangle ) ) };
|
||||
auto const launchvelocity { static_cast<float>( Random( velocity[ value_limit::min ], velocity[ value_limit::max ] ) ) };
|
||||
|
||||
Particle.velocity = launchvector * launchvelocity;
|
||||
|
||||
Particle.rotation = glm::radians( Random( 0, 360 ) );
|
||||
Particle.size = Random( size[ value_limit::min ], size[ value_limit::max ] );
|
||||
Particle.opacity = Random( opacity[ value_limit::min ], opacity[ value_limit::max ] );
|
||||
Particle.opacity = Random( opacity[ value_limit::min ], opacity[ value_limit::max ] ) / Global.SmokeFidelity;
|
||||
Particle.age = 0;
|
||||
}
|
||||
|
||||
@@ -112,7 +124,7 @@ smoke_source::initialize() {
|
||||
m_max_particles =
|
||||
// put a cap on number of particles in a single source. TBD, TODO: make it part of he source configuration?
|
||||
std::min(
|
||||
2000,
|
||||
static_cast<int>( 500 * Global.SmokeFidelity ),
|
||||
// NOTE: given nature of the smoke we're presuming opacity decreases over time and the particle is killed when it reaches 0
|
||||
// this gives us estimate of longest potential lifespan of single particle, and how many particles total can there be at any given time
|
||||
// TBD, TODO: explicit lifespan variable as part of the source configuration?
|
||||
@@ -150,11 +162,16 @@ smoke_source::update( double const Timedelta, bool const Onlydespawn ) {
|
||||
glm::dvec3{ std::numeric_limits<double>::lowest() } };
|
||||
|
||||
m_spawncount = (
|
||||
Onlydespawn ?
|
||||
( ( false == Global.Smoke ) || ( true == Onlydespawn ) ) ?
|
||||
0.f :
|
||||
std::min<float>(
|
||||
m_spawncount + ( m_spawnrate * Timedelta ),
|
||||
m_spawncount + ( m_spawnrate * Timedelta * Global.SmokeFidelity ),
|
||||
m_max_particles ) );
|
||||
// HACK: don't spawn particles in tunnels, to prevent smoke clipping through 'terrain' outside
|
||||
if( ( m_ownertype == owner_type::vehicle )
|
||||
&& ( m_owner.vehicle->RaTrackGet()->eEnvironment == e_tunnel ) ) {
|
||||
m_spawncount = 0.f;
|
||||
}
|
||||
// update spawned particles
|
||||
for( auto particleiterator { std::begin( m_particles ) }; particleiterator != std::end( m_particles ); ++particleiterator ) {
|
||||
|
||||
@@ -276,13 +293,14 @@ smoke_source::initialize( smoke_particle &Particle ) {
|
||||
|
||||
if( m_ownertype == owner_type::vehicle ) {
|
||||
Particle.opacity *= m_owner.vehicle->MoverParameters->dizel_fill;
|
||||
auto const enginerevolutionsfactor { 1.5f }; // high engine revolutions increase initial particle velocity
|
||||
switch( m_owner.vehicle->MoverParameters->EngineType ) {
|
||||
case TEngineType::DieselElectric: {
|
||||
Particle.velocity *= 1.0 + m_owner.vehicle->MoverParameters->enrot / ( m_owner.vehicle->MoverParameters->DElist[ m_owner.vehicle->MoverParameters->MainCtrlPosNo ].RPM / 60.0 );
|
||||
Particle.velocity *= 1.0 + enginerevolutionsfactor * m_owner.vehicle->MoverParameters->enrot / ( m_owner.vehicle->MoverParameters->DElist[ m_owner.vehicle->MoverParameters->MainCtrlPosNo ].RPM / 60.0 );
|
||||
break;
|
||||
}
|
||||
case TEngineType::DieselEngine: {
|
||||
Particle.velocity *= 1.0 + m_owner.vehicle->MoverParameters->enrot / m_owner.vehicle->MoverParameters->nmax;
|
||||
Particle.velocity *= 1.0 + enginerevolutionsfactor * m_owner.vehicle->MoverParameters->enrot / m_owner.vehicle->MoverParameters->nmax;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -399,7 +417,9 @@ particle_manager::find( std::string const &Template ) {
|
||||
smoke_source source;
|
||||
cParser parser( templatepath + templatename + ".txt", cParser::buffer_FILE );
|
||||
if( source.deserialize( parser ) ) {
|
||||
// if deserialization didn't fail cache the source as template for future instances
|
||||
// if deserialization didn't fail finish source setup...
|
||||
source.m_opacitymodifier.bind( &Global.SmokeFidelity );
|
||||
// ...then cache the source as template for future instances
|
||||
m_sourcetemplates.emplace( templatename, source );
|
||||
// should be 'safe enough' to return lookup result directly afterwards
|
||||
return &( m_sourcetemplates.find( templatename )->second );
|
||||
|
||||
29
particles.h
29
particles.h
@@ -48,9 +48,15 @@ public:
|
||||
// updates state of provided variable
|
||||
void
|
||||
update( Type_ &Variable, double const Timedelta ) const;
|
||||
Type_ const &
|
||||
void
|
||||
bind( Type_ const *Modifier ) {
|
||||
m_valuechangemodifier = Modifier; }
|
||||
Type_
|
||||
value_change() const {
|
||||
return m_valuechange; }
|
||||
return (
|
||||
m_valuechangemodifier == nullptr ?
|
||||
m_valuechange :
|
||||
m_valuechange / *( m_valuechangemodifier ) ); }
|
||||
|
||||
private:
|
||||
//types
|
||||
@@ -59,6 +65,7 @@ private:
|
||||
// Type_ m_intialvalue { Type_( 0 ) }; // meters per second; velocity applied to freshly spawned particles
|
||||
Type_ m_valuechange { Type_( 0 ) }; // meters per second; change applied to initial velocity
|
||||
Type_ m_valuelimits[ 2 ] { Type_( std::numeric_limits<Type_>::lowest() ), Type_( std::numeric_limits<Type_>::max() ) };
|
||||
Type_ const *m_valuechangemodifier{ nullptr }; // optional modifier applied to value change
|
||||
};
|
||||
|
||||
|
||||
@@ -86,6 +93,9 @@ public:
|
||||
// updates state of owned particles
|
||||
void
|
||||
update( double const Timedelta, bool const Onlydespawn );
|
||||
glm::vec3 const &
|
||||
color() const {
|
||||
return m_emitter.color; }
|
||||
glm::dvec3
|
||||
location() const;
|
||||
// provides access to bounding area data
|
||||
@@ -109,6 +119,7 @@ private:
|
||||
float velocity[ 2 ] { 1.f, 1.f };
|
||||
float size[ 2 ] { 1.f, 1.f };
|
||||
float opacity[ 2 ] { 1.f, 1.f };
|
||||
glm::vec3 color { 16.f / 255.f };
|
||||
|
||||
void deserialize( cParser &Input );
|
||||
void initialize( smoke_particle &Particle );
|
||||
@@ -138,20 +149,14 @@ private:
|
||||
particle_emitter m_emitter;
|
||||
// bool m_inheritvelocity { false }; // whether spawned particle should receive velocity of its owner
|
||||
// TODO: replace modifiers with configurable interpolator item allowing keyframe-based changes over time
|
||||
// fixedstep_modifier<glm::vec3> m_velocitymodifier; // particle velocity
|
||||
fixedstep_modifier<float> m_sizemodifier; // particle billboard size
|
||||
// fixedstep_modifier<glm::vec4> m_colormodifier; // particle billboard color and opacity
|
||||
// fixedstep_modifier<glm::vec3> m_colormodifier; // particle billboard color and opacity
|
||||
fixedstep_modifier<float> m_opacitymodifier;
|
||||
// texture_handle m_texture { -1 }; // texture assigned to particle billboards
|
||||
// current state
|
||||
float m_spawncount { 0.f }; // number of particles to spawn during next update
|
||||
particle_sequence m_particles; // collection of spawned particles
|
||||
size_t m_max_particles; // maximum number of particles existing
|
||||
/*
|
||||
smoke_sequence::iterator // helpers, iterators marking currently used part of the particle container
|
||||
m_particlehead,
|
||||
m_particletail;
|
||||
*/
|
||||
scene::bounding_area m_area; // bounding sphere of owned particles
|
||||
};
|
||||
|
||||
@@ -204,7 +209,11 @@ void
|
||||
fixedstep_modifier<Type_>::update( Type_ &Variable, double const Timedelta ) const {
|
||||
// HACK: float cast to avoid vec3 and double mismatch
|
||||
// TBD, TODO: replace with vector types specialization
|
||||
Variable += ( m_valuechange * static_cast<float>( Timedelta ) );
|
||||
auto const valuechange { (
|
||||
m_valuechangemodifier == nullptr ?
|
||||
m_valuechange :
|
||||
m_valuechange / *( m_valuechangemodifier ) ) };
|
||||
Variable += ( valuechange * static_cast<float>( Timedelta ) );
|
||||
// clamp down to allowed value range
|
||||
Variable = glm::max( Variable, m_valuelimits[ value_limit::min ] );
|
||||
Variable = glm::min( Variable, m_valuelimits[ value_limit::max ] );
|
||||
|
||||
@@ -127,7 +127,8 @@ basic_precipitation::update() {
|
||||
|
||||
m_camerapos = Global.pCamera.Pos;
|
||||
|
||||
// intercept sudden user-induced camera jumps
|
||||
// intercept sudden user-induced camera jumps...
|
||||
// ...from free fly mode change
|
||||
if( m_freeflymode != FreeFlyModeFlag ) {
|
||||
m_freeflymode = FreeFlyModeFlag;
|
||||
if( true == m_freeflymode ) {
|
||||
@@ -142,14 +143,17 @@ basic_precipitation::update() {
|
||||
}
|
||||
cameramove = glm::dvec3{ 0.0 };
|
||||
}
|
||||
// ...from jump between cab and window/mirror view
|
||||
if( m_windowopen != Global.CabWindowOpen ) {
|
||||
m_windowopen = Global.CabWindowOpen;
|
||||
cameramove = glm::dvec3{ 0.0 };
|
||||
}
|
||||
// ... from cab change
|
||||
if( ( simulation::Train != nullptr ) && ( simulation::Train->iCabn != m_activecab ) ) {
|
||||
m_activecab = simulation::Train->iCabn;
|
||||
cameramove = glm::dvec3{ 0.0 };
|
||||
}
|
||||
// ... from camera jump to another location
|
||||
if( glm::length( cameramove ) > 100.0 ) {
|
||||
cameramove = glm::dvec3{ 0.0 };
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
/*************************************************************************
|
||||
* GLFW 3.2 - www.glfw.org
|
||||
* GLFW 3.3 - www.glfw.org
|
||||
* A library for OpenGL, window and input
|
||||
*------------------------------------------------------------------------
|
||||
* Copyright (c) 2002-2006 Marcus Geelnard
|
||||
* Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||
* Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -45,12 +45,13 @@ extern "C" {
|
||||
* more information.
|
||||
*/
|
||||
/*! @defgroup native Native access
|
||||
* @brief Functions related to accessing native handles.
|
||||
*
|
||||
* **By using the native access functions you assert that you know what you're
|
||||
* doing and how to fix problems caused by using them. If you don't, you
|
||||
* shouldn't be using them.**
|
||||
*
|
||||
* Before the inclusion of @ref glfw3native.h, you may define exactly one
|
||||
* Before the inclusion of @ref glfw3native.h, you may define zero or more
|
||||
* window system API macro and zero or more context creation API macros.
|
||||
*
|
||||
* The chosen backends must match those the library was compiled for. Failure
|
||||
@@ -61,13 +62,13 @@ extern "C" {
|
||||
* * `GLFW_EXPOSE_NATIVE_COCOA`
|
||||
* * `GLFW_EXPOSE_NATIVE_X11`
|
||||
* * `GLFW_EXPOSE_NATIVE_WAYLAND`
|
||||
* * `GLFW_EXPOSE_NATIVE_MIR`
|
||||
*
|
||||
* The available context API macros are:
|
||||
* * `GLFW_EXPOSE_NATIVE_WGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_NSGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_GLX`
|
||||
* * `GLFW_EXPOSE_NATIVE_EGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_OSMESA`
|
||||
*
|
||||
* These macros select which of the native access functions that are declared
|
||||
* and which platform-specific headers to include. It is then up your (by
|
||||
@@ -80,26 +81,27 @@ extern "C" {
|
||||
* System headers and types
|
||||
*************************************************************************/
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
|
||||
// example to allow applications to correctly declare a GL_ARB_debug_output
|
||||
// callback) but windows.h assumes no one will define APIENTRY before it does
|
||||
#if defined(GLFW_APIENTRY_DEFINED)
|
||||
#undef APIENTRY
|
||||
#undef GLFW_APIENTRY_DEFINED
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_COCOA)
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||
#if defined(__OBJC__)
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
typedef void* id;
|
||||
#endif
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_X11)
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||
#include <wayland-client.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_MIR)
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
@@ -114,6 +116,9 @@ extern "C" {
|
||||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
|
||||
#include <GL/osmesa.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
@@ -284,6 +289,56 @@ GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI Window glfwGetX11Window(GLFWwindow* window);
|
||||
|
||||
/*! @brief Sets the current primary selection to the specified string.
|
||||
*
|
||||
* @param[in] string A UTF-8 encoded string.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @pointer_lifetime The specified string is copied before this function
|
||||
* returns.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref clipboard
|
||||
* @sa glfwGetX11SelectionString
|
||||
* @sa glfwSetClipboardString
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI void glfwSetX11SelectionString(const char* string);
|
||||
|
||||
/*! @brief Returns the contents of the current primary selection as a string.
|
||||
*
|
||||
* If the selection is empty or if its contents cannot be converted, `NULL`
|
||||
* is returned and a @ref GLFW_FORMAT_UNAVAILABLE error is generated.
|
||||
*
|
||||
* @return The contents of the selection as a UTF-8 encoded string, or `NULL`
|
||||
* if an [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @pointer_lifetime The returned string is allocated and freed by GLFW. You
|
||||
* should not free it yourself. It is valid until the next call to @ref
|
||||
* glfwGetX11SelectionString or @ref glfwSetX11SelectionString, or until the
|
||||
* library is terminated.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref clipboard
|
||||
* @sa glfwSetX11SelectionString
|
||||
* @sa glfwGetClipboardString
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI const char* glfwGetX11SelectionString(void);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
@@ -360,50 +415,6 @@ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
|
||||
GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_MIR)
|
||||
/*! @brief Returns the `MirConnection*` used by GLFW.
|
||||
*
|
||||
* @return The `MirConnection*` used by GLFW, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI MirConnection* glfwGetMirDisplay(void);
|
||||
|
||||
/*! @brief Returns the Mir output ID of the specified monitor.
|
||||
*
|
||||
* @return The Mir output ID of the specified monitor, or zero if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `MirSurface*` of the specified window.
|
||||
*
|
||||
* @return The `MirSurface*` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||
/*! @brief Returns the `EGLDisplay` used by GLFW.
|
||||
*
|
||||
@@ -448,6 +459,64 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window);
|
||||
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
|
||||
/*! @brief Retrieves the color buffer associated with the specified window.
|
||||
*
|
||||
* @param[in] window The window whose color buffer to retrieve.
|
||||
* @param[out] width Where to store the width of the color buffer, or `NULL`.
|
||||
* @param[out] height Where to store the height of the color buffer, or `NULL`.
|
||||
* @param[out] format Where to store the OSMesa pixel format of the color
|
||||
* buffer, or `NULL`.
|
||||
* @param[out] buffer Where to store the address of the color buffer, or
|
||||
* `NULL`.
|
||||
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, int* height, int* format, void** buffer);
|
||||
|
||||
/*! @brief Retrieves the depth buffer associated with the specified window.
|
||||
*
|
||||
* @param[in] window The window whose depth buffer to retrieve.
|
||||
* @param[out] width Where to store the width of the depth buffer, or `NULL`.
|
||||
* @param[out] height Where to store the height of the depth buffer, or `NULL`.
|
||||
* @param[out] bytesPerValue Where to store the number of bytes per depth
|
||||
* buffer element, or `NULL`.
|
||||
* @param[out] buffer Where to store the address of the depth buffer, or
|
||||
* `NULL`.
|
||||
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, int* height, int* bytesPerValue, void** buffer);
|
||||
|
||||
/*! @brief Returns the `OSMesaContext` of the specified window.
|
||||
*
|
||||
* @return The `OSMesaContext` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
18
renderer.cpp
18
renderer.cpp
@@ -80,6 +80,9 @@ std::vector<std::pair<glm::vec3, glm::vec2>> const billboard_vertices {
|
||||
void
|
||||
opengl_particles::update( opengl_camera const &Camera ) {
|
||||
|
||||
if (!Global.Smoke)
|
||||
return;
|
||||
|
||||
m_particlevertices.clear();
|
||||
// build a list of visible smoke sources
|
||||
// NOTE: arranged by distance to camera, if we ever need sorting and/or total amount cap-based culling
|
||||
@@ -100,6 +103,12 @@ opengl_particles::update( opengl_camera const &Camera ) {
|
||||
particle_vertex vertex;
|
||||
for( auto const &source : sources ) {
|
||||
|
||||
auto const particlecolor {
|
||||
glm::clamp(
|
||||
source.second.color()
|
||||
* ( glm::vec3 { Global.DayLight.ambient } + 0.35f * glm::vec3{ Global.DayLight.diffuse } )
|
||||
* 255.f,
|
||||
glm::vec3{ 0.f }, glm::vec3{ 255.f } ) };
|
||||
auto const &particles { source.second.sequence() };
|
||||
// TODO: put sanity cap on the overall amount of particles that can be drawn
|
||||
auto const sizestep { 256.0 * billboard_vertices.size() };
|
||||
@@ -107,9 +116,9 @@ opengl_particles::update( opengl_camera const &Camera ) {
|
||||
sizestep * std::ceil( m_particlevertices.size() + ( particles.size() * billboard_vertices.size() ) / sizestep ) );
|
||||
for( auto const &particle : particles ) {
|
||||
// TODO: particle color support
|
||||
vertex.color.r =
|
||||
vertex.color.g =
|
||||
vertex.color.b = Global.fLuminance * 0.125f;
|
||||
vertex.color[ 0 ] = static_cast<std::uint8_t>( particlecolor.r );
|
||||
vertex.color[ 1 ] = static_cast<std::uint8_t>( particlecolor.g );
|
||||
vertex.color[ 2 ] = static_cast<std::uint8_t>( particlecolor.b );
|
||||
vertex.color.a = std::clamp(particle.opacity, 0.0f, 1.0f);
|
||||
|
||||
auto const offset { glm::vec3{ particle.position - Camera.position() } };
|
||||
@@ -145,6 +154,9 @@ opengl_particles::update( opengl_camera const &Camera ) {
|
||||
void
|
||||
opengl_particles::render() {
|
||||
|
||||
if (!Global.Smoke)
|
||||
return;
|
||||
|
||||
if( m_buffercapacity == 0 ) { return; }
|
||||
if( m_particlevertices.empty() ) { return; }
|
||||
|
||||
|
||||
@@ -200,13 +200,17 @@ world_environment::update_wind() {
|
||||
|
||||
m_wind.change_time -= timedelta;
|
||||
if( m_wind.change_time < 0 ) {
|
||||
m_wind.change_time = Random( 5, 30 );
|
||||
m_wind.velocity_change = Random( -1, 1 );
|
||||
if( Random() < 0.2 ) {
|
||||
m_wind.change_time = Random( 5, 15 );
|
||||
m_wind.velocity_change = Random( -0.2, 0.2 );
|
||||
if( Random() < 0.05 ) {
|
||||
// changes in wind direction should be less frequent than changes in wind speed
|
||||
// TBD, TODO: configuration-driven direction change frequency
|
||||
m_wind.azimuth_change = Random( -5, 5 );
|
||||
}
|
||||
else {
|
||||
// keep direction change periods short, to avoid too drastic changes in direction
|
||||
m_wind.azimuth_change = 0.0;
|
||||
}
|
||||
}
|
||||
// TBD, TODO: wind configuration
|
||||
m_wind.azimuth = clamp_circular( m_wind.azimuth + m_wind.azimuth_change * timedelta );
|
||||
@@ -219,9 +223,9 @@ world_environment::update_wind() {
|
||||
m_wind.vector =
|
||||
std::max( 0.f, m_wind.velocity )
|
||||
* glm::vec3(
|
||||
std::sin( polarangle ) * std::sin( azimuthalangle ),
|
||||
std::sin( polarangle ) * std::sin( azimuthalangle ) * -1,
|
||||
std::cos( polarangle ),
|
||||
std::sin( polarangle ) * std::cos( azimuthalangle ) * -1 );
|
||||
std::sin( polarangle ) * std::cos( azimuthalangle ) );
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -40,6 +40,9 @@ public:
|
||||
glm::vec3 const &
|
||||
wind() const {
|
||||
return m_wind.vector; }
|
||||
float const &
|
||||
wind_azimuth() const {
|
||||
return m_wind.azimuth; }
|
||||
|
||||
private:
|
||||
// types
|
||||
|
||||
@@ -49,20 +49,22 @@ basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Sch
|
||||
// (try to) set the cargo type for empty cars
|
||||
parameters.LoadAmount = 0.f; // safety measure against edge cases
|
||||
parameters.AssignLoad( "passengers" );
|
||||
parameters.ComputeMass();
|
||||
}
|
||||
|
||||
if( parameters.LoadType.name == "passengers" ) {
|
||||
// NOTE: for the time being we're doing simple, random load change calculation
|
||||
// TODO: exchange driven by station parameters and time of the day
|
||||
auto unloadcount = static_cast<int>(
|
||||
TestFlag( parameters.DamageFlag, dtrain_out ) ? parameters.LoadAmount :
|
||||
laststop ? parameters.LoadAmount :
|
||||
firststop ? 0 :
|
||||
std::min<float>(
|
||||
parameters.LoadAmount,
|
||||
Random( parameters.MaxLoad * 0.15f * stationsizemodifier ) ) );
|
||||
auto loadcount = static_cast<int>(
|
||||
laststop ?
|
||||
0 :
|
||||
TestFlag( parameters.DamageFlag, dtrain_out ) ? 0 :
|
||||
laststop ? 0 :
|
||||
Random( parameters.MaxLoad * 0.15f * stationsizemodifier ) );
|
||||
if( true == firststop ) {
|
||||
// larger group at the initial station
|
||||
|
||||
2
stdafx.h
2
stdafx.h
@@ -39,6 +39,8 @@
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
// stl
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
15
uart.cpp
15
uart.cpp
@@ -242,6 +242,12 @@ void uart_input::poll()
|
||||
uint16_t current1 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[0] / conf.currentmax * conf.currentuart);
|
||||
uint16_t current2 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[1] / conf.currentmax * conf.currentuart);
|
||||
uint16_t current3 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[2] / conf.currentmax * conf.currentuart);
|
||||
uint16_t lv_voltage = (uint16_t)std::min( conf.lvuart, trainstate.lv_voltage / conf.lvmax * conf.lvuart );
|
||||
|
||||
if( trainstate.cab > 0 ) {
|
||||
// NOTE: moving from a cab to engine room doesn't change cab indicator
|
||||
m_trainstatecab = trainstate.cab - 1;
|
||||
}
|
||||
|
||||
std::array<uint8_t, 31> buffer {
|
||||
//byte 0
|
||||
@@ -271,7 +277,8 @@ void uart_input::poll()
|
||||
| trainstate.compressor_overload << 6),
|
||||
//byte 6
|
||||
(uint8_t)(
|
||||
trainstate.recorder_braking << 3
|
||||
m_trainstatecab << 2
|
||||
| trainstate.recorder_braking << 3
|
||||
| trainstate.recorder_power << 4
|
||||
| trainstate.radio_stop <<5
|
||||
| trainstate.alerter_sound << 7),
|
||||
@@ -289,8 +296,10 @@ void uart_input::poll()
|
||||
SPLIT_INT16(current2),
|
||||
//byte 19-20
|
||||
SPLIT_INT16(current3),
|
||||
//byte 21-30
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
//byte 21-22
|
||||
SPLIT_INT16(lv_voltage),
|
||||
//byte 23-30
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
if (conf.debug)
|
||||
|
||||
3
uart.h
3
uart.h
@@ -27,6 +27,8 @@ public:
|
||||
float hvuart = 65535.0f;
|
||||
float currentmax = 10000.0f;
|
||||
float currentuart = 65535.0f;
|
||||
float lvmax = 150.0f;
|
||||
float lvuart = 65535.0f;
|
||||
|
||||
bool mainenable = true;
|
||||
bool scndenable = true;
|
||||
@@ -66,4 +68,5 @@ private:
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> last_update;
|
||||
conf_t conf;
|
||||
bool data_pending = false;
|
||||
std::uint8_t m_trainstatecab { 0 }; // helper, keeps track of last active cab. 0: front cab, 1: rear cab
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user