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

Merge branch 'milek-dev' into gfx-work

This commit is contained in:
milek7
2019-09-07 02:40:38 +02:00
27 changed files with 2315 additions and 626 deletions

View File

@@ -503,7 +503,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
VelSignalLast = -1.0; VelSignalLast = -1.0;
} }
iTableDirection = iDirection; // ustalenie w jakim kierunku jest wypełniana tabelka względem pojazdu 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) fTrackLength = pVehicle->RaTranslationGet(); // pozycja na tym torze (odległość od Point1)
fLastDir = pVehicle->DirectionGet() * pVehicle->RaDirectionGet(); // ustalenie kierunku skanowania na torze fLastDir = pVehicle->DirectionGet() * pVehicle->RaDirectionGet(); // ustalenie kierunku skanowania na torze
if( fLastDir < 0.0 ) { if( fLastDir < 0.0 ) {
@@ -1136,6 +1136,17 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
if( sSpeedTable[ i ].fDist > 0.0 ) { if( sSpeedTable[ i ].fDist > 0.0 ) {
// check signals ahead // check signals ahead
if( sSpeedTable[ i ].IsProperSemaphor( OrderCurrentGet() ) ) { 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 ) { if( SemNextIndex == -1 ) {
// jeśli jest mienięty poprzedni semafor a wcześniej // jeśli jest mienięty poprzedni semafor a wcześniej
// byl nowy to go dorzucamy do zmiennej, żeby cały czas widział najbliższy // 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]; p = pVehicles[0];
while (p) while (p)
{ {
// HACK: wagony muszą mieć baterię załączoną do otwarcia drzwi...
if( p != pVehicle ) { if( p != pVehicle ) {
if( ( ( p->MoverParameters->Couplers[ end::front ].CouplingFlag & ( coupling::control ) ) == 0 ) if( ( ( p->MoverParameters->Couplers[ end::front ].CouplingFlag & ( coupling::control ) ) == 0 )
&& ( ( p->MoverParameters->Couplers[ end::rear ].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 ); p->MoverParameters->BatterySwitch( true );
}
}
// enable heating and converter in carriages with can be heated // 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 ) { if( p->MoverParameters->HeatingPower > 0 ) {
p->MoverParameters->HeatingAllow = true; p->MoverParameters->HeatingAllow = true;
p->MoverParameters->ConverterSwitch( true, range_t::local ); p->MoverParameters->ConverterSwitch( true, range_t::local );
} }
} }
}
if (p->asDestination == "none") if (p->asDestination == "none")
p->DestinationSet(TrainParams->Relation2, TrainParams->TrainName); // relacja docelowa, jeśli nie było 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 */ /* mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_FS ) ); GBH */
BrakeLevelSet( gbh_FS ); BrakeLevelSet( gbh_FS );
// don't charge the brakes too often, or we risk overcharging // 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 double scandist = scanmax; // zmodyfikuje na rzeczywiście przeskanowane
basic_event *e = NULL; // event potencjalnie od semafora 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 // 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 auto const dir = startdir * pVehicles[0]->VectorFront(); // wektor w kierunku jazdy/szukania
if( !scantrack ) { if( !scantrack ) {
// jeśli wstecz wykryto koniec toru to raczej nic się nie da w takiej sytuacji zrobić // jeśli wstecz wykryto koniec toru to raczej nic się nie da w takiej sytuacji zrobić

View File

@@ -848,16 +848,19 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
//*************************************************************/// koniec //*************************************************************/// koniec
// wezykow // wezykow
// uginanie zderzakow // uginanie zderzakow
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; ++i) {
{
double dist = MoverParameters->Couplers[i].Dist / 2.0; auto const dist { clamp( MoverParameters->Couplers[ i ].Dist / 2.0, -MoverParameters->Couplers[ i ].DmaxB, 0.0 ) };
if (smBuforLewy[i])
if (dist < 0) if( dist >= 0.0 ) { continue; }
if( smBuforLewy[ i ] ) {
smBuforLewy[ i ]->SetTranslate( Math3D::vector3( dist, 0, 0 ) ); 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 ) ); smBuforPrawy[ i ]->SetTranslate( Math3D::vector3( dist, 0, 0 ) );
} }
}
} // vehicle within 50m } // vehicle within 50m
// Winger 160204 - podnoszenie pantografow // 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 // load the cargo now that we know whether the vehicle will allow it
MoverParameters->AssignLoad( LoadType, Load ); MoverParameters->AssignLoad( LoadType, Load );
MoverParameters->ComputeMass();
bool driveractive = (fVel != 0.0); // jeśli prędkość niezerowa, to aktywujemy ruch bool driveractive = (fVel != 0.0); // jeśli prędkość niezerowa, to aktywujemy ruch
if (!MoverParameters->CheckLocomotiveParameters( if (!MoverParameters->CheckLocomotiveParameters(
@@ -2190,12 +2194,9 @@ void TDynamicObject::Move(double fDistance)
// Ra 2F1J: to nie jest stabilne (powoduje rzucanie taborem) i wymaga // Ra 2F1J: to nie jest stabilne (powoduje rzucanie taborem) i wymaga
// dopracowania // dopracowania
fAdjustment = vFront.Length() - fAxleDist; // na łuku będzie ujemny 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 // if (fabs(fAdjustment)>0.02) //jeśli jest zbyt dużo, to rozłożyć na kilka przeliczeń (wygasza drgania?)
// przeliczeń
// (wygasza drgania?)
//{//parę centymetrów trzeba by już skorygować; te błędy mogą się też //{//parę centymetrów trzeba by już skorygować; te błędy mogą się też
// generować na ostrych // generować na ostrych łukach
//łukach
// fAdjustment*=0.5; //w jednym kroku korygowany jest ułamek błędu // fAdjustment*=0.5; //w jednym kroku korygowany jest ułamek błędu
//} //}
// else // else
@@ -2418,6 +2419,7 @@ void TDynamicObject::update_exchange( double const Deltatime ) {
m_exchange.unload_count -= exchangesize; m_exchange.unload_count -= exchangesize;
MoverParameters->LoadStatus = 1; MoverParameters->LoadStatus = 1;
MoverParameters->LoadAmount = std::max( 0.f, MoverParameters->LoadAmount - exchangesize ); MoverParameters->LoadAmount = std::max( 0.f, MoverParameters->LoadAmount - exchangesize );
MoverParameters->ComputeMass();
update_load_visibility(); update_load_visibility();
} }
if( m_exchange.unload_count < 0.01 ) { if( m_exchange.unload_count < 0.01 ) {
@@ -2432,6 +2434,7 @@ void TDynamicObject::update_exchange( double const Deltatime ) {
m_exchange.load_count -= exchangesize; m_exchange.load_count -= exchangesize;
MoverParameters->LoadStatus = 2; MoverParameters->LoadStatus = 2;
MoverParameters->LoadAmount = std::min( MoverParameters->MaxLoad, MoverParameters->LoadAmount + exchangesize ); // std::max not strictly needed but, eh MoverParameters->LoadAmount = std::min( MoverParameters->MaxLoad, MoverParameters->LoadAmount + exchangesize ); // std::max not strictly needed but, eh
MoverParameters->ComputeMass();
update_load_visibility(); update_load_visibility();
} }
} }
@@ -2768,8 +2771,8 @@ bool TDynamicObject::Update(double dt, double dt1)
auto Frj { 0.0 }; auto Frj { 0.0 };
auto osie { 0 }; auto osie { 0 };
// 0a. ustal aktualna nastawe zadania sily napedowej i hamowania // 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->MainCtrlPos = ctOwner->Controlling()->MainCtrlPos*MoverParameters->MainCtrlPosNo / std::max(1, ctOwner->Controlling()->MainCtrlPosNo);
MoverParameters->ScndCtrlActualPos = ctOwner->Controlling()->ScndCtrlActualPos; MoverParameters->ScndCtrlActualPos = ctOwner->Controlling()->ScndCtrlActualPos;
} }
@@ -3110,7 +3113,10 @@ bool TDynamicObject::Update(double dt, double dt1)
-vPosition.x, -vPosition.x,
vPosition.z, vPosition.z,
vPosition.y }; 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 // McZapkie-260202 - dMoveLen przyda sie przy stukocie kol
dDOMoveLen = GetdMoveLen() + MoverParameters->ComputeMovement(dt, dt1, ts, tp, tmpTraction, l, r); dDOMoveLen = GetdMoveLen() + MoverParameters->ComputeMovement(dt, dt1, ts, tp, tmpTraction, l, r);
if( Mechanik ) if( Mechanik )
@@ -3620,7 +3626,10 @@ bool TDynamicObject::FastUpdate(double dt)
-vPosition.x, -vPosition.x,
vPosition.z, vPosition.z,
vPosition.y }; 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 // McZapkie: parametry powinny byc pobierane z toru
// ts.R=MyTrack->fRadius; // ts.R=MyTrack->fRadius;
// ts.Len= Max0R(MoverParameters->BDist,MoverParameters->ADist); // ts.Len= Max0R(MoverParameters->BDist,MoverParameters->ADist);
@@ -3904,7 +3913,7 @@ void TDynamicObject::RenderSounds() {
} }
// NBMX sygnal odjazdu // NBMX sygnal odjazdu
if( MoverParameters->Doors.has_warning ) { if( MoverParameters->Doors.has_warning ) {
for( auto &door : m_doorsounds ) { for( auto &departuresignalsound : m_departuresignalsounds ) {
// TBD, TODO: per-location door state triggers? // TBD, TODO: per-location door state triggers?
if( ( MoverParameters->DepartureSignal ) if( ( MoverParameters->DepartureSignal )
/* /*
@@ -3915,10 +3924,10 @@ void TDynamicObject::RenderSounds() {
) { ) {
// for the autonomous doors play the warning automatically whenever a door is closing // for the autonomous doors play the warning automatically whenever a door is closing
// MC: pod warunkiem ze jest zdefiniowane w chk // 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 { else {
door.sDepartureSignal.stop(); departuresignalsound.stop();
} }
} }
} }
@@ -4227,12 +4236,7 @@ void TDynamicObject::RenderSounds() {
if( MoverParameters->EventFlag ) { if( MoverParameters->EventFlag ) {
// McZapkie: w razie wykolejenia // McZapkie: w razie wykolejenia
if( true == TestFlag( MoverParameters->DamageFlag, dtrain_out ) ) { if( true == TestFlag( MoverParameters->DamageFlag, dtrain_out ) ) {
if( GetVelocity() > 0 ) { rsDerailment.play( sound_flags::exclusive );
rsDerailment.play();
}
else {
rsDerailment.stop();
}
} }
MoverParameters->EventFlag = false; 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 }; sound_source soundtemplate { sound_placement::general, 25.f };
soundtemplate.deserialize( parser, sound_type::multipart, sound_parameters::range ); soundtemplate.deserialize( parser, sound_type::multipart, sound_parameters::range );
soundtemplate.owner( this ); soundtemplate.owner( this );
for( auto &door : m_doorsounds ) { for( auto &departuresignalsound : m_departuresignalsounds ) {
// apply configuration to all defined doors, but preserve their individual offsets // apply configuration to all defined doors, but preserve their individual offsets
auto const dooroffset { door.lock.offset() }; auto const soundoffset { departuresignalsound.offset() };
door.sDepartureSignal = soundtemplate; departuresignalsound = soundtemplate;
door.sDepartureSignal.offset( dooroffset ); departuresignalsound.offset( soundoffset );
} }
} }
@@ -5393,7 +5397,6 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
// left... // left...
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, MoverParameters->Dim.H * 0.5f, offset } };
door.placement = side::left; door.placement = side::left;
door.sDepartureSignal.offset( location );
door.rsDoorClose.offset( location ); door.rsDoorClose.offset( location );
door.rsDoorOpen.offset( location ); door.rsDoorOpen.offset( location );
door.lock.offset( location ); door.lock.offset( location );
@@ -5405,9 +5408,8 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
if( ( sides == "both" ) if( ( sides == "both" )
|| ( sides == "right" ) ) { || ( sides == "right" ) ) {
// ...and 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.placement = side::right;
door.sDepartureSignal.offset( location );
door.rsDoorClose.offset( location ); door.rsDoorClose.offset( location );
door.rsDoorOpen.offset( location ); door.rsDoorOpen.offset( location );
door.lock.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 ); door.step_open.offset( location );
m_doorsounds.emplace_back( door ); 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 );
} }
} }

View File

@@ -322,7 +322,6 @@ private:
}; };
struct door_sounds { struct door_sounds {
sound_source sDepartureSignal { sound_placement::general };
sound_source rsDoorOpen { sound_placement::general }; // Ra: przeniesione z kabiny sound_source rsDoorOpen { sound_placement::general }; // Ra: przeniesione z kabiny
sound_source rsDoorClose { sound_placement::general }; sound_source rsDoorClose { sound_placement::general };
sound_source lock { 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::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<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<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 bool m_doorlocks { false }; // sound helper, current state of door locks
sound_source sHorn1 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; sound_source sHorn1 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
sound_source sHorn2 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; sound_source sHorn2 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
@@ -620,7 +620,7 @@ private:
Axle1.GetTranslation() : Axle1.GetTranslation() :
Axle0.GetTranslation(); }; Axle0.GetTranslation(); };
// zwraca tor z aktywną osią // zwraca tor z aktywną osią
inline TTrack * RaTrackGet() const { inline TTrack const * RaTrackGet() const {
return iAxleFirst ? return iAxleFirst ?
Axle1.GetTrack() : Axle1.GetTrack() :
Axle0.GetTrack(); }; Axle0.GetTrack(); };

View File

@@ -185,12 +185,6 @@ global_settings::ConfigParse(cParser &Parser) {
Parser.getTokens(); Parser.getTokens();
Parser >> DisabledLogTypes; Parser >> DisabledLogTypes;
} }
else if( token == "adjustscreenfreq" )
{
// McZapkie-240403 - czestotliwosc odswiezania ekranu
Parser.getTokens();
Parser >> bAdjustScreenFreq;
}
else if (token == "mousescale") else if (token == "mousescale")
{ {
// McZapkie-060503 - czulosc ruchu myszy (krecenia glowa) // McZapkie-060503 - czulosc ruchu myszy (krecenia glowa)
@@ -364,6 +358,18 @@ global_settings::ConfigParse(cParser &Parser) {
>> shadowtune.depth >> shadowtune.depth
>> shadowtune.distance; >> 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" ) { else if( token == "splinefidelity" ) {
// segment size during spline->geometry conversion // segment size during spline->geometry conversion
float splinefidelity; float splinefidelity;
@@ -660,7 +666,7 @@ global_settings::ConfigParse(cParser &Parser) {
>> uart_conf.updatetime; >> uart_conf.updatetime;
} }
else if( token == "uarttune" ) { else if( token == "uarttune" ) {
Parser.getTokens( 14 ); Parser.getTokens( 16 );
Parser Parser
>> uart_conf.mainbrakemin >> uart_conf.mainbrakemin
>> uart_conf.mainbrakemax >> uart_conf.mainbrakemax
@@ -675,7 +681,9 @@ global_settings::ConfigParse(cParser &Parser) {
>> uart_conf.hvmax >> uart_conf.hvmax
>> uart_conf.hvuart >> uart_conf.hvuart
>> uart_conf.currentmax >> uart_conf.currentmax
>> uart_conf.currentuart; >> uart_conf.currentuart
>> uart_conf.lvmax
>> uart_conf.lvuart;
} }
else if( token == "uartfeature" ) { else if( token == "uartfeature" ) {
Parser.getTokens( 4 ); Parser.getTokens( 4 );

View File

@@ -126,6 +126,8 @@ struct global_settings {
GLint iMaxTextureSize{ 4096 }; // maksymalny rozmiar tekstury GLint iMaxTextureSize{ 4096 }; // maksymalny rozmiar tekstury
int iMultisampling{ 2 }; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px 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 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 ResourceSweep{ true }; // gfx resource garbage collection
bool ResourceMove{ false }; // gfx resources are moved between cpu and gpu side instead of sending a copy 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 bool compress_tex{ true }; // all textures are compressed on gpu side

View File

@@ -657,6 +657,7 @@ struct TCoupling {
double CForce = 0.0; /*sila z jaka dzialal*/ double CForce = 0.0; /*sila z jaka dzialal*/
double Dist = 0.0; /*strzalka ugiecia zderzaków*/ double Dist = 0.0; /*strzalka ugiecia zderzaków*/
bool CheckCollision = false; /*czy sprawdzac sile czy pedy*/ bool CheckCollision = false; /*czy sprawdzac sile czy pedy*/
float stretch_duration { 0.f }; // seconds, elapsed time with excessive force applied to the coupler
power_coupling power_high; power_coupling power_high;
// power_coupling power_low; // TODO: implement this // power_coupling power_low; // TODO: implement this
@@ -1143,6 +1144,7 @@ public:
/*--opis konkretnego egzemplarza taboru*/ /*--opis konkretnego egzemplarza taboru*/
TLocation Loc { 0.0, 0.0, 0.0 }; //pozycja pojazdów do wyznaczenia odległości pomiędzy sprzęgami 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 }; TRotation Rot { 0.0, 0.0, 0.0 };
glm::vec3 Front{};
std::string Name; /*nazwa wlasna*/ std::string Name; /*nazwa wlasna*/
TCoupling Couplers[2]; //urzadzenia zderzno-sprzegowe, polaczenia miedzy wagonami TCoupling Couplers[2]; //urzadzenia zderzno-sprzegowe, polaczenia miedzy wagonami
std::array<neighbour_data, 2> Neighbours; // potential collision sources 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); bool Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false, bool Audible = true);
int DettachStatus(int ConnectNo); int DettachStatus(int ConnectNo);
bool Dettach(int ConnectNo); bool Dettach(int ConnectNo);
void damage_coupler( int const End );
void derail( int const Reason );
bool DirectionForward(); bool DirectionForward();
bool DirectionBackward( void );/*! kierunek ruchu*/ bool DirectionBackward( void );/*! kierunek ruchu*/
void BrakeLevelSet(double b); void BrakeLevelSet(double b);
@@ -1417,8 +1421,8 @@ public:
bool ChangeCab(int direction); bool ChangeCab(int direction);
bool CurrentSwitch(bool const State); bool CurrentSwitch(bool const State);
void UpdateBatteryVoltage(double dt); 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 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, const TLocation &NewLoc, TRotation &NewRot); //oblicza przesuniecie pojazdu - wersja zoptymalizowana 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 ); void compute_movement_( double const Deltatime );
double ShowEngineRotation(int VehN); double ShowEngineRotation(int VehN);
@@ -1498,7 +1502,7 @@ public:
/*funkcje obliczajace sily*/ /*funkcje obliczajace sily*/
void ComputeConstans(void);//ABu: wczesniejsze wyznaczenie stalych dla liczenia sil void ComputeConstans(void);//ABu: wczesniejsze wyznaczenie stalych dla liczenia sil
double ComputeMass(void); void ComputeMass(void);
void ComputeTotalForce(double dt); void ComputeTotalForce(double dt);
double Adhesive(double staticfriction) const; double Adhesive(double staticfriction) const;
double TractionForce(double dt); double TractionForce(double dt);
@@ -1507,7 +1511,7 @@ public:
double BrakeForceP(double press, double velocity); double BrakeForceP(double press, double velocity);
double BrakeForce(const TTrackParam &Track); double BrakeForce(const TTrackParam &Track);
double CouplerForce(int const End, double dt); 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*/ /*obrot kol uwzgledniajacy poslizg*/
double ComputeRotatingWheel(double WForce, double dt, double n) const; double ComputeRotatingWheel(double WForce, double dt, double n) const;
@@ -1646,3 +1650,11 @@ private:
}; };
//double Distance(TLocation Loc1, TLocation Loc2, TDimension Dim1, TDimension Dim2); //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

View File

@@ -995,68 +995,140 @@ double TMoverParameters::PipeRatio(void)
// Q: 20160716 // Q: 20160716
// Wykrywanie kolizji // Wykrywanie kolizji
// ************************************************************************************************* // *************************************************************************************************
void TMoverParameters::CollisionDetect(int CouplerN, double dt) void TMoverParameters::CollisionDetect(int const End, double const dt)
{ {
double CCF, Vprev, VprevC; if( Neighbours[ End ].vehicle == nullptr ) { return; } // shouldn't normally happen but, eh
bool VirtualCoupling;
CCF = 0; auto &coupler { Couplers[ End ] };
// with Couplers[CouplerN] do auto *othervehicle { Neighbours[ End ].vehicle->MoverParameters };
auto &coupler = Couplers[ CouplerN ]; auto const otherend { Neighbours[ End ].vehicle_end };
auto &othercoupler { othervehicle->Couplers[ otherend ] };
if (coupler.Connected != nullptr) auto velocity { V };
{ auto othervehiclevelocity { othervehicle->V };
VirtualCoupling = (coupler.CouplingFlag == ctrain_virtual); // calculate collision force and new velocities for involved vehicles
Vprev = V; auto const VirtualCoupling { ( coupler.CouplingFlag == coupling::faux ) };
VprevC = coupler.Connected->V; auto CCF { 0.0 };
switch (CouplerN)
{ switch( End ) {
case 0: case 0: {
CCF = CCF =
ComputeCollision( ComputeCollision(
V, velocity, othervehiclevelocity,
coupler.Connected->V, TotalMass, othervehicle->TotalMass,
TotalMass, ( coupler.beta + othercoupler.beta ) / 2.0,
coupler.Connected->TotalMass,
(coupler.beta + coupler.Connected->Couplers[coupler.ConnectedNr].beta) / 2.0,
VirtualCoupling ) VirtualCoupling )
/ ( dt ); / ( dt );
break; // yB: ej ej ej, a po break; // yB: ej ej ej, a po
case 1: }
case 1: {
CCF = CCF =
ComputeCollision( ComputeCollision(
coupler.Connected->V, othervehiclevelocity, velocity,
V, othervehicle->TotalMass, TotalMass,
coupler.Connected->TotalMass, ( coupler.beta + othercoupler.beta ) / 2.0,
TotalMass,
(coupler.beta + coupler.Connected->Couplers[coupler.ConnectedNr].beta) / 2.0,
VirtualCoupling ) VirtualCoupling )
/ ( dt ); / ( dt );
break; // czemu tu jest +0.01?? break;
} }
AccS = AccS + (V - Vprev) / dt; // korekta przyspieszenia o siły wynikające ze zderzeń? default: {
coupler.Connected->AccS += (coupler.Connected->V - VprevC) / dt; break;
if ((coupler.Dist > 0) && (!VirtualCoupling)) }
if (FuzzyLogic(abs(CCF), 5.0 * (coupler.FmaxC + 1.0), p_coupldmg)) }
{ //! zerwanie sprzegu
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 ) ) if( SetFlag( DamageFlag, dtrain_coupling ) )
EventFlag = true; EventFlag = true;
if ((coupler.CouplingFlag & ctrain_pneumatic) == ctrain_pneumatic) auto &coupler { Couplers[ End ] };
AlarmChainFlag = true; // hamowanie nagle - zerwanie przewodow hamulcowych
if( ( coupler.CouplingFlag & ctrain_pneumatic ) == ctrain_pneumatic ) {
// hamowanie nagle - zerwanie przewodow hamulcowych
AlarmChainFlag = true;
}
coupler.CouplingFlag = 0; coupler.CouplingFlag = 0;
switch (CouplerN) // wyzerowanie flag podlaczenia ale ciagle sa wirtualnie polaczone if( coupler.Connected != nullptr ) {
{ switch( End ) {
case 0: // break connection with other vehicle, if there's any
coupler.Connected->Couplers[1].CouplingFlag = 0; case 0: {
break; coupler.Connected->Couplers[ end::rear ].CouplingFlag = 0;
case 1:
coupler.Connected->Couplers[0].CouplingFlag = 0;
break; break;
} }
case 1: {
coupler.Connected->Couplers[ end::front ].CouplingFlag = 0;
break;
}
default: {
break;
}
}
}
WriteLog( "Bad driving: " + Name + " broke a coupler" ); 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, double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShape &Shape,
TTrackParam &Track, TTractionParam &ElectricTraction, TTrackParam &Track, TTractionParam &ElectricTraction,
const TLocation &NewLoc, TRotation &NewRot) TLocation const &NewLoc, TRotation const &NewRot)
{ {
const double Vepsilon = 1e-5; const double Vepsilon = 1e-5;
const double Aepsilon = 1e-3; // ASBSpeed=0.8; 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 // TODO: investigate, seems supplied NewRot is always 0 although the code here suggests some actual values are expected
Loc = NewLoc; Loc = NewLoc;
Rot = NewRot; Rot = NewRot;
NewRot.Rx = 0;
NewRot.Ry = 0;
NewRot.Rz = 0;
if (dL == 0) // oblicz przesuniecie} 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, double TMoverParameters::FastComputeMovement(double dt, const TTrackShape &Shape,
TTrackParam &Track, const TLocation &NewLoc, TTrackParam &Track, TLocation const &NewLoc,
TRotation &NewRot) TRotation const &NewRot)
{ {
int b; int b;
// T_MoverParameters::FastComputeMovement(dt, Shape, Track, NewLoc, NewRot); // T_MoverParameters::FastComputeMovement(dt, Shape, Track, NewLoc, NewRot);
Loc = NewLoc; Loc = NewLoc;
Rot = NewRot; Rot = NewRot;
NewRot.Rx = 0.0;
NewRot.Ry = 0.0;
NewRot.Rz = 0.0;
if (dL == 0) // oblicz przesuniecie if (dL == 0) // oblicz przesuniecie
{ {
@@ -1410,7 +1476,13 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) {
break; break;
} }
case TPowerSource::Main: { 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; break;
} }
default: { default: {
@@ -1710,7 +1782,7 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) {
OilPump.pressure = OilPump.pressure =
std::max<float>( std::max<float>(
OilPump.pressure_target, 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 ); OilPump.pressure = clamp( OilPump.pressure, 0.f, 1.5f );
} }
@@ -4020,7 +4092,6 @@ void TMoverParameters::ComputeConstans(void)
double BearingF, RollF, HideModifier; double BearingF, RollF, HideModifier;
double Curvature; // Ra 2014-07: odwrotność promienia double Curvature; // Ra 2014-07: odwrotność promienia
TotalMass = ComputeMass();
TotalMassxg = TotalMass * g; // TotalMass*g TotalMassxg = TotalMass * g; // TotalMass*g
BearingF = 2.0 * (DamageFlag && dtrain_bearing); BearingF = 2.0 * (DamageFlag && dtrain_bearing);
@@ -4071,29 +4142,28 @@ void TMoverParameters::ComputeConstans(void)
// Q: 20160713 // Q: 20160713
// Oblicza masę ładunku // 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ą // 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: // juz zoptymalizowane:
FStand = FrictionForce(RunningShape.R, RunningTrack.DamageFlag); // siła oporów ruchu 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); double old_nrot = abs(nrot);
nrot = v2n(); // przeliczenie prędkości liniowej na obrotową 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 &othercoupler { othervehicle->Couplers[ otherend ] };
auto const othervehiclemove { ( othervehicle->dMoveLen * DirPatch( End, 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 { ( auto const distancedelta { (
End == end::front ? End == end::front ?
othervehiclemove - dMoveLen : othervehiclemove - dMoveLen :
dMoveLen - othervehiclemove ) }; dMoveLen - othervehiclemove ) };
auto const initialdistance { Neighbours[ End ].distance }; // odległość od sprzęgu sąsiada
auto const newdistance = auto const newdistance { initialdistance + 10.0 * distancedelta };
initialdistance
+ 10.0 * distancedelta;
auto const dV { V - ( othervehicle->V * DirPatch( End, otherend ) ) }; auto const dV { V - ( othervehicle->V * DirPatch( End, otherend ) ) };
auto const absdV { std::abs( dV ) }; auto const absdV { std::abs( dV ) };
@@ -4462,11 +4535,15 @@ double TMoverParameters::CouplerForce( int const End, double dt ) {
} }
coupler.CheckCollision = false; coupler.CheckCollision = false;
coupler.Dist = 0.0;
double CF { 0.0 }; double CF { 0.0 };
if( ( coupler.CouplingFlag != coupling::faux ) if( ( coupler.CouplingFlag != coupling::faux )
|| ( initialdistance < 0 ) ) { || ( initialdistance < 0 ) ) {
coupler.Dist = clamp( newdistance, -coupler.DmaxB, coupler.DmaxC );
double BetaAvg = 0; double BetaAvg = 0;
double Fmax = 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; 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 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 ) { if( distDelta > 0 ) {
CF = ( -( coupler.SpringKC + othercoupler.SpringKC ) * coupler.Dist / 2.0 ) * DirF( End ) 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; - Fmax * dV * BetaAvg;
} }
// liczenie sily ze sprezystosci sprzegu // liczenie sily ze sprezystosci sprzegu
if( coupler.Dist > ( coupler.DmaxC + othercoupler.DmaxC ) ) { if( newdistance > ( coupler.DmaxC + othercoupler.DmaxC ) ) {
// zderzenie // zderzenie
coupler.CheckCollision = true; 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 ) { if( distDelta > 0 ) {
CF = ( -( coupler.SpringKB + othercoupler.SpringKB ) * coupler.Dist / 2.0 ) * DirF( End ) 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; - Fmax * dV * BetaAvg;
} }
// liczenie sily ze sprezystosci zderzaka // liczenie sily ze sprezystosci zderzaka
if( -coupler.Dist > ( coupler.DmaxB + othercoupler.DmaxB ) ) { if( -newdistance > ( coupler.DmaxB + othercoupler.DmaxB ) ) {
// zderzenie // zderzenie
coupler.CheckCollision = true; coupler.CheckCollision = true;
if( ( coupler.CouplerType == TCouplerType::Automatic ) 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_ks] = eimv[eimv_Fr] / eimv[eimv_FMAXMAX];
eimv[eimv_df] = eimv[eimv_ks] * eimc[eimc_s_dfmax]; eimv[eimv_df] = eimv[eimv_ks] * eimc[eimc_s_dfmax];
eimv[eimv_fp] = DirAbsolute * enrot * eimc[eimc_s_p] + eimv[eimv_fp] = DirAbsolute * enrot * eimc[eimc_s_p] + eimv[eimv_df]; // do przemyslenia dzialanie pp z tmpV
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_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]); // eimv[eimv_pole]:=eimv[eimv_U]/(eimv[eimv_fp]*eimc[eimc_s_cfu]);
if ((abs(eimv[eimv_fp]) <= eimv[eimv_fkr])) if ((abs(eimv[eimv_fp]) <= eimv[eimv_fkr]))
eimv[eimv_pole] = eimc[eimc_f_cfu] / eimc[eimc_s_cfu]; eimv[eimv_pole] = eimc[eimc_f_cfu] / eimc[eimc_s_cfu];
else else
eimv[eimv_pole] = eimv[eimv_pole] = eimv[eimv_Uzsmax] / eimc[eimc_s_cfu] / abs(eimv[eimv_fp]);
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_U] = eimv[eimv_pole] * eimv[eimv_fp] * eimc[eimc_s_cfu];
eimv[eimv_Ic] = (eimv[eimv_fp] - DirAbsolute * enrot * eimc[eimc_s_p]) * eimv[eimv_Ic] = (eimv[eimv_fp] - DirAbsolute * enrot * eimc[eimc_s_p]) * eimc[eimc_s_dfic] * eimv[eimv_pole];
eimc[eimc_s_dfic] * eimv[eimv_pole];
eimv[eimv_If] = eimv[eimv_Ic] * eimc[eimc_s_icif]; 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_M] = eimv[eimv_pole] * eimv[eimv_Ic] * eimc[eimc_s_cim];
eimv[eimv_Ipoj] = (eimv[eimv_Ic] * NPoweredAxles * eimv[eimv_U]) / eimv[eimv_Ipoj] = (eimv[eimv_Ic] * NPoweredAxles * eimv[eimv_U]) / (Voltage - eimc[eimc_f_DU]) + eimc[eimc_f_I0];
(Voltage - eimc[eimc_f_DU]) + eimv[eimv_Pm] = ActiveDir * eimv[eimv_M] * NPoweredAxles * enrot * Pirazy2 / 1000;
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_Pe] = eimv[eimv_Ipoj] * Voltage / 1000;
eimv[eimv_eta] = eimv[eimv_Pm] / eimv[eimv_Pe]; eimv[eimv_eta] = eimv[eimv_Pm] / eimv[eimv_Pe];
@@ -5447,7 +5531,7 @@ double TMoverParameters::TractionForce( double dt ) {
if( ( RlistSize > 0 ) if( ( RlistSize > 0 )
&& ( ( std::abs( eimv[ eimv_If ] ) > 1.0 ) && ( ( std::abs( eimv[ eimv_If ] ) > 1.0 )
|| ( tmpV > 0.1 ) ) ) { && ( tmpV > 0.1 ) ) ) {
int i = 0; int i = 0;
while( ( i < RlistSize - 1 ) while( ( i < RlistSize - 1 )
@@ -7079,6 +7163,7 @@ TMoverParameters::AssignLoad( std::string const &Name, float const Amount ) {
if( Name == loadattributes.name ) { if( Name == loadattributes.name ) {
LoadType = loadattributes; LoadType = loadattributes;
LoadAmount = clamp( Amount, 0.f, MaxLoad ) ; LoadAmount = clamp( Amount, 0.f, MaxLoad ) ;
ComputeMass();
return true; return true;
} }
} }
@@ -7121,6 +7206,7 @@ bool TMoverParameters::LoadingDone(double const LSpeed, std::string const &Loadn
if( LoadAmount == 0.f ) { if( LoadAmount == 0.f ) {
AssignLoad(""); // jak nic nie ma, to nie ma też nazwy AssignLoad(""); // jak nic nie ma, to nie ma też nazwy
} }
ComputeMass();
} }
} }
else if( LSpeed > 0 ) { else if( LSpeed > 0 ) {
@@ -7135,6 +7221,7 @@ bool TMoverParameters::LoadingDone(double const LSpeed, std::string const &Loadn
LoadStatus = 4; // skończony załadunek LoadStatus = 4; // skończony załadunek
LoadAmount = std::min<float>( MaxLoad * ( 1.0 + OverLoadFactor ), LoadAmount ); LoadAmount = std::min<float>( MaxLoad * ( 1.0 + OverLoadFactor ), LoadAmount );
} }
ComputeMass();
} }
} }
@@ -10681,3 +10768,9 @@ double TMoverParameters::ShowCurrentP(int AmpN) const
return current; return current;
} }
} }
namespace simulation {
weights_table Weights;
} // simulation

