mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 20:59:19 +02:00
Merge branch 'tmj-dev'
This commit is contained in:
@@ -80,6 +80,7 @@ set(SOURCES
|
|||||||
"utilities.cpp"
|
"utilities.cpp"
|
||||||
"light.cpp"
|
"light.cpp"
|
||||||
"uitranscripts.cpp"
|
"uitranscripts.cpp"
|
||||||
|
"station.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
set (PREFIX "")
|
set (PREFIX "")
|
||||||
|
|||||||
233
Driver.cpp
233
Driver.cpp
@@ -891,8 +891,6 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
|||||||
mvOccupied->DoorLeft(true);
|
mvOccupied->DoorLeft(true);
|
||||||
if (p2 & prawe)
|
if (p2 & prawe)
|
||||||
mvOccupied->DoorRight(true);
|
mvOccupied->DoorRight(true);
|
||||||
// if (p2&3) //żeby jeszcze poczekał chwilę, zanim zamknie
|
|
||||||
// WaitingSet(10); //10 sekund (wziąć z rozkładu????)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -916,50 +914,72 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
|||||||
// pojazd podłączony z tyłu (patrząc od czoła)
|
// pojazd podłączony z tyłu (patrząc od czoła)
|
||||||
p = p->Next();
|
p = p->Next();
|
||||||
}
|
}
|
||||||
// if (p7&3) //żeby jeszcze poczekał chwilę, zanim zamknie
|
}
|
||||||
// WaitingSet(10); //10 sekund (wziąć z rozkładu????)
|
}
|
||||||
|
if (TrainParams->UpdateMTable( simulation::Time, asNextStop) ) {
|
||||||
|
// to się wykona tylko raz po zatrzymaniu na W4
|
||||||
|
if( TrainParams->StationIndex < TrainParams->StationCount ) {
|
||||||
|
// jeśli są dalsze stacje, bez trąbienia przed odjazdem
|
||||||
|
// also ignore any horn cue that may be potentially set below 1 km/h and before the actual full stop
|
||||||
|
iDrivigFlags &= ~( moveStartHorn | moveStartHornNow );
|
||||||
|
}
|
||||||
|
// perform loading/unloading
|
||||||
|
auto const exchangetime { simulation::Station.update_load( pVehicles[ 0 ], *TrainParams ) };
|
||||||
|
// TBD: adjust time to load exchange size
|
||||||
|
if( fStopTime > -55 ) {
|
||||||
|
// na końcu rozkładu się ustawia 60s i tu by było skrócenie
|
||||||
|
// WaitingSet( 15.0 + Random( 15.0 ) ); // 10 sekund (wziąć z rozkładu????) - czekanie
|
||||||
|
// with door open on both sides calculated loading time is halved
|
||||||
|
// p7=platform side (1:left, 2:right, 3:both)
|
||||||
|
auto const platformside = static_cast<int>( std::floor( sSpeedTable[ i ].evEvent->ValueGet( 2 ) ) ) % 10;
|
||||||
|
WaitingSet(
|
||||||
|
platformside == 3 ?
|
||||||
|
exchangetime * 0.5 :
|
||||||
|
exchangetime );
|
||||||
|
}
|
||||||
|
// update brake settings and ai braking tables
|
||||||
|
// NOTE: this calculation is run after completing loading/unloading
|
||||||
|
// remember to move it to a more fitting spot, when loading/unloading taks some actual time
|
||||||
|
AutoRewident(); // nastawianie hamulca do jazdy pociągowej
|
||||||
|
|
||||||
|
if( TrainParams->CheckTrainLatency() < 0.0 ) {
|
||||||
|
// odnotowano spóźnienie
|
||||||
|
iDrivigFlags |= moveLate;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// przyjazd o czasie
|
||||||
|
iDrivigFlags &= ~moveLate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( fStopTime > -5 ) // na końcu rozkładu się ustawia 60s i tu by było skrócenie
|
if (TrainParams->DirectionChange()) {
|
||||||
WaitingSet( 15.0 + Random( 15.0 ) ); // 10 sekund (wziąć z rozkładu????) - czekanie
|
// jeśli "@" w rozkładzie, to wykonanie dalszych komend
|
||||||
// niezależne od sposobu obsługi drzwi, bo opóźnia również kierownika
|
// wykonanie kolejnej komendy, nie dotyczy ostatniej stacji
|
||||||
}
|
if (iDrivigFlags & movePushPull) {
|
||||||
if (TrainParams->UpdateMTable( simulation::Time, asNextStop) )
|
// SN61 ma się też nie ruszać, chyba że ma wagony
|
||||||
{ // to się wykona tylko raz po zatrzymaniu na W4
|
|
||||||
if (TrainParams->CheckTrainLatency() < 0.0)
|
|
||||||
iDrivigFlags |= moveLate; // odnotowano spóźnienie
|
|
||||||
else
|
|
||||||
iDrivigFlags &= ~moveLate; // przyjazd o czasie
|
|
||||||
if (TrainParams->DirectionChange()) // jeśli "@" w rozkładzie, to
|
|
||||||
// wykonanie dalszych komend
|
|
||||||
{ // wykonanie kolejnej komendy, nie dotyczy ostatniej stacji
|
|
||||||
if (iDrivigFlags & movePushPull) // SN61 ma się też nie ruszać,
|
|
||||||
// chyba że ma wagony
|
|
||||||
{
|
|
||||||
iDrivigFlags |= moveStopHere; // EZT ma stać przy peronie
|
iDrivigFlags |= moveStopHere; // EZT ma stać przy peronie
|
||||||
if (OrderNextGet() != Change_direction)
|
if (OrderNextGet() != Change_direction) {
|
||||||
{
|
|
||||||
OrderPush(Change_direction); // zmiana kierunku
|
OrderPush(Change_direction); // zmiana kierunku
|
||||||
OrderPush(TrainParams->StationIndex <
|
OrderPush(
|
||||||
TrainParams->StationCount ?
|
TrainParams->StationIndex < TrainParams->StationCount ?
|
||||||
Obey_train :
|
Obey_train :
|
||||||
Shunt); // to dalej wg rozkładu
|
Shunt); // to dalej wg rozkładu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // a dla lokomotyw...
|
else {
|
||||||
iDrivigFlags &=
|
// a dla lokomotyw...
|
||||||
~(moveStopPoint | moveStopHere); // pozwolenie na
|
// pozwolenie na przejechanie za W4 przed czasem i nie ma stać
|
||||||
// przejechanie za W4
|
iDrivigFlags &= ~( moveStopPoint | moveStopHere );
|
||||||
// przed czasem i nie
|
}
|
||||||
// ma stać
|
// przejście do kolejnego rozkazu (zmiana kierunku, odczepianie)
|
||||||
JumpToNextOrder(); // przejście do kolejnego rozkazu (zmiana
|
JumpToNextOrder();
|
||||||
// kierunku, odczepianie)
|
// ma nie podjeżdżać pod W4 po przeciwnej stronie
|
||||||
iDrivigFlags &= ~moveStopCloser; // ma nie podjeżdżać pod W4 po
|
iDrivigFlags &= ~moveStopCloser;
|
||||||
// przeciwnej stronie
|
// ten W4 nie liczy się już zupełnie (nie wyśle SetVelocity)
|
||||||
sSpeedTable[i].iFlags = 0; // ten W4 nie liczy się już zupełnie
|
sSpeedTable[i].iFlags = 0;
|
||||||
// (nie wyśle SetVelocity)
|
// jechać
|
||||||
sSpeedTable[i].fVelNext = -1; // jechać
|
sSpeedTable[i].fVelNext = -1;
|
||||||
continue; // nie analizować prędkości
|
// nie analizować prędkości
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (OrderCurrentGet() == Shunt)
|
if (OrderCurrentGet() == Shunt)
|
||||||
@@ -969,7 +989,6 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
|||||||
}
|
}
|
||||||
if (TrainParams->StationIndex < TrainParams->StationCount)
|
if (TrainParams->StationIndex < TrainParams->StationCount)
|
||||||
{ // jeśli są dalsze stacje, czekamy do godziny odjazdu
|
{ // jeśli są dalsze stacje, czekamy do godziny odjazdu
|
||||||
|
|
||||||
if (TrainParams->IsTimeToGo(simulation::Time.data().wHour, simulation::Time.data().wMinute))
|
if (TrainParams->IsTimeToGo(simulation::Time.data().wHour, simulation::Time.data().wMinute))
|
||||||
{ // z dalszą akcją czekamy do godziny odjazdu
|
{ // z dalszą akcją czekamy do godziny odjazdu
|
||||||
/* potencjalny problem z ruszaniem z w4
|
/* potencjalny problem z ruszaniem z w4
|
||||||
@@ -992,16 +1011,16 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
|||||||
+ ": at " + std::to_string(simulation::Time.data().wHour) + ":" + std::to_string(simulation::Time.data().wMinute)
|
+ ": at " + std::to_string(simulation::Time.data().wHour) + ":" + std::to_string(simulation::Time.data().wMinute)
|
||||||
+ " next " + asNextStop); // informacja
|
+ " next " + asNextStop); // informacja
|
||||||
#endif
|
#endif
|
||||||
if (int(floor(sSpeedTable[i].evEvent->ValueGet(1))) & 1)
|
if( int( floor( sSpeedTable[ i ].evEvent->ValueGet( 1 ) ) ) & 1 ) {
|
||||||
iDrivigFlags |= moveStopHere; // nie podjeżdżać do semafora,
|
// nie podjeżdżać do semafora, jeśli droga nie jest wolna
|
||||||
// jeśli droga nie jest wolna
|
iDrivigFlags |= moveStopHere;
|
||||||
else
|
}
|
||||||
iDrivigFlags &= ~moveStopHere; //po czasie jedź dalej
|
else {
|
||||||
iDrivigFlags |= moveStopCloser; // do następnego W4 podjechać
|
//po czasie jedź dalej
|
||||||
// blisko (z dociąganiem)
|
iDrivigFlags &= ~moveStopHere;
|
||||||
iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed odjazdem
|
}
|
||||||
sSpeedTable[i].iFlags =
|
iDrivigFlags |= moveStopCloser; // do następnego W4 podjechać blisko (z dociąganiem)
|
||||||
0; // nie liczy się już zupełnie (nie wyśle SetVelocity)
|
sSpeedTable[i].iFlags = 0; // nie liczy się już zupełnie (nie wyśle SetVelocity)
|
||||||
sSpeedTable[i].fVelNext = -1; // można jechać za W4
|
sSpeedTable[i].fVelNext = -1; // można jechać za W4
|
||||||
if (go == cm_Unknown) // jeśli nie było komendy wcześniej
|
if (go == cm_Unknown) // jeśli nie było komendy wcześniej
|
||||||
go = cm_Ready; // gotów do odjazdu z W4 (semafor może
|
go = cm_Ready; // gotów do odjazdu z W4 (semafor może
|
||||||
@@ -1772,34 +1791,55 @@ void TController::AutoRewident()
|
|||||||
p = 0; // będziemy tu liczyć wagony od lokomotywy dla nastawy GP
|
p = 0; // będziemy tu liczyć wagony od lokomotywy dla nastawy GP
|
||||||
while (d)
|
while (d)
|
||||||
{ // 3. Nastawianie
|
{ // 3. Nastawianie
|
||||||
switch (ustaw)
|
if( ( true == AIControllFlag )
|
||||||
{
|
|| ( d != pVehicle ) ) {
|
||||||
case bdelay_P: // towarowy P - lokomotywa na G, reszta na P.
|
// don't touch human-controlled vehicle, but others are free game
|
||||||
d->MoverParameters->BrakeDelaySwitch(d->MoverParameters->Power > 1 ? bdelay_G :
|
switch( ustaw ) {
|
||||||
bdelay_P);
|
|
||||||
break;
|
case bdelay_P: {
|
||||||
case bdelay_G: // towarowy G - wszystko na G, jeśli nie ma to P (powinno się wyłączyć
|
// towarowy P - lokomotywa na G, reszta na P.
|
||||||
// hamulec)
|
d->MoverParameters->BrakeDelaySwitch(
|
||||||
d->MoverParameters->BrakeDelaySwitch(
|
d->MoverParameters->Power > 1 ?
|
||||||
TestFlag(d->MoverParameters->BrakeDelays, bdelay_G) ? bdelay_G : bdelay_P);
|
bdelay_G :
|
||||||
break;
|
bdelay_P );
|
||||||
case bdelay_R: // towarowy GP - lokomotywa oraz 5 pierwszych pojazdów przy niej na G, reszta
|
break;
|
||||||
// na P
|
}
|
||||||
if (d->MoverParameters->Power > 1)
|
case bdelay_G: {
|
||||||
{
|
// towarowy G - wszystko na G, jeśli nie ma to P (powinno się wyłączyć hamulec)
|
||||||
d->MoverParameters->BrakeDelaySwitch(bdelay_G);
|
d->MoverParameters->BrakeDelaySwitch(
|
||||||
p = 0; // a jak będzie druga w środku?
|
TestFlag( d->MoverParameters->BrakeDelays, bdelay_G ) ?
|
||||||
|
bdelay_G :
|
||||||
|
bdelay_P );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case bdelay_R: {
|
||||||
|
// towarowy GP - lokomotywa oraz 5 pierwszych pojazdów przy niej na G, reszta na P
|
||||||
|
if( d->MoverParameters->Power > 1 ) {
|
||||||
|
d->MoverParameters->BrakeDelaySwitch( bdelay_G );
|
||||||
|
p = 0; // a jak będzie druga w środku?
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d->MoverParameters->BrakeDelaySwitch(
|
||||||
|
++p <= 5 ?
|
||||||
|
bdelay_G :
|
||||||
|
bdelay_P );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 16 + bdelay_R: {
|
||||||
|
// pasażerski R - na R, jeśli nie ma to P
|
||||||
|
d->MoverParameters->BrakeDelaySwitch(
|
||||||
|
TestFlag( d->MoverParameters->BrakeDelays, bdelay_R ) ?
|
||||||
|
bdelay_R :
|
||||||
|
bdelay_P );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 16 + bdelay_P: {
|
||||||
|
// pasażerski P - wszystko na P
|
||||||
|
d->MoverParameters->BrakeDelaySwitch( bdelay_P );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
d->MoverParameters->BrakeDelaySwitch(++p <= 5 ? bdelay_G : bdelay_P);
|
|
||||||
break;
|
|
||||||
case 16 + bdelay_R: // pasażerski R - na R, jeśli nie ma to P
|
|
||||||
d->MoverParameters->BrakeDelaySwitch(
|
|
||||||
TestFlag(d->MoverParameters->BrakeDelays, bdelay_R) ? bdelay_R : bdelay_P);
|
|
||||||
break;
|
|
||||||
case 16 + bdelay_P: // pasażerski P - wszystko na P
|
|
||||||
d->MoverParameters->BrakeDelaySwitch(bdelay_P);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła)
|
d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła)
|
||||||
}
|
}
|
||||||
@@ -2094,22 +2134,16 @@ void TController::SetVelocity(double NewVel, double NewVelNext, TStopReason r)
|
|||||||
if (OrderList[OrderPos] ?
|
if (OrderList[OrderPos] ?
|
||||||
OrderList[OrderPos] & (Obey_train | Shunt | Connect | Prepare_engine) :
|
OrderList[OrderPos] & (Obey_train | Shunt | Connect | Prepare_engine) :
|
||||||
true) // jeśli jedzie w dowolnym trybie
|
true) // jeśli jedzie w dowolnym trybie
|
||||||
if ((mvOccupied->Vel <
|
if ((mvOccupied->Vel < 1.0)) // jesli stoi (na razie, bo chyba powinien też, gdy hamuje przed semaforem)
|
||||||
1.0)) // jesli stoi (na razie, bo chyba powinien też, gdy hamuje przed semaforem)
|
|
||||||
if (iDrivigFlags & moveStartHorn) // jezeli trąbienie włączone
|
if (iDrivigFlags & moveStartHorn) // jezeli trąbienie włączone
|
||||||
if (!(iDrivigFlags & (moveStartHornDone | moveConnect))) // jeśli nie zatrąbione
|
if (!(iDrivigFlags & (moveStartHornDone | moveConnect)))
|
||||||
// i nie jest to moment
|
// jeśli nie zatrąbione i nie jest to moment podłączania składu
|
||||||
// podłączania składu
|
if (mvOccupied->CategoryFlag & 1)
|
||||||
if (mvOccupied->CategoryFlag & 1) // tylko pociągi trąbią (unimogi tylko na
|
// tylko pociągi trąbią (unimogi tylko na torach, więc trzeba raczej sprawdzać tor)
|
||||||
// torach, więc trzeba raczej sprawdzać
|
if ((NewVel >= 1.0) || (NewVel < 0.0)) {
|
||||||
// tor)
|
// o ile prędkość jest znacząca
|
||||||
if ((NewVel >= 1.0) || (NewVel < 0.0)) // o ile prędkość jest znacząca
|
// zatrąb po odhamowaniu
|
||||||
{ // fWarningDuration=0.3; //czas trąbienia
|
iDrivigFlags |= moveStartHornNow;
|
||||||
// if (AIControllFlag) //jak siedzi krasnoludek, to włączy trąbienie
|
|
||||||
// mvOccupied->WarningSignal=pVehicle->iHornWarning; //wysokość tonu
|
|
||||||
// (2=wysoki)
|
|
||||||
// iDrivigFlags|=moveStartHornDone; //nie trąbić aż do ruszenia
|
|
||||||
iDrivigFlags |= moveStartHornNow; // zatrąb po odhamowaniu
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VelSignal = NewVel; // prędkość zezwolona na aktualnym odcinku
|
VelSignal = NewVel; // prędkość zezwolona na aktualnym odcinku
|
||||||
@@ -3648,12 +3682,9 @@ TController::UpdateSituation(double dt) {
|
|||||||
// but when enabled all the time it produces silly effect
|
// but when enabled all the time it produces silly effect
|
||||||
// przy prowadzeniu samochodu trzeba każdą oś odsuwać oddzielnie, inaczej kicha wychodzi
|
// przy prowadzeniu samochodu trzeba każdą oś odsuwać oddzielnie, inaczej kicha wychodzi
|
||||||
if (mvOccupied->CategoryFlag & 2) // jeśli samochód
|
if (mvOccupied->CategoryFlag & 2) // jeśli samochód
|
||||||
// if (fabs(mvOccupied->OffsetTrackH)<mvOccupied->Dim.W) //Ra: szerokość drogi tu
|
// if (fabs(mvOccupied->OffsetTrackH)<mvOccupied->Dim.W) //Ra: szerokość drogi tu powinna być?
|
||||||
// powinna być?
|
if (!mvOccupied->ChangeOffsetH(-0.01 * mvOccupied->Vel * dt)) // ruch w poprzek drogi
|
||||||
if (!mvOccupied->ChangeOffsetH(-0.01 * mvOccupied->Vel * dt)) // ruch w poprzek
|
mvOccupied->ChangeOffsetH(0.01 * mvOccupied->Vel * dt); // Ra: co to miało być, to nie wiem
|
||||||
// drogi
|
|
||||||
mvOccupied->ChangeOffsetH(0.01 * mvOccupied->Vel *
|
|
||||||
dt); // Ra: co to miało być, to nie wiem
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3720,7 +3751,7 @@ TController::UpdateSituation(double dt) {
|
|||||||
if( fWarningDuration < 0.05 )
|
if( fWarningDuration < 0.05 )
|
||||||
mvOccupied->WarningSignal = 0; // a tu się kończy
|
mvOccupied->WarningSignal = 0; // a tu się kończy
|
||||||
}
|
}
|
||||||
if( mvOccupied->Vel >= 3.0 ) {
|
if( mvOccupied->Vel >= 5.0 ) {
|
||||||
// jesli jedzie, można odblokować trąbienie, bo się wtedy nie włączy
|
// jesli jedzie, można odblokować trąbienie, bo się wtedy nie włączy
|
||||||
iDrivigFlags &= ~moveStartHornDone; // zatrąbi dopiero jak następnym razem stanie
|
iDrivigFlags &= ~moveStartHornDone; // zatrąbi dopiero jak następnym razem stanie
|
||||||
iDrivigFlags |= moveStartHorn; // i trąbić przed następnym ruszeniem
|
iDrivigFlags |= moveStartHorn; // i trąbić przed następnym ruszeniem
|
||||||
@@ -3729,7 +3760,7 @@ TController::UpdateSituation(double dt) {
|
|||||||
if( ( true == TestFlag( iDrivigFlags, moveStartHornNow ) )
|
if( ( true == TestFlag( iDrivigFlags, moveStartHornNow ) )
|
||||||
&& ( true == Ready )
|
&& ( true == Ready )
|
||||||
&& ( iEngineActive != 0 )
|
&& ( iEngineActive != 0 )
|
||||||
&& ( fStopTime >= 0 ) ) {
|
&& ( mvControlling->MainCtrlPos > 0 ) ) {
|
||||||
// uruchomienie trąbienia przed ruszeniem
|
// uruchomienie trąbienia przed ruszeniem
|
||||||
fWarningDuration = 0.3; // czas trąbienia
|
fWarningDuration = 0.3; // czas trąbienia
|
||||||
mvOccupied->WarningSignal = pVehicle->iHornWarning; // wysokość tonu (2=wysoki)
|
mvOccupied->WarningSignal = pVehicle->iHornWarning; // wysokość tonu (2=wysoki)
|
||||||
|
|||||||
218
DynObj.cpp
218
DynObj.cpp
@@ -556,14 +556,14 @@ TDynamicObject::toggle_lights() {
|
|||||||
for( auto §ionlight : SectionLightLevels ) {
|
for( auto §ionlight : SectionLightLevels ) {
|
||||||
|
|
||||||
std::string const &compartmentname = sectionlight.compartment->pName;
|
std::string const &compartmentname = sectionlight.compartment->pName;
|
||||||
if( ( compartmentname.find( "corridor" ) != std::string::npos )
|
if( ( compartmentname.find( "corridor" ) == 0 )
|
||||||
|| ( compartmentname.find( "korytarz" ) != std::string::npos ) ) {
|
|| ( compartmentname.find( "korytarz" ) == 0 ) ) {
|
||||||
// corridors are lit 100% of time
|
// corridors are lit 100% of time
|
||||||
sectionlight.level = 0.75f;
|
sectionlight.level = 0.75f;
|
||||||
}
|
}
|
||||||
else if(
|
else if(
|
||||||
( compartmentname.find( "compartment" ) != std::string::npos )
|
( compartmentname.find( "compartment" ) == 0 )
|
||||||
|| ( compartmentname.find( "przedzial" ) != std::string::npos ) ) {
|
|| ( compartmentname.find( "przedzial" ) == 0 ) ) {
|
||||||
// compartments are lit with 75% probability
|
// compartments are lit with 75% probability
|
||||||
sectionlight.level = ( Random() < 0.75 ? 0.75f : 0.15f );
|
sectionlight.level = ( Random() < 0.75 ? 0.75f : 0.15f );
|
||||||
}
|
}
|
||||||
@@ -978,6 +978,22 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
|
|||||||
section.load->SetLightLevel( section.level, true );
|
section.load->SetLightLevel( section.level, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// load chunks visibility
|
||||||
|
for( auto const §ion : SectionLoadVisibility ) {
|
||||||
|
section.submodel->iVisible = section.visible;
|
||||||
|
if( false == section.visible ) {
|
||||||
|
// if the section root isn't visible we can skip meddling with its children
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// if the section root is visible set the state of section chunks
|
||||||
|
auto *sectionchunk { section.submodel->ChildGet() };
|
||||||
|
auto visiblechunkcount { section.visible_chunks };
|
||||||
|
while( sectionchunk != nullptr ) {
|
||||||
|
sectionchunk->iVisible = ( visiblechunkcount > 0 );
|
||||||
|
--visiblechunkcount;
|
||||||
|
sectionchunk = sectionchunk->NextGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ABu 29.01.05 koniec przeklejenia *************************************
|
// ABu 29.01.05 koniec przeklejenia *************************************
|
||||||
|
|
||||||
@@ -1797,8 +1813,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
|||||||
{
|
{
|
||||||
size_t dlugosc = MoreParams.length();
|
size_t dlugosc = MoreParams.length();
|
||||||
ActPar = ToUpper(MoreParams.substr(0, kropka)); // pierwszy parametr;
|
ActPar = ToUpper(MoreParams.substr(0, kropka)); // pierwszy parametr;
|
||||||
MoreParams = MoreParams.substr(kropka + 1, dlugosc - kropka); // reszta do dalszej
|
MoreParams = MoreParams.substr(kropka + 1, dlugosc - kropka); // reszta do dalszej obrobki
|
||||||
// obrobki
|
|
||||||
kropka = MoreParams.find(".");
|
kropka = MoreParams.find(".");
|
||||||
|
|
||||||
if (ActPar.substr(0, 1) == "B") // jesli hamulce
|
if (ActPar.substr(0, 1) == "B") // jesli hamulce
|
||||||
@@ -1910,6 +1925,41 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
} // koniec hamulce
|
} // koniec hamulce
|
||||||
|
else if( ( ActPar.size() >= 3 )
|
||||||
|
&& ( ActPar.substr( 0, 2 ) == "WF" ) ) {
|
||||||
|
// wheel flat
|
||||||
|
// TODO: convert this whole mess to something more elegant one day
|
||||||
|
ActPar.erase( 0, 2 );
|
||||||
|
auto fixedflatsize { 0 };
|
||||||
|
{
|
||||||
|
// fixed size flat
|
||||||
|
auto const indexend { ActPar.find_first_not_of( "1234567890", 0 ) };
|
||||||
|
fixedflatsize = std::atoi( ActPar.substr( 0, indexend ).c_str() );
|
||||||
|
ActPar.erase( 0, indexend );
|
||||||
|
}
|
||||||
|
// optional parameters
|
||||||
|
auto randomflatsize { 0 };
|
||||||
|
auto randomflatchance { 100 };
|
||||||
|
while( false == ActPar.empty() ) {
|
||||||
|
if( ActPar[ 0 ] == 'R' ) {
|
||||||
|
// random flat size
|
||||||
|
auto const indexstart { 1 };
|
||||||
|
auto const indexend { ActPar.find_first_not_of( "1234567890", indexstart ) };
|
||||||
|
randomflatsize = std::atoi( ActPar.substr( indexstart, indexend ).c_str() );
|
||||||
|
ActPar.erase( 0, indexend );
|
||||||
|
}
|
||||||
|
else if( ActPar[ 0 ] == 'P' ) {
|
||||||
|
// random flat probability
|
||||||
|
auto const indexstart { 1 };
|
||||||
|
auto const indexend { ActPar.find_first_not_of( "1234567890", indexstart ) };
|
||||||
|
randomflatchance = std::atoi( ActPar.substr( indexstart, indexend ).c_str() );
|
||||||
|
ActPar.erase( 0, indexend );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( Random(0, 100) <= randomflatchance ) {
|
||||||
|
MoverParameters->WheelFlat += fixedflatsize + Random( 0, randomflatsize );
|
||||||
|
}
|
||||||
|
}
|
||||||
/* else if (ActPar.substr(0, 1) == "") // tu mozna wpisac inny prefiks i inne rzeczy
|
/* else if (ActPar.substr(0, 1) == "") // tu mozna wpisac inny prefiks i inne rzeczy
|
||||||
{
|
{
|
||||||
// jakies inne prefiksy
|
// jakies inne prefiksy
|
||||||
@@ -2012,9 +2062,9 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
|||||||
// check the low poly interior for potential compartments of interest, ie ones which can be individually lit
|
// check the low poly interior for potential compartments of interest, ie ones which can be individually lit
|
||||||
// TODO: definition of relevant compartments in the .mmd file
|
// TODO: definition of relevant compartments in the .mmd file
|
||||||
TSubModel *submodel { nullptr };
|
TSubModel *submodel { nullptr };
|
||||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab1" ) ) != nullptr ) { SectionLightLevels.emplace_back( submodel, nullptr, 0.0f ); }
|
if( ( submodel = mdLowPolyInt->GetFromName( "cab1" ) ) != nullptr ) { SectionLightLevels.push_back( { submodel, nullptr, 0.0f } ); }
|
||||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab2" ) ) != nullptr ) { SectionLightLevels.emplace_back( submodel, nullptr, 0.0f ); }
|
if( ( submodel = mdLowPolyInt->GetFromName( "cab2" ) ) != nullptr ) { SectionLightLevels.push_back( { submodel, nullptr, 0.0f } ); }
|
||||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab0" ) ) != nullptr ) { SectionLightLevels.emplace_back( submodel, nullptr, 0.0f ); }
|
if( ( submodel = mdLowPolyInt->GetFromName( "cab0" ) ) != nullptr ) { SectionLightLevels.push_back( { submodel, nullptr, 0.0f } ); }
|
||||||
// passenger car compartments
|
// passenger car compartments
|
||||||
std::vector<std::string> nameprefixes = { "corridor", "korytarz", "compartment", "przedzial" };
|
std::vector<std::string> nameprefixes = { "corridor", "korytarz", "compartment", "przedzial" };
|
||||||
int compartmentindex;
|
int compartmentindex;
|
||||||
@@ -2029,19 +2079,17 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
|||||||
std::to_string( compartmentindex ) );
|
std::to_string( compartmentindex ) );
|
||||||
submodel = mdLowPolyInt->GetFromName( compartmentname );
|
submodel = mdLowPolyInt->GetFromName( compartmentname );
|
||||||
if( submodel != nullptr ) {
|
if( submodel != nullptr ) {
|
||||||
// if specified compartment was found we check also for potential matching section in the currently assigned load
|
SectionLightLevels.push_back( {
|
||||||
// NOTE: if the load gets changed this will invalidate stored pointers. TODO: rebuild the table on load change
|
|
||||||
SectionLightLevels.emplace_back(
|
|
||||||
submodel,
|
submodel,
|
||||||
( mdLoad != nullptr ?
|
nullptr, // pointers to load sections are generated afterwards
|
||||||
mdLoad->GetFromName( compartmentname ):
|
0.0f } );
|
||||||
nullptr ),
|
|
||||||
0.0f );
|
|
||||||
}
|
}
|
||||||
++compartmentindex;
|
++compartmentindex;
|
||||||
} while( ( submodel != nullptr )
|
} while( ( submodel != nullptr )
|
||||||
|| ( compartmentindex < 2 ) ); // chain can start from prefix00 or prefix01
|
|| ( compartmentindex < 2 ) ); // chain can start from prefix00 or prefix01
|
||||||
}
|
}
|
||||||
|
update_load_sections();
|
||||||
|
update_load_visibility();
|
||||||
}
|
}
|
||||||
// wyszukiwanie zderzakow
|
// wyszukiwanie zderzakow
|
||||||
if( mdModel ) {
|
if( mdModel ) {
|
||||||
@@ -2430,31 +2478,115 @@ bool TDynamicObject::UpdateForce(double dt, double dt1, bool FullVer)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TDynamicObject::LoadUpdate()
|
void TDynamicObject::LoadUpdate() {
|
||||||
{ // przeładowanie modelu ładunku
|
// przeładowanie modelu ładunku
|
||||||
// Ra: nie próbujemy wczytywać modeli miliony razy podczas renderowania!!!
|
// Ra: nie próbujemy wczytywać modeli miliony razy podczas renderowania!!!
|
||||||
if ((mdLoad == NULL) && (MoverParameters->Load > 0))
|
if( ( mdLoad == nullptr )
|
||||||
{
|
&& ( MoverParameters->Load > 0 ) ) {
|
||||||
std::string asLoadName =
|
|
||||||
asBaseDir + MoverParameters->LoadType + ".t3d"; // zapamiętany katalog pojazdu
|
if( false == MoverParameters->LoadType.empty() ) {
|
||||||
// asLoadName=MoverParameters->LoadType;
|
|
||||||
// if (MoverParameters->LoadType!=AnsiString("passengers"))
|
Global.asCurrentTexturePath = asBaseDir; // bieżąca ścieżka do tekstur to dynamic/...
|
||||||
Global.asCurrentTexturePath = asBaseDir; // bieżąca ścieżka do tekstur to dynamic/...
|
|
||||||
mdLoad = TModelsManager::GetModel(asLoadName.c_str()); // nowy ładunek
|
// try first specialized version of the load model, vehiclename_loadname
|
||||||
Global.asCurrentTexturePath =
|
auto const specializedloadfilename { asBaseDir + MoverParameters->TypeName + "_" + MoverParameters->LoadType };
|
||||||
std::string(szTexturePath); // z powrotem defaultowa sciezka do tekstur
|
if( ( true == FileExists( specializedloadfilename + ".e3d" ) )
|
||||||
// Ra: w MMD można by zapisać położenie modelu ładunku (np. węgiel) w
|
|| ( true == FileExists( specializedloadfilename + ".t3d" ) ) ) {
|
||||||
// zależności od
|
mdLoad = TModelsManager::GetModel( specializedloadfilename, true );
|
||||||
// załadowania
|
}
|
||||||
|
if( mdLoad == nullptr ) {
|
||||||
|
// if this fails, try generic load model
|
||||||
|
mdLoad = TModelsManager::GetModel( asBaseDir + MoverParameters->LoadType, true );
|
||||||
|
}
|
||||||
|
if( mdLoad != nullptr ) {
|
||||||
|
// TODO: discern from vehicle component which merely uses vehicle directory and has no animations, so it can be initialized outright
|
||||||
|
// and actual vehicles which get their initialization after their animations are set up
|
||||||
|
mdLoad->Init();
|
||||||
|
}
|
||||||
|
// update bindings between lowpoly sections and potential load chunks placed inside them
|
||||||
|
update_load_sections();
|
||||||
|
|
||||||
|
Global.asCurrentTexturePath = std::string( szTexturePath ); // z powrotem defaultowa sciezka do tekstur
|
||||||
|
}
|
||||||
|
// Ra: w MMD można by zapisać położenie modelu ładunku (np. węgiel) w zależności od załadowania
|
||||||
|
}
|
||||||
|
else if( MoverParameters->Load == 0 ) {
|
||||||
|
// nie ma ładunku
|
||||||
|
mdLoad = nullptr;
|
||||||
|
// erase bindings between lowpoly sections and potential load chunks placed inside them
|
||||||
|
update_load_sections();
|
||||||
}
|
}
|
||||||
else if (MoverParameters->Load == 0)
|
|
||||||
mdLoad = NULL; // nie ma ładunku
|
|
||||||
// if ((mdLoad==NULL)&&(MoverParameters->Load>0))
|
|
||||||
// {
|
|
||||||
// mdLoad=NULL; //Ra: to jest tu bez sensu - co autor miał na myśli?
|
|
||||||
// }
|
|
||||||
MoverParameters->LoadStatus &= 3; // po zakończeniu będzie równe zero
|
MoverParameters->LoadStatus &= 3; // po zakończeniu będzie równe zero
|
||||||
};
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TDynamicObject::update_load_sections() {
|
||||||
|
|
||||||
|
SectionLoadVisibility.clear();
|
||||||
|
|
||||||
|
for( auto §ion : SectionLightLevels ) {
|
||||||
|
|
||||||
|
section.load = (
|
||||||
|
mdLoad != nullptr ?
|
||||||
|
mdLoad->GetFromName( section.compartment->pName ) :
|
||||||
|
nullptr );
|
||||||
|
|
||||||
|
if( ( section.load != nullptr )
|
||||||
|
&& ( section.load->count_children() > 0 ) ) {
|
||||||
|
SectionLoadVisibility.push_back( { section.load, false } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shuffle_load_sections();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TDynamicObject::update_load_visibility() {
|
||||||
|
|
||||||
|
if( Random() < 0.25 ) {
|
||||||
|
shuffle_load_sections();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto loadpercentage { (
|
||||||
|
MoverParameters->MaxLoad == 0.0 ?
|
||||||
|
0.0 :
|
||||||
|
100.0 * MoverParameters->Load / MoverParameters->MaxLoad ) };
|
||||||
|
auto const sectionloadpercentage { (
|
||||||
|
SectionLoadVisibility.empty() ?
|
||||||
|
0.0 :
|
||||||
|
100.0 / SectionLoadVisibility.size() ) };
|
||||||
|
// set as many sections as we can, given overall load percentage and how much of full percentage is covered by each chunk
|
||||||
|
std::for_each(
|
||||||
|
std::begin( SectionLoadVisibility ), std::end( SectionLoadVisibility ),
|
||||||
|
[&]( section_visibility §ion ) {
|
||||||
|
section.visible = ( loadpercentage > 0.0 );
|
||||||
|
section.visible_chunks = 0;
|
||||||
|
auto const sectionchunkcount { section.submodel->count_children() };
|
||||||
|
auto const sectionchunkloadpercentage{ (
|
||||||
|
sectionchunkcount == 0 ?
|
||||||
|
0.0 :
|
||||||
|
sectionloadpercentage / sectionchunkcount ) };
|
||||||
|
auto *sectionchunk { section.submodel->ChildGet() };
|
||||||
|
while( sectionchunk != nullptr ) {
|
||||||
|
if( loadpercentage > 0.0 ) {
|
||||||
|
++section.visible_chunks;
|
||||||
|
loadpercentage -= sectionchunkloadpercentage;
|
||||||
|
}
|
||||||
|
sectionchunk = sectionchunk->NextGet();
|
||||||
|
} } );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TDynamicObject::shuffle_load_sections() {
|
||||||
|
|
||||||
|
std::shuffle( std::begin( SectionLoadVisibility ), std::end( SectionLoadVisibility ), Global.random_engine );
|
||||||
|
// shift chunks assigned to corridors to the end of the list, so they show up last
|
||||||
|
std::stable_partition(
|
||||||
|
std::begin( SectionLoadVisibility ), std::end( SectionLoadVisibility ),
|
||||||
|
[]( section_visibility const §ion ) {
|
||||||
|
return (
|
||||||
|
( section.submodel->pName.find( "compartment" ) == 0 )
|
||||||
|
|| ( section.submodel->pName.find( "przedzial" ) == 0 ) ); } );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Ra:
|
Ra:
|
||||||
@@ -3639,7 +3771,7 @@ void TDynamicObject::RenderSounds() {
|
|||||||
}
|
}
|
||||||
// NBMX Obsluga drzwi, MC: zuniwersalnione
|
// NBMX Obsluga drzwi, MC: zuniwersalnione
|
||||||
if( ( true == MoverParameters->DoorLeftOpened )
|
if( ( true == MoverParameters->DoorLeftOpened )
|
||||||
&& ( dDoorMoveL < MoverParameters->DoorMaxShiftL ) ) {
|
&& ( dDoorMoveL < MoverParameters->DoorMaxShiftL ) ) {
|
||||||
|
|
||||||
for( auto &door : m_doorsounds ) {
|
for( auto &door : m_doorsounds ) {
|
||||||
if( door.rsDoorClose.offset().x > 0.f ) {
|
if( door.rsDoorClose.offset().x > 0.f ) {
|
||||||
@@ -3650,7 +3782,7 @@ void TDynamicObject::RenderSounds() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( ( false == MoverParameters->DoorLeftOpened )
|
if( ( false == MoverParameters->DoorLeftOpened )
|
||||||
&& ( dDoorMoveL > 0.01 ) ) {
|
&& ( dDoorMoveL > 0.01 ) ) {
|
||||||
|
|
||||||
for( auto &door : m_doorsounds ) {
|
for( auto &door : m_doorsounds ) {
|
||||||
if( door.rsDoorClose.offset().x > 0.f ) {
|
if( door.rsDoorClose.offset().x > 0.f ) {
|
||||||
@@ -3661,7 +3793,7 @@ void TDynamicObject::RenderSounds() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( ( true == MoverParameters->DoorRightOpened )
|
if( ( true == MoverParameters->DoorRightOpened )
|
||||||
&& ( dDoorMoveR < MoverParameters->DoorMaxShiftR ) ) {
|
&& ( dDoorMoveR < MoverParameters->DoorMaxShiftR ) ) {
|
||||||
|
|
||||||
for( auto &door : m_doorsounds ) {
|
for( auto &door : m_doorsounds ) {
|
||||||
if( door.rsDoorClose.offset().x < 0.f ) {
|
if( door.rsDoorClose.offset().x < 0.f ) {
|
||||||
@@ -3672,7 +3804,7 @@ void TDynamicObject::RenderSounds() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( ( false == MoverParameters->DoorRightOpened )
|
if( ( false == MoverParameters->DoorRightOpened )
|
||||||
&& ( dDoorMoveR > 0.01 ) ) {
|
&& ( dDoorMoveR > 0.01 ) ) {
|
||||||
|
|
||||||
for( auto &door : m_doorsounds ) {
|
for( auto &door : m_doorsounds ) {
|
||||||
if( door.rsDoorClose.offset().x < 0.f ) {
|
if( door.rsDoorClose.offset().x < 0.f ) {
|
||||||
@@ -3855,7 +3987,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
|
|||||||
std::string asFileName = BaseDir + TypeName + ".mmd";
|
std::string asFileName = BaseDir + TypeName + ".mmd";
|
||||||
std::string asLoadName;
|
std::string asLoadName;
|
||||||
if( false == MoverParameters->LoadType.empty() ) {
|
if( false == MoverParameters->LoadType.empty() ) {
|
||||||
asLoadName = BaseDir + MoverParameters->LoadType + ".t3d";
|
asLoadName = BaseDir + MoverParameters->LoadType;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string asAnimName;
|
std::string asAnimName;
|
||||||
|
|||||||
12
DynObj.h
12
DynObj.h
@@ -195,13 +195,16 @@ public:
|
|||||||
TSubModel *compartment;
|
TSubModel *compartment;
|
||||||
TSubModel *load;
|
TSubModel *load;
|
||||||
float level;
|
float level;
|
||||||
section_light( TSubModel *Compartment, TSubModel *Load, float const Level ) :
|
|
||||||
compartment(Compartment), load(Load), level(Level)
|
|
||||||
{}
|
|
||||||
};
|
};
|
||||||
std::vector<section_light> SectionLightLevels; // table of light levels for specific compartments of associated 3d model
|
std::vector<section_light> SectionLightLevels; // table of light levels for specific compartments of associated 3d model
|
||||||
bool SectionLightsActive { false }; // flag indicating whether section lights were set.
|
bool SectionLightsActive { false }; // flag indicating whether section lights were set.
|
||||||
float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?)
|
float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?)
|
||||||
|
struct section_visibility {
|
||||||
|
TSubModel *submodel;
|
||||||
|
bool visible;
|
||||||
|
int visible_chunks;
|
||||||
|
};
|
||||||
|
std::vector<section_visibility> SectionLoadVisibility; // visibility of specific sections of the load 3d model
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe
|
// zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe
|
||||||
@@ -465,6 +468,9 @@ private:
|
|||||||
void AttachPrev(TDynamicObject *Object, int iType = 1);
|
void AttachPrev(TDynamicObject *Object, int iType = 1);
|
||||||
bool UpdateForce(double dt, double dt1, bool FullVer);
|
bool UpdateForce(double dt, double dt1, bool FullVer);
|
||||||
void LoadUpdate();
|
void LoadUpdate();
|
||||||
|
void update_load_sections();
|
||||||
|
void update_load_visibility();
|
||||||
|
void shuffle_load_sections();
|
||||||
bool Update(double dt, double dt1);
|
bool Update(double dt, double dt1);
|
||||||
bool FastUpdate(double dt);
|
bool FastUpdate(double dt);
|
||||||
void Move(double fDistance);
|
void Move(double fDistance);
|
||||||
|
|||||||
2
EU07.cpp
2
EU07.cpp
@@ -259,7 +259,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Global.asVersion = "M7 16.02.2018 (based on tmj 180215)";
|
Global.asVersion = "M7 24.02.2018 (based on tmj 7440b1d)";
|
||||||
|
|
||||||
for (int i = 1; i < argc; ++i)
|
for (int i = 1; i < argc; ++i)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ struct global_settings {
|
|||||||
float fFriction{ 1.f }; // mnożnik tarcia - KURS90
|
float fFriction{ 1.f }; // mnożnik tarcia - KURS90
|
||||||
bool bLiveTraction{ true };
|
bool bLiveTraction{ true };
|
||||||
float Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
|
float Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
|
||||||
GLfloat FogColor[ 3 ] = { 0.6f, 0.7f, 0.8f };
|
glm::vec3 FogColor = { 0.6f, 0.7f, 0.8f };
|
||||||
double fFogStart{ 1700 };
|
double fFogStart{ 1700 };
|
||||||
double fFogEnd{ 2000 };
|
double fFogEnd{ 2000 };
|
||||||
std::string Season{}; // season of the year, based on simulation date
|
std::string Season{}; // season of the year, based on simulation date
|
||||||
|
|||||||
@@ -1021,7 +1021,7 @@ public:
|
|||||||
int PulseForceCount = 0;
|
int PulseForceCount = 0;
|
||||||
|
|
||||||
/*dla drezyny, silnika spalinowego i parowego*/
|
/*dla drezyny, silnika spalinowego i parowego*/
|
||||||
double eAngle = 1.5;
|
double eAngle = M_PI * 0.5;
|
||||||
|
|
||||||
/*-dla wagonow*/
|
/*-dla wagonow*/
|
||||||
double Load = 0.0; /*masa w T lub ilosc w sztukach - zaladowane*/
|
double Load = 0.0; /*masa w T lub ilosc w sztukach - zaladowane*/
|
||||||
|
|||||||
@@ -8516,7 +8516,8 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
|||||||
else if (Command == "PantFront") /*Winger 160204*/
|
else if (Command == "PantFront") /*Winger 160204*/
|
||||||
{ // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
|
{ // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
|
||||||
// Czemu EZT ma być traktowane inaczej? Ukrotnienie ma, a człon może być odwrócony
|
// Czemu EZT ma być traktowane inaczej? Ukrotnienie ma, a człon może być odwrócony
|
||||||
if ((TrainType == dt_EZT))
|
if ((TrainType == dt_EZT)
|
||||||
|
|| (TrainType == dt_ET41))
|
||||||
{ //'ezt'
|
{ //'ezt'
|
||||||
if ((CValue1 == 1))
|
if ((CValue1 == 1))
|
||||||
{
|
{
|
||||||
@@ -8560,7 +8561,8 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
|||||||
}
|
}
|
||||||
else if (Command == "PantRear") /*Winger 160204, ABu 310105 i 030305*/
|
else if (Command == "PantRear") /*Winger 160204, ABu 310105 i 030305*/
|
||||||
{ // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
|
{ // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
|
||||||
if ((TrainType == dt_EZT))
|
if ((TrainType == dt_EZT)
|
||||||
|
||(TrainType == dt_ET41))
|
||||||
{ //'ezt'
|
{ //'ezt'
|
||||||
if ((CValue1 == 1))
|
if ((CValue1 == 1))
|
||||||
{
|
{
|
||||||
|
|||||||
19
Model3d.cpp
19
Model3d.cpp
@@ -729,6 +729,25 @@ void TSubModel::NextAdd(TSubModel *SubModel)
|
|||||||
Next = SubModel;
|
Next = SubModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int TSubModel::count_siblings() {
|
||||||
|
|
||||||
|
auto siblingcount { 0 };
|
||||||
|
auto *sibling { Next };
|
||||||
|
while( sibling != nullptr ) {
|
||||||
|
++siblingcount;
|
||||||
|
sibling = sibling->Next;
|
||||||
|
}
|
||||||
|
return siblingcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TSubModel::count_children() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
Child == nullptr ?
|
||||||
|
0 :
|
||||||
|
1 + Child->count_siblings() );
|
||||||
|
}
|
||||||
|
|
||||||
int TSubModel::FlagsCheck()
|
int TSubModel::FlagsCheck()
|
||||||
{ // analiza koniecznych zmian pomiędzy submodelami
|
{ // analiza koniecznych zmian pomiędzy submodelami
|
||||||
// samo pomijanie glBindTexture() nie poprawi wydajności
|
// samo pomijanie glBindTexture() nie poprawi wydajności
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ public:
|
|||||||
void NextAdd(TSubModel *SubModel);
|
void NextAdd(TSubModel *SubModel);
|
||||||
TSubModel * NextGet() { return Next; };
|
TSubModel * NextGet() { return Next; };
|
||||||
TSubModel * ChildGet() { return Child; };
|
TSubModel * ChildGet() { return Child; };
|
||||||
|
int count_siblings();
|
||||||
|
int count_children();
|
||||||
int TriangleAdd(TModel3d *m, material_handle tex, int tri);
|
int TriangleAdd(TModel3d *m, material_handle tex, int tri);
|
||||||
void SetRotate(float3 vNewRotateAxis, float fNewAngle);
|
void SetRotate(float3 vNewRotateAxis, float fNewAngle);
|
||||||
void SetRotateXYZ( Math3D::vector3 vNewAngles);
|
void SetRotateXYZ( Math3D::vector3 vNewAngles);
|
||||||
|
|||||||
44
Spring.cpp
44
Spring.cpp
@@ -10,48 +10,31 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Spring.h"
|
#include "Spring.h"
|
||||||
|
|
||||||
TSpring::TSpring()
|
void TSpring::Init(double nKs, double nKd) {
|
||||||
{
|
|
||||||
vForce1 = vForce2 = Math3D::vector3(0, 0, 0);
|
|
||||||
Ks = 0;
|
|
||||||
Kd = 0;
|
|
||||||
restLen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
TSpring::~TSpring()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void TSpring::Init(double nrestLen, double nKs, double nKd)
|
|
||||||
{
|
|
||||||
Ks = nKs;
|
Ks = nKs;
|
||||||
Kd = nKd;
|
Kd = nKd;
|
||||||
restLen = nrestLen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Math3D::vector3 TSpring::ComputateForces( Math3D::vector3 const &pPosition1, Math3D::vector3 const &pPosition2)
|
Math3D::vector3 TSpring::ComputateForces( Math3D::vector3 const &pPosition1, Math3D::vector3 const &pPosition2) {
|
||||||
{
|
|
||||||
|
|
||||||
double dist, Hterm, Dterm;
|
Math3D::vector3 springForce;
|
||||||
Math3D::vector3 springForce, deltaV;
|
|
||||||
// p1 = &system[spring->p1];
|
// p1 = &system[spring->p1];
|
||||||
// p2 = &system[spring->p2];
|
// p2 = &system[spring->p2];
|
||||||
// VectorDifference(&p1->pos,&p2->pos,&deltaP); // Vector distance
|
// VectorDifference(&p1->pos,&p2->pos,&deltaP); // Vector distance
|
||||||
auto deltaP = pPosition1 - pPosition2;
|
auto deltaP = pPosition1 - pPosition2;
|
||||||
// dist = VectorLength(&deltaP); // Magnitude of
|
// dist = VectorLength(&deltaP); // Magnitude of deltaP
|
||||||
// deltaP
|
auto dist = deltaP.Length();
|
||||||
dist = deltaP.Length();
|
if( dist > restLen ) {
|
||||||
if (dist != 0.0 ) {
|
|
||||||
|
|
||||||
// Hterm = (dist - spring->restLen) * spring->Ks; // Ks * (dist - rest)
|
// Hterm = (dist - spring->restLen) * spring->Ks; // Ks * (dist - rest)
|
||||||
Hterm = ( dist - restLen ) * Ks; // Ks * (dist - rest)
|
auto Hterm = ( dist - restLen ) * Ks; // Ks * (dist - rest)
|
||||||
|
|
||||||
// VectorDifference(&p1->v,&p2->v,&deltaV); // Delta Velocity Vector
|
// VectorDifference(&p1->v,&p2->v,&deltaV); // Delta Velocity Vector
|
||||||
deltaV = pPosition1 - pPosition2;
|
auto deltaV = pPosition1 - pPosition2;
|
||||||
|
|
||||||
// Dterm = (DotProduct(&deltaV,&deltaP) * spring->Kd) / dist; // Damping Term
|
// Dterm = (DotProduct(&deltaV,&deltaP) * spring->Kd) / dist; // Damping Term
|
||||||
// Dterm = (DotProduct(deltaV,deltaP) * Kd) / dist;
|
auto Dterm = (DotProduct(deltaV,deltaP) * Kd) / dist;
|
||||||
Dterm = 0;
|
//Dterm = 0;
|
||||||
|
|
||||||
// ScaleVector(&deltaP,1.0f / dist, &springForce); // Normalize Distance Vector
|
// ScaleVector(&deltaP,1.0f / dist, &springForce); // Normalize Distance Vector
|
||||||
// ScaleVector(&springForce,-(Hterm + Dterm),&springForce); // Calc Force
|
// ScaleVector(&springForce,-(Hterm + Dterm),&springForce); // Calc Force
|
||||||
@@ -60,14 +43,7 @@ Math3D::vector3 TSpring::ComputateForces( Math3D::vector3 const &pPosition1, Mat
|
|||||||
// VectorDifference(&p2->f,&springForce,&p2->f); // - Force on Particle 2
|
// VectorDifference(&p2->f,&springForce,&p2->f); // - Force on Particle 2
|
||||||
}
|
}
|
||||||
|
|
||||||
vForce1 = springForce;
|
|
||||||
vForce2 = springForce;
|
|
||||||
|
|
||||||
return springForce;
|
return springForce;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TSpring::Render()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
25
Spring.h
25
Spring.h
@@ -11,9 +11,8 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#define ParticlesH
|
#define ParticlesH
|
||||||
|
|
||||||
#include "dumb3d.h"
|
#include "dumb3d.h"
|
||||||
|
/*
|
||||||
#define STATIC_THRESHOLD 0.17f
|
#define STATIC_THRESHOLD 0.17f
|
||||||
// efine STATIC_THRESHOLD 0.03f
|
|
||||||
const double m_Kd = 0.02f; // DAMPING FACTOR
|
const double m_Kd = 0.02f; // DAMPING FACTOR
|
||||||
const double m_Kr = 0.8f; // 1.0 = SUPERBALL BOUNCE 0.0 = DEAD WEIGHT
|
const double m_Kr = 0.8f; // 1.0 = SUPERBALL BOUNCE 0.0 = DEAD WEIGHT
|
||||||
const double m_Ksh = 5.0f; // HOOK'S SPRING CONSTANT
|
const double m_Ksh = 5.0f; // HOOK'S SPRING CONSTANT
|
||||||
@@ -21,22 +20,20 @@ const double m_Ksd = 0.1f; // SPRING DAMPING CONSTANT
|
|||||||
|
|
||||||
const double m_Csf = 0.9f; // Default Static Friction
|
const double m_Csf = 0.9f; // Default Static Friction
|
||||||
const double m_Ckf = 0.7f; // Default Kinetic Friction
|
const double m_Ckf = 0.7f; // Default Kinetic Friction
|
||||||
|
*/
|
||||||
|
class TSpring {
|
||||||
|
|
||||||
class TSpring
|
public:
|
||||||
{
|
TSpring() = default;
|
||||||
public:
|
|
||||||
TSpring();
|
|
||||||
~TSpring();
|
|
||||||
// void Init(TParticnp1, TParticle *np2, double nKs= 0.5f, double nKd= 0.002f,
|
// void Init(TParticnp1, TParticle *np2, double nKs= 0.5f, double nKd= 0.002f,
|
||||||
// double nrestLen= -1.0f);
|
// double nrestLen= -1.0f);
|
||||||
void Init(double nrestLen, double nKs = 0.5f, double nKd = 0.002f);
|
void Init(double nKs = 0.5f, double nKd = 0.002f);
|
||||||
Math3D::vector3 ComputateForces( Math3D::vector3 const &pPosition1, Math3D::vector3 const &pPosition2);
|
Math3D::vector3 ComputateForces( Math3D::vector3 const &pPosition1, Math3D::vector3 const &pPosition2);
|
||||||
void Render();
|
private:
|
||||||
Math3D::vector3 vForce1, vForce2;
|
// members
|
||||||
double restLen; // LENGTH OF SPRING AT REST
|
double restLen { 0.01 }; // LENGTH OF SPRING AT REST
|
||||||
double Ks; // SPRING CONSTANT
|
double Ks { 0.0 }; // SPRING CONSTANT
|
||||||
double Kd; // SPRING DAMPING
|
double Kd { 0.0 }; // SPRING DAMPING
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
132
Train.cpp
132
Train.cpp
@@ -380,7 +380,7 @@ bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
MechSpring.Init(0.015, 250);
|
MechSpring.Init(250);
|
||||||
vMechVelocity = Math3D::vector3(0, 0, 0);
|
vMechVelocity = Math3D::vector3(0, 0, 0);
|
||||||
pMechOffset = Math3D::vector3( 0, 0, 0 );
|
pMechOffset = Math3D::vector3( 0, 0, 0 );
|
||||||
fMechSpringX = 1;
|
fMechSpringX = 1;
|
||||||
@@ -3312,9 +3312,10 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// in the rear cab sides are reversed
|
// in the rear cab sides are reversed...
|
||||||
if( Train->mvOccupied->DoorRight( true ) ) {
|
if( Train->mvOccupied->DoorRight( true ) ) {
|
||||||
Train->ggDoorRightButton.UpdateValue( 1.0, Train->dsbSwitch );
|
// ...but so are the switches
|
||||||
|
Train->ggDoorLeftButton.UpdateValue( 1.0, Train->dsbSwitch );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3326,9 +3327,10 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// in the rear cab sides are reversed
|
// in the rear cab sides are reversed...
|
||||||
if( Train->mvOccupied->DoorRight( false ) ) {
|
if( Train->mvOccupied->DoorRight( false ) ) {
|
||||||
Train->ggDoorRightButton.UpdateValue( 0.0, Train->dsbSwitch );
|
// ...but so are the switches
|
||||||
|
Train->ggDoorLeftButton.UpdateValue( 0.0, Train->dsbSwitch );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3353,9 +3355,10 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// in the rear cab sides are reversed
|
// in the rear cab sides are reversed...
|
||||||
if( Train->mvOccupied->DoorLeft( true ) ) {
|
if( Train->mvOccupied->DoorLeft( true ) ) {
|
||||||
Train->ggDoorLeftButton.UpdateValue( 1.0, Train->dsbSwitch );
|
// ...but so are the switches
|
||||||
|
Train->ggDoorRightButton.UpdateValue( 1.0, Train->dsbSwitch );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3367,9 +3370,10 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// in the rear cab sides are reversed
|
// in the rear cab sides are reversed...
|
||||||
if( Train->mvOccupied->DoorLeft( false ) ) {
|
if( Train->mvOccupied->DoorLeft( false ) ) {
|
||||||
Train->ggDoorLeftButton.UpdateValue( 0.0, Train->dsbSwitch );
|
// ...but so are the switches
|
||||||
|
Train->ggDoorRightButton.UpdateValue( 0.0, Train->dsbSwitch );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3667,50 +3671,72 @@ void TTrain::UpdateMechPosition(double dt)
|
|||||||
// Granice mozna ustalic doswiadczalnie. Ja proponuje 14:20
|
// Granice mozna ustalic doswiadczalnie. Ja proponuje 14:20
|
||||||
double const iVel = std::min( DynamicObject->GetVelocity(), 150.0 );
|
double const iVel = std::min( DynamicObject->GetVelocity(), 150.0 );
|
||||||
|
|
||||||
if( !Global.iSlowMotion // musi być pełna prędkość
|
if( ( false == Global.iSlowMotion ) // musi być pełna prędkość
|
||||||
&& ( pMechOffset.y < 4.0 ) ) // Ra 15-01: przy oglądaniu pantografu bujanie przeszkadza
|
&& ( pMechOffset.y < 4.0 ) ) // Ra 15-01: przy oglądaniu pantografu bujanie przeszkadza
|
||||||
{
|
{
|
||||||
|
Math3D::vector3 shakevector;
|
||||||
|
if( ( mvOccupied->EngineType == DieselElectric )
|
||||||
|
|| ( mvOccupied->EngineType == DieselEngine ) ) {
|
||||||
|
if( std::abs( mvOccupied->enrot ) > 0.0 ) {
|
||||||
|
// engine vibration
|
||||||
|
shakevector.x +=
|
||||||
|
( std::cos( mvOccupied->eAngle * 4.0 ) * dt * EngineShake.scale )
|
||||||
|
// fade in with rpm above threshold
|
||||||
|
* clamp(
|
||||||
|
( mvOccupied->enrot - EngineShake.fadein_offset ) * EngineShake.fadein_factor,
|
||||||
|
0.0, 1.0 )
|
||||||
|
// fade out with rpm above threshold
|
||||||
|
* interpolate(
|
||||||
|
1.0, 0.0,
|
||||||
|
clamp(
|
||||||
|
( mvOccupied->enrot - EngineShake.fadeout_offset ) * EngineShake.fadeout_factor,
|
||||||
|
0.0, 1.0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
if( iVel > 0.5 ) {
|
if( iVel > 0.5 ) {
|
||||||
// acceleration-driven base shake
|
// acceleration-driven base shake
|
||||||
shake += 1.25 * MechSpring.ComputateForces(
|
shakevector += Math3D::vector3(
|
||||||
Math3D::vector3(
|
-mvOccupied->AccN * dt * 5.0, // highlight side sway
|
||||||
-mvControlled->AccN * dt * 5.0, // highlight side sway
|
-mvOccupied->AccVert * dt,
|
||||||
-mvControlled->AccVert * dt,
|
-mvOccupied->AccSVBased * dt * 1.25 ); // accent acceleration/deceleration
|
||||||
-mvControlled->AccSVBased * dt * 1.25 ), // accent acceleration/deceleration
|
|
||||||
pMechShake );
|
|
||||||
|
|
||||||
if( Random( iVel ) > 25.0 ) {
|
|
||||||
// extra shake at increased velocity
|
|
||||||
shake += MechSpring.ComputateForces(
|
|
||||||
Math3D::vector3(
|
|
||||||
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringX,
|
|
||||||
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringY,
|
|
||||||
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringZ )
|
|
||||||
* 1.25,
|
|
||||||
pMechShake );
|
|
||||||
// * (( 200 - DynamicObject->MyTrack->iQualityFlag ) * 0.0075 ); // scale to 75-150% based on track quality
|
|
||||||
}
|
|
||||||
// shake *= 0.85;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shake += 1.25 * MechSpring.ComputateForces( shakevector, pMechShake );
|
||||||
|
|
||||||
|
if( Random( iVel ) > 25.0 ) {
|
||||||
|
// extra shake at increased velocity
|
||||||
|
shake += MechSpring.ComputateForces(
|
||||||
|
Math3D::vector3(
|
||||||
|
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringX,
|
||||||
|
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringY,
|
||||||
|
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringZ )
|
||||||
|
* 1.25,
|
||||||
|
pMechShake );
|
||||||
|
// * (( 200 - DynamicObject->MyTrack->iQualityFlag ) * 0.0075 ); // scale to 75-150% based on track quality
|
||||||
|
}
|
||||||
|
shake *= 0.85;
|
||||||
|
|
||||||
vMechVelocity -= ( shake + vMechVelocity * 100 ) * ( fMechSpringX + fMechSpringY + fMechSpringZ ) / ( 200 );
|
vMechVelocity -= ( shake + vMechVelocity * 100 ) * ( fMechSpringX + fMechSpringY + fMechSpringZ ) / ( 200 );
|
||||||
// shake *= 0.95 * dt; // shake damping
|
// shake *= 0.95 * dt; // shake damping
|
||||||
|
|
||||||
// McZapkie:
|
// McZapkie:
|
||||||
pMechShake += vMechVelocity * dt;
|
pMechShake += vMechVelocity * dt;
|
||||||
|
if( ( pMechShake.y > fMechMaxSpring )
|
||||||
|
|| ( pMechShake.y < -fMechMaxSpring ) ) {
|
||||||
|
vMechVelocity.y = -vMechVelocity.y;
|
||||||
|
}
|
||||||
// Ra 2015-01: dotychczasowe rzucanie
|
// Ra 2015-01: dotychczasowe rzucanie
|
||||||
pMechOffset += vMechMovement * dt;
|
pMechOffset += vMechMovement * dt;
|
||||||
if( ( pMechShake.y > fMechMaxSpring ) || ( pMechShake.y < -fMechMaxSpring ) )
|
|
||||||
vMechVelocity.y = -vMechVelocity.y;
|
|
||||||
// ABu011104: 5*pMechShake.y, zeby ladnie pudlem rzucalo :)
|
// ABu011104: 5*pMechShake.y, zeby ladnie pudlem rzucalo :)
|
||||||
pMechPosition = pMechOffset + Math3D::vector3( 1.5 * pMechShake.x, 2.0 * pMechShake.y, 1.5 * pMechShake.z );
|
pMechPosition = pMechOffset + Math3D::vector3( 1.5 * pMechShake.x, 2.0 * pMechShake.y, 1.5 * pMechShake.z );
|
||||||
// vMechMovement = 0.5 * vMechMovement;
|
|
||||||
|
// pMechShake = interpolate( pMechShake, Math3D::vector3(), clamp( dt, 0.0, 1.0 ) );
|
||||||
}
|
}
|
||||||
else { // hamowanie rzucania przy spadku FPS
|
else { // hamowanie rzucania przy spadku FPS
|
||||||
pMechShake -= pMechShake * std::min( dt, 1.0 ); // po tym chyba potrafią zostać jakieś ułamki, które powodują zjazd
|
pMechShake -= pMechShake * std::min( dt, 1.0 ); // po tym chyba potrafią zostać jakieś ułamki, które powodują zjazd
|
||||||
pMechOffset += vMechMovement * dt;
|
pMechOffset += vMechMovement * dt;
|
||||||
vMechVelocity.y = 0.5 * vMechVelocity.y;
|
vMechVelocity.y = 0.5 * vMechVelocity.y;
|
||||||
pMechPosition = pMechOffset + Math3D::vector3( pMechShake.x, 5 * pMechShake.y, pMechShake.z );
|
pMechPosition = pMechOffset + Math3D::vector3( pMechShake.x, 5 * pMechShake.y, pMechShake.z );
|
||||||
// vMechMovement = 0.5 * vMechMovement;
|
|
||||||
}
|
}
|
||||||
// numer kabiny (-1: kabina B)
|
// numer kabiny (-1: kabina B)
|
||||||
if( DynamicObject->Mechanik ) // może nie być?
|
if( DynamicObject->Mechanik ) // może nie być?
|
||||||
@@ -4838,17 +4864,20 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
|
|
||||||
// NOTE: crude way to have the pantographs go back up if they're dropped due to insufficient pressure etc
|
// NOTE: crude way to have the pantographs go back up if they're dropped due to insufficient pressure etc
|
||||||
// TODO: rework it into something more elegant, when redoing the whole consist/unit/cab etc arrangement
|
// TODO: rework it into something more elegant, when redoing the whole consist/unit/cab etc arrangement
|
||||||
if( ( mvControlled->Battery )
|
if( false == DynamicObject->Mechanik->AIControllFlag ) {
|
||||||
|| ( mvControlled->ConverterFlag ) ) {
|
// don't mess with the ai driving, at least not while switches don't follow ai-set vehicle state
|
||||||
if( ggPantAllDownButton.GetDesiredValue() < 0.05 ) {
|
if( ( mvControlled->Battery )
|
||||||
// the 'lower all' button overrides state of switches, while active itself
|
|| ( mvControlled->ConverterFlag ) ) {
|
||||||
if( ( false == mvControlled->PantFrontUp )
|
if( ggPantAllDownButton.GetDesiredValue() < 0.05 ) {
|
||||||
&& ( ggPantFrontButton.GetDesiredValue() >= 0.95 ) ) {
|
// the 'lower all' button overrides state of switches, while active itself
|
||||||
mvControlled->PantFront( true );
|
if( ( false == mvControlled->PantFrontUp )
|
||||||
}
|
&& ( ggPantFrontButton.GetDesiredValue() >= 0.95 ) ) {
|
||||||
if( ( false == mvControlled->PantRearUp )
|
mvControlled->PantFront( true );
|
||||||
&& ( ggPantRearButton.GetDesiredValue() >= 0.95 ) ) {
|
}
|
||||||
mvControlled->PantRear( true );
|
if( ( false == mvControlled->PantRearUp )
|
||||||
|
&& ( ggPantRearButton.GetDesiredValue() >= 0.95 ) ) {
|
||||||
|
mvControlled->PantRear( true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4878,7 +4907,7 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
m_radiomessages.erase(
|
m_radiomessages.erase(
|
||||||
std::remove_if(
|
std::remove_if(
|
||||||
std::begin( m_radiomessages ), std::end( m_radiomessages ),
|
std::begin( m_radiomessages ), std::end( m_radiomessages ),
|
||||||
[]( sound_source &source ) {
|
[]( sound_source const &source ) {
|
||||||
return ( false == source.is_playing() ); } ),
|
return ( false == source.is_playing() ); } ),
|
||||||
std::end( m_radiomessages ) );
|
std::end( m_radiomessages ) );
|
||||||
}
|
}
|
||||||
@@ -5320,7 +5349,7 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
|
|||||||
parser
|
parser
|
||||||
>> ks
|
>> ks
|
||||||
>> kd;
|
>> kd;
|
||||||
MechSpring.Init(MechSpring.restLen, ks, kd);
|
MechSpring.Init(ks, kd);
|
||||||
parser.getTokens(6, false);
|
parser.getTokens(6, false);
|
||||||
parser
|
parser
|
||||||
>> fMechSpringX
|
>> fMechSpringX
|
||||||
@@ -5330,6 +5359,15 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
|
|||||||
>> fMechRoll
|
>> fMechRoll
|
||||||
>> fMechPitch;
|
>> fMechPitch;
|
||||||
}
|
}
|
||||||
|
else if( token == "enginespring:" ) {
|
||||||
|
parser.getTokens( 5, false );
|
||||||
|
parser
|
||||||
|
>> EngineShake.scale
|
||||||
|
>> EngineShake.fadein_offset
|
||||||
|
>> EngineShake.fadein_factor
|
||||||
|
>> EngineShake.fadeout_offset
|
||||||
|
>> EngineShake.fadeout_factor;
|
||||||
|
}
|
||||||
|
|
||||||
} while (token != "");
|
} while (token != "");
|
||||||
}
|
}
|
||||||
|
|||||||
7
Train.h
7
Train.h
@@ -503,6 +503,13 @@ public: // reszta może by?publiczna
|
|||||||
double fMechMaxSpring;
|
double fMechMaxSpring;
|
||||||
double fMechRoll;
|
double fMechRoll;
|
||||||
double fMechPitch;
|
double fMechPitch;
|
||||||
|
struct engineshake_config {
|
||||||
|
float scale { 2.f };
|
||||||
|
float fadein_offset { 1.5f };
|
||||||
|
float fadein_factor { 0.3f };
|
||||||
|
float fadeout_offset { 10.f };
|
||||||
|
float fadeout_factor { 0.5f };
|
||||||
|
} EngineShake;
|
||||||
|
|
||||||
sound_source dsbReverserKey { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // hunter-121211
|
sound_source dsbReverserKey { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // hunter-121211
|
||||||
sound_source dsbNastawnikJazdy { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
sound_source dsbNastawnikJazdy { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||||
|
|||||||
28
World.cpp
28
World.cpp
@@ -46,6 +46,7 @@ namespace simulation {
|
|||||||
|
|
||||||
simulation_time Time;
|
simulation_time Time;
|
||||||
|
|
||||||
|
basic_station Station;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -1093,10 +1094,13 @@ TWorld::Update_Camera( double const Deltatime ) {
|
|||||||
else {
|
else {
|
||||||
// patrzenie standardowe
|
// patrzenie standardowe
|
||||||
Camera.Pos = Train->GetWorldMechPosition(); // Train.GetPosition1();
|
Camera.Pos = Train->GetWorldMechPosition(); // Train.GetPosition1();
|
||||||
if( !Global.iPause ) { // podczas pauzy nie przeliczać kątów przypadkowymi wartościami
|
if( !Global.iPause ) {
|
||||||
Camera.Roll = atan( Train->pMechShake.x * Train->fMechRoll ); // hustanie kamery na boki
|
// podczas pauzy nie przeliczać kątów przypadkowymi wartościami
|
||||||
Camera.Pitch -= 0.5 * atan( Train->vMechVelocity.z * Train->fMechPitch ); // hustanie kamery przod tyl //Ra: tu
|
// hustanie kamery na boki
|
||||||
// jest uciekanie kamery w górę!!!
|
Camera.Roll = atan( Train->vMechVelocity.x * Train->fMechRoll );
|
||||||
|
// hustanie kamery przod tyl
|
||||||
|
// Ra: tu jest uciekanie kamery w górę!!!
|
||||||
|
Camera.Pitch -= 0.5 * atan( Train->vMechVelocity.z * Train->fMechPitch );
|
||||||
}
|
}
|
||||||
// ABu011104: rzucanie pudlem
|
// ABu011104: rzucanie pudlem
|
||||||
/*
|
/*
|
||||||
@@ -1368,7 +1372,7 @@ TWorld::Update_UI() {
|
|||||||
if( ( vehicle->MoverParameters->BrakeDelayFlag & bdelay_M ) == bdelay_M )
|
if( ( vehicle->MoverParameters->BrakeDelayFlag & bdelay_M ) == bdelay_M )
|
||||||
uitextline2 += "+Mg";
|
uitextline2 += "+Mg";
|
||||||
|
|
||||||
uitextline2 += ", Load: " + to_string( vehicle->MoverParameters->LoadFlag, 0 );
|
uitextline2 += ", Load: " + to_string( vehicle->MoverParameters->LoadFlag, 0 ) + " (" + to_string( vehicle->MoverParameters->Load, 0 ) + ")";
|
||||||
|
|
||||||
uitextline2 +=
|
uitextline2 +=
|
||||||
"; Pant: "
|
"; Pant: "
|
||||||
@@ -1614,7 +1618,8 @@ TWorld::Update_UI() {
|
|||||||
Acc = ( vehicle->MoverParameters->Vel - VelPrev ) / 3.6;
|
Acc = ( vehicle->MoverParameters->Vel - VelPrev ) / 3.6;
|
||||||
VelPrev = vehicle->MoverParameters->Vel;
|
VelPrev = vehicle->MoverParameters->Vel;
|
||||||
}
|
}
|
||||||
uitextline2 += ( "; As=" ) + to_string( Acc, 2 ); // przyspieszenie wzdłużne
|
uitextline2 += "; As=" + to_string( Acc, 2 ); // przyspieszenie wzdłużne
|
||||||
|
uitextline2 += " eAngle=" + to_string( std::cos( vehicle->MoverParameters->eAngle ), 2 );
|
||||||
|
|
||||||
uitextline3 =
|
uitextline3 =
|
||||||
"cyl.ham. " + to_string( vehicle->MoverParameters->BrakePress, 2 )
|
"cyl.ham. " + to_string( vehicle->MoverParameters->BrakePress, 2 )
|
||||||
@@ -2241,17 +2246,16 @@ world_environment::update() {
|
|||||||
// tonal impact of skydome color is inversely proportional to how high the sun is above the horizon
|
// tonal impact of skydome color is inversely proportional to how high the sun is above the horizon
|
||||||
// (this is pure conjecture, aimed more to 'look right' than be accurate)
|
// (this is pure conjecture, aimed more to 'look right' than be accurate)
|
||||||
float const ambienttone = clamp( 1.0f - ( Global.SunAngle / 90.0f ), 0.0f, 1.0f );
|
float const ambienttone = clamp( 1.0f - ( Global.SunAngle / 90.0f ), 0.0f, 1.0f );
|
||||||
Global.DayLight.ambient[ 0 ] = interpolate( skydomehsv.z, skydomecolour.x, ambienttone );
|
Global.DayLight.ambient[ 0 ] = interpolate( skydomehsv.z, skydomecolour.r, ambienttone );
|
||||||
Global.DayLight.ambient[ 1 ] = interpolate( skydomehsv.z, skydomecolour.y, ambienttone );
|
Global.DayLight.ambient[ 1 ] = interpolate( skydomehsv.z, skydomecolour.g, ambienttone );
|
||||||
Global.DayLight.ambient[ 2 ] = interpolate( skydomehsv.z, skydomecolour.z, ambienttone );
|
Global.DayLight.ambient[ 2 ] = interpolate( skydomehsv.z, skydomecolour.b, ambienttone );
|
||||||
|
|
||||||
Global.fLuminance = intensity;
|
Global.fLuminance = intensity;
|
||||||
|
|
||||||
// update the fog. setting it to match the average colour of the sky dome is cheap
|
// update the fog. setting it to match the average colour of the sky dome is cheap
|
||||||
// but quite effective way to make the distant items blend with background better
|
// but quite effective way to make the distant items blend with background better
|
||||||
Global.FogColor[ 0 ] = skydomecolour.x;
|
// NOTE: base brightness calculation provides scaled up value, so we bring it back to 'real' one here
|
||||||
Global.FogColor[ 1 ] = skydomecolour.y;
|
Global.FogColor = m_skydome.GetAverageHorizonColor();
|
||||||
Global.FogColor[ 2 ] = skydomecolour.z;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
3
World.h
3
World.h
@@ -20,6 +20,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "stars.h"
|
#include "stars.h"
|
||||||
#include "skydome.h"
|
#include "skydome.h"
|
||||||
#include "messaging.h"
|
#include "messaging.h"
|
||||||
|
#include "station.h"
|
||||||
|
|
||||||
// wrapper for simulation time
|
// wrapper for simulation time
|
||||||
class simulation_time {
|
class simulation_time {
|
||||||
@@ -59,6 +60,8 @@ namespace simulation {
|
|||||||
|
|
||||||
extern simulation_time Time;
|
extern simulation_time Time;
|
||||||
|
|
||||||
|
extern basic_station Station; // temporary object, for station functionality tests
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class opengl_renderer;
|
class opengl_renderer;
|
||||||
|
|||||||
33
renderer.cpp
33
renderer.cpp
@@ -1049,7 +1049,7 @@ opengl_renderer::setup_drawing( bool const Alpha ) {
|
|||||||
// setup fog
|
// setup fog
|
||||||
if( Global.fFogEnd > 0 ) {
|
if( Global.fFogEnd > 0 ) {
|
||||||
// fog setup
|
// fog setup
|
||||||
::glFogfv( GL_FOG_COLOR, Global.FogColor );
|
::glFogfv( GL_FOG_COLOR, glm::value_ptr( Global.FogColor ) );
|
||||||
::glFogf( GL_FOG_DENSITY, static_cast<GLfloat>( 1.0 / Global.fFogEnd ) );
|
::glFogf( GL_FOG_DENSITY, static_cast<GLfloat>( 1.0 / Global.fFogEnd ) );
|
||||||
::glEnable( GL_FOG );
|
::glEnable( GL_FOG );
|
||||||
}
|
}
|
||||||
@@ -1828,6 +1828,37 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
|
|||||||
Render( memcell );
|
Render( memcell );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef EU07_USE_DEBUG_CULLING
|
||||||
|
// debug
|
||||||
|
::glLineWidth( 2.f );
|
||||||
|
float const width = cell->m_area.radius;
|
||||||
|
float const height = cell->m_area.radius * 0.2f;
|
||||||
|
glDisable( GL_LIGHTING );
|
||||||
|
glDisable( GL_TEXTURE_2D );
|
||||||
|
glColor3ub( 255, 128, 128 );
|
||||||
|
glBegin( GL_LINE_LOOP );
|
||||||
|
glVertex3f( -width, height, width );
|
||||||
|
glVertex3f( -width, height, -width );
|
||||||
|
glVertex3f( width, height, -width );
|
||||||
|
glVertex3f( width, height, width );
|
||||||
|
glEnd();
|
||||||
|
glBegin( GL_LINE_LOOP );
|
||||||
|
glVertex3f( -width, 0, width );
|
||||||
|
glVertex3f( -width, 0, -width );
|
||||||
|
glVertex3f( width, 0, -width );
|
||||||
|
glVertex3f( width, 0, width );
|
||||||
|
glEnd();
|
||||||
|
glBegin( GL_LINES );
|
||||||
|
glVertex3f( -width, height, width ); glVertex3f( -width, 0, width );
|
||||||
|
glVertex3f( -width, height, -width ); glVertex3f( -width, 0, -width );
|
||||||
|
glVertex3f( width, height, -width ); glVertex3f( width, 0, -width );
|
||||||
|
glVertex3f( width, height, width ); glVertex3f( width, 0, width );
|
||||||
|
glEnd();
|
||||||
|
glColor3ub( 255, 255, 255 );
|
||||||
|
glEnable( GL_TEXTURE_2D );
|
||||||
|
glEnable( GL_LIGHTING );
|
||||||
|
glLineWidth( 1.f );
|
||||||
#endif
|
#endif
|
||||||
// post-render cleanup
|
// post-render cleanup
|
||||||
::glPopMatrix();
|
::glPopMatrix();
|
||||||
|
|||||||
14
skydome.cpp
14
skydome.cpp
@@ -242,7 +242,7 @@ void CSkyDome::RebuildColors() {
|
|||||||
zenithluminance = PerezFunctionO1( perezluminance, m_thetasun, zenithluminance );
|
zenithluminance = PerezFunctionO1( perezluminance, m_thetasun, zenithluminance );
|
||||||
|
|
||||||
// start with fresh average for the new pass
|
// start with fresh average for the new pass
|
||||||
glm::vec3 averagecolor { 0.0f, 0.0f, 0.0f };
|
glm::vec3 averagecolor, averagehorizoncolor;
|
||||||
|
|
||||||
// trough all vertices
|
// trough all vertices
|
||||||
glm::vec3 vertex;
|
glm::vec3 vertex;
|
||||||
@@ -332,14 +332,16 @@ void CSkyDome::RebuildColors() {
|
|||||||
}
|
}
|
||||||
// save
|
// save
|
||||||
m_colours[ i ] = color;
|
m_colours[ i ] = color;
|
||||||
averagecolor += color * 8.0f; // save for edge cases each vertex goes in 8 triangles
|
averagecolor += color;
|
||||||
|
if( ( m_vertices.size() - i ) <= ( m_tesselation * 2 ) ) {
|
||||||
|
// calculate horizon colour from the bottom band of tris
|
||||||
|
averagehorizoncolor += color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// NOTE: average reduced to 25% makes nice tint value for clouds lit from behind
|
// NOTE: average reduced to 25% makes nice tint value for clouds lit from behind
|
||||||
// down the road we could interpolate between it and full strength average, to improve accuracy of cloud appearance
|
// down the road we could interpolate between it and full strength average, to improve accuracy of cloud appearance
|
||||||
m_averagecolour = averagecolor / static_cast<float>( m_indices.size() );
|
m_averagecolour = glm::max( glm::vec3(), averagecolor / static_cast<float>( m_vertices.size() ) );
|
||||||
m_averagecolour.r = std::max( m_averagecolour.r, 0.0f );
|
m_averagehorizoncolour = glm::max( glm::vec3(), averagehorizoncolor / static_cast<float>( m_tesselation * 2 ) );
|
||||||
m_averagecolour.g = std::max( m_averagecolour.g, 0.0f );
|
|
||||||
m_averagecolour.b = std::max( m_averagecolour.b, 0.0f );
|
|
||||||
|
|
||||||
if( m_coloursbuffer != -1 ) {
|
if( m_coloursbuffer != -1 ) {
|
||||||
// the colour buffer was already initialized, so on this run we update its content
|
// the colour buffer was already initialized, so on this run we update its content
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ public:
|
|||||||
void Render();
|
void Render();
|
||||||
|
|
||||||
// retrieves average colour of the sky dome
|
// retrieves average colour of the sky dome
|
||||||
glm::vec3 GetAverageColor() { return m_averagecolour; }
|
glm::vec3 GetAverageColor() { return m_averagecolour * 8.f / 6.f; }
|
||||||
|
glm::vec3 GetAverageHorizonColor() { return m_averagehorizoncolour; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// shading parametrs
|
// shading parametrs
|
||||||
@@ -35,6 +36,7 @@ private:
|
|||||||
float m_overcast;
|
float m_overcast;
|
||||||
float m_gammacorrection;
|
float m_gammacorrection;
|
||||||
glm::vec3 m_averagecolour;
|
glm::vec3 m_averagecolour;
|
||||||
|
glm::vec3 m_averagehorizoncolour;
|
||||||
|
|
||||||
// data
|
// data
|
||||||
int const m_tesselation;
|
int const m_tesselation;
|
||||||
|
|||||||
87
sound.cpp
87
sound.cpp
@@ -454,8 +454,8 @@ sound_source::stop( bool const Skipend ) {
|
|||||||
|
|
||||||
if( ( false == Skipend )
|
if( ( false == Skipend )
|
||||||
&& ( sound( sound_id::end ).buffer != null_handle )
|
&& ( sound( sound_id::end ).buffer != null_handle )
|
||||||
&& ( sound( sound_id::end ).buffer != sound( sound_id::main ).buffer ) // end == main can happen in malformed legacy cases
|
/* && ( sound( sound_id::end ).buffer != sound( sound_id::main ).buffer ) */ // end == main can happen in malformed legacy cases
|
||||||
/* && ( sound( sound_id::end ).playing == 0 ) */ ) {
|
/* && ( sound( sound_id::end ).playing == 0 ) */ ) {
|
||||||
// spawn potentially defined sound end sample, if the emitter is currently active
|
// spawn potentially defined sound end sample, if the emitter is currently active
|
||||||
insert( sound_id::end );
|
insert( sound_id::end );
|
||||||
}
|
}
|
||||||
@@ -482,19 +482,31 @@ sound_source::update_basic( audio::openal_source &Source ) {
|
|||||||
|
|
||||||
if( true == Source.is_playing ) {
|
if( true == Source.is_playing ) {
|
||||||
|
|
||||||
if( ( true == m_stop )
|
auto const soundhandle { Source.sounds[ Source.sound_index ] };
|
||||||
&& ( Source.sounds[ Source.sound_index ] != sound_id::end ) ) {
|
|
||||||
// kill the sound if stop was requested, unless it's sound bookend sample
|
if( sound( sound_id::begin ).buffer != null_handle ) {
|
||||||
Source.stop();
|
// potentially a multipart sound
|
||||||
update_counter( Source.sounds[ Source.sound_index ], -1 );
|
// detect the moment when the sound moves from startup sample to the main
|
||||||
if( false == is_playing() ) {
|
if( ( false == Source.is_looping )
|
||||||
m_stop = false;
|
&& ( soundhandle == sound_id::main ) ) {
|
||||||
|
// when it happens update active sample counters, and activate the looping
|
||||||
|
update_counter( sound_id::begin, -1 );
|
||||||
|
update_counter( soundhandle, 1 );
|
||||||
|
Source.loop( TestFlag( m_flags, sound_flags::looping ) );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ( true == m_stop )
|
||||||
|
&& ( soundhandle != sound_id::end ) ) {
|
||||||
|
// kill the sound if stop was requested, unless it's sound bookend sample
|
||||||
|
update_counter( soundhandle, -1 );
|
||||||
|
Source.stop();
|
||||||
|
m_stop = is_playing(); // end the stop mode when all active sounds are dead
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if( ( true == m_stopend )
|
if( ( true == m_stopend )
|
||||||
&& ( Source.sounds[ Source.sound_index ] == sound_id::end ) ) {
|
&& ( soundhandle == sound_id::end ) ) {
|
||||||
// kill the sound if it's the bookend sample and stopping it was requested
|
// kill the sound if it's the bookend sample and stopping it was requested
|
||||||
Source.stop();
|
Source.stop();
|
||||||
update_counter( sound_id::end, -1 );
|
update_counter( sound_id::end, -1 );
|
||||||
@@ -504,25 +516,13 @@ sound_source::update_basic( audio::openal_source &Source ) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if( sound( sound_id::begin ).buffer != null_handle ) {
|
|
||||||
// potentially a multipart sound
|
|
||||||
// detect the moment when the sound moves from startup sample to the main
|
|
||||||
auto const soundhandle { Source.sounds[ Source.sound_index ] };
|
|
||||||
if( ( false == Source.is_looping )
|
|
||||||
&& ( soundhandle == sound_id::main ) ) {
|
|
||||||
// when it happens update active sample counters, and activate the looping
|
|
||||||
update_counter( sound_id::begin, -1 );
|
|
||||||
update_counter( soundhandle, 1 );
|
|
||||||
Source.loop( true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check and update if needed current sound properties
|
// check and update if needed current sound properties
|
||||||
update_location();
|
update_location();
|
||||||
update_soundproofing();
|
update_soundproofing();
|
||||||
Source.sync_with( m_properties );
|
Source.sync_with( m_properties );
|
||||||
if( Source.sync != sync_state::good ) {
|
if( Source.sync != sync_state::good ) {
|
||||||
// if the sync went wrong we let the renderer kill its part of the emitter, and update our playcounter(s) to match
|
// if the sync went wrong we let the renderer kill its part of the emitter, and update our playcounter(s) to match
|
||||||
update_counter( Source.sounds[ Source.sound_index ], -1 );
|
update_counter( soundhandle, -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -533,10 +533,9 @@ sound_source::update_basic( audio::openal_source &Source ) {
|
|||||||
// the emitter wasn't yet started
|
// the emitter wasn't yet started
|
||||||
auto const soundhandle { Source.sounds[ Source.sound_index ] };
|
auto const soundhandle { Source.sounds[ Source.sound_index ] };
|
||||||
// emitter initialization
|
// emitter initialization
|
||||||
if( ( soundhandle == sound_id::main )
|
if( soundhandle == sound_id::main ) {
|
||||||
&& ( true == TestFlag( m_flags, sound_flags::looping ) ) ) {
|
|
||||||
// main sample can be optionally set to loop
|
// main sample can be optionally set to loop
|
||||||
Source.loop( true );
|
Source.loop( TestFlag( m_flags, sound_flags::looping ) );
|
||||||
}
|
}
|
||||||
Source.range( m_range );
|
Source.range( m_range );
|
||||||
Source.pitch( m_pitchvariation );
|
Source.pitch( m_pitchvariation );
|
||||||
@@ -570,6 +569,18 @@ sound_source::update_combined( audio::openal_source &Source ) {
|
|||||||
|
|
||||||
auto const soundhandle { Source.sounds[ Source.sound_index ] };
|
auto const soundhandle { Source.sounds[ Source.sound_index ] };
|
||||||
|
|
||||||
|
if( sound( sound_id::begin ).buffer != null_handle ) {
|
||||||
|
// potentially a multipart sound
|
||||||
|
// detect the moment when the sound moves from startup sample to the main
|
||||||
|
if( ( false == Source.is_looping )
|
||||||
|
&& ( soundhandle == ( sound_id::chunk | 0 ) ) ) {
|
||||||
|
// when it happens update active sample counters, and activate the looping
|
||||||
|
update_counter( sound_id::begin, -1 );
|
||||||
|
update_counter( soundhandle, 1 );
|
||||||
|
Source.loop( true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( ( true == m_stop )
|
if( ( true == m_stop )
|
||||||
&& ( soundhandle != sound_id::end ) ) {
|
&& ( soundhandle != sound_id::end ) ) {
|
||||||
// kill the sound if stop was requested, unless it's sound bookend sample
|
// kill the sound if stop was requested, unless it's sound bookend sample
|
||||||
@@ -582,7 +593,7 @@ sound_source::update_combined( audio::openal_source &Source ) {
|
|||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if( ( true == m_stopend )
|
if( ( true == m_stopend )
|
||||||
&& ( Source.sounds[ Source.sound_index ] == sound_id::end ) ) {
|
&& ( soundhandle == sound_id::end ) ) {
|
||||||
// kill the sound if it's the bookend sample and stopping it was requested
|
// kill the sound if it's the bookend sample and stopping it was requested
|
||||||
Source.stop();
|
Source.stop();
|
||||||
update_counter( sound_id::end, -1 );
|
update_counter( sound_id::end, -1 );
|
||||||
@@ -592,19 +603,6 @@ sound_source::update_combined( audio::openal_source &Source ) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if( sound( sound_id::begin ).buffer != null_handle ) {
|
|
||||||
// potentially a multipart sound
|
|
||||||
// detect the moment when the sound moves from startup sample to the main
|
|
||||||
auto const soundhandle { Source.sounds[ Source.sound_index ] };
|
|
||||||
if( ( false == Source.is_looping )
|
|
||||||
&& ( soundhandle == ( sound_id::chunk | 0 ) ) ) {
|
|
||||||
// when it happens update active sample counters, and activate the looping
|
|
||||||
update_counter( sound_id::begin, -1 );
|
|
||||||
update_counter( soundhandle, 1 );
|
|
||||||
Source.loop( true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ( soundhandle & sound_id::chunk ) != 0 ) {
|
if( ( soundhandle & sound_id::chunk ) != 0 ) {
|
||||||
// for sound chunks, test whether the chunk should still be active given current value of the controlling variable
|
// for sound chunks, test whether the chunk should still be active given current value of the controlling variable
|
||||||
auto const soundpoint { compute_combined_point() };
|
auto const soundpoint { compute_combined_point() };
|
||||||
@@ -629,7 +627,7 @@ sound_source::update_combined( audio::openal_source &Source ) {
|
|||||||
Source.sync_with( m_properties );
|
Source.sync_with( m_properties );
|
||||||
if( Source.sync != sync_state::good ) {
|
if( Source.sync != sync_state::good ) {
|
||||||
// if the sync went wrong we let the renderer kill its part of the emitter, and update our playcounter(s) to match
|
// if the sync went wrong we let the renderer kill its part of the emitter, and update our playcounter(s) to match
|
||||||
update_counter( Source.sounds[ Source.sound_index ], -1 );
|
update_counter( soundhandle, -1 );
|
||||||
}
|
}
|
||||||
// ...and restore base properties
|
// ...and restore base properties
|
||||||
m_properties = baseproperties;
|
m_properties = baseproperties;
|
||||||
@@ -796,7 +794,7 @@ sound_source::empty() const {
|
|||||||
bool
|
bool
|
||||||
sound_source::is_playing( bool const Includesoundends ) const {
|
sound_source::is_playing( bool const Includesoundends ) const {
|
||||||
|
|
||||||
auto isplaying { ( sound( sound_id::begin ).playing + sound( sound_id::main ).playing ) > 0 };
|
auto isplaying { ( sound( sound_id::begin ).playing > 0 ) || ( sound( sound_id::main ).playing > 0 ) };
|
||||||
if( ( false == isplaying )
|
if( ( false == isplaying )
|
||||||
&& ( false == m_soundchunks.empty() ) ) {
|
&& ( false == m_soundchunks.empty() ) ) {
|
||||||
// for emitters with sample tables check also if any of the chunks is active
|
// for emitters with sample tables check also if any of the chunks is active
|
||||||
@@ -836,8 +834,9 @@ sound_source::location() const {
|
|||||||
void
|
void
|
||||||
sound_source::update_counter( sound_handle const Sound, int const Value ) {
|
sound_source::update_counter( sound_handle const Sound, int const Value ) {
|
||||||
|
|
||||||
sound( Sound ).playing = std::max( 0, sound( Sound ).playing + Value );
|
// sound( Sound ).playing = std::max( 0, sound( Sound ).playing + Value );
|
||||||
// assert( sound( Sound ).playing >= 0 );
|
sound( Sound ).playing += Value;
|
||||||
|
assert( sound( Sound ).playing >= 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
10
sound.h
10
sound.h
@@ -179,15 +179,15 @@ private:
|
|||||||
template <class Iterator_>
|
template <class Iterator_>
|
||||||
void
|
void
|
||||||
insert( Iterator_ First, Iterator_ Last ) {
|
insert( Iterator_ First, Iterator_ Last ) {
|
||||||
uint32_sequence sounds;
|
update_counter( *First, 1 );
|
||||||
std::vector<audio::buffer_handle> buffers;
|
std::vector<audio::buffer_handle> buffers;
|
||||||
|
uint32_sequence sounds;
|
||||||
std::for_each(
|
std::for_each(
|
||||||
First, Last,
|
First, Last,
|
||||||
[&]( sound_handle const &soundhandle ) {
|
[&]( sound_handle const &soundhandle ) {
|
||||||
sounds.emplace_back( soundhandle );
|
buffers.emplace_back( sound( soundhandle ).buffer );
|
||||||
buffers.emplace_back( sound( soundhandle ).buffer ); } );
|
sounds.emplace_back( soundhandle ); } );
|
||||||
audio::renderer.insert( std::begin( buffers ), std::end( buffers ), this, sounds );
|
audio::renderer.insert( std::begin( buffers ), std::end( buffers ), this, sounds ); }
|
||||||
update_counter( *First, 1 ); }
|
|
||||||
sound_data &
|
sound_data &
|
||||||
sound( sound_handle const Sound );
|
sound( sound_handle const Sound );
|
||||||
sound_data const &
|
sound_data const &
|
||||||
|
|||||||
73
station.cpp
Normal file
73
station.cpp
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "station.h"
|
||||||
|
|
||||||
|
#include "DynObj.h"
|
||||||
|
#include "mtable.h"
|
||||||
|
|
||||||
|
// exchanges load with consist attached to specified vehicle, operating on specified schedule
|
||||||
|
double
|
||||||
|
basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Schedule ) {
|
||||||
|
|
||||||
|
auto const firststop { Schedule.StationIndex == 1 };
|
||||||
|
auto const laststop { Schedule.StationIndex == Schedule.StationCount };
|
||||||
|
// HACK: determine whether current station is a (small) stop from the presence of "po" at the name end
|
||||||
|
auto const stationname { Schedule.TimeTable[ Schedule.StationIndex ].StationName };
|
||||||
|
auto const stationequipment { Schedule.TimeTable[ Schedule.StationIndex ].StationWare };
|
||||||
|
auto const trainstop { (
|
||||||
|
( ( stationname.size() >= 2 ) && ( stationname.substr( stationname.size() - 2 ) == "po" ) )
|
||||||
|
|| ( stationequipment.find( "po" ) != std::string::npos ) ) };
|
||||||
|
// train stops exchange smaller groups than regular stations
|
||||||
|
// NOTE: this is crude and unaccurate, but for now will do
|
||||||
|
auto const stationsizemodifier { ( trainstop ? 1.0 : 2.0 ) };
|
||||||
|
// go through all vehicles and update their load
|
||||||
|
// NOTE: for the time being we limit ourselves to passenger-carrying cars only
|
||||||
|
auto exchangetime { 0.0 };
|
||||||
|
|
||||||
|
auto *vehicle { First };
|
||||||
|
while( vehicle != nullptr ) {
|
||||||
|
|
||||||
|
auto ¶meters { *vehicle->MoverParameters };
|
||||||
|
|
||||||
|
if( ( true == parameters.LoadType.empty() )
|
||||||
|
&& ( parameters.LoadAccepted.find( "passengers" ) != std::string::npos ) ) {
|
||||||
|
// set the type for empty cars
|
||||||
|
parameters.LoadType = "passengers";
|
||||||
|
}
|
||||||
|
|
||||||
|
if( parameters.LoadType == "passengers" ) {
|
||||||
|
// NOTE: for the time being we're doing simple, random load change calculation
|
||||||
|
// TODO: exchange driven by station parameters and time of the day
|
||||||
|
auto unloadcount = static_cast<int>(
|
||||||
|
firststop ? 0 :
|
||||||
|
laststop ? parameters.Load :
|
||||||
|
std::min(
|
||||||
|
parameters.Load,
|
||||||
|
Random( parameters.MaxLoad * 0.10 * stationsizemodifier ) ) );
|
||||||
|
auto loadcount = static_cast<int>(
|
||||||
|
laststop ?
|
||||||
|
0 :
|
||||||
|
Random( parameters.MaxLoad * 0.15 * stationsizemodifier ) );
|
||||||
|
if( true == firststop ) {
|
||||||
|
// slightly larger group at the initial station
|
||||||
|
loadcount *= 2;
|
||||||
|
}
|
||||||
|
parameters.Load = std::min( parameters.MaxLoad, parameters.Load - unloadcount + loadcount );
|
||||||
|
vehicle->LoadUpdate();
|
||||||
|
vehicle->update_load_visibility();
|
||||||
|
|
||||||
|
exchangetime = std::max( exchangetime, unloadcount / parameters.UnLoadSpeed + loadcount / parameters.LoadSpeed);
|
||||||
|
}
|
||||||
|
vehicle = vehicle->Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return exchangetime;
|
||||||
|
}
|
||||||
22
station.h
Normal file
22
station.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Classes.h"
|
||||||
|
|
||||||
|
// a simple station, performs freight and passenger exchanges with visiting consists
|
||||||
|
class basic_station {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// methods
|
||||||
|
// exchanges load with consist attached to specified vehicle, operating on specified schedule; returns: time needed for exchange, in seconds
|
||||||
|
double
|
||||||
|
update_load( TDynamicObject *First, Mtable::TTrainParameters &Schedule );
|
||||||
|
};
|
||||||
35
uilayer.cpp
35
uilayer.cpp
@@ -90,12 +90,22 @@ ui_layer::render() {
|
|||||||
glDisable( GL_LIGHTING );
|
glDisable( GL_LIGHTING );
|
||||||
glDisable( GL_DEPTH_TEST );
|
glDisable( GL_DEPTH_TEST );
|
||||||
glDisable( GL_ALPHA_TEST );
|
glDisable( GL_ALPHA_TEST );
|
||||||
glEnable( GL_BLEND );
|
glEnable( GL_TEXTURE_2D );
|
||||||
|
glEnable( GL_BLEND );
|
||||||
|
|
||||||
|
::glColor4fv( glm::value_ptr( colors::white ) );
|
||||||
|
|
||||||
// render code here
|
// render code here
|
||||||
render_background();
|
render_background();
|
||||||
render_texture();
|
render_texture();
|
||||||
|
|
||||||
|
glDisable( GL_TEXTURE_2D );
|
||||||
|
glDisable( GL_TEXTURE_CUBE_MAP );
|
||||||
|
|
||||||
render_progress();
|
render_progress();
|
||||||
|
|
||||||
|
glDisable( GL_BLEND );
|
||||||
|
|
||||||
render_panels();
|
render_panels();
|
||||||
render_tooltip();
|
render_tooltip();
|
||||||
|
|
||||||
@@ -129,9 +139,6 @@ ui_layer::render_progress() {
|
|||||||
|
|
||||||
if( (m_progress == 0.0f) && (m_subtaskprogress == 0.0f) ) return;
|
if( (m_progress == 0.0f) && (m_subtaskprogress == 0.0f) ) return;
|
||||||
|
|
||||||
glPushAttrib( GL_ENABLE_BIT );
|
|
||||||
glDisable( GL_TEXTURE_2D );
|
|
||||||
|
|
||||||
glm::vec2 origin, size;
|
glm::vec2 origin, size;
|
||||||
if( m_progressbottom == true ) {
|
if( m_progressbottom == true ) {
|
||||||
origin = glm::vec2{ 0.0f, 768.0f - 20.0f };
|
origin = glm::vec2{ 0.0f, 768.0f - 20.0f };
|
||||||
@@ -177,8 +184,6 @@ ui_layer::render_progress() {
|
|||||||
( 0.5f * ( Global.iWindowHeight - height ) + origin.y * heightratio ) + ( charsize ) + ( ( size.y * heightratio - textheight ) * 0.5f * heightratio ) );
|
( 0.5f * ( Global.iWindowHeight - height ) + origin.y * heightratio ) + ( charsize ) + ( ( size.y * heightratio - textheight ) * 0.5f * heightratio ) );
|
||||||
print( m_progresstext );
|
print( m_progresstext );
|
||||||
}
|
}
|
||||||
|
|
||||||
glPopAttrib();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -186,9 +191,6 @@ ui_layer::render_panels() {
|
|||||||
|
|
||||||
if( m_panels.empty() ) { return; }
|
if( m_panels.empty() ) { return; }
|
||||||
|
|
||||||
glPushAttrib( GL_ENABLE_BIT );
|
|
||||||
glDisable( GL_TEXTURE_2D );
|
|
||||||
|
|
||||||
float const width = std::min( 4.f / 3.f, static_cast<float>(Global.iWindowWidth) / std::max( 1, Global.iWindowHeight ) ) * Global.iWindowHeight;
|
float const width = std::min( 4.f / 3.f, static_cast<float>(Global.iWindowWidth) / std::max( 1, Global.iWindowHeight ) ) * Global.iWindowHeight;
|
||||||
float const height = Global.iWindowHeight / 768.f;
|
float const height = Global.iWindowHeight / 768.f;
|
||||||
|
|
||||||
@@ -199,7 +201,7 @@ ui_layer::render_panels() {
|
|||||||
int lineidx = 0;
|
int lineidx = 0;
|
||||||
for( auto const &line : panel->text_lines ) {
|
for( auto const &line : panel->text_lines ) {
|
||||||
|
|
||||||
::glColor4fv( &line.color.x );
|
::glColor4fv( glm::value_ptr( line.color ) );
|
||||||
::glRasterPos2f(
|
::glRasterPos2f(
|
||||||
0.5f * ( Global.iWindowWidth - width ) + panel->origin_x * height,
|
0.5f * ( Global.iWindowWidth - width ) + panel->origin_x * height,
|
||||||
panel->origin_y * height + 20.f * lineidx );
|
panel->origin_y * height + 20.f * lineidx );
|
||||||
@@ -207,8 +209,6 @@ ui_layer::render_panels() {
|
|||||||
++lineidx;
|
++lineidx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glPopAttrib();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -219,13 +219,9 @@ ui_layer::render_tooltip() {
|
|||||||
glm::dvec2 mousepos;
|
glm::dvec2 mousepos;
|
||||||
glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y );
|
glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y );
|
||||||
|
|
||||||
glPushAttrib( GL_ENABLE_BIT );
|
::glColor4fv( glm::value_ptr( colors::white ) );
|
||||||
glDisable( GL_TEXTURE_2D );
|
|
||||||
::glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
||||||
::glRasterPos2f( mousepos.x + 20.0f, mousepos.y + 25.0f );
|
::glRasterPos2f( mousepos.x + 20.0f, mousepos.y + 25.0f );
|
||||||
print( m_tooltip );
|
print( m_tooltip );
|
||||||
|
|
||||||
glPopAttrib();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -254,8 +250,7 @@ void
|
|||||||
ui_layer::render_texture() {
|
ui_layer::render_texture() {
|
||||||
|
|
||||||
if( m_texture != 0 ) {
|
if( m_texture != 0 ) {
|
||||||
::glColor4f( 1.f, 1.f, 1.f, 1.f );
|
::glColor4fv( glm::value_ptr( colors::white ) );
|
||||||
::glDisable( GL_BLEND );
|
|
||||||
|
|
||||||
GfxRenderer.Bind_Texture( null_handle );
|
GfxRenderer.Bind_Texture( null_handle );
|
||||||
::glBindTexture( GL_TEXTURE_2D, m_texture );
|
::glBindTexture( GL_TEXTURE_2D, m_texture );
|
||||||
@@ -273,8 +268,6 @@ ui_layer::render_texture() {
|
|||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
::glBindTexture( GL_TEXTURE_2D, 0 );
|
::glBindTexture( GL_TEXTURE_2D, 0 );
|
||||||
|
|
||||||
::glEnable( GL_BLEND );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user