mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 19:49:19 +02:00
Merge branch 'tmj-dev'
This commit is contained in:
@@ -80,6 +80,7 @@ set(SOURCES
|
||||
"utilities.cpp"
|
||||
"light.cpp"
|
||||
"uitranscripts.cpp"
|
||||
"station.cpp"
|
||||
)
|
||||
|
||||
set (PREFIX "")
|
||||
|
||||
233
Driver.cpp
233
Driver.cpp
@@ -891,8 +891,6 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
mvOccupied->DoorLeft(true);
|
||||
if (p2 & prawe)
|
||||
mvOccupied->DoorRight(true);
|
||||
// if (p2&3) //żeby jeszcze poczekał chwilę, zanim zamknie
|
||||
// WaitingSet(10); //10 sekund (wziąć z rozkładu????)
|
||||
}
|
||||
}
|
||||
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)
|
||||
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
|
||||
WaitingSet( 15.0 + Random( 15.0 ) ); // 10 sekund (wziąć z rozkładu????) - czekanie
|
||||
// niezależne od sposobu obsługi drzwi, bo opóźnia również kierownika
|
||||
}
|
||||
if (TrainParams->UpdateMTable( simulation::Time, asNextStop) )
|
||||
{ // 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
|
||||
{
|
||||
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
|
||||
if (OrderNextGet() != Change_direction)
|
||||
{
|
||||
if (OrderNextGet() != Change_direction) {
|
||||
OrderPush(Change_direction); // zmiana kierunku
|
||||
OrderPush(TrainParams->StationIndex <
|
||||
TrainParams->StationCount ?
|
||||
Obey_train :
|
||||
Shunt); // to dalej wg rozkładu
|
||||
OrderPush(
|
||||
TrainParams->StationIndex < TrainParams->StationCount ?
|
||||
Obey_train :
|
||||
Shunt); // to dalej wg rozkładu
|
||||
}
|
||||
}
|
||||
else // a dla lokomotyw...
|
||||
iDrivigFlags &=
|
||||
~(moveStopPoint | moveStopHere); // pozwolenie na
|
||||
// przejechanie za W4
|
||||
// przed czasem i nie
|
||||
// ma stać
|
||||
JumpToNextOrder(); // przejście do kolejnego rozkazu (zmiana
|
||||
// kierunku, odczepianie)
|
||||
iDrivigFlags &= ~moveStopCloser; // ma nie podjeżdżać pod W4 po
|
||||
// przeciwnej stronie
|
||||
sSpeedTable[i].iFlags = 0; // ten W4 nie liczy się już zupełnie
|
||||
// (nie wyśle SetVelocity)
|
||||
sSpeedTable[i].fVelNext = -1; // jechać
|
||||
continue; // nie analizować prędkości
|
||||
else {
|
||||
// a dla lokomotyw...
|
||||
// pozwolenie na przejechanie za W4 przed czasem i nie ma stać
|
||||
iDrivigFlags &= ~( moveStopPoint | moveStopHere );
|
||||
}
|
||||
// przejście do kolejnego rozkazu (zmiana kierunku, odczepianie)
|
||||
JumpToNextOrder();
|
||||
// ma nie podjeżdżać pod W4 po przeciwnej stronie
|
||||
iDrivigFlags &= ~moveStopCloser;
|
||||
// ten W4 nie liczy się już zupełnie (nie wyśle SetVelocity)
|
||||
sSpeedTable[i].iFlags = 0;
|
||||
// jechać
|
||||
sSpeedTable[i].fVelNext = -1;
|
||||
// nie analizować prędkości
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (OrderCurrentGet() == Shunt)
|
||||
@@ -969,7 +989,6 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
}
|
||||
if (TrainParams->StationIndex < TrainParams->StationCount)
|
||||
{ // jeśli są dalsze stacje, czekamy do godziny odjazdu
|
||||
|
||||
if (TrainParams->IsTimeToGo(simulation::Time.data().wHour, simulation::Time.data().wMinute))
|
||||
{ // z dalszą akcją czekamy do godziny odjazdu
|
||||
/* 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)
|
||||
+ " next " + asNextStop); // informacja
|
||||
#endif
|
||||
if (int(floor(sSpeedTable[i].evEvent->ValueGet(1))) & 1)
|
||||
iDrivigFlags |= moveStopHere; // nie podjeżdżać do semafora,
|
||||
// jeśli droga nie jest wolna
|
||||
else
|
||||
iDrivigFlags &= ~moveStopHere; //po czasie jedź dalej
|
||||
iDrivigFlags |= moveStopCloser; // do następnego W4 podjechać
|
||||
// blisko (z dociąganiem)
|
||||
iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed odjazdem
|
||||
sSpeedTable[i].iFlags =
|
||||
0; // nie liczy się już zupełnie (nie wyśle SetVelocity)
|
||||
if( int( floor( sSpeedTable[ i ].evEvent->ValueGet( 1 ) ) ) & 1 ) {
|
||||
// nie podjeżdżać do semafora, jeśli droga nie jest wolna
|
||||
iDrivigFlags |= moveStopHere;
|
||||
}
|
||||
else {
|
||||
//po czasie jedź dalej
|
||||
iDrivigFlags &= ~moveStopHere;
|
||||
}
|
||||
iDrivigFlags |= moveStopCloser; // do następnego W4 podjechać blisko (z dociąganiem)
|
||||
sSpeedTable[i].iFlags = 0; // nie liczy się już zupełnie (nie wyśle SetVelocity)
|
||||
sSpeedTable[i].fVelNext = -1; // można jechać za W4
|
||||
if (go == cm_Unknown) // jeśli nie było komendy wcześniej
|
||||
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
|
||||
while (d)
|
||||
{ // 3. Nastawianie
|
||||
switch (ustaw)
|
||||
{
|
||||
case bdelay_P: // towarowy P - lokomotywa na G, reszta na P.
|
||||
d->MoverParameters->BrakeDelaySwitch(d->MoverParameters->Power > 1 ? bdelay_G :
|
||||
bdelay_P);
|
||||
break;
|
||||
case bdelay_G: // towarowy G - wszystko na G, jeśli nie ma to P (powinno się wyłączyć
|
||||
// hamulec)
|
||||
d->MoverParameters->BrakeDelaySwitch(
|
||||
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?
|
||||
if( ( true == AIControllFlag )
|
||||
|| ( d != pVehicle ) ) {
|
||||
// don't touch human-controlled vehicle, but others are free game
|
||||
switch( ustaw ) {
|
||||
|
||||
case bdelay_P: {
|
||||
// towarowy P - lokomotywa na G, reszta na P.
|
||||
d->MoverParameters->BrakeDelaySwitch(
|
||||
d->MoverParameters->Power > 1 ?
|
||||
bdelay_G :
|
||||
bdelay_P );
|
||||
break;
|
||||
}
|
||||
case bdelay_G: {
|
||||
// towarowy G - wszystko na G, jeśli nie ma to P (powinno się wyłączyć hamulec)
|
||||
d->MoverParameters->BrakeDelaySwitch(
|
||||
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)
|
||||
}
|
||||
@@ -2094,22 +2134,16 @@ void TController::SetVelocity(double NewVel, double NewVelNext, TStopReason r)
|
||||
if (OrderList[OrderPos] ?
|
||||
OrderList[OrderPos] & (Obey_train | Shunt | Connect | Prepare_engine) :
|
||||
true) // jeśli jedzie w dowolnym trybie
|
||||
if ((mvOccupied->Vel <
|
||||
1.0)) // jesli stoi (na razie, bo chyba powinien też, gdy hamuje przed semaforem)
|
||||
if ((mvOccupied->Vel < 1.0)) // jesli stoi (na razie, bo chyba powinien też, gdy hamuje przed semaforem)
|
||||
if (iDrivigFlags & moveStartHorn) // jezeli trąbienie włączone
|
||||
if (!(iDrivigFlags & (moveStartHornDone | moveConnect))) // jeśli nie zatrąbione
|
||||
// i nie jest to moment
|
||||
// podłączania składu
|
||||
if (mvOccupied->CategoryFlag & 1) // tylko pociągi trąbią (unimogi tylko na
|
||||
// torach, więc trzeba raczej sprawdzać
|
||||
// tor)
|
||||
if ((NewVel >= 1.0) || (NewVel < 0.0)) // o ile prędkość jest znacząca
|
||||
{ // fWarningDuration=0.3; //czas trąbienia
|
||||
// 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
|
||||
if (!(iDrivigFlags & (moveStartHornDone | moveConnect)))
|
||||
// jeśli nie zatrąbione i nie jest to moment podłączania składu
|
||||
if (mvOccupied->CategoryFlag & 1)
|
||||
// tylko pociągi trąbią (unimogi tylko na torach, więc trzeba raczej sprawdzać tor)
|
||||
if ((NewVel >= 1.0) || (NewVel < 0.0)) {
|
||||
// o ile prędkość jest znacząca
|
||||
// zatrąb po odhamowaniu
|
||||
iDrivigFlags |= moveStartHornNow;
|
||||
}
|
||||
}
|
||||
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
|
||||
// przy prowadzeniu samochodu trzeba każdą oś odsuwać oddzielnie, inaczej kicha wychodzi
|
||||
if (mvOccupied->CategoryFlag & 2) // jeśli samochód
|
||||
// if (fabs(mvOccupied->OffsetTrackH)<mvOccupied->Dim.W) //Ra: szerokość drogi tu
|
||||
// powinna być?
|
||||
if (!mvOccupied->ChangeOffsetH(-0.01 * mvOccupied->Vel * dt)) // ruch w poprzek
|
||||
// drogi
|
||||
mvOccupied->ChangeOffsetH(0.01 * mvOccupied->Vel *
|
||||
dt); // Ra: co to miało być, to nie wiem
|
||||
// if (fabs(mvOccupied->OffsetTrackH)<mvOccupied->Dim.W) //Ra: szerokość drogi tu powinna być?
|
||||
if (!mvOccupied->ChangeOffsetH(-0.01 * mvOccupied->Vel * dt)) // ruch w poprzek 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 )
|
||||
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
|
||||
iDrivigFlags &= ~moveStartHornDone; // zatrąbi dopiero jak następnym razem stanie
|
||||
iDrivigFlags |= moveStartHorn; // i trąbić przed następnym ruszeniem
|
||||
@@ -3729,7 +3760,7 @@ TController::UpdateSituation(double dt) {
|
||||
if( ( true == TestFlag( iDrivigFlags, moveStartHornNow ) )
|
||||
&& ( true == Ready )
|
||||
&& ( iEngineActive != 0 )
|
||||
&& ( fStopTime >= 0 ) ) {
|
||||
&& ( mvControlling->MainCtrlPos > 0 ) ) {
|
||||
// uruchomienie trąbienia przed ruszeniem
|
||||
fWarningDuration = 0.3; // czas trąbienia
|
||||
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 ) {
|
||||
|
||||
std::string const &compartmentname = sectionlight.compartment->pName;
|
||||
if( ( compartmentname.find( "corridor" ) != std::string::npos )
|
||||
|| ( compartmentname.find( "korytarz" ) != std::string::npos ) ) {
|
||||
if( ( compartmentname.find( "corridor" ) == 0 )
|
||||
|| ( compartmentname.find( "korytarz" ) == 0 ) ) {
|
||||
// corridors are lit 100% of time
|
||||
sectionlight.level = 0.75f;
|
||||
}
|
||||
else if(
|
||||
( compartmentname.find( "compartment" ) != std::string::npos )
|
||||
|| ( compartmentname.find( "przedzial" ) != std::string::npos ) ) {
|
||||
( compartmentname.find( "compartment" ) == 0 )
|
||||
|| ( compartmentname.find( "przedzial" ) == 0 ) ) {
|
||||
// compartments are lit with 75% probability
|
||||
sectionlight.level = ( Random() < 0.75 ? 0.75f : 0.15f );
|
||||
}
|
||||
@@ -978,6 +978,22 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
|
||||
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 *************************************
|
||||
|
||||
@@ -1797,8 +1813,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
{
|
||||
size_t dlugosc = MoreParams.length();
|
||||
ActPar = ToUpper(MoreParams.substr(0, kropka)); // pierwszy parametr;
|
||||
MoreParams = MoreParams.substr(kropka + 1, dlugosc - kropka); // reszta do dalszej
|
||||
// obrobki
|
||||
MoreParams = MoreParams.substr(kropka + 1, dlugosc - kropka); // reszta do dalszej obrobki
|
||||
kropka = MoreParams.find(".");
|
||||
|
||||
if (ActPar.substr(0, 1) == "B") // jesli hamulce
|
||||
@@ -1910,6 +1925,41 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
{
|
||||
}
|
||||
} // 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
|
||||
{
|
||||
// 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
|
||||
// TODO: definition of relevant compartments in the .mmd file
|
||||
TSubModel *submodel { nullptr };
|
||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab1" ) ) != nullptr ) { SectionLightLevels.emplace_back( submodel, nullptr, 0.0f ); }
|
||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab2" ) ) != nullptr ) { SectionLightLevels.emplace_back( submodel, nullptr, 0.0f ); }
|
||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab0" ) ) != 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.push_back( { submodel, nullptr, 0.0f } ); }
|
||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab0" ) ) != nullptr ) { SectionLightLevels.push_back( { submodel, nullptr, 0.0f } ); }
|
||||
// passenger car compartments
|
||||
std::vector<std::string> nameprefixes = { "corridor", "korytarz", "compartment", "przedzial" };
|
||||
int compartmentindex;
|
||||
@@ -2029,19 +2079,17 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
std::to_string( compartmentindex ) );
|
||||
submodel = mdLowPolyInt->GetFromName( compartmentname );
|
||||
if( submodel != nullptr ) {
|
||||
// if specified compartment was found we check also for potential matching section in the currently assigned load
|
||||
// NOTE: if the load gets changed this will invalidate stored pointers. TODO: rebuild the table on load change
|
||||
SectionLightLevels.emplace_back(
|
||||
SectionLightLevels.push_back( {
|
||||
submodel,
|
||||
( mdLoad != nullptr ?
|
||||
mdLoad->GetFromName( compartmentname ):
|
||||
nullptr ),
|
||||
0.0f );
|
||||
nullptr, // pointers to load sections are generated afterwards
|
||||
0.0f } );
|
||||
}
|
||||
++compartmentindex;
|
||||
} while( ( submodel != nullptr )
|
||||
|| ( compartmentindex < 2 ) ); // chain can start from prefix00 or prefix01
|
||||
}
|
||||
update_load_sections();
|
||||
update_load_visibility();
|
||||
}
|
||||
// wyszukiwanie zderzakow
|
||||
if( mdModel ) {
|
||||
@@ -2430,31 +2478,115 @@ bool TDynamicObject::UpdateForce(double dt, double dt1, bool FullVer)
|
||||
return true;
|
||||
}
|
||||
|
||||
void TDynamicObject::LoadUpdate()
|
||||
{ // przeładowanie modelu ładunku
|
||||
void TDynamicObject::LoadUpdate() {
|
||||
// przeładowanie modelu ładunku
|
||||
// Ra: nie próbujemy wczytywać modeli miliony razy podczas renderowania!!!
|
||||
if ((mdLoad == NULL) && (MoverParameters->Load > 0))
|
||||
{
|
||||
std::string asLoadName =
|
||||
asBaseDir + MoverParameters->LoadType + ".t3d"; // zapamiętany katalog pojazdu
|
||||
// asLoadName=MoverParameters->LoadType;
|
||||
// if (MoverParameters->LoadType!=AnsiString("passengers"))
|
||||
Global.asCurrentTexturePath = asBaseDir; // bieżąca ścieżka do tekstur to dynamic/...
|
||||
mdLoad = TModelsManager::GetModel(asLoadName.c_str()); // nowy ładunek
|
||||
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
|
||||
if( ( mdLoad == nullptr )
|
||||
&& ( MoverParameters->Load > 0 ) ) {
|
||||
|
||||
if( false == MoverParameters->LoadType.empty() ) {
|
||||
|
||||
Global.asCurrentTexturePath = asBaseDir; // bieżąca ścieżka do tekstur to dynamic/...
|
||||
|
||||
// try first specialized version of the load model, vehiclename_loadname
|
||||
auto const specializedloadfilename { asBaseDir + MoverParameters->TypeName + "_" + MoverParameters->LoadType };
|
||||
if( ( true == FileExists( specializedloadfilename + ".e3d" ) )
|
||||
|| ( true == FileExists( specializedloadfilename + ".t3d" ) ) ) {
|
||||
mdLoad = TModelsManager::GetModel( specializedloadfilename, true );
|
||||
}
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
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:
|
||||
@@ -3639,7 +3771,7 @@ void TDynamicObject::RenderSounds() {
|
||||
}
|
||||
// NBMX Obsluga drzwi, MC: zuniwersalnione
|
||||
if( ( true == MoverParameters->DoorLeftOpened )
|
||||
&& ( dDoorMoveL < MoverParameters->DoorMaxShiftL ) ) {
|
||||
&& ( dDoorMoveL < MoverParameters->DoorMaxShiftL ) ) {
|
||||
|
||||
for( auto &door : m_doorsounds ) {
|
||||
if( door.rsDoorClose.offset().x > 0.f ) {
|
||||
@@ -3650,7 +3782,7 @@ void TDynamicObject::RenderSounds() {
|
||||
}
|
||||
}
|
||||
if( ( false == MoverParameters->DoorLeftOpened )
|
||||
&& ( dDoorMoveL > 0.01 ) ) {
|
||||
&& ( dDoorMoveL > 0.01 ) ) {
|
||||
|
||||
for( auto &door : m_doorsounds ) {
|
||||
if( door.rsDoorClose.offset().x > 0.f ) {
|
||||
@@ -3661,7 +3793,7 @@ void TDynamicObject::RenderSounds() {
|
||||
}
|
||||
}
|
||||
if( ( true == MoverParameters->DoorRightOpened )
|
||||
&& ( dDoorMoveR < MoverParameters->DoorMaxShiftR ) ) {
|
||||
&& ( dDoorMoveR < MoverParameters->DoorMaxShiftR ) ) {
|
||||
|
||||
for( auto &door : m_doorsounds ) {
|
||||
if( door.rsDoorClose.offset().x < 0.f ) {
|
||||
@@ -3672,7 +3804,7 @@ void TDynamicObject::RenderSounds() {
|
||||
}
|
||||
}
|
||||
if( ( false == MoverParameters->DoorRightOpened )
|
||||
&& ( dDoorMoveR > 0.01 ) ) {
|
||||
&& ( dDoorMoveR > 0.01 ) ) {
|
||||
|
||||
for( auto &door : m_doorsounds ) {
|
||||
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 asLoadName;
|
||||
if( false == MoverParameters->LoadType.empty() ) {
|
||||
asLoadName = BaseDir + MoverParameters->LoadType + ".t3d";
|
||||
asLoadName = BaseDir + MoverParameters->LoadType;
|
||||
}
|
||||
|
||||
std::string asAnimName;
|
||||
|
||||
12
DynObj.h
12
DynObj.h
@@ -195,13 +195,16 @@ public:
|
||||
TSubModel *compartment;
|
||||
TSubModel *load;
|
||||
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
|
||||
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?)
|
||||
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:
|
||||
// zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe
|
||||
@@ -465,6 +468,9 @@ private:
|
||||
void AttachPrev(TDynamicObject *Object, int iType = 1);
|
||||
bool UpdateForce(double dt, double dt1, bool FullVer);
|
||||
void LoadUpdate();
|
||||
void update_load_sections();
|
||||
void update_load_visibility();
|
||||
void shuffle_load_sections();
|
||||
bool Update(double dt, double dt1);
|
||||
bool FastUpdate(double dt);
|
||||
void Move(double fDistance);
|
||||
|
||||
2
EU07.cpp
2
EU07.cpp
@@ -259,7 +259,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
#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)
|
||||
{
|
||||
|
||||
@@ -69,7 +69,7 @@ struct global_settings {
|
||||
float fFriction{ 1.f }; // mnożnik tarcia - KURS90
|
||||
bool bLiveTraction{ true };
|
||||
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 fFogEnd{ 2000 };
|
||||
std::string Season{}; // season of the year, based on simulation date
|
||||
|
||||
@@ -1021,7 +1021,7 @@ public:
|
||||
int PulseForceCount = 0;
|
||||
|
||||
/*dla drezyny, silnika spalinowego i parowego*/
|
||||
double eAngle = 1.5;
|
||||
double eAngle = M_PI * 0.5;
|
||||
|
||||
/*-dla wagonow*/
|
||||
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*/
|
||||
{ // 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
|
||||
if ((TrainType == dt_EZT))
|
||||
if ((TrainType == dt_EZT)
|
||||
|| (TrainType == dt_ET41))
|
||||
{ //'ezt'
|
||||
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*/
|
||||
{ // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
|
||||
if ((TrainType == dt_EZT))
|
||||
if ((TrainType == dt_EZT)
|
||||
||(TrainType == dt_ET41))
|
||||
{ //'ezt'
|
||||
if ((CValue1 == 1))
|
||||
{
|
||||
|
||||
19
Model3d.cpp
19
Model3d.cpp
@@ -729,6 +729,25 @@ void TSubModel::NextAdd(TSubModel *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()
|
||||
{ // analiza koniecznych zmian pomiędzy submodelami
|
||||
// samo pomijanie glBindTexture() nie poprawi wydajności
|
||||
|
||||
@@ -161,6 +161,8 @@ public:
|
||||
void NextAdd(TSubModel *SubModel);
|
||||
TSubModel * NextGet() { return Next; };
|
||||
TSubModel * ChildGet() { return Child; };
|
||||
int count_siblings();
|
||||
int count_children();
|
||||
int TriangleAdd(TModel3d *m, material_handle tex, int tri);
|
||||
void SetRotate(float3 vNewRotateAxis, float fNewAngle);
|
||||
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 "Spring.h"
|
||||
|
||||
TSpring::TSpring()
|
||||
{
|
||||
vForce1 = vForce2 = Math3D::vector3(0, 0, 0);
|
||||
Ks = 0;
|
||||
Kd = 0;
|
||||
restLen = 0;
|
||||
}
|
||||
|
||||
TSpring::~TSpring()
|
||||
{
|
||||
}
|
||||
|
||||
void TSpring::Init(double nrestLen, double nKs, double nKd)
|
||||
{
|
||||
void TSpring::Init(double nKs, double nKd) {
|
||||
Ks = nKs;
|
||||
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, deltaV;
|
||||
Math3D::vector3 springForce;
|
||||
// p1 = &system[spring->p1];
|
||||
// p2 = &system[spring->p2];
|
||||
// VectorDifference(&p1->pos,&p2->pos,&deltaP); // Vector distance
|
||||
auto deltaP = pPosition1 - pPosition2;
|
||||
// dist = VectorLength(&deltaP); // Magnitude of
|
||||
// deltaP
|
||||
dist = deltaP.Length();
|
||||
if (dist != 0.0 ) {
|
||||
// dist = VectorLength(&deltaP); // Magnitude of deltaP
|
||||
auto dist = deltaP.Length();
|
||||
if( dist > restLen ) {
|
||||
|
||||
// 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
|
||||
deltaV = pPosition1 - pPosition2;
|
||||
auto deltaV = pPosition1 - pPosition2;
|
||||
|
||||
// Dterm = (DotProduct(&deltaV,&deltaP) * spring->Kd) / dist; // Damping Term
|
||||
// Dterm = (DotProduct(deltaV,deltaP) * Kd) / dist;
|
||||
Dterm = 0;
|
||||
auto Dterm = (DotProduct(deltaV,deltaP) * Kd) / dist;
|
||||
//Dterm = 0;
|
||||
|
||||
// ScaleVector(&deltaP,1.0f / dist, &springForce); // Normalize Distance Vector
|
||||
// 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
|
||||
}
|
||||
|
||||
vForce1 = springForce;
|
||||
vForce2 = springForce;
|
||||
|
||||
return springForce;
|
||||
}
|
||||
|
||||
void TSpring::Render()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
25
Spring.h
25
Spring.h
@@ -11,9 +11,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#define ParticlesH
|
||||
|
||||
#include "dumb3d.h"
|
||||
|
||||
/*
|
||||
#define STATIC_THRESHOLD 0.17f
|
||||
// efine STATIC_THRESHOLD 0.03f
|
||||
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_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_Ckf = 0.7f; // Default Kinetic Friction
|
||||
*/
|
||||
class TSpring {
|
||||
|
||||
class TSpring
|
||||
{
|
||||
public:
|
||||
TSpring();
|
||||
~TSpring();
|
||||
public:
|
||||
TSpring() = default;
|
||||
// void Init(TParticnp1, TParticle *np2, double nKs= 0.5f, double nKd= 0.002f,
|
||||
// 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);
|
||||
void Render();
|
||||
Math3D::vector3 vForce1, vForce2;
|
||||
double restLen; // LENGTH OF SPRING AT REST
|
||||
double Ks; // SPRING CONSTANT
|
||||
double Kd; // SPRING DAMPING
|
||||
private:
|
||||
private:
|
||||
// members
|
||||
double restLen { 0.01 }; // LENGTH OF SPRING AT REST
|
||||
double Ks { 0.0 }; // SPRING CONSTANT
|
||||
double Kd { 0.0 }; // SPRING DAMPING
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
pMechOffset = Math3D::vector3( 0, 0, 0 );
|
||||
fMechSpringX = 1;
|
||||
@@ -3312,9 +3312,10 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman
|
||||
}
|
||||
}
|
||||
else {
|
||||
// in the rear cab sides are reversed
|
||||
// in the rear cab sides are reversed...
|
||||
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 {
|
||||
// in the rear cab sides are reversed
|
||||
// in the rear cab sides are reversed...
|
||||
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 {
|
||||
// in the rear cab sides are reversed
|
||||
// in the rear cab sides are reversed...
|
||||
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 {
|
||||
// in the rear cab sides are reversed
|
||||
// in the rear cab sides are reversed...
|
||||
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
|
||||
double const iVel = std::min( DynamicObject->GetVelocity(), 150.0 );
|
||||
|
||||
if( !Global.iSlowMotion // musi być pełna prędkość
|
||||
&& ( pMechOffset.y < 4.0 ) ) // Ra 15-01: przy oglądaniu pantografu bujanie przeszkadza
|
||||
if( ( false == Global.iSlowMotion ) // musi być pełna prędkość
|
||||
&& ( 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 ) {
|
||||
// acceleration-driven base shake
|
||||
shake += 1.25 * MechSpring.ComputateForces(
|
||||
Math3D::vector3(
|
||||
-mvControlled->AccN * dt * 5.0, // highlight side sway
|
||||
-mvControlled->AccVert * dt,
|
||||
-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;
|
||||
shakevector += Math3D::vector3(
|
||||
-mvOccupied->AccN * dt * 5.0, // highlight side sway
|
||||
-mvOccupied->AccVert * dt,
|
||||
-mvOccupied->AccSVBased * dt * 1.25 ); // accent acceleration/deceleration
|
||||
}
|
||||
|
||||
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 );
|
||||
// shake *= 0.95 * dt; // shake damping
|
||||
|
||||
// McZapkie:
|
||||
pMechShake += vMechVelocity * dt;
|
||||
if( ( pMechShake.y > fMechMaxSpring )
|
||||
|| ( pMechShake.y < -fMechMaxSpring ) ) {
|
||||
vMechVelocity.y = -vMechVelocity.y;
|
||||
}
|
||||
// Ra 2015-01: dotychczasowe rzucanie
|
||||
pMechOffset += vMechMovement * dt;
|
||||
if( ( pMechShake.y > fMechMaxSpring ) || ( pMechShake.y < -fMechMaxSpring ) )
|
||||
vMechVelocity.y = -vMechVelocity.y;
|
||||
// ABu011104: 5*pMechShake.y, zeby ladnie pudlem rzucalo :)
|
||||
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
|
||||
pMechShake -= pMechShake * std::min( dt, 1.0 ); // po tym chyba potrafią zostać jakieś ułamki, które powodują zjazd
|
||||
pMechOffset += vMechMovement * dt;
|
||||
vMechVelocity.y = 0.5 * vMechVelocity.y;
|
||||
pMechPosition = pMechOffset + Math3D::vector3( pMechShake.x, 5 * pMechShake.y, pMechShake.z );
|
||||
// vMechMovement = 0.5 * vMechMovement;
|
||||
}
|
||||
// numer kabiny (-1: kabina B)
|
||||
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
|
||||
// TODO: rework it into something more elegant, when redoing the whole consist/unit/cab etc arrangement
|
||||
if( ( mvControlled->Battery )
|
||||
|| ( mvControlled->ConverterFlag ) ) {
|
||||
if( ggPantAllDownButton.GetDesiredValue() < 0.05 ) {
|
||||
// the 'lower all' button overrides state of switches, while active itself
|
||||
if( ( false == mvControlled->PantFrontUp )
|
||||
&& ( ggPantFrontButton.GetDesiredValue() >= 0.95 ) ) {
|
||||
mvControlled->PantFront( true );
|
||||
}
|
||||
if( ( false == mvControlled->PantRearUp )
|
||||
&& ( ggPantRearButton.GetDesiredValue() >= 0.95 ) ) {
|
||||
mvControlled->PantRear( true );
|
||||
if( false == DynamicObject->Mechanik->AIControllFlag ) {
|
||||
// don't mess with the ai driving, at least not while switches don't follow ai-set vehicle state
|
||||
if( ( mvControlled->Battery )
|
||||
|| ( mvControlled->ConverterFlag ) ) {
|
||||
if( ggPantAllDownButton.GetDesiredValue() < 0.05 ) {
|
||||
// the 'lower all' button overrides state of switches, while active itself
|
||||
if( ( false == mvControlled->PantFrontUp )
|
||||
&& ( ggPantFrontButton.GetDesiredValue() >= 0.95 ) ) {
|
||||
mvControlled->PantFront( 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(
|
||||
std::remove_if(
|
||||
std::begin( m_radiomessages ), std::end( m_radiomessages ),
|
||||
[]( sound_source &source ) {
|
||||
[]( sound_source const &source ) {
|
||||
return ( false == source.is_playing() ); } ),
|
||||
std::end( m_radiomessages ) );
|
||||
}
|
||||
@@ -5320,7 +5349,7 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
|
||||
parser
|
||||
>> ks
|
||||
>> kd;
|
||||
MechSpring.Init(MechSpring.restLen, ks, kd);
|
||||
MechSpring.Init(ks, kd);
|
||||
parser.getTokens(6, false);
|
||||
parser
|
||||
>> fMechSpringX
|
||||
@@ -5330,6 +5359,15 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
|
||||
>> fMechRoll
|
||||
>> 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 != "");
|
||||
}
|
||||
|
||||
7
Train.h
7
Train.h
@@ -503,6 +503,13 @@ public: // reszta może by?publiczna
|
||||
double fMechMaxSpring;
|
||||
double fMechRoll;
|
||||
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 dsbNastawnikJazdy { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
|
||||
28
World.cpp
28
World.cpp
@@ -46,6 +46,7 @@ namespace simulation {
|
||||
|
||||
simulation_time Time;
|
||||
|
||||
basic_station Station;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -1093,10 +1094,13 @@ TWorld::Update_Camera( double const Deltatime ) {
|
||||
else {
|
||||
// patrzenie standardowe
|
||||
Camera.Pos = Train->GetWorldMechPosition(); // Train.GetPosition1();
|
||||
if( !Global.iPause ) { // podczas pauzy nie przeliczać kątów przypadkowymi wartościami
|
||||
Camera.Roll = atan( Train->pMechShake.x * Train->fMechRoll ); // hustanie kamery na boki
|
||||
Camera.Pitch -= 0.5 * atan( Train->vMechVelocity.z * Train->fMechPitch ); // hustanie kamery przod tyl //Ra: tu
|
||||
// jest uciekanie kamery w górę!!!
|
||||
if( !Global.iPause ) {
|
||||
// podczas pauzy nie przeliczać kątów przypadkowymi wartościami
|
||||
// hustanie kamery na boki
|
||||
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
|
||||
/*
|
||||
@@ -1368,7 +1372,7 @@ TWorld::Update_UI() {
|
||||
if( ( vehicle->MoverParameters->BrakeDelayFlag & bdelay_M ) == bdelay_M )
|
||||
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 +=
|
||||
"; Pant: "
|
||||
@@ -1614,7 +1618,8 @@ TWorld::Update_UI() {
|
||||
Acc = ( vehicle->MoverParameters->Vel - VelPrev ) / 3.6;
|
||||
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 =
|
||||
"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
|
||||
// (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 );
|
||||
Global.DayLight.ambient[ 0 ] = interpolate( skydomehsv.z, skydomecolour.x, ambienttone );
|
||||
Global.DayLight.ambient[ 1 ] = interpolate( skydomehsv.z, skydomecolour.y, ambienttone );
|
||||
Global.DayLight.ambient[ 2 ] = interpolate( skydomehsv.z, skydomecolour.z, ambienttone );
|
||||
Global.DayLight.ambient[ 0 ] = interpolate( skydomehsv.z, skydomecolour.r, ambienttone );
|
||||
Global.DayLight.ambient[ 1 ] = interpolate( skydomehsv.z, skydomecolour.g, ambienttone );
|
||||
Global.DayLight.ambient[ 2 ] = interpolate( skydomehsv.z, skydomecolour.b, ambienttone );
|
||||
|
||||
Global.fLuminance = intensity;
|
||||
|
||||
// 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
|
||||
Global.FogColor[ 0 ] = skydomecolour.x;
|
||||
Global.FogColor[ 1 ] = skydomecolour.y;
|
||||
Global.FogColor[ 2 ] = skydomecolour.z;
|
||||
// NOTE: base brightness calculation provides scaled up value, so we bring it back to 'real' one here
|
||||
Global.FogColor = m_skydome.GetAverageHorizonColor();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
3
World.h
3
World.h
@@ -20,6 +20,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "stars.h"
|
||||
#include "skydome.h"
|
||||
#include "messaging.h"
|
||||
#include "station.h"
|
||||
|
||||
// wrapper for simulation time
|
||||
class simulation_time {
|
||||
@@ -59,6 +60,8 @@ namespace simulation {
|
||||
|
||||
extern simulation_time Time;
|
||||
|
||||
extern basic_station Station; // temporary object, for station functionality tests
|
||||
|
||||
}
|
||||
|
||||
class opengl_renderer;
|
||||
|
||||
33
renderer.cpp
33
renderer.cpp
@@ -1049,7 +1049,7 @@ opengl_renderer::setup_drawing( bool const Alpha ) {
|
||||
// setup fog
|
||||
if( Global.fFogEnd > 0 ) {
|
||||
// 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 ) );
|
||||
::glEnable( GL_FOG );
|
||||
}
|
||||
@@ -1828,6 +1828,37 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
|
||||
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
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
|
||||
14
skydome.cpp
14
skydome.cpp
@@ -242,7 +242,7 @@ void CSkyDome::RebuildColors() {
|
||||
zenithluminance = PerezFunctionO1( perezluminance, m_thetasun, zenithluminance );
|
||||
|
||||
// start with fresh average for the new pass
|
||||
glm::vec3 averagecolor { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec3 averagecolor, averagehorizoncolor;
|
||||
|
||||
// trough all vertices
|
||||
glm::vec3 vertex;
|
||||
@@ -332,14 +332,16 @@ void CSkyDome::RebuildColors() {
|
||||
}
|
||||
// save
|
||||
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
|
||||
// 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.r = std::max( m_averagecolour.r, 0.0f );
|
||||
m_averagecolour.g = std::max( m_averagecolour.g, 0.0f );
|
||||
m_averagecolour.b = std::max( m_averagecolour.b, 0.0f );
|
||||
m_averagecolour = glm::max( glm::vec3(), averagecolor / static_cast<float>( m_vertices.size() ) );
|
||||
m_averagehorizoncolour = glm::max( glm::vec3(), averagehorizoncolor / static_cast<float>( m_tesselation * 2 ) );
|
||||
|
||||
if( m_coloursbuffer != -1 ) {
|
||||
// the colour buffer was already initialized, so on this run we update its content
|
||||
|
||||
@@ -23,7 +23,8 @@ public:
|
||||
void Render();
|
||||
|
||||
// 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:
|
||||
// shading parametrs
|
||||
@@ -35,6 +36,7 @@ private:
|
||||
float m_overcast;
|
||||
float m_gammacorrection;
|
||||
glm::vec3 m_averagecolour;
|
||||
glm::vec3 m_averagehorizoncolour;
|
||||
|
||||
// data
|
||||
int const m_tesselation;
|
||||
|
||||
87
sound.cpp
87
sound.cpp
@@ -454,8 +454,8 @@ sound_source::stop( bool const Skipend ) {
|
||||
|
||||
if( ( false == Skipend )
|
||||
&& ( 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 ).playing == 0 ) */ ) {
|
||||
/* && ( sound( sound_id::end ).buffer != sound( sound_id::main ).buffer ) */ // end == main can happen in malformed legacy cases
|
||||
/* && ( sound( sound_id::end ).playing == 0 ) */ ) {
|
||||
// spawn potentially defined sound end sample, if the emitter is currently active
|
||||
insert( sound_id::end );
|
||||
}
|
||||
@@ -482,19 +482,31 @@ sound_source::update_basic( audio::openal_source &Source ) {
|
||||
|
||||
if( true == Source.is_playing ) {
|
||||
|
||||
if( ( true == m_stop )
|
||||
&& ( Source.sounds[ Source.sound_index ] != sound_id::end ) ) {
|
||||
// kill the sound if stop was requested, unless it's sound bookend sample
|
||||
Source.stop();
|
||||
update_counter( Source.sounds[ Source.sound_index ], -1 );
|
||||
if( false == is_playing() ) {
|
||||
m_stop = false;
|
||||
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::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;
|
||||
}
|
||||
/*
|
||||
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
|
||||
Source.stop();
|
||||
update_counter( sound_id::end, -1 );
|
||||
@@ -504,25 +516,13 @@ sound_source::update_basic( audio::openal_source &Source ) {
|
||||
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
|
||||
update_location();
|
||||
update_soundproofing();
|
||||
Source.sync_with( m_properties );
|
||||
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
|
||||
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
|
||||
auto const soundhandle { Source.sounds[ Source.sound_index ] };
|
||||
// emitter initialization
|
||||
if( ( soundhandle == sound_id::main )
|
||||
&& ( true == TestFlag( m_flags, sound_flags::looping ) ) ) {
|
||||
if( soundhandle == sound_id::main ) {
|
||||
// main sample can be optionally set to loop
|
||||
Source.loop( true );
|
||||
Source.loop( TestFlag( m_flags, sound_flags::looping ) );
|
||||
}
|
||||
Source.range( m_range );
|
||||
Source.pitch( m_pitchvariation );
|
||||
@@ -570,6 +569,18 @@ sound_source::update_combined( audio::openal_source &Source ) {
|
||||
|
||||
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 )
|
||||
&& ( soundhandle != sound_id::end ) ) {
|
||||
// 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 )
|
||||
&& ( 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
|
||||
Source.stop();
|
||||
update_counter( sound_id::end, -1 );
|
||||
@@ -592,19 +603,6 @@ sound_source::update_combined( audio::openal_source &Source ) {
|
||||
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 ) {
|
||||
// for sound chunks, test whether the chunk should still be active given current value of the controlling variable
|
||||
auto const soundpoint { compute_combined_point() };
|
||||
@@ -629,7 +627,7 @@ sound_source::update_combined( audio::openal_source &Source ) {
|
||||
Source.sync_with( m_properties );
|
||||
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
|
||||
update_counter( Source.sounds[ Source.sound_index ], -1 );
|
||||
update_counter( soundhandle, -1 );
|
||||
}
|
||||
// ...and restore base properties
|
||||
m_properties = baseproperties;
|
||||
@@ -796,7 +794,7 @@ sound_source::empty() const {
|
||||
bool
|
||||
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 )
|
||||
&& ( false == m_soundchunks.empty() ) ) {
|
||||
// for emitters with sample tables check also if any of the chunks is active
|
||||
@@ -836,8 +834,9 @@ sound_source::location() const {
|
||||
void
|
||||
sound_source::update_counter( sound_handle const Sound, int const Value ) {
|
||||
|
||||
sound( Sound ).playing = std::max( 0, sound( Sound ).playing + Value );
|
||||
// assert( sound( Sound ).playing >= 0 );
|
||||
// sound( Sound ).playing = std::max( 0, sound( Sound ).playing + Value );
|
||||
sound( Sound ).playing += Value;
|
||||
assert( sound( Sound ).playing >= 0 );
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
10
sound.h
10
sound.h
@@ -179,15 +179,15 @@ private:
|
||||
template <class Iterator_>
|
||||
void
|
||||
insert( Iterator_ First, Iterator_ Last ) {
|
||||
uint32_sequence sounds;
|
||||
update_counter( *First, 1 );
|
||||
std::vector<audio::buffer_handle> buffers;
|
||||
uint32_sequence sounds;
|
||||
std::for_each(
|
||||
First, Last,
|
||||
[&]( sound_handle const &soundhandle ) {
|
||||
sounds.emplace_back( soundhandle );
|
||||
buffers.emplace_back( sound( soundhandle ).buffer ); } );
|
||||
audio::renderer.insert( std::begin( buffers ), std::end( buffers ), this, sounds );
|
||||
update_counter( *First, 1 ); }
|
||||
buffers.emplace_back( sound( soundhandle ).buffer );
|
||||
sounds.emplace_back( soundhandle ); } );
|
||||
audio::renderer.insert( std::begin( buffers ), std::end( buffers ), this, sounds ); }
|
||||
sound_data &
|
||||
sound( sound_handle const Sound );
|
||||
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_DEPTH_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_background();
|
||||
render_texture();
|
||||
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
glDisable( GL_TEXTURE_CUBE_MAP );
|
||||
|
||||
render_progress();
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
|
||||
render_panels();
|
||||
render_tooltip();
|
||||
|
||||
@@ -129,9 +139,6 @@ ui_layer::render_progress() {
|
||||
|
||||
if( (m_progress == 0.0f) && (m_subtaskprogress == 0.0f) ) return;
|
||||
|
||||
glPushAttrib( GL_ENABLE_BIT );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
|
||||
glm::vec2 origin, size;
|
||||
if( m_progressbottom == true ) {
|
||||
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 ) );
|
||||
print( m_progresstext );
|
||||
}
|
||||
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -186,9 +191,6 @@ ui_layer::render_panels() {
|
||||
|
||||
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 height = Global.iWindowHeight / 768.f;
|
||||
|
||||
@@ -199,7 +201,7 @@ ui_layer::render_panels() {
|
||||
int lineidx = 0;
|
||||
for( auto const &line : panel->text_lines ) {
|
||||
|
||||
::glColor4fv( &line.color.x );
|
||||
::glColor4fv( glm::value_ptr( line.color ) );
|
||||
::glRasterPos2f(
|
||||
0.5f * ( Global.iWindowWidth - width ) + panel->origin_x * height,
|
||||
panel->origin_y * height + 20.f * lineidx );
|
||||
@@ -207,8 +209,6 @@ ui_layer::render_panels() {
|
||||
++lineidx;
|
||||
}
|
||||
}
|
||||
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -219,13 +219,9 @@ ui_layer::render_tooltip() {
|
||||
glm::dvec2 mousepos;
|
||||
glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y );
|
||||
|
||||
glPushAttrib( GL_ENABLE_BIT );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
::glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||
::glColor4fv( glm::value_ptr( colors::white ) );
|
||||
::glRasterPos2f( mousepos.x + 20.0f, mousepos.y + 25.0f );
|
||||
print( m_tooltip );
|
||||
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -254,8 +250,7 @@ void
|
||||
ui_layer::render_texture() {
|
||||
|
||||
if( m_texture != 0 ) {
|
||||
::glColor4f( 1.f, 1.f, 1.f, 1.f );
|
||||
::glDisable( GL_BLEND );
|
||||
::glColor4fv( glm::value_ptr( colors::white ) );
|
||||
|
||||
GfxRenderer.Bind_Texture( null_handle );
|
||||
::glBindTexture( GL_TEXTURE_2D, m_texture );
|
||||
@@ -273,8 +268,6 @@ ui_layer::render_texture() {
|
||||
glEnd();
|
||||
|
||||
::glBindTexture( GL_TEXTURE_2D, 0 );
|
||||
|
||||
::glEnable( GL_BLEND );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user