16
0
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:
milek7
2018-02-24 16:05:35 +01:00
25 changed files with 678 additions and 338 deletions

View File

@@ -80,6 +80,7 @@ set(SOURCES
"utilities.cpp"
"light.cpp"
"uitranscripts.cpp"
"station.cpp"
)
set (PREFIX "")

View File

@@ -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)

View File

@@ -556,14 +556,14 @@ TDynamicObject::toggle_lights() {
for( auto &sectionlight : 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 &section : 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 &section : 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 &section ) {
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 &section ) {
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;

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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

View File

@@ -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*/

View File

@@ -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))
{

View File

@@ -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

View File

@@ -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);

View File

@@ -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()
{
}
//---------------------------------------------------------------------------

View File

@@ -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
View File

@@ -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 != "");
}

View File

@@ -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 };

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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;

View File

@@ -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
View File

@@ -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
View 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 &parameters { *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
View 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 );
};

View File

@@ -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 );
}
}

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 18
#define VERSION_MINOR 215
#define VERSION_MINOR 223
#define VERSION_REVISION 0