View File

@@ -35,7 +35,7 @@ public:
if( true == mapping.second ) { if( true == mapping.second ) {
return true; 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; mapping.first->second = itemhandle;
return false; } return false; }
bool insert (Type_ *Item) bool insert (Type_ *Item)

View File

@@ -509,7 +509,7 @@ dictionary_source *TTrain::GetTrainState() {
// induction motor state data // induction motor state data
char const *TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" }; 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 *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" }; char const *TXTP[ 3 ] = { "bc", "bp", "sp" };
for( int j = 0; j < 10; ++j ) for( int j = 0; j < 10; ++j )
dict->insert( ( "eimp_t_" + std::string( TXTT[ j ] ) ), fEIMParams[ 0 ][ j ] ); dict->insert( ( "eimp_t_" + std::string( TXTT[ j ] ) ), fEIMParams[ 0 ][ j ] );
@@ -597,6 +597,7 @@ TTrain::get_state() const {
btLampkaNadmWent.GetValue(), btLampkaNadmWent.GetValue(),
btLampkaWysRozr.GetValue(), btLampkaWysRozr.GetValue(),
btLampkaOgrzewanieSkladu.GetValue(), btLampkaOgrzewanieSkladu.GetValue(),
static_cast<std::uint8_t>( iCabn ),
btHaslerBrakes.GetValue(), btHaslerBrakes.GetValue(),
btHaslerCurrent.GetValue(), btHaslerCurrent.GetValue(),
( TestFlag( mvOccupied->SecuritySystem.Status, s_CAalarm ) || TestFlag( mvOccupied->SecuritySystem.Status, s_SHPalarm ) ), ( 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->PipePress ),
static_cast<float>( mvOccupied->BrakePress ), static_cast<float>( mvOccupied->BrakePress ),
fHVoltage, 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 ) { if( Command.action == GLFW_PRESS ) {
// NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors // NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors
if( false == ( if( false == (
Train->mvOccupied->ActiveCab == 1 ? ( Train->ggDoorLeftButton.GetDesiredValue() > 0.5 )
Train->mvOccupied->Doors.instances[side::left].is_opening || Train->mvOccupied->Doors.instances[ side::left ].is_open : || ( Train->ggDoorLeftOnButton.GetDesiredValue() > 0.5 ) ) ) {
Train->mvOccupied->Doors.instances[side::right].is_opening || Train->mvOccupied->Doors.instances[ side::right ].is_open ) ) {
// open // open
OnCommand_dooropenleft( Train, Command ); OnCommand_dooropenleft( Train, Command );
} }
@@ -4283,9 +4284,8 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman
else if( Command.action == GLFW_RELEASE ) { else if( Command.action == GLFW_RELEASE ) {
if( true == ( if( true == (
Train->mvOccupied->ActiveCab == 1 ? ( Train->ggDoorLeftButton.GetDesiredValue() > 0.5 )
Train->mvOccupied->Doors.instances[side::left].is_opening || Train->mvOccupied->Doors.instances[ side::left ].is_open : || ( Train->ggDoorLeftOnButton.GetDesiredValue() > 0.5 ) ) ) {
Train->mvOccupied->Doors.instances[side::right].is_opening || Train->mvOccupied->Doors.instances[ side::right ].is_open ) ) {
// open // open
if( ( Train->mvOccupied->Doors.has_autowarning ) if( ( Train->mvOccupied->Doors.has_autowarning )
&& ( Train->mvOccupied->DepartureSignal ) ) { && ( Train->mvOccupied->DepartureSignal ) ) {
@@ -4345,7 +4345,7 @@ void TTrain::OnCommand_doorpermitleft( TTrain *Train, command_data const &Comman
} }
else { else {
// two-state switch // 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 ); Train->mvOccupied->PermitDoors( side, newstate );
// visual feedback // visual feedback
@@ -4381,7 +4381,7 @@ void TTrain::OnCommand_doorpermitright( TTrain *Train, command_data const &Comma
} }
else { else {
// two-state switch // 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 ); Train->mvOccupied->PermitDoors( side, newstate );
// visual feedback // visual feedback
@@ -4520,9 +4520,8 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma
if( Command.action == GLFW_PRESS ) { if( Command.action == GLFW_PRESS ) {
// NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors // NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors
if( false == ( if( false == (
Train->mvOccupied->ActiveCab == 1 ? ( Train->ggDoorRightButton.GetDesiredValue() > 0.5 )
Train->mvOccupied->Doors.instances[side::right].is_opening || Train->mvOccupied->Doors.instances[ side::right ].is_open : || ( Train->ggDoorRightOnButton.GetDesiredValue() > 0.5 ) ) ) {
Train->mvOccupied->Doors.instances[side::left].is_opening || Train->mvOccupied->Doors.instances[ side::left ].is_open ) ) {
// open // open
OnCommand_dooropenright( Train, Command ); OnCommand_dooropenright( Train, Command );
} }
@@ -4542,9 +4541,8 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma
else if( Command.action == GLFW_RELEASE ) { else if( Command.action == GLFW_RELEASE ) {
if( true == ( if( true == (
Train->mvOccupied->ActiveCab == 1 ? ( Train->ggDoorRightButton.GetDesiredValue() > 0.5 )
Train->mvOccupied->Doors.instances[side::right].is_opening || Train->mvOccupied->Doors.instances[ side::right ].is_open : || ( Train->ggDoorRightOnButton.GetDesiredValue() > 0.5 ) ) ) {
Train->mvOccupied->Doors.instances[side::left].is_opening || Train->mvOccupied->Doors.instances[ side::left ].is_open ) ) {
// open // open
if( ( Train->mvOccupied->Doors.has_autowarning ) if( ( Train->mvOccupied->Doors.has_autowarning )
&& ( Train->mvOccupied->DepartureSignal ) ) { && ( Train->mvOccupied->DepartureSignal ) ) {
@@ -5416,7 +5414,9 @@ bool TTrain::Update( double const Deltatime )
in++; in++;
iPowerNo = 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][0] = p->MoverParameters->enrot*60;
fDieselParams[1 + in][1] = p->MoverParameters->nrot; 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][5] = p->MoverParameters->dizel_engage;
fDieselParams[1 + in][6] = p->MoverParameters->dizel_heat.Twy; fDieselParams[1 + in][6] = p->MoverParameters->dizel_heat.Twy;
fDieselParams[1 + in][7] = p->MoverParameters->OilPump.pressure; 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-> //fDieselParams[1 + in][9] = p->MoverParameters->
bMains[in] = p->MoverParameters->Mains; bMains[in] = p->MoverParameters->Mains;
fCntVol[in] = p->MoverParameters->BatteryVoltage; fCntVol[in] = p->MoverParameters->BatteryVoltage;

10
Train.h
View File

@@ -70,8 +70,10 @@ public:
find( TSubModel const *Control ) const; find( TSubModel const *Control ) const;
}; };
class TTrain class TTrain {
{
friend class drivingaid_panel;
public: public:
// types // types
struct state_t { struct state_t {
@@ -89,6 +91,7 @@ class TTrain
std::uint8_t ventilator_overload; std::uint8_t ventilator_overload;
std::uint8_t motor_overload_threshold; std::uint8_t motor_overload_threshold;
std::uint8_t train_heating; std::uint8_t train_heating;
std::uint8_t cab;
std::uint8_t recorder_braking; std::uint8_t recorder_braking;
std::uint8_t recorder_power; std::uint8_t recorder_power;
std::uint8_t alerter_sound; std::uint8_t alerter_sound;
@@ -99,6 +102,7 @@ class TTrain
float brake_pressure; float brake_pressure;
float hv_voltage; float hv_voltage;
std::array<float, 3> hv_current; std::array<float, 3> hv_current;
float lv_voltage;
}; };
// methods // methods
@@ -632,7 +636,7 @@ public: // reszta może by?publiczna
*/ */
// McZapkie: opis kabiny - obszar poruszania sie mechanika oraz zajetosc // McZapkie: opis kabiny - obszar poruszania sie mechanika oraz zajetosc
std::array<TCab, maxcab + 1> Cabine; // przedzial maszynowy, kabina 1 (A), kabina 2 (B) 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 // McZapkie: do poruszania sie po kabinie
Math3D::vector3 pMechSittingPosition; // ABu 180404 Math3D::vector3 pMechSittingPosition; // ABu 180404
Math3D::vector3 MirrorPosition( bool lewe ); Math3D::vector3 MirrorPosition( bool lewe );

View File

@@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/.
#include "Globals.h" #include "Globals.h"
#include "simulation.h" #include "simulation.h"
#include "Train.h" #include "Train.h"
#include "dictionary.h"
#include "sceneeditor.h" #include "sceneeditor.h"
#include "renderer.h" #include "renderer.h"
#include "uilayer.h" #include "uilayer.h"
@@ -129,6 +130,9 @@ eu07_application::init( int Argc, char *Argv[] ) {
if( ( result = init_audio() ) != 0 ) { if( ( result = init_audio() ) != 0 ) {
return result; return result;
} }
if( ( result = init_data() ) != 0 ) {
return result;
}
m_taskqueue.init(); m_taskqueue.init();
if( ( result = init_modes() ) != 0 ) { if( ( result = init_modes() ) != 0 ) {
return result; return result;
@@ -752,6 +756,23 @@ eu07_application::init_audio() {
return 0; 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 int
eu07_application::init_modes() { eu07_application::init_modes() {

View File

@@ -98,6 +98,7 @@ private:
void init_callbacks(); void init_callbacks();
int init_gfx(); int init_gfx();
int init_audio(); int init_audio();
int init_data();
int init_modes(); int init_modes();
bool init_network(); bool init_network();

View File

@@ -162,7 +162,7 @@ openal_source::sync_with( sound_properties const &State ) {
|| ( false == is_in_range ) ) { || ( false == is_in_range ) ) {
// if the emitter is outside of its nominal hearing range or was outside of it during last check // 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 // 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 { auto const rangefactor {
interpolate( interpolate(
1.f, 0.f, 1.f, 0.f,

View File

@@ -136,7 +136,7 @@ drivingaid_panel::update() {
} }
} }
std::string textline = 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 ] : locale::strings[ locale::string::driver_aid_alerter ] :
" " ); " " );
textline += textline +=
@@ -958,6 +958,14 @@ debug_panel::update_section_scenario( std::vector<text_line> &Output ) {
textline = "Cloud cover: " + to_string( Global.Overcast, 3 ); textline = "Cloud cover: " + to_string( Global.Overcast, 3 );
textline += "\nLight level: " + to_string( Global.fLuminance, 3 ); textline += "\nLight level: " + to_string( Global.fLuminance, 3 );
if( Global.FakeLight ) { textline += "(*)"; } 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"; textline += "\nAir temperature: " + to_string( Global.AirTemperature, 1 ) + " deg C";
Output.emplace_back( textline, Global.UITextColor ); Output.emplace_back( textline, Global.UITextColor );

View File

@@ -35,12 +35,24 @@ smoke_source::particle_emitter::deserialize( cParser &Input ) {
while( ( false == ( ( key = Input.getToken<std::string>( true, "\n\r\t ,;[]" ) ).empty() ) ) while( ( false == ( ( key = Input.getToken<std::string>( true, "\n\r\t ,;[]" ) ).empty() ) )
&& ( key != "}" ) ) { && ( 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 ) }; auto const lookup { variablemap.find( key ) };
if( lookup == variablemap.end() ) { continue; } if( lookup != variablemap.end() ) {
lookup->second = Input.getToken<float>( true, "\n\r\t ,;[]" ); lookup->second = Input.getToken<float>( true, "\n\r\t ,;[]" );
} }
} }
}
}
void void
smoke_source::particle_emitter::initialize( smoke_particle &Particle ) { 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 auto const azimuthalangle { glm::radians( Random( -180, 180 ) ) }; // phi
// convert spherical coordinates to opengl coordinates // convert spherical coordinates to opengl coordinates
auto const launchvector { glm::vec3( auto const launchvector { glm::vec3(
std::sin( polarangle ) * std::sin( azimuthalangle ), std::sin( polarangle ) * std::sin( azimuthalangle ) * -1,
std::cos( polarangle ), 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 ] ) ) }; auto const launchvelocity { static_cast<float>( Random( velocity[ value_limit::min ], velocity[ value_limit::max ] ) ) };
Particle.velocity = launchvector * launchvelocity; Particle.velocity = launchvector * launchvelocity;
Particle.rotation = glm::radians( Random( 0, 360 ) ); Particle.rotation = glm::radians( Random( 0, 360 ) );
Particle.size = Random( size[ value_limit::min ], size[ value_limit::max ] ); 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; Particle.age = 0;
} }
@@ -112,7 +124,7 @@ smoke_source::initialize() {
m_max_particles = m_max_particles =
// put a cap on number of particles in a single source. TBD, TODO: make it part of he source configuration? // put a cap on number of particles in a single source. TBD, TODO: make it part of he source configuration?
std::min( 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 // 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 // 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? // 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() } }; glm::dvec3{ std::numeric_limits<double>::lowest() } };
m_spawncount = ( m_spawncount = (
Onlydespawn ? ( ( false == Global.Smoke ) || ( true == Onlydespawn ) ) ?
0.f : 0.f :
std::min<float>( std::min<float>(
m_spawncount + ( m_spawnrate * Timedelta ), m_spawncount + ( m_spawnrate * Timedelta * Global.SmokeFidelity ),
m_max_particles ) ); 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 // update spawned particles
for( auto particleiterator { std::begin( m_particles ) }; particleiterator != std::end( m_particles ); ++particleiterator ) { 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 ) { if( m_ownertype == owner_type::vehicle ) {
Particle.opacity *= m_owner.vehicle->MoverParameters->dizel_fill; 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 ) { switch( m_owner.vehicle->MoverParameters->EngineType ) {
case TEngineType::DieselElectric: { 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; break;
} }
case TEngineType::DieselEngine: { 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; break;
} }
default: { default: {
@@ -399,7 +417,9 @@ particle_manager::find( std::string const &Template ) {
smoke_source source; smoke_source source;
cParser parser( templatepath + templatename + ".txt", cParser::buffer_FILE ); cParser parser( templatepath + templatename + ".txt", cParser::buffer_FILE );
if( source.deserialize( parser ) ) { 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 ); m_sourcetemplates.emplace( templatename, source );
// should be 'safe enough' to return lookup result directly afterwards // should be 'safe enough' to return lookup result directly afterwards
return &( m_sourcetemplates.find( templatename )->second ); return &( m_sourcetemplates.find( templatename )->second );

View File

@@ -48,9 +48,15 @@ public:
// updates state of provided variable // updates state of provided variable
void void
update( Type_ &Variable, double const Timedelta ) const; update( Type_ &Variable, double const Timedelta ) const;
Type_ const & void
bind( Type_ const *Modifier ) {
m_valuechangemodifier = Modifier; }
Type_
value_change() const { value_change() const {
return m_valuechange; } return (
m_valuechangemodifier == nullptr ?
m_valuechange :
m_valuechange / *( m_valuechangemodifier ) ); }
private: private:
//types //types
@@ -59,6 +65,7 @@ private:
// Type_ m_intialvalue { Type_( 0 ) }; // meters per second; velocity applied to freshly spawned particles // 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_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_ 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 // updates state of owned particles
void void
update( double const Timedelta, bool const Onlydespawn ); update( double const Timedelta, bool const Onlydespawn );
glm::vec3 const &
color() const {
return m_emitter.color; }
glm::dvec3 glm::dvec3
location() const; location() const;
// provides access to bounding area data // provides access to bounding area data
@@ -109,6 +119,7 @@ private:
float velocity[ 2 ] { 1.f, 1.f }; float velocity[ 2 ] { 1.f, 1.f };
float size[ 2 ] { 1.f, 1.f }; float size[ 2 ] { 1.f, 1.f };
float opacity[ 2 ] { 1.f, 1.f }; float opacity[ 2 ] { 1.f, 1.f };
glm::vec3 color { 16.f / 255.f };
void deserialize( cParser &Input ); void deserialize( cParser &Input );
void initialize( smoke_particle &Particle ); void initialize( smoke_particle &Particle );
@@ -138,20 +149,14 @@ private:
particle_emitter m_emitter; particle_emitter m_emitter;
// bool m_inheritvelocity { false }; // whether spawned particle should receive velocity of its owner // 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 // 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<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; fixedstep_modifier<float> m_opacitymodifier;
// texture_handle m_texture { -1 }; // texture assigned to particle billboards // texture_handle m_texture { -1 }; // texture assigned to particle billboards
// current state // current state
float m_spawncount { 0.f }; // number of particles to spawn during next update float m_spawncount { 0.f }; // number of particles to spawn during next update
particle_sequence m_particles; // collection of spawned particles particle_sequence m_particles; // collection of spawned particles
size_t m_max_particles; // maximum number of particles existing 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 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 { fixedstep_modifier<Type_>::update( Type_ &Variable, double const Timedelta ) const {
// HACK: float cast to avoid vec3 and double mismatch // HACK: float cast to avoid vec3 and double mismatch
// TBD, TODO: replace with vector types specialization // 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 // clamp down to allowed value range
Variable = glm::max( Variable, m_valuelimits[ value_limit::min ] ); Variable = glm::max( Variable, m_valuelimits[ value_limit::min ] );
Variable = glm::min( Variable, m_valuelimits[ value_limit::max ] ); Variable = glm::min( Variable, m_valuelimits[ value_limit::max ] );

View File

@@ -127,7 +127,8 @@ basic_precipitation::update() {
m_camerapos = Global.pCamera.Pos; 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 ) { if( m_freeflymode != FreeFlyModeFlag ) {
m_freeflymode = FreeFlyModeFlag; m_freeflymode = FreeFlyModeFlag;
if( true == m_freeflymode ) { if( true == m_freeflymode ) {
@@ -142,14 +143,17 @@ basic_precipitation::update() {
} }
cameramove = glm::dvec3{ 0.0 }; cameramove = glm::dvec3{ 0.0 };
} }
// ...from jump between cab and window/mirror view
if( m_windowopen != Global.CabWindowOpen ) { if( m_windowopen != Global.CabWindowOpen ) {
m_windowopen = Global.CabWindowOpen; m_windowopen = Global.CabWindowOpen;
cameramove = glm::dvec3{ 0.0 }; cameramove = glm::dvec3{ 0.0 };
} }
// ... from cab change
if( ( simulation::Train != nullptr ) && ( simulation::Train->iCabn != m_activecab ) ) { if( ( simulation::Train != nullptr ) && ( simulation::Train->iCabn != m_activecab ) ) {
m_activecab = simulation::Train->iCabn; m_activecab = simulation::Train->iCabn;
cameramove = glm::dvec3{ 0.0 }; cameramove = glm::dvec3{ 0.0 };
} }
// ... from camera jump to another location
if( glm::length( cameramove ) > 100.0 ) { if( glm::length( cameramove ) > 100.0 ) {
cameramove = glm::dvec3{ 0.0 }; cameramove = glm::dvec3{ 0.0 };
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
/************************************************************************* /*************************************************************************
* GLFW 3.2 - www.glfw.org * GLFW 3.3 - www.glfw.org
* A library for OpenGL, window and input * A library for OpenGL, window and input
*------------------------------------------------------------------------ *------------------------------------------------------------------------
* Copyright (c) 2002-2006 Marcus Geelnard * 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 * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -45,12 +45,13 @@ extern "C" {
* more information. * more information.
*/ */
/*! @defgroup native Native access /*! @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 * **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 * doing and how to fix problems caused by using them. If you don't, you
* shouldn't be using them.** * 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. * window system API macro and zero or more context creation API macros.
* *
* The chosen backends must match those the library was compiled for. Failure * 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_COCOA`
* * `GLFW_EXPOSE_NATIVE_X11` * * `GLFW_EXPOSE_NATIVE_X11`
* * `GLFW_EXPOSE_NATIVE_WAYLAND` * * `GLFW_EXPOSE_NATIVE_WAYLAND`
* * `GLFW_EXPOSE_NATIVE_MIR`
* *
* The available context API macros are: * The available context API macros are:
* * `GLFW_EXPOSE_NATIVE_WGL` * * `GLFW_EXPOSE_NATIVE_WGL`
* * `GLFW_EXPOSE_NATIVE_NSGL` * * `GLFW_EXPOSE_NATIVE_NSGL`
* * `GLFW_EXPOSE_NATIVE_GLX` * * `GLFW_EXPOSE_NATIVE_GLX`
* * `GLFW_EXPOSE_NATIVE_EGL` * * `GLFW_EXPOSE_NATIVE_EGL`
* * `GLFW_EXPOSE_NATIVE_OSMESA`
* *
* These macros select which of the native access functions that are declared * 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 * and which platform-specific headers to include. It is then up your (by
@@ -80,26 +81,27 @@ extern "C" {
* System headers and types * 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 // 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 // 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 // callback) but windows.h assumes no one will define APIENTRY before it does
#if defined(GLFW_APIENTRY_DEFINED)
#undef APIENTRY #undef APIENTRY
#undef GLFW_APIENTRY_DEFINED
#endif
#include <windows.h> #include <windows.h>
#elif defined(GLFW_EXPOSE_NATIVE_COCOA) #elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL)
#include <ApplicationServices/ApplicationServices.h>
#if defined(__OBJC__) #if defined(__OBJC__)
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#else #else
#include <ApplicationServices/ApplicationServices.h>
typedef void* id; typedef void* id;
#endif #endif
#elif defined(GLFW_EXPOSE_NATIVE_X11) #elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h> #include <X11/extensions/Xrandr.h>
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) #elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
#include <wayland-client.h> #include <wayland-client.h>
#elif defined(GLFW_EXPOSE_NATIVE_MIR)
#include <mir_toolkit/mir_client_library.h>
#endif #endif
#if defined(GLFW_EXPOSE_NATIVE_WGL) #if defined(GLFW_EXPOSE_NATIVE_WGL)
@@ -114,6 +116,9 @@ extern "C" {
#if defined(GLFW_EXPOSE_NATIVE_EGL) #if defined(GLFW_EXPOSE_NATIVE_EGL)
#include <EGL/egl.h> #include <EGL/egl.h>
#endif #endif
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
#include <GL/osmesa.h>
#endif
/************************************************************************* /*************************************************************************
@@ -284,6 +289,56 @@ GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
* @ingroup native * @ingroup native
*/ */
GLFWAPI Window glfwGetX11Window(GLFWwindow* window); 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 #endif
#if defined(GLFW_EXPOSE_NATIVE_GLX) #if defined(GLFW_EXPOSE_NATIVE_GLX)
@@ -360,50 +415,6 @@ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
#endif #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) #if defined(GLFW_EXPOSE_NATIVE_EGL)
/*! @brief Returns the `EGLDisplay` used by GLFW. /*! @brief Returns the `EGLDisplay` used by GLFW.
* *
@@ -448,6 +459,64 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window);
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window);
#endif #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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -80,6 +80,9 @@ std::vector<std::pair<glm::vec3, glm::vec2>> const billboard_vertices {
void void
opengl_particles::update( opengl_camera const &Camera ) { opengl_particles::update( opengl_camera const &Camera ) {
if (!Global.Smoke)
return;
m_particlevertices.clear(); m_particlevertices.clear();
// build a list of visible smoke sources // 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 // 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; particle_vertex vertex;
for( auto const &source : sources ) { 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() }; auto const &particles { source.second.sequence() };
// TODO: put sanity cap on the overall amount of particles that can be drawn // TODO: put sanity cap on the overall amount of particles that can be drawn
auto const sizestep { 256.0 * billboard_vertices.size() }; 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 ) ); sizestep * std::ceil( m_particlevertices.size() + ( particles.size() * billboard_vertices.size() ) / sizestep ) );
for( auto const &particle : particles ) { for( auto const &particle : particles ) {
// TODO: particle color support // TODO: particle color support
vertex.color.r = vertex.color[ 0 ] = static_cast<std::uint8_t>( particlecolor.r );
vertex.color.g = vertex.color[ 1 ] = static_cast<std::uint8_t>( particlecolor.g );
vertex.color.b = Global.fLuminance * 0.125f; vertex.color[ 2 ] = static_cast<std::uint8_t>( particlecolor.b );
vertex.color.a = std::clamp(particle.opacity, 0.0f, 1.0f); vertex.color.a = std::clamp(particle.opacity, 0.0f, 1.0f);
auto const offset { glm::vec3{ particle.position - Camera.position() } }; auto const offset { glm::vec3{ particle.position - Camera.position() } };
@@ -145,6 +154,9 @@ opengl_particles::update( opengl_camera const &Camera ) {
void void
opengl_particles::render() { opengl_particles::render() {
if (!Global.Smoke)
return;
if( m_buffercapacity == 0 ) { return; } if( m_buffercapacity == 0 ) { return; }
if( m_particlevertices.empty() ) { return; } if( m_particlevertices.empty() ) { return; }

View File

@@ -200,13 +200,17 @@ world_environment::update_wind() {
m_wind.change_time -= timedelta; m_wind.change_time -= timedelta;
if( m_wind.change_time < 0 ) { if( m_wind.change_time < 0 ) {
m_wind.change_time = Random( 5, 30 ); m_wind.change_time = Random( 5, 15 );
m_wind.velocity_change = Random( -1, 1 ); m_wind.velocity_change = Random( -0.2, 0.2 );
if( Random() < 0.2 ) { if( Random() < 0.05 ) {
// changes in wind direction should be less frequent than changes in wind speed // changes in wind direction should be less frequent than changes in wind speed
// TBD, TODO: configuration-driven direction change frequency // TBD, TODO: configuration-driven direction change frequency
m_wind.azimuth_change = Random( -5, 5 ); 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 // TBD, TODO: wind configuration
m_wind.azimuth = clamp_circular( m_wind.azimuth + m_wind.azimuth_change * timedelta ); m_wind.azimuth = clamp_circular( m_wind.azimuth + m_wind.azimuth_change * timedelta );
@@ -219,9 +223,9 @@ world_environment::update_wind() {
m_wind.vector = m_wind.vector =
std::max( 0.f, m_wind.velocity ) std::max( 0.f, m_wind.velocity )
* glm::vec3( * glm::vec3(
std::sin( polarangle ) * std::sin( azimuthalangle ), std::sin( polarangle ) * std::sin( azimuthalangle ) * -1,
std::cos( polarangle ), std::cos( polarangle ),
std::sin( polarangle ) * std::cos( azimuthalangle ) * -1 ); std::sin( polarangle ) * std::cos( azimuthalangle ) );
} }
void void

View File

@@ -40,6 +40,9 @@ public:
glm::vec3 const & glm::vec3 const &
wind() const { wind() const {
return m_wind.vector; } return m_wind.vector; }
float const &
wind_azimuth() const {
return m_wind.azimuth; }
private: private:
// types // types

View File

@@ -49,20 +49,22 @@ basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Sch
// (try to) set the cargo type for empty cars // (try to) set the cargo type for empty cars
parameters.LoadAmount = 0.f; // safety measure against edge cases parameters.LoadAmount = 0.f; // safety measure against edge cases
parameters.AssignLoad( "passengers" ); parameters.AssignLoad( "passengers" );
parameters.ComputeMass();
} }
if( parameters.LoadType.name == "passengers" ) { if( parameters.LoadType.name == "passengers" ) {
// NOTE: for the time being we're doing simple, random load change calculation // NOTE: for the time being we're doing simple, random load change calculation
// TODO: exchange driven by station parameters and time of the day // TODO: exchange driven by station parameters and time of the day
auto unloadcount = static_cast<int>( auto unloadcount = static_cast<int>(
TestFlag( parameters.DamageFlag, dtrain_out ) ? parameters.LoadAmount :
laststop ? parameters.LoadAmount : laststop ? parameters.LoadAmount :
firststop ? 0 : firststop ? 0 :
std::min<float>( std::min<float>(
parameters.LoadAmount, parameters.LoadAmount,
Random( parameters.MaxLoad * 0.15f * stationsizemodifier ) ) ); Random( parameters.MaxLoad * 0.15f * stationsizemodifier ) ) );
auto loadcount = static_cast<int>( auto loadcount = static_cast<int>(
laststop ? TestFlag( parameters.DamageFlag, dtrain_out ) ? 0 :
0 : laststop ? 0 :
Random( parameters.MaxLoad * 0.15f * stationsizemodifier ) ); Random( parameters.MaxLoad * 0.15f * stationsizemodifier ) );
if( true == firststop ) { if( true == firststop ) {
// larger group at the initial station // larger group at the initial station

View File

@@ -39,6 +39,8 @@
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
// stl // stl
#define _USE_MATH_DEFINES
#include <cmath>
#include <cstddef> #include <cstddef>
#include <cstdlib> #include <cstdlib>
#include <cstdio> #include <cstdio>

View File

@@ -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 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 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 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 { std::array<uint8_t, 31> buffer {
//byte 0 //byte 0
@@ -271,7 +277,8 @@ void uart_input::poll()
| trainstate.compressor_overload << 6), | trainstate.compressor_overload << 6),
//byte 6 //byte 6
(uint8_t)( (uint8_t)(
trainstate.recorder_braking << 3 m_trainstatecab << 2
| trainstate.recorder_braking << 3
| trainstate.recorder_power << 4 | trainstate.recorder_power << 4
| trainstate.radio_stop <<5 | trainstate.radio_stop <<5
| trainstate.alerter_sound << 7), | trainstate.alerter_sound << 7),
@@ -289,8 +296,10 @@ void uart_input::poll()
SPLIT_INT16(current2), SPLIT_INT16(current2),
//byte 19-20 //byte 19-20
SPLIT_INT16(current3), SPLIT_INT16(current3),
//byte 21-30 //byte 21-22
0, 0, 0, 0, 0, 0, 0, 0, 0, 0 SPLIT_INT16(lv_voltage),
//byte 23-30
0, 0, 0, 0, 0, 0, 0, 0
}; };
if (conf.debug) if (conf.debug)

3
uart.h
View File

@@ -27,6 +27,8 @@ public:
float hvuart = 65535.0f; float hvuart = 65535.0f;
float currentmax = 10000.0f; float currentmax = 10000.0f;
float currentuart = 65535.0f; float currentuart = 65535.0f;
float lvmax = 150.0f;
float lvuart = 65535.0f;
bool mainenable = true; bool mainenable = true;
bool scndenable = true; bool scndenable = true;
@@ -66,4 +68,5 @@ private:
std::chrono::time_point<std::chrono::high_resolution_clock> last_update; std::chrono::time_point<std::chrono::high_resolution_clock> last_update;
conf_t conf; conf_t conf;
bool data_pending = false; bool data_pending = false;
std::uint8_t m_trainstatecab { 0 }; // helper, keeps track of last active cab. 0: front cab, 1: rear cab
}; };

View File

@@ -1 +1 @@
#define VERSION_INFO "M7 (gfx-work) 8.08.2019" #define VERSION_INFO "M7 (gfx-work) 7.09.2019"