16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-24 00:49:18 +02:00

Merge branch 'milek-dev' into gfx-work

This commit is contained in:
milek7
2018-10-11 00:14:49 +02:00
45 changed files with 2215 additions and 1246 deletions

View File

@@ -446,7 +446,8 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable
m_materialdata.textures_alpha = 0x30300030; m_materialdata.textures_alpha = 0x30300030;
} }
fBlinkTimer = double( Random( 1000 * fOffTime ) ) / ( 1000 * fOffTime ); // TODO: redo the random timer initialization
// fBlinkTimer = Random() * ( fOnTime + fOffTime );
pModel = TModelsManager::GetModel( asName ); pModel = TModelsManager::GetModel( asName );
return ( pModel != nullptr ); return ( pModel != nullptr );
@@ -548,9 +549,73 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
if( Framestamp == m_framestamp ) { return; } if( Framestamp == m_framestamp ) { return; }
fBlinkTimer -= Timer::GetDeltaTime(); auto const timedelta { Timer::GetDeltaTime() };
if( fBlinkTimer <= 0 )
fBlinkTimer += fOffTime; // interpretacja ułamka zależnie od typu
// case ls_Off: ustalenie czasu migotania, t<1s (f>1Hz), np. 0.1 => t=0.1 (f=10Hz)
// case ls_On: ustalenie wypełnienia ułamkiem, np. 1.25 => zapalony przez 1/4 okresu
// case ls_Blink: ustalenie częstotliwości migotania, f<1Hz (t>1s), np. 2.2 => f=0.2Hz (t=5s)
float modeintegral, modefractional;
for( int idx = 0; idx < iNumLights; ++idx ) {
modefractional = std::modf( std::abs( lsLights[ idx ] ), &modeintegral );
if( modeintegral >= ls_Dark ) {
// light threshold modes don't use timers
continue;
}
auto const mode { static_cast<int>( modeintegral ) };
auto &opacity { m_lightopacities[ idx ] };
auto &timer { m_lighttimers[ idx ] };
if( ( modeintegral < ls_Blink ) && ( modefractional < 0.01f ) ) {
// simple flip modes
switch( mode ) {
case ls_Off: {
// reduce to zero
timer = std::max<float>( 0.f, timer - timedelta );
break;
}
case ls_On: {
// increase to max value
timer = std::min<float>( fTransitionTime, timer + timedelta );
break;
}
default: {
break;
}
}
opacity = timer / fTransitionTime;
}
else {
// blink modes
auto const ontime { (
( mode == ls_Blink ) ? ( ( modefractional < 0.01f ) ? fOnTime : ( 1.f / modefractional ) * 0.5f ) :
( mode == ls_Off ) ? modefractional * 0.5f :
( mode == ls_On ) ? modefractional * ( fOnTime + fOffTime ) :
fOnTime ) }; // fallback
auto const offtime { (
( mode == ls_Blink ) ? ( ( modefractional < 0.01f ) ? fOffTime : ontime ) :
( mode == ls_Off ) ? ontime :
( mode == ls_On ) ? ( fOnTime + fOffTime ) - ontime :
fOffTime ) }; // fallback
auto const transitiontime {
std::min(
1.f,
std::min( ontime, offtime ) * 0.9f ) };
timer = clamp_circular<float>( timer + timedelta * ( lsLights[ idx ] > 0.f ? 1.f : -1.f ), ontime + offtime );
// set opacity depending on blink stage
if( timer < ontime ) {
// blink on
opacity = clamp( timer / transitiontime, 0.f, 1.f );
}
else {
// blink off
opacity = 1.f - clamp( ( timer - ontime ) / transitiontime, 0.f, 1.f );
}
}
}
// Ra 2F1I: to by można pomijać dla modeli bez animacji, których jest większość // Ra 2F1I: to by można pomijać dla modeli bez animacji, których jest większość
TAnimContainer *pCurrent; TAnimContainer *pCurrent;
@@ -569,17 +634,19 @@ void TAnimModel::RaPrepare()
bool state; // stan światła bool state; // stan światła
for (int i = 0; i < iNumLights; ++i) for (int i = 0; i < iNumLights; ++i)
{ {
auto const lightmode { static_cast<int>( lsLights[ i ] ) }; auto const lightmode { static_cast<int>( std::abs( lsLights[ i ] ) ) };
switch( lightmode ) { switch( lightmode ) {
case ls_On: case ls_On:
case ls_Off: { case ls_Off:
// zapalony albo zgaszony
state = ( lightmode == ls_On );
break;
}
case ls_Blink: { case ls_Blink: {
// migotanie if (LightsOn[i]) {
state = ( fBlinkTimer < fOnTime ); LightsOn[i]->iVisible = ( m_lightopacities[i] > 0.f );
LightsOn[i]->SetVisibilityLevel( m_lightopacities[i], true, false );
}
if (LightsOff[i]) {
LightsOff[i]->iVisible = ( m_lightopacities[i] < 1.f );
LightsOff[i]->SetVisibilityLevel( 1.f, true, false );
}
break; break;
} }
case ls_Dark: { case ls_Dark: {
@@ -607,11 +674,17 @@ void TAnimModel::RaPrepare()
break; break;
} }
} }
if (LightsOn[i]) if( lightmode >= ls_Dark ) {
// crude as hell but for test will do :x
if (LightsOn[i]) {
LightsOn[i]->iVisible = state; LightsOn[i]->iVisible = state;
// TODO: set visibility for the entire submodel's children as well
LightsOn[i]->fVisible = m_lightopacities[i];
}
if (LightsOff[i]) if (LightsOff[i])
LightsOff[i]->iVisible = !state; LightsOff[i]->iVisible = !state;
} }
}
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( this ); //żeby nie robić cudzych animacji TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( this ); //żeby nie robić cudzych animacji
TSubModel::pasText = &asText; // przekazanie tekstu do wyświetlacza (!!!! do przemyślenia) TSubModel::pasText = &asText; // przekazanie tekstu do wyświetlacza (!!!! do przemyślenia)
if (pAdvanced) // jeśli jest zaawansowana animacja if (pAdvanced) // jeśli jest zaawansowana animacja
@@ -775,8 +848,9 @@ void TAnimModel::AnimationVND(void *pData, double a, double b, double c, double
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void TAnimModel::LightSet(int const n, float const v) void TAnimModel::LightSet(int const n, float const v)
{ // ustawienie światła (n) na wartość (v) { // ustawienie światła (n) na wartość (v)
if (n >= iMaxNumLights) if( n >= iMaxNumLights ) {
return; // przekroczony zakres return; // przekroczony zakres
}
lsLights[ n ] = v; lsLights[ n ] = v;
}; };

View File

@@ -179,7 +179,7 @@ private:
// members // members
TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli
TModel3d *pModel { nullptr }; TModel3d *pModel { nullptr };
double fBlinkTimer { 0.0 }; // double fBlinkTimer { 0.0 };
int iNumLights { 0 }; int iNumLights { 0 };
TSubModel *LightsOn[ iMaxNumLights ]; // Ra: te wskaźniki powinny być w ramach TModel3d TSubModel *LightsOn[ iMaxNumLights ]; // Ra: te wskaźniki powinny być w ramach TModel3d
TSubModel *LightsOff[ iMaxNumLights ]; TSubModel *LightsOff[ iMaxNumLights ];
@@ -188,10 +188,13 @@ private:
std::string asText; // tekst dla wyświetlacza znakowego std::string asText; // tekst dla wyświetlacza znakowego
TAnimAdvanced *pAdvanced { nullptr }; TAnimAdvanced *pAdvanced { nullptr };
// TODO: wrap into a light state struct
float lsLights[ iMaxNumLights ]; float lsLights[ iMaxNumLights ];
// float fDark { DefaultDarkThresholdLevel }; // poziom zapalanie światła (powinno być chyba powiązane z danym światłem?) std::array<float, iMaxNumLights> m_lighttimers { 0.f };
float fOnTime { 0.66f }; std::array<float, iMaxNumLights> m_lightopacities { 1.f };
float fOffTime { 0.66f + 0.66f }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza float fOnTime { 1.f / 2 };// { 60.f / 45.f / 2 };
float fOffTime { 1.f / 2 };// { 60.f / 45.f / 2 }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza
float fTransitionTime { fOnTime * 0.9f }; // time
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
}; };

View File

@@ -115,9 +115,17 @@ set(SOURCES
"imgui/imgui_demo.cpp" "imgui/imgui_demo.cpp"
"imgui/imgui_draw.cpp" "imgui/imgui_draw.cpp"
"imgui/imgui_impl_glfw.cpp" "imgui/imgui_impl_glfw.cpp"
"imgui/imgui_impl_opengl3.cpp"
) )
option(USE_IMGUI_GL3 "Use OpenGL3+ imgui implementation" ON)
if (USE_IMGUI_GL3)
set(SOURCES ${SOURCES} "imgui/imgui_impl_opengl3.cpp")
else()
add_definitions(-DEU07_USEIMGUIIMPLOPENGL2)
set(SOURCES ${SOURCES} "imgui/imgui_impl_opengl2.cpp")
endif()
set (PREFIX "") set (PREFIX "")
if (WIN32) if (WIN32)

View File

@@ -339,8 +339,8 @@ std::string TSpeedPos::TableText() const
{ // pozycja tabelki pr?dko?ci { // pozycja tabelki pr?dko?ci
if (iFlags & spEnabled) if (iFlags & spEnabled)
{ // o ile pozycja istotna { // o ile pozycja istotna
return "Flags:" + to_hex_str(iFlags, 8) + ", Dist:" + to_string(fDist, 1, 6) + return to_hex_str(iFlags, 8) + " " + to_string(fDist, 1, 6) +
", Vel:" + (fVelNext == -1.0 ? " - " : to_string(static_cast<int>(fVelNext), 0, 3)) + ", Name:" + GetName(); " " + (fVelNext == -1.0 ? " -" : to_string(static_cast<int>(fVelNext), 0, 3)) + " " + GetName();
} }
return "Empty"; return "Empty";
} }
@@ -2437,6 +2437,11 @@ bool TController::PrepareEngine()
mvOccupied->ConverterSwitch( true ); mvOccupied->ConverterSwitch( true );
// w EN57 sprężarka w ra jest zasilana z silnikowego // w EN57 sprężarka w ra jest zasilana z silnikowego
mvOccupied->CompressorSwitch( true ); mvOccupied->CompressorSwitch( true );
// enable motor blowers
mvOccupied->MotorBlowersSwitchOff( false, side::front );
mvOccupied->MotorBlowersSwitch( true, side::front );
mvOccupied->MotorBlowersSwitchOff( false, side::rear );
mvOccupied->MotorBlowersSwitch( true, side::rear );
} }
} }
else else
@@ -4254,123 +4259,6 @@ TController::UpdateSituation(double dt) {
fMaxProximityDist = 10.0; //[m] fMaxProximityDist = 10.0; //[m]
fVelPlus = 1.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania fVelPlus = 1.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu
if (AIControllFlag) {
if (iVehicleCount >= 0) {
// jeśli była podana ilość wagonów
if (iDrivigFlags & movePress) {
// jeśli dociskanie w celu odczepienia
// 3. faza odczepiania.
SetVelocity(2, 0); // jazda w ustawionym kierunku z prędkością 2
if ((mvControlling->MainCtrlPos > 0) ||
(mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic)) // jeśli jazda
{
WriteLog(mvOccupied->Name + " odczepianie w kierunku " + std::to_string(mvOccupied->DirAbsolute));
TDynamicObject *p =
pVehicle; // pojazd do odczepienia, w (pVehicle) siedzi AI
int d; // numer sprzęgu, który sprawdzamy albo odczepiamy
int n = iVehicleCount; // ile wagonów ma zostać
do
{ // szukanie pojazdu do odczepienia
d = p->DirectionGet() > 0 ?
0 :
1; // numer sprzęgu od strony czoła składu
// if (p->MoverParameters->Couplers[d].CouplerType==Articulated)
// //jeśli sprzęg typu wózek (za mało)
if (p->MoverParameters->Couplers[d].CouplingFlag &
ctrain_depot) // jeżeli sprzęg zablokowany
// if (p->GetTrack()->) //a nie stoi na torze warsztatowym
// (ustalić po czym poznać taki tor)
++n; // to liczymy człony jako jeden
p->MoverParameters->BrakeReleaser(1); // wyluzuj pojazd, aby dało się dopychać
p->MoverParameters->BrakeLevelSet(0); // hamulec na zero, aby nie hamował
if (n)
{ // jeśli jeszcze nie koniec
p = p->Prev(); // kolejny w stronę czoła składu (licząc od
// tyłu), bo dociskamy
if (!p)
iVehicleCount = -2,
n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone
}
} while (n--);
if( p ? p->MoverParameters->Couplers[ d ].CouplingFlag == coupling::faux : true ) {
// no target, or already just virtual coupling
WriteLog( mvOccupied->Name + " didn't find anything to disconnect." );
iVehicleCount = -2; // odczepiono, co było do odczepienia
} else if ( p->Dettach(d) == coupling::faux ) {
// tylko jeśli odepnie
WriteLog( mvOccupied->Name + " odczepiony." );
iVehicleCount = -2;
} // a jak nie, to dociskać dalej
}
if (iVehicleCount >= 0) // zmieni się po odczepieniu
if (!mvOccupied->DecLocalBrakeLevel(1))
{ // dociśnij sklad
WriteLog( mvOccupied->Name + " dociskanie..." );
// mvOccupied->BrakeReleaser(); //wyluzuj lokomotywę
// Ready=true; //zamiast sprawdzenia odhamowania całego składu
IncSpeed(); // dla (Ready)==false nie ruszy
}
}
if ((mvOccupied->Vel < 0.01) && !(iDrivigFlags & movePress))
{ // 2. faza odczepiania: zmień kierunek na przeciwny i dociśnij
// za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach
// powino zostać wyłączone)
// WriteLog("Zahamowanie składu");
mvOccupied->BrakeLevelSet(
mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ?
1 :
3 );
double p = mvOccupied->BrakePressureActual.PipePressureVal;
if( p < 3.9 ) {
// tu może być 0 albo -1 nawet
// TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia sensu 0 oraz -1 w tym miejscu
p = 3.9;
}
if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ?
mvOccupied->BrakePress > 2 :
mvOccupied->PipePress < p + 0.1)
{ // jeśli w miarę został zahamowany (ciśnienie mniejsze niż podane na
// pozycji 3, zwyle 0.37)
if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic)
mvOccupied->BrakeLevelSet(0); // wyłączenie EP, gdy wystarczy (może
// nie być potrzebne, bo na początku
// jest)
WriteLog("Luzowanie lokomotywy i zmiana kierunku");
mvOccupied->BrakeReleaser(1); // wyluzuj lokomotywę; a ST45?
mvOccupied->DecLocalBrakeLevel(LocalBrakePosNo); // zwolnienie hamulca
iDrivigFlags |= movePress; // następnie będzie dociskanie
DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na przeciwny (dociskanie)
CheckVehicles(); // od razu zmienić światła (zgasić) - bez tego się nie odczepi
/*
// NOTE: disabled to prevent closing the door before passengers can disembark
fStopTime = 0.0; // nie ma na co czekać z odczepianiem
*/
}
}
else {
if( mvOccupied->Vel > 0.01 ) {
// 1st phase(?)
// bring it to stop if it's not already stopped
SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie
}
}
} // odczepiania
else // to poniżej jeśli ilość wagonów ujemna
if (iDrivigFlags & movePress)
{ // 4. faza odczepiania: zwolnij i zmień kierunek
SetVelocity(0, 0, stopJoin); // wyłączyć przyspieszanie
if (!DecSpeed()) // jeśli już bardziej wyłączyć się nie da
{ // ponowna zmiana kierunku
WriteLog( mvOccupied->Name + " ponowna zmiana kierunku" );
DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na właściwy
iDrivigFlags &= ~movePress; // koniec dociskania
JumpToNextOrder(); // zmieni światła
TableClear(); // skanowanie od nowa
iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed ruszeniem
SetVelocity(fShuntVelocity, fShuntVelocity); // ustawienie prędkości jazdy
}
}
}
break; break;
} }
case Shunt: { case Shunt: {
@@ -4585,10 +4473,13 @@ TController::UpdateSituation(double dt) {
} }
// ustalanie zadanej predkosci // ustalanie zadanej predkosci
if (iDrivigFlags & moveActive) // jeśli może skanować sygnały i reagować na komendy if (iDrivigFlags & moveActive) {
{ // jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy
// Ra: tu by jeszcze trzeba było wstawić uzależnienie (VelDesired) od odległości od SetDriverPsyche(); // ustawia AccPreferred (potrzebne tu?)
// przeszkody
// jeśli może skanować sygnały i reagować na komendy
// jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy
// Ra: tu by jeszcze trzeba było wstawić uzależnienie (VelDesired) od odległości od przeszkody
// no chyba żeby to uwzgldnić już w (ActualProximityDist) // no chyba żeby to uwzgldnić już w (ActualProximityDist)
VelDesired = fVelMax; // wstępnie prędkość maksymalna dla pojazdu(-ów), będzie VelDesired = fVelMax; // wstępnie prędkość maksymalna dla pojazdu(-ów), będzie
// następnie ograniczana // następnie ograniczana
@@ -4597,9 +4488,6 @@ TController::UpdateSituation(double dt) {
// jeśli ma rozkład i ograniczenie w rozkładzie to nie przekraczać rozkladowej // jeśli ma rozkład i ograniczenie w rozkładzie to nie przekraczać rozkladowej
VelDesired = min_speed( VelDesired, TrainParams->TTVmax ); VelDesired = min_speed( VelDesired, TrainParams->TTVmax );
} }
SetDriverPsyche(); // ustawia AccPreferred (potrzebne tu?)
// szukanie optymalnych wartości // szukanie optymalnych wartości
AccDesired = AccPreferred; // AccPreferred wynika z osobowości mechanika AccDesired = AccPreferred; // AccPreferred wynika z osobowości mechanika
VelNext = VelDesired; // maksymalna prędkość wynikająca z innych czynników niż trajektoria ruchu VelNext = VelDesired; // maksymalna prędkość wynikająca z innych czynników niż trajektoria ruchu
@@ -4647,6 +4535,126 @@ TController::UpdateSituation(double dt) {
default: default:
break; break;
} }
// disconnect mode potentially overrides scan results
// TBD: when in this mode skip scanning altogether?
if( ( OrderCurrentGet() & Disconnect ) != 0 ) {
if (AIControllFlag) {
if (iVehicleCount >= 0) {
// jeśli była podana ilość wagonów
if (iDrivigFlags & movePress) {
// jeśli dociskanie w celu odczepienia
// 3. faza odczepiania.
SetVelocity(2, 0); // jazda w ustawionym kierunku z prędkością 2
if ((mvControlling->MainCtrlPos > 0) ||
(mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic)) // jeśli jazda
{
WriteLog(mvOccupied->Name + " odczepianie w kierunku " + std::to_string(mvOccupied->DirAbsolute));
TDynamicObject *p =
pVehicle; // pojazd do odczepienia, w (pVehicle) siedzi AI
int d; // numer sprzęgu, który sprawdzamy albo odczepiamy
int n = iVehicleCount; // ile wagonów ma zostać
do
{ // szukanie pojazdu do odczepienia
d = p->DirectionGet() > 0 ?
0 :
1; // numer sprzęgu od strony czoła składu
// if (p->MoverParameters->Couplers[d].CouplerType==Articulated)
// //jeśli sprzęg typu wózek (za mało)
if (p->MoverParameters->Couplers[d].CouplingFlag & ctrain_depot) // jeżeli sprzęg zablokowany
// if (p->GetTrack()->) //a nie stoi na torze warsztatowym
// (ustalić po czym poznać taki tor)
++n; // to liczymy człony jako jeden
p->MoverParameters->BrakeReleaser(1); // wyluzuj pojazd, aby dało się dopychać
p->MoverParameters->BrakeLevelSet(0); // hamulec na zero, aby nie hamował
if (n)
{ // jeśli jeszcze nie koniec
p = p->Prev(); // kolejny w stronę czoła składu (licząc od
// tyłu), bo dociskamy
if (!p)
iVehicleCount = -2,
n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone
}
} while (n--);
if( p ? p->MoverParameters->Couplers[ d ].CouplingFlag == coupling::faux : true ) {
// no target, or already just virtual coupling
WriteLog( mvOccupied->Name + " didn't find anything to disconnect." );
iVehicleCount = -2; // odczepiono, co było do odczepienia
} else if ( p->Dettach(d) == coupling::faux ) {
// tylko jeśli odepnie
WriteLog( mvOccupied->Name + " odczepiony." );
iVehicleCount = -2;
} // a jak nie, to dociskać dalej
}
if (iVehicleCount >= 0) // zmieni się po odczepieniu
if (!mvOccupied->DecLocalBrakeLevel(1))
{ // dociśnij sklad
WriteLog( mvOccupied->Name + " dociskanie..." );
// mvOccupied->BrakeReleaser(); //wyluzuj lokomotywę
// Ready=true; //zamiast sprawdzenia odhamowania całego składu
IncSpeed(); // dla (Ready)==false nie ruszy
}
}
if ((mvOccupied->Vel < 0.01) && !(iDrivigFlags & movePress))
{ // 2. faza odczepiania: zmień kierunek na przeciwny i dociśnij
// za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach
// powino zostać wyłączone)
// WriteLog("Zahamowanie składu");
mvOccupied->BrakeLevelSet(
mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ?
1 :
3 );
double p = mvOccupied->BrakePressureActual.PipePressureVal;
if( p < 3.9 ) {
// tu może być 0 albo -1 nawet
// TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia sensu 0 oraz -1 w tym miejscu
p = 3.9;
}
if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ?
mvOccupied->BrakePress > 2 :
mvOccupied->PipePress < p + 0.1)
{ // jeśli w miarę został zahamowany (ciśnienie mniejsze niż podane na
// pozycji 3, zwyle 0.37)
if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic)
mvOccupied->BrakeLevelSet(0); // wyłączenie EP, gdy wystarczy (może
// nie być potrzebne, bo na początku jest)
WriteLog("Luzowanie lokomotywy i zmiana kierunku");
mvOccupied->BrakeReleaser(1); // wyluzuj lokomotywę; a ST45?
mvOccupied->DecLocalBrakeLevel(LocalBrakePosNo); // zwolnienie hamulca
iDrivigFlags |= movePress; // następnie będzie dociskanie
DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na przeciwny (dociskanie)
CheckVehicles(); // od razu zmienić światła (zgasić) - bez tego się nie odczepi
/*
// NOTE: disabled to prevent closing the door before passengers can disembark
fStopTime = 0.0; // nie ma na co czekać z odczepianiem
*/
}
}
else {
if( mvOccupied->Vel > 0.01 ) {
// 1st phase(?)
// bring it to stop if it's not already stopped
SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie
}
}
} // odczepiania
else // to poniżej jeśli ilość wagonów ujemna
if (iDrivigFlags & movePress)
{ // 4. faza odczepiania: zwolnij i zmień kierunek
SetVelocity(0, 0, stopJoin); // wyłączyć przyspieszanie
if (!DecSpeed()) // jeśli już bardziej wyłączyć się nie da
{ // ponowna zmiana kierunku
WriteLog( mvOccupied->Name + " ponowna zmiana kierunku" );
DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na właściwy
iDrivigFlags &= ~movePress; // koniec dociskania
JumpToNextOrder(); // zmieni światła
TableClear(); // skanowanie od nowa
iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed ruszeniem
SetVelocity(fShuntVelocity, fShuntVelocity); // ustawienie prędkości jazdy
}
}
}
}
if( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) { if( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) {
// if ordered to change direction, try to stop // if ordered to change direction, try to stop

View File

@@ -167,7 +167,7 @@ static const bool Aggressive = true;
static const bool Easyman = false; static const bool Easyman = false;
static const bool AIdriver = true; static const bool AIdriver = true;
static const bool Humandriver = false; static const bool Humandriver = false;
static const int maxorders = 32; // ilość rozkazów w tabelce static const int maxorders = 64; // ilość rozkazów w tabelce
static const int maxdriverfails = 4; // ile błędów może zrobić AI zanim zmieni nastawienie static const int maxdriverfails = 4; // ile błędów może zrobić AI zanim zmieni nastawienie
extern bool WriteLogFlag; // logowanie parametrów fizycznych extern bool WriteLogFlag; // logowanie parametrów fizycznych
static const int BrakeAccTableSize = 20; static const int BrakeAccTableSize = 20;

View File

@@ -2687,7 +2687,7 @@ void TDynamicObject::LoadUpdate() {
} }
else if( MoverParameters->LoadAmount == 0 ) { else if( MoverParameters->LoadAmount == 0 ) {
// nie ma ładunku // nie ma ładunku
MoverParameters->AssignLoad( "" ); // MoverParameters->AssignLoad( "" );
mdLoad = nullptr; mdLoad = nullptr;
// erase bindings between lowpoly sections and potential load chunks placed inside them // erase bindings between lowpoly sections and potential load chunks placed inside them
update_load_sections(); update_load_sections();
@@ -5274,6 +5274,35 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
} }
} }
else if( token == "motorblower:" ) {
sound_source blowertemplate { sound_placement::engine };
blowertemplate.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency );
blowertemplate.owner( this );
auto const amplitudedivisor = static_cast<float>(
MoverParameters->MotorBlowers[ side::front ].speed > 0.f ?
MoverParameters->MotorBlowers[ side::front ].speed * MoverParameters->nmax * 60 + MoverParameters->Power * 3 :
MoverParameters->MotorBlowers[ side::front ].speed * -1 );
blowertemplate.m_amplitudefactor /= amplitudedivisor;
blowertemplate.m_frequencyfactor /= amplitudedivisor;
if( true == m_powertrainsounds.motors.empty() ) {
// fallback for cases without specified motor locations, convert sound template to a single sound source
m_powertrainsounds.motorblowers.emplace_back( blowertemplate );
}
else {
// apply configuration to all defined motor blowers
for( auto &blower : m_powertrainsounds.motorblowers ) {
// combine potential x- and y-axis offsets of the sound template with z-axis offsets of individual blowers
auto bloweroffset { blowertemplate.offset() };
bloweroffset.z = blower.offset().z;
blower = blowertemplate;
blower.offset( bloweroffset );
}
}
}
else if( token == "inverter:" ) { else if( token == "inverter:" ) {
// plik z dzwiekiem wentylatora, mnozniki i ofsety amp. i czest. // plik z dzwiekiem wentylatora, mnozniki i ofsety amp. i czest.
m_powertrainsounds.inverter.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); m_powertrainsounds.inverter.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency );
@@ -5621,10 +5650,13 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
auto const offset { std::atof( token.c_str() ) * -1.f }; auto const offset { std::atof( token.c_str() ) * -1.f };
// NOTE: we skip setting owner of the sounds, it'll be done during individual sound deserialization // NOTE: we skip setting owner of the sounds, it'll be done during individual sound deserialization
sound_source motor { sound_placement::external }; // generally traction motor sound_source motor { sound_placement::external }; // generally traction motor
sound_source motorblower { sound_placement::engine }; // associated motor blowers
// add entry to the list // add entry to the list
auto const location { glm::vec3 { 0.f, 0.f, offset } }; auto const location { glm::vec3 { 0.f, 0.f, offset } };
motor.offset( location ); motor.offset( location );
m_powertrainsounds.motors.emplace_back( motor ); m_powertrainsounds.motors.emplace_back( motor );
motorblower.offset( location );
m_powertrainsounds.motorblowers.emplace_back( motorblower );
} }
} }
@@ -6728,6 +6760,27 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
motor.stop(); motor.stop();
} }
} }
// motor blowers
if( false == motorblowers.empty() ) {
for( auto &blowersound : motorblowers ) {
// match the motor blower and the sound source based on whether they're located in the front or the back of the vehicle
auto const &blower { Vehicle.MotorBlowers[ ( blowersound.offset().z > 0 ? side::front : side::rear ) ] };
if( blower.revolutions > 1 ) {
blowersound
.pitch(
true == blowersound.is_combined() ?
blower.revolutions * 0.01f :
blowersound.m_frequencyoffset + blowersound.m_frequencyfactor * blower.revolutions )
.gain( blowersound.m_amplitudeoffset + blowersound.m_amplitudefactor * blower.revolutions )
.play( sound_flags::exclusive | sound_flags::looping );
}
else {
blowersound.stop();
}
}
}
// inverter sounds // inverter sounds
if( Vehicle.EngineType == TEngineType::ElectricInductionMotor ) { if( Vehicle.EngineType == TEngineType::ElectricInductionMotor ) {
if( Vehicle.InverterFrequency > 0.1 ) { if( Vehicle.InverterFrequency > 0.1 ) {
@@ -7034,7 +7087,7 @@ vehicle_table::erase_disabled() {
if( ( simulation::Train != nullptr ) if( ( simulation::Train != nullptr )
&& ( simulation::Train->Dynamic() == vehicle ) ) { && ( simulation::Train->Dynamic() == vehicle ) ) {
// clear potential train binding // clear potential train binding
// TBD, TODO: manually eject the driver first ? // TBD, TODO: kill vehicle sounds
SafeDelete( simulation::Train ); SafeDelete( simulation::Train );
} }
// remove potential entries in the light array // remove potential entries in the light array

View File

@@ -330,6 +330,7 @@ private:
struct powertrain_sounds { struct powertrain_sounds {
sound_source inverter { sound_placement::engine }; sound_source inverter { sound_placement::engine };
std::vector<sound_source> motorblowers;
std::vector<sound_source> motors; // generally traction motor(s) std::vector<sound_source> motors; // generally traction motor(s)
double motor_volume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal double motor_volume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal
float motor_momentum { 0.f }; // recent change in motor revolutions float motor_momentum { 0.f }; // recent change in motor revolutions

View File

@@ -349,6 +349,11 @@ global_settings::ConfigParse(cParser &Parser) {
Parser >> splinefidelity; Parser >> splinefidelity;
SplineFidelity = clamp( splinefidelity, 1.f, 4.f ); SplineFidelity = clamp( splinefidelity, 1.f, 4.f );
} }
else if( token == "createswitchtrackbeds" ) {
// podwójna jasność ambient
Parser.getTokens();
Parser >> CreateSwitchTrackbeds;
}
else if( token == "gfx.resource.sweep" ) { else if( token == "gfx.resource.sweep" ) {
Parser.getTokens(); Parser.getTokens();

View File

@@ -53,6 +53,7 @@ struct global_settings {
// settings // settings
// filesystem // filesystem
bool bLoadTraction{ true }; bool bLoadTraction{ true };
bool CreateSwitchTrackbeds { true };
std::string szTexturesTGA{ ".tga" }; // lista tekstur od TGA std::string szTexturesTGA{ ".tga" }; // lista tekstur od TGA
std::string szTexturesDDS{ ".dds" }; // lista tekstur od DDS std::string szTexturesDDS{ ".dds" }; // lista tekstur od DDS
std::string szDefaultExt{ szTexturesDDS }; std::string szDefaultExt{ szTexturesDDS };

View File

@@ -166,6 +166,7 @@ enum class start_t {
manual, manual,
automatic, automatic,
manualwithautofallback, manualwithautofallback,
converter,
battery battery
}; };
// recognized vehicle light locations and types; can be combined // recognized vehicle light locations and types; can be combined
@@ -619,51 +620,68 @@ struct TCoupling {
int sounds { 0 }; // sounds emitted by the coupling devices int sounds { 0 }; // sounds emitted by the coupling devices
}; };
// basic approximation of a fuel pump class TMoverParameters
// TODO: fuel consumption, optional automatic engine start after activation { // Ra: wrapper na kod pascalowy, przejmujący jego funkcje Q: 20160824 - juz nie wrapper a klasa bazowa :)
struct fuel_pump { private:
// types
// basic approximation of a generic device
// TBD: inheritance or composition?
struct basic_device {
// config
start_t start_type { start_t::manual };
// ld inputs
bool is_enabled { false }; // device is allowed/requested to operate bool is_enabled { false }; // device is allowed/requested to operate
bool is_disabled { false }; // device is requested to stop bool is_disabled { false }; // device is requested to stop
// TODO: add remaining inputs; start conditions and potential breakers
// ld outputs
bool is_active { false }; // device is working bool is_active { false }; // device is working
start_t start_type { start_t::manual }; };
struct cooling_fan : public basic_device {
// config
float speed { 0.f }; // cooling fan rpm; either fraction of parent rpm, or absolute value if negative
// ld outputs
float revolutions { 0.f }; // current fan rpm
}; };
// basic approximation of a fuel pump // basic approximation of a fuel pump
struct fuel_pump : public basic_device {
// TODO: fuel consumption, optional automatic engine start after activation // TODO: fuel consumption, optional automatic engine start after activation
struct oil_pump { };
bool is_enabled { false }; // device is allowed/requested to operate // basic approximation of an oil pump
bool is_disabled { false }; // device is requested to stop struct oil_pump : public basic_device {
bool is_active { false }; // device is working // config
start_t start_type { start_t::manual };
float resource_amount { 1.f };
float pressure_minimum { 0.f }; // lowest acceptable working pressure float pressure_minimum { 0.f }; // lowest acceptable working pressure
float pressure_maximum { 0.65f }; // oil pressure at maximum engine revolutions float pressure_maximum { 0.65f }; // oil pressure at maximum engine revolutions
// ld inputs
float resource_amount { 1.f }; // amount of affected resource, compared to nominal value
// internal data
float pressure_target { 0.f }; float pressure_target { 0.f };
float pressure_present { 0.f }; // ld outputs
float pressure { 0.f }; // current pressure
}; };
struct water_pump { // basic approximation of a water pump
struct water_pump : public basic_device {
// ld inputs
// TODO: move to breaker list in the basic device once implemented
bool breaker { true }; // device is allowed to operate bool breaker { true }; // device is allowed to operate
bool is_enabled { false }; // device is requested to operate
bool is_disabled { false }; // device is requested to stop
bool is_active { false }; // device is working
start_t start_type { start_t::manual };
}; };
struct water_heater { struct water_heater {
// config
bool breaker { true }; // device is allowed to operate
bool is_enabled { false }; // device is requested to operate
bool is_active { false }; // device is working
bool is_damaged { false }; // device is damaged
struct heater_config_t { struct heater_config_t {
float temp_min { -1 }; // lowest accepted temperature float temp_min { -1 }; // lowest accepted temperature
float temp_max { -1 }; // highest accepted temperature float temp_max { -1 }; // highest accepted temperature
} config; } config;
// ld inputs
bool breaker { true }; // device is allowed to operate
bool is_enabled { false }; // device is requested to operate
// ld outputs
bool is_active { false }; // device is working
bool is_damaged { false }; // device is damaged
}; };
struct heat_data { struct heat_data {
@@ -718,8 +736,6 @@ struct heat_data {
float temperatura2 { 40.0 }; float temperatura2 { 40.0 };
}; };
class TMoverParameters
{ // Ra: wrapper na kod pascalowy, przejmujący jego funkcje Q: 20160824 - juz nie wrapper a klasa bazowa :)
public: public:
double dMoveLen = 0.0; double dMoveLen = 0.0;
@@ -1040,6 +1056,7 @@ public:
water_heater WaterHeater; water_heater WaterHeater;
bool WaterCircuitsLink { false }; // optional connection between water circuits bool WaterCircuitsLink { false }; // optional connection between water circuits
heat_data dizel_heat; heat_data dizel_heat;
std::array<cooling_fan, 2> MotorBlowers;
int BrakeCtrlPos = -2; /*nastawa hamulca zespolonego*/ int BrakeCtrlPos = -2; /*nastawa hamulca zespolonego*/
double BrakeCtrlPosR = 0.0; /*nastawa hamulca zespolonego - plynna dla FV4a*/ double BrakeCtrlPosR = 0.0; /*nastawa hamulca zespolonego - plynna dla FV4a*/
@@ -1343,6 +1360,8 @@ public:
bool FuelPumpSwitchOff( bool State, range_t const Notify = range_t::consist ); // fuel pump state toggle bool FuelPumpSwitchOff( bool State, range_t const Notify = range_t::consist ); // fuel pump state toggle
bool OilPumpSwitch( bool State, range_t const Notify = range_t::consist ); // oil pump state toggle bool OilPumpSwitch( bool State, range_t const Notify = range_t::consist ); // oil pump state toggle
bool OilPumpSwitchOff( bool State, range_t const Notify = range_t::consist ); // oil pump state toggle bool OilPumpSwitchOff( bool State, range_t const Notify = range_t::consist ); // oil pump state toggle
bool MotorBlowersSwitch( bool State, side const Side, range_t const Notify = range_t::consist ); // traction motor fan state toggle
bool MotorBlowersSwitchOff( bool State, side const Side, range_t const Notify = range_t::consist ); // traction motor fan state toggle
bool MainSwitch( bool const State, range_t const Notify = range_t::consist );/*! wylacznik glowny*/ bool MainSwitch( bool const State, range_t const Notify = range_t::consist );/*! wylacznik glowny*/
bool ConverterSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl przetwornicy*/ bool ConverterSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl przetwornicy*/
bool CompressorSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl sprezarki*/ bool CompressorSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl sprezarki*/
@@ -1353,6 +1372,7 @@ public:
void WaterHeaterCheck( double const Timestep ); void WaterHeaterCheck( double const Timestep );
void FuelPumpCheck( double const Timestep ); void FuelPumpCheck( double const Timestep );
void OilPumpCheck( double const Timestep ); void OilPumpCheck( double const Timestep );
void MotorBlowersCheck( double const Timestep );
bool FuseOn(void); //bezpiecznik nadamiary bool FuseOn(void); //bezpiecznik nadamiary
bool FuseFlagCheck(void) const; // sprawdzanie flagi nadmiarowego bool FuseFlagCheck(void) const; // sprawdzanie flagi nadmiarowego
void FuseOff(void); // wylaczenie nadmiarowego void FuseOff(void); // wylaczenie nadmiarowego

View File

@@ -1436,6 +1436,8 @@ void TMoverParameters::compute_movement_( double const Deltatime ) {
SetFlag( SoundFlag, sound::relay ); SetFlag( SoundFlag, sound::relay );
} }
} }
// traction motors
MotorBlowersCheck( Deltatime );
// uklady hamulcowe: // uklady hamulcowe:
ConverterCheck( Deltatime ); ConverterCheck( Deltatime );
if (VeselVolume > 0) if (VeselVolume > 0)
@@ -1532,6 +1534,11 @@ void TMoverParameters::WaterPumpCheck( double const Timestep ) {
// water heater status check // water heater status check
void TMoverParameters::WaterHeaterCheck( double const Timestep ) { void TMoverParameters::WaterHeaterCheck( double const Timestep ) {
WaterHeater.is_damaged = (
( true == WaterHeater.is_damaged )
|| ( ( true == WaterHeater.is_active )
&& ( false == WaterPump.is_active ) ) );
WaterHeater.is_active = ( WaterHeater.is_active = (
( false == WaterHeater.is_damaged ) ( false == WaterHeater.is_damaged )
&& ( true == Battery ) && ( true == Battery )
@@ -1543,11 +1550,6 @@ void TMoverParameters::WaterHeaterCheck( double const Timestep ) {
&& ( dizel_heat.temperatura1 > WaterHeater.config.temp_max ) ) { && ( dizel_heat.temperatura1 > WaterHeater.config.temp_max ) ) {
WaterHeater.is_active = false; WaterHeater.is_active = false;
} }
WaterHeater.is_damaged = (
( true == WaterHeater.is_damaged )
|| ( ( true == WaterHeater.is_active )
&& ( false == WaterPump.is_active ) ) );
} }
// fuel pump status update // fuel pump status update
@@ -1590,20 +1592,57 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) {
true == OilPump.is_active ? std::min( minpressure + 0.1f, OilPump.pressure_maximum ) : // slight pressure margin to give time to switch off the pump and start the engine true == OilPump.is_active ? std::min( minpressure + 0.1f, OilPump.pressure_maximum ) : // slight pressure margin to give time to switch off the pump and start the engine
0.f ); 0.f );
if( OilPump.pressure_present < OilPump.pressure_target ) { if( OilPump.pressure < OilPump.pressure_target ) {
// TODO: scale change rate from 0.01-0.05 with oil/engine temperature/idle time // TODO: scale change rate from 0.01-0.05 with oil/engine temperature/idle time
OilPump.pressure_present = OilPump.pressure =
std::min<float>( std::min<float>(
OilPump.pressure_target, OilPump.pressure_target,
OilPump.pressure_present + ( enrot > 5.0 ? 0.05 : 0.035 ) * Timestep ); OilPump.pressure + ( enrot > 5.0 ? 0.05 : 0.035 ) * Timestep );
} }
if( OilPump.pressure_present > OilPump.pressure_target ) { if( OilPump.pressure > OilPump.pressure_target ) {
OilPump.pressure_present = OilPump.pressure =
std::max<float>( std::max<float>(
OilPump.pressure_target, OilPump.pressure_target,
OilPump.pressure_present - 0.01 * Timestep ); OilPump.pressure - 0.01 * Timestep );
}
OilPump.pressure = clamp( OilPump.pressure, 0.f, 1.5f );
}
void TMoverParameters::MotorBlowersCheck( double const Timestep ) {
// activation check
for( auto &blower : MotorBlowers ) {
blower.is_active = (
// TODO: bind properly power source when ld is in place
( blower.start_type == start_t::battery ? Battery :
blower.start_type == start_t::converter ? ConverterFlag :
Mains ) // power source
// breaker condition disabled until it's implemented in the class data
// && ( true == blower.breaker )
&& ( false == blower.is_disabled )
&& ( ( true == blower.is_active )
|| ( blower.start_type == start_t::manual ? blower.is_enabled : true ) ) );
}
// update
for( auto &fan : MotorBlowers ) {
auto const revolutionstarget { (
fan.is_active ?
( fan.speed > 0.f ? fan.speed * static_cast<float>( enrot ) * 60 : fan.speed * -1 ) :
0.f ) };
if( std::abs( fan.revolutions - revolutionstarget ) < 0.01f ) {
fan.revolutions = revolutionstarget;
continue;
}
if( revolutionstarget > 0.f ) {
auto const speedincreasecap { std::max( 50.f, fan.speed * 0.05f * -1 ) }; // 5% of fixed revolution speed, or 50
fan.revolutions += clamp( revolutionstarget - fan.revolutions, speedincreasecap * -2, speedincreasecap ) * Timestep;
}
else {
fan.revolutions *= std::max( 0.0, 1.0 - Timestep );
}
} }
OilPump.pressure_present = clamp( OilPump.pressure_present, 0.f, 1.5f );
} }
@@ -2606,6 +2645,60 @@ bool TMoverParameters::OilPumpSwitchOff( bool State, range_t const Notify ) {
return ( OilPump.is_disabled != initialstate ); return ( OilPump.is_disabled != initialstate );
} }
bool TMoverParameters::MotorBlowersSwitch( bool State, side const Side, range_t const Notify ) {
auto &fan { MotorBlowers[ Side ] };
if( ( fan.start_type != start_t::manual )
&& ( fan.start_type != start_t::manualwithautofallback ) ) {
// automatic device ignores 'manual' state commands
return false;
}
bool const initialstate { fan.is_enabled };
fan.is_enabled = State;
if( Notify != range_t::local ) {
SendCtrlToNext(
( Side == side::front ? "MotorBlowersFrontSwitch" : "MotorBlowersRearSwitch" ),
( fan.is_enabled ? 1 : 0 ),
CabNo,
( Notify == range_t::unit ?
coupling::control | coupling::permanent :
coupling::control ) );
}
return ( fan.is_enabled != initialstate );
}
bool TMoverParameters::MotorBlowersSwitchOff( bool State, side const Side, range_t const Notify ) {
auto &fan { MotorBlowers[ Side ] };
if( ( fan.start_type != start_t::manual )
&& ( fan.start_type != start_t::manualwithautofallback ) ) {
// automatic device ignores 'manual' state commands
return false;
}
bool const initialstate { fan.is_disabled };
fan.is_disabled = State;
if( Notify != range_t::local ) {
SendCtrlToNext(
( Side == side::front ? "MotorBlowersFrontSwitchOff" : "MotorBlowersRearSwitchOff" ),
( fan.is_disabled ? 1 : 0 ),
CabNo,
( Notify == range_t::unit ?
coupling::control | coupling::permanent :
coupling::control ) );
}
return ( fan.is_disabled != initialstate );
}
// ************************************************************************************************* // *************************************************************************************************
// Q: 20160713 // Q: 20160713
// włączenie / wyłączenie obwodu głownego // włączenie / wyłączenie obwodu głownego
@@ -6020,7 +6113,7 @@ bool TMoverParameters::dizel_StartupCheck() {
} }
// test the oil pump // test the oil pump
if( ( false == OilPump.is_active ) if( ( false == OilPump.is_active )
|| ( OilPump.pressure_present < OilPump.pressure_minimum ) ) { || ( OilPump.pressure < OilPump.pressure_minimum ) ) {
engineisready = false; engineisready = false;
if( OilPump.start_type == start_t::manual ) { if( OilPump.start_type == start_t::manual ) {
// with manual pump control startup procedure is done only once per starter switch press // with manual pump control startup procedure is done only once per starter switch press
@@ -6545,15 +6638,14 @@ TMoverParameters::AssignLoad( std::string const &Name, float const Amount ) {
} }
} }
// can't mix load types, at least for the time being
if( ( LoadAmount > 0 ) && ( LoadType.name != Name ) ) { return false; }
if( Name.empty() ) { if( Name.empty() ) {
// empty the vehicle // empty the vehicle if requested
LoadType = load_attributes(); LoadType = load_attributes();
LoadAmount = 0.f; LoadAmount = 0.f;
return true; return true;
} }
// can't mix load types, at least for the time being
if( ( LoadAmount > 0 ) && ( LoadType.name != Name ) ) { return false; }
for( auto const &loadattributes : LoadAttributes ) { for( auto const &loadattributes : LoadAttributes ) {
if( Name == loadattributes.name ) { if( Name == loadattributes.name ) {
@@ -8211,59 +8303,54 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) {
} }
extract_value( ConverterStartDelay, "ConverterStartDelay", line, "" ); extract_value( ConverterStartDelay, "ConverterStartDelay", line, "" );
// compressor // devices
{
std::map<std::string, start_t> starts { std::map<std::string, start_t> starts {
{ "Manual", start_t::manual }, { "Manual", start_t::manual },
{ "Automatic", start_t::automatic } { "Automatic", start_t::automatic },
}; { "Mixed", start_t::manualwithautofallback },
{ "Battery", start_t::battery },
{ "Converter", start_t::converter } };
// compressor
{
auto lookup = starts.find( extract_value( "CompressorStart", line ) ); auto lookup = starts.find( extract_value( "CompressorStart", line ) );
CompressorStart = CompressorStart =
lookup != starts.end() ? lookup != starts.end() ?
lookup->second : lookup->second :
start_t::manual; start_t::manual;
} }
// fuel pump // fuel pump
{ {
std::map<std::string, start_t> starts {
{ "Manual", start_t::manual },
{ "Automatic", start_t::automatic },
{ "Mixed", start_t::manualwithautofallback }
};
auto lookup = starts.find( extract_value( "FuelStart", line ) ); auto lookup = starts.find( extract_value( "FuelStart", line ) );
FuelPump.start_type = FuelPump.start_type =
lookup != starts.end() ? lookup != starts.end() ?
lookup->second : lookup->second :
start_t::manual; start_t::manual;
} }
// oil pump // oil pump
{ {
std::map<std::string, start_t> starts {
{ "Manual", start_t::manual },
{ "Automatic", start_t::automatic },
{ "Mixed", start_t::manualwithautofallback }
};
auto lookup = starts.find( extract_value( "OilStart", line ) ); auto lookup = starts.find( extract_value( "OilStart", line ) );
OilPump.start_type = OilPump.start_type =
lookup != starts.end() ? lookup != starts.end() ?
lookup->second : lookup->second :
start_t::manual; start_t::manual;
} }
// water pump // water pump
{ {
std::map<std::string, start_t> starts {
{ "Manual", start_t::manual },
{ "Battery", start_t::battery }
};
auto lookup = starts.find( extract_value( "WaterStart", line ) ); auto lookup = starts.find( extract_value( "WaterStart", line ) );
WaterPump.start_type = WaterPump.start_type =
lookup != starts.end() ? lookup != starts.end() ?
lookup->second : lookup->second :
start_t::manual; start_t::manual;
} }
// traction motor fans
{
auto lookup = starts.find( extract_value( "MotorBlowersStart", line ) );
MotorBlowers[side::front].start_type =
MotorBlowers[side::rear].start_type =
lookup != starts.end() ?
lookup->second :
start_t::manual;
}
} }
void TMoverParameters::LoadFIZ_Blending(std::string const &line) { void TMoverParameters::LoadFIZ_Blending(std::string const &line) {
@@ -8516,6 +8603,10 @@ void TMoverParameters::LoadFIZ_Engine( std::string const &Input ) {
extract_value( WaterHeater.config.temp_min, "HeaterMinTemperature", Input, "" ); extract_value( WaterHeater.config.temp_min, "HeaterMinTemperature", Input, "" );
extract_value( WaterHeater.config.temp_max, "HeaterMaxTemperature", Input, "" ); extract_value( WaterHeater.config.temp_max, "HeaterMaxTemperature", Input, "" );
} }
// traction motors
extract_value( MotorBlowers[ side::front ].speed, "MotorBlowersSpeed", Input, "" );
MotorBlowers[ side::rear ] = MotorBlowers[ side::front ];
} }
void TMoverParameters::LoadFIZ_Switches( std::string const &Input ) { void TMoverParameters::LoadFIZ_Switches( std::string const &Input ) {
@@ -9292,6 +9383,38 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
} }
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
} }
else if( Command == "MotorBlowersFrontSwitch" ) {
if( ( MotorBlowers[ side::front ].start_type != start_t::manual )
&& ( MotorBlowers[ side::front ].start_type != start_t::manualwithautofallback ) ) {
// automatic device ignores 'manual' state commands
MotorBlowers[side::front].is_enabled = ( CValue1 == 1 );
}
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
}
else if( Command == "MotorBlowersFrontSwitchOff" ) {
if( ( MotorBlowers[ side::front ].start_type != start_t::manual )
&& ( MotorBlowers[ side::front ].start_type != start_t::manualwithautofallback ) ) {
// automatic device ignores 'manual' state commands
MotorBlowers[side::front].is_disabled = ( CValue1 == 1 );
}
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
}
else if( Command == "MotorBlowersRearSwitch" ) {
if( ( MotorBlowers[ side::rear ].start_type != start_t::manual )
&& ( MotorBlowers[ side::rear ].start_type != start_t::manualwithautofallback ) ) {
// automatic device ignores 'manual' state commands
MotorBlowers[side::rear].is_enabled = ( CValue1 == 1 );
}
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
}
else if( Command == "MotorBlowersRearSwitchOff" ) {
if( ( MotorBlowers[ side::rear ].start_type != start_t::manual )
&& ( MotorBlowers[ side::rear ].start_type != start_t::manualwithautofallback ) ) {
// automatic device ignores 'manual' state commands
MotorBlowers[side::rear].is_disabled = ( CValue1 == 1 );
}
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
}
else if (Command == "MainSwitch") else if (Command == "MainSwitch")
{ {
if (CValue1 == 1) { if (CValue1 == 1) {

View File

@@ -72,6 +72,23 @@ void TSubModel::Name(std::string const &Name)
pName = Name; pName = Name;
}; };
// sets visibility level (alpha component) to specified value
void
TSubModel::SetVisibilityLevel( float const Level, bool const Includechildren, bool const Includesiblings ) {
fVisible = Level;
if( true == Includesiblings ) {
auto sibling { this };
while( ( sibling = sibling->Next ) != nullptr ) {
sibling->SetVisibilityLevel( Level, Includechildren, false ); // no need for all siblings to duplicate the work
}
}
if( ( true == Includechildren )
&& ( Child != nullptr ) ) {
Child->SetVisibilityLevel( Level, Includechildren, true ); // node's children include child's siblings and children
}
}
// sets light level (alpha component of illumination color) to specified value // sets light level (alpha component of illumination color) to specified value
void void
TSubModel::SetLightLevel( float const Level, bool const Includechildren, bool const Includesiblings ) { TSubModel::SetLightLevel( float const Level, bool const Includechildren, bool const Includesiblings ) {
@@ -1340,7 +1357,8 @@ void TSubModel::serialize(std::ostream &s,
else else
sn_utils::ls_int32(s, (int32_t)get_container_pos(textures, m_materialname)); sn_utils::ls_int32(s, (int32_t)get_container_pos(textures, m_materialname));
sn_utils::ls_float32(s, fVisible); // sn_utils::ls_float32(s, fVisible);
sn_utils::ls_float32(s, 1.f);
sn_utils::ls_float32(s, fLight); sn_utils::ls_float32(s, fLight);
sn_utils::s_vec4(s, f4Ambient); sn_utils::s_vec4(s, f4Ambient);
@@ -1460,7 +1478,8 @@ void TSubModel::deserialize(std::istream &s)
tVboPtr = sn_utils::ld_int32(s); tVboPtr = sn_utils::ld_int32(s);
iTexture = sn_utils::ld_int32(s); iTexture = sn_utils::ld_int32(s);
fVisible = sn_utils::ld_float32(s); // fVisible = sn_utils::ld_float32(s);
auto discard = sn_utils::ld_float32(s);
fLight = sn_utils::ld_float32(s); fLight = sn_utils::ld_float32(s);
f4Ambient = sn_utils::d_vec4(s); f4Ambient = sn_utils::d_vec4(s);

View File

@@ -100,7 +100,6 @@ private:
int iNumVerts { -1 }; // ilość wierzchołków (1 dla FreeSpotLight) int iNumVerts { -1 }; // ilość wierzchołków (1 dla FreeSpotLight)
int tVboPtr; // początek na liście wierzchołków albo indeksów int tVboPtr; // początek na liście wierzchołków albo indeksów
int iTexture { 0 }; // numer nazwy tekstury, -1 wymienna, 0 brak int iTexture { 0 }; // numer nazwy tekstury, -1 wymienna, 0 brak
float fVisible { 0.0f }; // próg jasności światła do załączenia submodelu
float fLight { -1.0f }; // próg jasności światła do zadziałania selfillum float fLight { -1.0f }; // próg jasności światła do zadziałania selfillum
glm::vec4 glm::vec4
f4Ambient { 1.0f,1.0f,1.0f,1.0f }, f4Ambient { 1.0f,1.0f,1.0f,1.0f },
@@ -143,6 +142,7 @@ public: // chwilowo
TSubModel **smLetter{ nullptr }; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D) TSubModel **smLetter{ nullptr }; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D)
TSubModel *Parent{ nullptr }; // nadrzędny, np. do wymnażania macierzy TSubModel *Parent{ nullptr }; // nadrzędny, np. do wymnażania macierzy
int iVisible { 1 }; // roboczy stan widoczności int iVisible { 1 }; // roboczy stan widoczności
float fVisible { 1.f }; // visibility level
std::string m_materialname; // robocza nazwa tekstury do zapisania w pliku binarnym std::string m_materialname; // robocza nazwa tekstury do zapisania w pliku binarnym
std::string pName; // robocza nazwa std::string pName; // robocza nazwa
private: private:
@@ -195,6 +195,8 @@ public:
uint32_t Flags() const { return iFlags; }; uint32_t Flags() const { return iFlags; };
void UnFlagNext() { iFlags &= 0x00FFFFFF; }; void UnFlagNext() { iFlags &= 0x00FFFFFF; };
void ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular ); void ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular );
// sets visibility level (alpha component) to specified value
void SetVisibilityLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
// sets light level (alpha component of illumination color) to specified value // sets light level (alpha component of illumination color) to specified value
void SetLightLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false ); void SetLightLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
inline float3 Translation1Get() { inline float3 Translation1Get() {

View File

@@ -112,9 +112,6 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
ErrorLog( "Bad track: zero length spline \"" + pOwner->name() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" ); ErrorLog( "Bad track: zero length spline \"" + pOwner->name() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
fLength = 0.01; // crude workaround TODO: fix this properly fLength = 0.01; // crude workaround TODO: fix this properly
/*
return false; // zerowe nie mogą być
*/
} }
fStoop = std::atan2((Point2.y - Point1.y), fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie fStoop = std::atan2((Point2.y - Point1.y), fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie
@@ -126,13 +123,12 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
// NOTE: a workaround for too short switches (less than 3 segments) messing up animation/generation of blades // NOTE: a workaround for too short switches (less than 3 segments) messing up animation/generation of blades
fStep = fLength / ( 3.0 * Global.SplineFidelity ); fStep = fLength / ( 3.0 * Global.SplineFidelity );
} }
iSegCount = static_cast<int>( std::ceil( fLength / fStep ) ); // potrzebne do VBO // iSegCount = static_cast<int>( std::ceil( fLength / fStep ) ); // potrzebne do VBO
/*
iSegCount = ( iSegCount = (
pOwner->eType == tt_Switch ? pOwner->eType == tt_Switch ?
6 * Global.SplineFidelity : 6 * Global.SplineFidelity :
static_cast<int>( std::ceil( fLength / fStep ) ) ); // potrzebne do VBO static_cast<int>( std::ceil( fLength / fStep ) ) ); // potrzebne do VBO
*/
fStep = fLength / iSegCount; // update step to equalize size of individual pieces fStep = fLength / iSegCount; // update step to equalize size of individual pieces
fTsBuffer.resize( iSegCount + 1 ); fTsBuffer.resize( iSegCount + 1 );
@@ -376,7 +372,7 @@ Math3D::vector3 TSegment::FastGetPoint(double const t) const
interpolate( Point1, Point2, t ) ); interpolate( Point1, Point2, t ) );
} }
bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, const gfx::basic_vertex *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, float fOffsetX, glm::vec3 **p, bool bRender) bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, const gfx::vertex_array &ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, float fOffsetX, glm::vec3 **p, bool bRender)
{ // generowanie trójkątów dla odcinka trajektorii ruchu { // generowanie trójkątów dla odcinka trajektorii ruchu
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku // standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
// po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli // po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli
@@ -457,7 +453,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
Output.emplace_back( Output.emplace_back(
pt, pt,
glm::normalize( norm ), glm::normalize( norm ),
glm::vec2 { ( jmm1 * ShapePoints[ j ].texture.x + m1 * ShapePoints[ j + iNumShapePoints ].texture.x ) / texturescale, tv1 } ); glm::vec2 { 1.f - ( jmm1 * ShapePoints[ j ].texture.x + m1 * ShapePoints[ j + iNumShapePoints ].texture.x ) / texturescale, tv1 } );
} }
if( p ) // jeśli jest wskaźnik do tablicy if( p ) // jeśli jest wskaźnik do tablicy
if( *p ) if( *p )
@@ -477,7 +473,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
Output.emplace_back( Output.emplace_back(
pt, pt,
glm::normalize( norm ), glm::normalize( norm ),
glm::vec2 { ( jmm2 * ShapePoints[ j ].texture.x + m2 * ShapePoints[ j + iNumShapePoints ].texture.x ) / texturescale, tv2 } ); glm::vec2 { 1.f - ( jmm2 * ShapePoints[ j ].texture.x + m2 * ShapePoints[ j + iNumShapePoints ].texture.x ) / texturescale, tv2 } );
} }
if( p ) // jeśli jest wskaźnik do tablicy if( p ) // jeśli jest wskaźnik do tablicy
if( *p ) if( *p )
@@ -501,7 +497,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
Output.emplace_back( Output.emplace_back(
pt, pt,
glm::normalize( norm ), glm::normalize( norm ),
glm::vec2 { ShapePoints[ j ].texture.x / texturescale, tv1 } ); glm::vec2 { 1.f - ShapePoints[ j ].texture.x / texturescale, tv1 } );
pt = parallel2 * ShapePoints[ j ].position.x + pos2; pt = parallel2 * ShapePoints[ j ].position.x + pos2;
pt.y += ShapePoints[ j ].position.y; pt.y += ShapePoints[ j ].position.y;
@@ -512,7 +508,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
Output.emplace_back( Output.emplace_back(
pt, pt,
glm::normalize( norm ), glm::normalize( norm ),
glm::vec2 { ShapePoints[ j ].texture.x / texturescale, tv2 } ); glm::vec2 { 1.f - ShapePoints[ j ].texture.x / texturescale, tv2 } );
} }
} }
} }

View File

@@ -116,7 +116,7 @@ public:
r2 = fRoll2; } r2 = fRoll2; }
bool bool
RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, gfx::basic_vertex const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, float fOffsetX = 0.f, glm::vec3 **p = nullptr, bool bRender = true); RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, gfx::vertex_array const &ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, float fOffsetX = 0.f, glm::vec3 **p = nullptr, bool bRender = true);
/* /*
void void
Render(); Render();

1576
Track.cpp

File diff suppressed because it is too large Load Diff

13
Track.h
View File

@@ -93,6 +93,8 @@ class TSwitchExtension
*evMinus = nullptr; // zdarzenia sygnalizacji rozprucia *evMinus = nullptr; // zdarzenia sygnalizacji rozprucia
float fVelocity = -1.0; // maksymalne ograniczenie prędkości (ustawianej eventem) float fVelocity = -1.0; // maksymalne ograniczenie prędkości (ustawianej eventem)
Math3D::vector3 vTrans; // docelowa translacja przesuwnicy Math3D::vector3 vTrans; // docelowa translacja przesuwnicy
material_handle m_material3 = 0; // texture of auto generated switch trackbed
gfx::geometry_handle Geometry3; // geometry of auto generated switch trackbed
}; };
class TIsolated class TIsolated
@@ -134,7 +136,7 @@ private:
// members // members
int iAxles { 0 }; // ilość osi na odcinkach obsługiwanych przez obiekt int iAxles { 0 }; // ilość osi na odcinkach obsługiwanych przez obiekt
TIsolated *pNext { nullptr }; // odcinki izolowane są trzymane w postaci listy jednikierunkowej TIsolated *pNext { nullptr }; // odcinki izolowane są trzymane w postaci listy jednikierunkowej
TIsolated *pParent { nullptr }; // optional parent piece, collecting data from its children TIsolated *pParent { nullptr }; // optional parent piece, receiving data from its children
static TIsolated *pRoot; // początek listy static TIsolated *pRoot; // początek listy
}; };
@@ -222,6 +224,7 @@ public:
void ConnectPrevNext(TTrack *pNewPrev, int typ); void ConnectPrevNext(TTrack *pNewPrev, int typ);
void ConnectNextPrev(TTrack *pNewNext, int typ); void ConnectNextPrev(TTrack *pNewNext, int typ);
void ConnectNextNext(TTrack *pNewNext, int typ); void ConnectNextNext(TTrack *pNewNext, int typ);
material_handle copy_adjacent_trackbed_material( TTrack const *Exclude = nullptr );
inline double Length() const { inline double Length() const {
return Segment->GetLength(); }; return Segment->GetLength(); };
inline std::shared_ptr<TSegment> CurrentSegment() const { inline std::shared_ptr<TSegment> CurrentSegment() const {
@@ -289,6 +292,7 @@ public:
void VelocitySet(float v); void VelocitySet(float v);
double VelocityGet(); double VelocityGet();
void ConnectionsLog(); void ConnectionsLog();
bool DoubleSlip() const;
private: private:
// radius() subclass details, calculates node's bounding radius // radius() subclass details, calculates node's bounding radius
@@ -301,6 +305,13 @@ private:
void export_as_text_( std::ostream &Output ) const; void export_as_text_( std::ostream &Output ) const;
// returns texture length for specified material // returns texture length for specified material
float texture_length( material_handle const Material ); float texture_length( material_handle const Material );
// creates profile for a part of current path
void create_switch_trackbed( gfx::vertex_array &Output );
void create_track_rail_profile( gfx::vertex_array &Right, gfx::vertex_array &Left );
void create_track_blade_profile( gfx::vertex_array &Right, gfx::vertex_array &Left );
void create_track_bed_profile( gfx::vertex_array &Output, TTrack const *Previous, TTrack const *Next );
void create_road_profile( gfx::vertex_array &Output, bool const Forcetransition = false );
void create_road_side_profile( gfx::vertex_array &Right, gfx::vertex_array &Left, gfx::vertex_array const &Road, bool const Forcetransition = false );
}; };

View File

@@ -567,7 +567,7 @@ TTraction::wire_color() const {
color.r *= Global.DayLight.ambient[ 0 ]; color.r *= Global.DayLight.ambient[ 0 ];
color.g *= Global.DayLight.ambient[ 1 ]; color.g *= Global.DayLight.ambient[ 1 ];
color.b *= Global.DayLight.ambient[ 2 ]; color.b *= Global.DayLight.ambient[ 2 ];
color *= 0.5f; color *= 0.35f;
} }
else { else {
// tymczasowo pokazanie zasilanych odcinków // tymczasowo pokazanie zasilanych odcinków

229
Train.cpp
View File

@@ -266,6 +266,9 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = {
{ user_command::compressorenable, &TTrain::OnCommand_compressorenable }, { user_command::compressorenable, &TTrain::OnCommand_compressorenable },
{ user_command::compressordisable, &TTrain::OnCommand_compressordisable }, { user_command::compressordisable, &TTrain::OnCommand_compressordisable },
{ user_command::compressortogglelocal, &TTrain::OnCommand_compressortogglelocal }, { user_command::compressortogglelocal, &TTrain::OnCommand_compressortogglelocal },
{ user_command::motorblowerstogglefront, &TTrain::OnCommand_motorblowerstogglefront },
{ user_command::motorblowerstogglerear, &TTrain::OnCommand_motorblowerstogglerear },
{ user_command::motorblowersdisableall, &TTrain::OnCommand_motorblowersdisableall },
{ user_command::motorconnectorsopen, &TTrain::OnCommand_motorconnectorsopen }, { user_command::motorconnectorsopen, &TTrain::OnCommand_motorconnectorsopen },
{ user_command::motorconnectorsclose, &TTrain::OnCommand_motorconnectorsclose }, { user_command::motorconnectorsclose, &TTrain::OnCommand_motorconnectorsclose },
{ user_command::motordisconnect, &TTrain::OnCommand_motordisconnect }, { user_command::motordisconnect, &TTrain::OnCommand_motordisconnect },
@@ -448,7 +451,9 @@ bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d)
PyObject *TTrain::GetTrainState() { PyObject *TTrain::GetTrainState() {
auto const *mover = DynamicObject->MoverParameters; auto const *mover = DynamicObject->MoverParameters;
PyEval_AcquireLock();
auto *dict = PyDict_New(); auto *dict = PyDict_New();
PyEval_ReleaseLock();
if( ( dict == nullptr ) if( ( dict == nullptr )
|| ( mover == nullptr ) ) { || ( mover == nullptr ) ) {
return nullptr; return nullptr;
@@ -2776,8 +2781,193 @@ void TTrain::OnCommand_compressortogglelocal( TTrain *Train, command_data const
} }
} }
void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &cmd ) { void TTrain::OnCommand_motorblowerstogglefront( TTrain *Train, command_data const &Command ) {
command_data Command = cmd;
if( Command.action == GLFW_REPEAT ) { return; }
if( Train->ggMotorBlowersFrontButton.type() == TGaugeType::push ) {
// impulse switch
// currently there's no off button so we always try to turn it on
OnCommand_motorblowersenablefront( Train, Command );
}
else {
// two-state switch
if( Command.action == GLFW_RELEASE ) { return; }
if( false == Train->mvControlled->MotorBlowers[side::front].is_enabled ) {
// turn on
OnCommand_motorblowersenablefront( Train, Command );
}
else {
//turn off
OnCommand_motorblowersdisablefront( Train, Command );
}
}
}
void TTrain::OnCommand_motorblowersenablefront( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_REPEAT ) { return; }
if( Train->ggMotorBlowersFrontButton.type() == TGaugeType::push ) {
// impulse switch
if( Command.action == GLFW_PRESS ) {
// visual feedback
Train->ggMotorBlowersFrontButton.UpdateValue( 1.f, Train->dsbSwitch );
Train->mvControlled->MotorBlowersSwitch( true, side::front );
}
else if( Command.action == GLFW_RELEASE ) {
// visual feedback
Train->ggMotorBlowersFrontButton.UpdateValue( 0.f, Train->dsbSwitch );
Train->mvControlled->MotorBlowersSwitch( false, side::front );
}
}
else {
// two-state switch, only cares about press events
if( Command.action == GLFW_PRESS ) {
// visual feedback
Train->ggMotorBlowersFrontButton.UpdateValue( 1.f, Train->dsbSwitch );
Train->mvControlled->MotorBlowersSwitch( true, side::front );
Train->mvControlled->MotorBlowersSwitchOff( false, side::front );
}
}
}
void TTrain::OnCommand_motorblowersdisablefront( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_REPEAT ) { return; }
if( Train->ggMotorBlowersFrontButton.type() == TGaugeType::push ) {
// impulse switch
// currently there's no disable return type switch
return;
}
else {
// two-state switch, only cares about press events
if( Command.action == GLFW_PRESS ) {
// visual feedback
Train->ggMotorBlowersFrontButton.UpdateValue( 0.f, Train->dsbSwitch );
Train->mvControlled->MotorBlowersSwitch( false, side::front );
Train->mvControlled->MotorBlowersSwitchOff( true, side::front );
}
}
}
void TTrain::OnCommand_motorblowerstogglerear( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_REPEAT ) { return; }
if( Train->ggMotorBlowersRearButton.type() == TGaugeType::push ) {
// impulse switch
// currently there's no off button so we always try to turn it on
OnCommand_motorblowersenablerear( Train, Command );
}
else {
// two-state switch
if( Command.action == GLFW_RELEASE ) { return; }
if( false == Train->mvControlled->MotorBlowers[ side::rear ].is_enabled ) {
// turn on
OnCommand_motorblowersenablerear( Train, Command );
}
else {
//turn off
OnCommand_motorblowersdisablerear( Train, Command );
}
}
}
void TTrain::OnCommand_motorblowersenablerear( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_REPEAT ) { return; }
if( Train->ggMotorBlowersRearButton.type() == TGaugeType::push ) {
// impulse switch
if( Command.action == GLFW_PRESS ) {
// visual feedback
Train->ggMotorBlowersRearButton.UpdateValue( 1.f, Train->dsbSwitch );
Train->mvControlled->MotorBlowersSwitch( true, side::rear );
}
else if( Command.action == GLFW_RELEASE ) {
// visual feedback
Train->ggMotorBlowersRearButton.UpdateValue( 0.f, Train->dsbSwitch );
Train->mvControlled->MotorBlowersSwitch( false, side::rear );
}
}
else {
// two-state switch, only cares about press events
if( Command.action == GLFW_PRESS ) {
// visual feedback
Train->ggMotorBlowersRearButton.UpdateValue( 1.f, Train->dsbSwitch );
Train->mvControlled->MotorBlowersSwitch( true, side::rear );
Train->mvControlled->MotorBlowersSwitchOff( false, side::rear );
}
}
}
void TTrain::OnCommand_motorblowersdisablerear( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_REPEAT ) { return; }
if( Train->ggMotorBlowersRearButton.type() == TGaugeType::push ) {
// impulse switch
// currently there's no disable return type switch
return;
}
else {
// two-state switch, only cares about press events
if( Command.action == GLFW_PRESS ) {
// visual feedback
Train->ggMotorBlowersRearButton.UpdateValue( 0.f, Train->dsbSwitch );
Train->mvControlled->MotorBlowersSwitch( false, side::rear );
Train->mvControlled->MotorBlowersSwitchOff( true, side::rear );
}
}
}
void TTrain::OnCommand_motorblowersdisableall( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_REPEAT ) { return; }
if( Train->ggMotorBlowersAllOffButton.type() == TGaugeType::push ) {
// impulse switch
if( Command.action == GLFW_PRESS ) {
// visual feedback
Train->ggMotorBlowersAllOffButton.UpdateValue( 1.f, Train->dsbSwitch );
Train->mvControlled->MotorBlowersSwitchOff( true, side::front );
Train->mvControlled->MotorBlowersSwitchOff( true, side::rear );
}
else if( Command.action == GLFW_RELEASE ) {
// visual feedback
Train->ggMotorBlowersAllOffButton.UpdateValue( 0.f, Train->dsbSwitch );
Train->mvControlled->MotorBlowersSwitchOff( false, side::front );
Train->mvControlled->MotorBlowersSwitchOff( false, side::rear );
}
}
else {
// two-state switch, only cares about press events
// NOTE: generally this switch doesn't come in two-state form
if( Command.action == GLFW_PRESS ) {
if( Train->ggMotorBlowersAllOffButton.GetDesiredValue() < 0.5f ) {
// switch is off, activate
Train->mvControlled->MotorBlowersSwitchOff( true, side::front );
Train->mvControlled->MotorBlowersSwitchOff( true, side::rear );
// visual feedback
Train->ggMotorBlowersRearButton.UpdateValue( 1.f, Train->dsbSwitch );
}
else {
// deactivate
Train->mvControlled->MotorBlowersSwitchOff( false, side::front );
Train->mvControlled->MotorBlowersSwitchOff( false, side::rear );
// visual feedback
Train->ggMotorBlowersRearButton.UpdateValue( 0.f, Train->dsbSwitch );
}
}
}
}
void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &Command ) {
// TODO: don't rely on presense of 3d model to determine presence of the switch // TODO: don't rely on presense of 3d model to determine presence of the switch
if( Train->ggStLinOffButton.SubModel == nullptr ) { if( Train->ggStLinOffButton.SubModel == nullptr ) {
if( Command.action == GLFW_PRESS ) { if( Command.action == GLFW_PRESS ) {
@@ -5055,7 +5245,7 @@ bool TTrain::Update( double const Deltatime )
ggWater1TempB.Update(); ggWater1TempB.Update();
} }
if( ggOilPressB.SubModel ) { if( ggOilPressB.SubModel ) {
ggOilPressB.UpdateValue( tmp->MoverParameters->OilPump.pressure_present ); ggOilPressB.UpdateValue( tmp->MoverParameters->OilPump.pressure );
ggOilPressB.Update(); ggOilPressB.Update();
} }
} }
@@ -5356,7 +5546,7 @@ bool TTrain::Update( double const Deltatime )
btLampkaRearRightEndLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::redmarker_right ) != 0 ); btLampkaRearRightEndLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::redmarker_right ) != 0 );
// others // others
btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA ); btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA );
btLampkaMotorBlowers.Turn( mvControlled->RventRot > 0.1 ); btLampkaMotorBlowers.Turn( ( mvControlled->MotorBlowers[ side::front ].is_active ) && ( mvControlled->MotorBlowers[ side::rear ].is_active ) );
} }
else { else {
// wylaczone // wylaczone
@@ -5715,6 +5905,9 @@ bool TTrain::Update( double const Deltatime )
ggWaterCircuitsLinkButton.Update(); ggWaterCircuitsLinkButton.Update();
ggFuelPumpButton.Update(); ggFuelPumpButton.Update();
ggOilPumpButton.Update(); ggOilPumpButton.Update();
ggMotorBlowersFrontButton.Update();
ggMotorBlowersRearButton.Update();
ggMotorBlowersAllOffButton.Update();
//------ //------
} }
// wyprowadzenie sygnałów dla haslera na PoKeys (zaznaczanie na taśmie) // wyprowadzenie sygnałów dla haslera na PoKeys (zaznaczanie na taśmie)
@@ -6945,6 +7138,9 @@ void TTrain::clear_cab_controls()
ggWaterCircuitsLinkButton.Clear(); ggWaterCircuitsLinkButton.Clear();
ggFuelPumpButton.Clear(); ggFuelPumpButton.Clear();
ggOilPumpButton.Clear(); ggOilPumpButton.Clear();
ggMotorBlowersFrontButton.Clear();
ggMotorBlowersRearButton.Clear();
ggMotorBlowersAllOffButton.Clear();
btLampkaPrzetw.Clear(); btLampkaPrzetw.Clear();
btLampkaPrzetwB.Clear(); btLampkaPrzetwB.Clear();
@@ -7289,6 +7485,26 @@ void TTrain::set_cab_controls() {
1.0 : 1.0 :
0.0 ); 0.0 );
} }
// traction motor fans
if( ggMotorBlowersFrontButton.type() != TGaugeType::push ) {
ggMotorBlowersFrontButton.PutValue(
mvControlled->MotorBlowers[side::front].is_enabled ?
1.0 :
0.0 );
}
if( ggMotorBlowersRearButton.type() != TGaugeType::push ) {
ggMotorBlowersRearButton.PutValue(
mvControlled->MotorBlowers[side::rear].is_enabled ?
1.0 :
0.0 );
}
if( ggMotorBlowersAllOffButton.type() != TGaugeType::push ) {
ggMotorBlowersAllOffButton.PutValue(
( mvControlled->MotorBlowers[side::front].is_disabled
|| mvControlled->MotorBlowers[ side::front ].is_disabled ) ?
1.0 :
0.0 );
}
// we reset all indicators, as they're set during the update pass // we reset all indicators, as they're set during the update pass
// TODO: when cleaning up break setting indicator state into a separate function, so we can reuse it // TODO: when cleaning up break setting indicator state into a separate function, so we can reuse it
@@ -7483,6 +7699,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
{ "fuelpump_sw:", ggFuelPumpButton }, { "fuelpump_sw:", ggFuelPumpButton },
{ "oilpump_sw:", ggOilPumpButton }, { "oilpump_sw:", ggOilPumpButton },
{ "oilpressb:", ggOilPressB }, { "oilpressb:", ggOilPressB },
{ "motorblowersfront_sw:", ggMotorBlowersFrontButton },
{ "motorblowersrear_sw:", ggMotorBlowersRearButton },
{ "motorblowersalloff_sw:", ggMotorBlowersAllOffButton },
{ "radio_sw:", ggRadioButton }, { "radio_sw:", ggRadioButton },
{ "radiochannel_sw:", ggRadioChannelSelector }, { "radiochannel_sw:", ggRadioChannelSelector },
{ "radiochannelprev_sw:", ggRadioChannelPrevious }, { "radiochannelprev_sw:", ggRadioChannelPrevious },
@@ -7648,7 +7867,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
// oil pressure // oil pressure
auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka
gauge.Load( Parser, DynamicObject, DynamicObject->mdKabina, nullptr ); gauge.Load( Parser, DynamicObject, DynamicObject->mdKabina, nullptr );
gauge.AssignFloat( &mvControlled->OilPump.pressure_present ); gauge.AssignFloat( &mvControlled->OilPump.pressure );
} }
else if( Label == "oiltemp:" ) { else if( Label == "oiltemp:" ) {
// oil temperature // oil temperature

13
Train.h
View File

@@ -252,6 +252,13 @@ class TTrain
static void OnCommand_compressorenable( TTrain *Train, command_data const &Command ); static void OnCommand_compressorenable( TTrain *Train, command_data const &Command );
static void OnCommand_compressordisable( TTrain *Train, command_data const &Command ); static void OnCommand_compressordisable( TTrain *Train, command_data const &Command );
static void OnCommand_compressortogglelocal( TTrain *Train, command_data const &Command ); static void OnCommand_compressortogglelocal( TTrain *Train, command_data const &Command );
static void OnCommand_motorblowerstogglefront( TTrain *Train, command_data const &Command );
static void OnCommand_motorblowersenablefront( TTrain *Train, command_data const &Command );
static void OnCommand_motorblowersdisablefront( TTrain *Train, command_data const &Command );
static void OnCommand_motorblowerstogglerear( TTrain *Train, command_data const &Command );
static void OnCommand_motorblowersenablerear( TTrain *Train, command_data const &Command );
static void OnCommand_motorblowersdisablerear( TTrain *Train, command_data const &Command );
static void OnCommand_motorblowersdisableall( TTrain *Train, command_data const &Command );
static void OnCommand_motorconnectorsopen( TTrain *Train, command_data const &Command ); static void OnCommand_motorconnectorsopen( TTrain *Train, command_data const &Command );
static void OnCommand_motorconnectorsclose( TTrain *Train, command_data const &Command ); static void OnCommand_motorconnectorsclose( TTrain *Train, command_data const &Command );
static void OnCommand_motordisconnect( TTrain *Train, command_data const &Command ); static void OnCommand_motordisconnect( TTrain *Train, command_data const &Command );
@@ -323,6 +330,7 @@ class TTrain
static void OnCommand_cabchangebackward( TTrain *Train, command_data const &Command ); static void OnCommand_cabchangebackward( TTrain *Train, command_data const &Command );
static void OnCommand_generictoggle( TTrain *Train, command_data const &Command ); static void OnCommand_generictoggle( TTrain *Train, command_data const &Command );
// members // members
TDynamicObject *DynamicObject { nullptr }; // przestawia zmiana pojazdu [F5] TDynamicObject *DynamicObject { nullptr }; // przestawia zmiana pojazdu [F5]
TMoverParameters *mvControlled { nullptr }; // człon, w którym sterujemy silnikiem TMoverParameters *mvControlled { nullptr }; // człon, w którym sterujemy silnikiem
@@ -351,7 +359,7 @@ public: // reszta może by?publiczna
TGauge ggI3B; TGauge ggI3B;
TGauge ggItotalB; TGauge ggItotalB;
TGauge ggOilPressB; TGauge ggOilPressB; // other unit oil pressure indicator
TGauge ggWater1TempB; TGauge ggWater1TempB;
// McZapkie: definicje regulatorow // McZapkie: definicje regulatorow
@@ -459,6 +467,9 @@ public: // reszta może by?publiczna
TGauge ggWaterCircuitsLinkButton; TGauge ggWaterCircuitsLinkButton;
TGauge ggFuelPumpButton; // fuel pump switch TGauge ggFuelPumpButton; // fuel pump switch
TGauge ggOilPumpButton; // fuel pump switch TGauge ggOilPumpButton; // fuel pump switch
TGauge ggMotorBlowersFrontButton; // front traction motor fan switch
TGauge ggMotorBlowersRearButton; // rear traction motor fan switch
TGauge ggMotorBlowersAllOffButton; // motor fans shutdown switch
TButton btLampkaPoslizg; TButton btLampkaPoslizg;
TButton btLampkaStyczn; TButton btLampkaStyczn;

View File

@@ -214,10 +214,13 @@ commanddescription_sequence Commands_descriptions = {
{ "generictoggle9", command_target::vehicle, command_mode::oneoff }, { "generictoggle9", command_target::vehicle, command_mode::oneoff },
{ "batterytoggle", command_target::vehicle, command_mode::oneoff }, { "batterytoggle", command_target::vehicle, command_mode::oneoff },
{ "batteryenable", command_target::vehicle, command_mode::oneoff }, { "batteryenable", command_target::vehicle, command_mode::oneoff },
{ "batterydisable", command_target::vehicle, command_mode::oneoff } { "batterydisable", command_target::vehicle, command_mode::oneoff },
{ "motorblowerstogglefront", command_target::vehicle, command_mode::oneoff },
{ "motorblowerstogglerear", command_target::vehicle, command_mode::oneoff },
{ "motorblowersdisableall", command_target::vehicle, command_mode::oneoff }
}; };
} } // simulation
void command_queue::update() void command_queue::update()
{ {

View File

@@ -209,6 +209,9 @@ enum class user_command {
batterytoggle, batterytoggle,
batteryenable, batteryenable,
batterydisable, batterydisable,
motorblowerstogglefront,
motorblowerstogglerear,
motorblowersdisableall,
none = -1 none = -1
}; };

View File

@@ -217,6 +217,10 @@ driverkeyboard_input::default_bindings() {
{ user_command::batterytoggle, GLFW_KEY_J }, { user_command::batterytoggle, GLFW_KEY_J },
// batteryenable, // batteryenable,
// batterydisable, // batterydisable,
{ user_command::motorblowerstogglefront, GLFW_KEY_N | keymodifier::shift },
{ user_command::motorblowerstogglerear, GLFW_KEY_M | keymodifier::shift },
{ user_command::motorblowersdisableall, GLFW_KEY_M | keymodifier::control }
}; };
} }

View File

@@ -182,6 +182,11 @@ driver_mode::update() {
// variable step simulation time routines // variable step simulation time routines
if( ( simulation::Train == nullptr ) && ( false == FreeFlyModeFlag ) ) {
// intercept cases when the driven train got removed after entering portal
InOutKey();
}
if( Global.changeDynObj ) { if( Global.changeDynObj ) {
// ABu zmiana pojazdu - przejście do innego // ABu zmiana pojazdu - przejście do innego
ChangeDynamic(); ChangeDynamic();

View File

@@ -499,6 +499,15 @@ drivermouse_input::default_bindings() {
{ "oilpump_sw:", { { "oilpump_sw:", {
user_command::oilpumptoggle, user_command::oilpumptoggle,
user_command::none } }, user_command::none } },
{ "motorblowersfront_sw:", {
user_command::motorblowerstogglefront,
user_command::none } },
{ "motorblowersrear_sw:", {
user_command::motorblowerstogglerear,
user_command::none } },
{ "motorblowersalloff_sw:", {
user_command::motorblowersdisableall,
user_command::none } },
{ "main_off_bt:", { { "main_off_bt:", {
user_command::linebreakeropen, user_command::linebreakeropen,
user_command::none } }, user_command::none } },

View File

@@ -353,7 +353,10 @@ debug_panel::render() {
render_section( "Vehicle AI", m_ailines ); render_section( "Vehicle AI", m_ailines );
render_section( "Vehicle Scan Table", m_scantablelines ); render_section( "Vehicle Scan Table", m_scantablelines );
render_section( "Scenario", m_scenariolines ); render_section( "Scenario", m_scenariolines );
render_section( "Scenario Event Queue", m_eventqueuelines ); if( true == render_section( "Scenario Event Queue", m_eventqueuelines ) ) {
// event queue filter
ImGui::Checkbox( "By This Vehicle Only", &m_eventqueueactivevehicleonly );
}
render_section( "Camera", m_cameralines ); render_section( "Camera", m_cameralines );
render_section( "Gfx Renderer", m_rendererlines ); render_section( "Gfx Renderer", m_rendererlines );
// toggles // toggles
@@ -411,7 +414,7 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
( mover.CompressorFlag ? 'C' : ( false == mover.CompressorAllowLocal ? '-' : ( ( mover.CompressorAllow || mover.CompressorStart == start_t::automatic ) ? 'c' : '.' ) ) ), ( mover.CompressorFlag ? 'C' : ( false == mover.CompressorAllowLocal ? '-' : ( ( mover.CompressorAllow || mover.CompressorStart == start_t::automatic ) ? 'c' : '.' ) ) ),
( mover.CompressorGovernorLock ? '!' : '.' ), ( mover.CompressorGovernorLock ? '!' : '.' ),
std::string( isplayervehicle ? locale::strings[ locale::string::debug_vehicle_radio ] + ( mover.Radio ? std::to_string( m_input.train->RadioChannel() ) : "-" ) : "" ).c_str(), std::string( isplayervehicle ? locale::strings[ locale::string::debug_vehicle_radio ] + ( mover.Radio ? std::to_string( m_input.train->RadioChannel() ) : "-" ) : "" ).c_str(),
std::string( isdieselenginepowered ? locale::strings[ locale::string::debug_vehicle_oilpressure ] + to_string( mover.OilPump.pressure_present, 2 ) : "" ).c_str(), std::string( isdieselenginepowered ? locale::strings[ locale::string::debug_vehicle_oilpressure ] + to_string( mover.OilPump.pressure, 2 ) : "" ).c_str(),
// power transfers // power transfers
mover.Couplers[ side::front ].power_high.voltage, mover.Couplers[ side::front ].power_high.voltage,
mover.Couplers[ side::front ].power_high.current, mover.Couplers[ side::front ].power_high.current,
@@ -437,6 +440,8 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
std::abs( mover.enrot ) * 60, std::abs( mover.enrot ) * 60,
std::abs( mover.nrot ) * mover.Transmision.Ratio * 60, std::abs( mover.nrot ) * mover.Transmision.Ratio * 60,
mover.RventRot * 60, mover.RventRot * 60,
mover.MotorBlowers[side::front].revolutions,
mover.MotorBlowers[side::rear].revolutions,
mover.dizel_heat.rpmw, mover.dizel_heat.rpmw,
mover.dizel_heat.rpmw2 ); mover.dizel_heat.rpmw2 );
@@ -759,6 +764,8 @@ debug_panel::update_section_scantable( std::vector<text_line> &Output ) {
if( m_input.mechanik == nullptr ) { return; } if( m_input.mechanik == nullptr ) { return; }
Output.emplace_back( "Flags: Dist: Vel: Name:", Global.UITextColor );
auto const &mechanik{ *m_input.mechanik }; auto const &mechanik{ *m_input.mechanik };
std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast<int>( mechanik.TableSize() ) - 1, 0, 30 ); std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast<int>( mechanik.TableSize() ) - 1, 0, 30 );
@@ -768,8 +775,8 @@ debug_panel::update_section_scantable( std::vector<text_line> &Output ) {
Output.emplace_back( Bezogonkow( scanline ), Global.UITextColor ); Output.emplace_back( Bezogonkow( scanline ), Global.UITextColor );
++i; ++i;
} while( i < speedtablesize ); } while( i < speedtablesize );
if( Output.empty() ) { if( Output.size() == 1 ) {
Output.emplace_back( "(no points of interest)", Global.UITextColor ); Output.front().data = "(no points of interest)";
} }
} }
@@ -782,7 +789,8 @@ debug_panel::update_section_scenario( std::vector<text_line> &Output ) {
Output.emplace_back( textline, Global.UITextColor ); Output.emplace_back( textline, Global.UITextColor );
// current luminance level // current luminance level
textline = "Light level: " + to_string( Global.fLuminance, 3 ); textline = "Cloud cover: " + to_string( Global.Overcast, 3 );
textline += "\nLight level: " + to_string( Global.fLuminance, 3 );
if( Global.FakeLight ) { textline += "(*)"; } if( Global.FakeLight ) { textline += "(*)"; }
textline += "\nAir temperature: " + to_string( Global.AirTemperature, 1 ) + " deg C"; textline += "\nAir temperature: " + to_string( Global.AirTemperature, 1 ) + " deg C";
@@ -797,28 +805,29 @@ debug_panel::update_section_eventqueue( std::vector<text_line> &Output ) {
// current event queue // current event queue
auto const time { Timer::GetTime() }; auto const time { Timer::GetTime() };
auto const *event { simulation::Events.begin() }; auto const *event { simulation::Events.begin() };
auto eventtableindex{ 0 };
Output.emplace_back( "Delay: Event:", Global.UITextColor );
while( ( event != nullptr ) while( ( event != nullptr )
&& ( eventtableindex < 30 ) ) { && ( Output.size() < 30 ) ) {
if( ( false == event->m_ignored ) if( ( false == event->m_ignored )
&& ( false == event->m_passive ) ) { && ( false == event->m_passive )
&& ( ( false == m_eventqueueactivevehicleonly )
|| ( event->m_activator == m_input.vehicle ) ) ) {
auto const delay { " " + to_string( std::max( 0.0, event->m_launchtime - time ), 1 ) }; auto const delay { " " + to_string( std::max( 0.0, event->m_launchtime - time ), 1 ) };
textline = textline = delay.substr( delay.length() - 6 )
"Delay: " + delay.substr( delay.length() - 6 ) + " " + event->m_name
+ ", Event: " + event->m_name
+ ( event->m_activator ? " (by: " + event->m_activator->asName + ")" : "" ) + ( event->m_activator ? " (by: " + event->m_activator->asName + ")" : "" )
+ ( event->m_sibling ? " (joint event)" : "" ); + ( event->m_sibling ? " (joint event)" : "" );
Output.emplace_back( textline, Global.UITextColor ); Output.emplace_back( textline, Global.UITextColor );
++eventtableindex;
} }
event = event->m_next; event = event->m_next;
} }
if( Output.empty() ) { if( Output.size() == 1 ) {
textline = "(no queued events)"; Output.front().data = "(no queued events)";
Output.emplace_back( textline, Global.UITextColor );
} }
} }
@@ -880,15 +889,16 @@ debug_panel::update_section_renderer( std::vector<text_line> &Output ) {
Output.emplace_back( GfxRenderer.info_stats(), Global.UITextColor ); Output.emplace_back( GfxRenderer.info_stats(), Global.UITextColor );
} }
void bool
debug_panel::render_section( std::string const &Header, std::vector<text_line> const &Lines ) { debug_panel::render_section( std::string const &Header, std::vector<text_line> const &Lines ) {
if( Lines.empty() ) { return; } if( true == Lines.empty() ) { return false; }
if( false == ImGui::CollapsingHeader( Header.c_str() ) ) { return; } if( false == ImGui::CollapsingHeader( Header.c_str() ) ) { return false; }
for( auto const &line : Lines ) { for( auto const &line : Lines ) {
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
} }
return true;
} }
void void

View File

@@ -72,7 +72,7 @@ private:
std::string update_vehicle_coupler( int const Side ); std::string update_vehicle_coupler( int const Side );
std::string update_vehicle_brake() const; std::string update_vehicle_brake() const;
// renders provided lines, under specified collapsing header // renders provided lines, under specified collapsing header
void render_section( std::string const &Header, std::vector<text_line> const &Lines ); bool render_section( std::string const &Header, std::vector<text_line> const &Lines );
// members // members
std::array<char, 1024> m_buffer; std::array<char, 1024> m_buffer;
input_data m_input; input_data m_input;
@@ -88,6 +88,7 @@ private:
int tprev { 0 }; // poprzedni czas int tprev { 0 }; // poprzedni czas
double VelPrev { 0.0 }; // poprzednia prędkość double VelPrev { 0.0 }; // poprzednia prędkość
double Acc { 0.0 }; // przyspieszenie styczne double Acc { 0.0 }; // przyspieszenie styczne
bool m_eventqueueactivevehicleonly { false };
}; };
class transcripts_panel : public ui_panel { class transcripts_panel : public ui_panel {

View File

@@ -33,7 +33,6 @@ void gl::glsl_common_setup()
layout(std140) uniform light_ubo layout(std140) uniform light_ubo
{ {
vec3 ambient; vec3 ambient;
float fog_density;
vec3 fog_color; vec3 fog_color;
uint lights_count; uint lights_count;
@@ -50,6 +49,8 @@ void gl::glsl_common_setup()
mat4 future; mat4 future;
float opacity; float opacity;
float emission; float emission;
float fog_density;
float alpha_mult;
}; };
layout (std140) uniform scene_ubo layout (std140) uniform scene_ubo

View File

@@ -58,7 +58,9 @@ namespace gl
glm::mat4 future; glm::mat4 future;
float opacity; float opacity;
float emission; float emission;
UBS_PAD(12); float fog_density;
float alpha_mult;
UBS_PAD(4);
void set_modelview(const glm::mat4 &mv) void set_modelview(const glm::mat4 &mv)
{ {
@@ -100,7 +102,7 @@ namespace gl
struct light_ubs struct light_ubs
{ {
glm::vec3 ambient; glm::vec3 ambient;
float fog_density; UBS_PAD(4);
glm::vec3 fog_color; glm::vec3 fog_color;
uint32_t lights_count; uint32_t lights_count;

View File

@@ -0,0 +1,201 @@
// dear imgui: Renderer for OpenGL2 (legacy OpenGL, fixed pipeline)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
// **Prefer using the code in imgui_impl_opengl3.cpp**
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
// confuse your GPU driver.
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2018-08-03: OpenGL: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications.
// 2018-06-08: Misc: Extracted imgui_impl_opengl2.cpp/.h away from the old combined GLFW/SDL+OpenGL2 examples.
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplGlfwGL2_RenderDrawData() in the .h file so you can call it yourself.
// 2017-09-01: OpenGL: Save and restore current polygon mode.
// 2016-09-10: OpenGL: Uploading font texture as RGBA32 to increase compatibility with users shaders (not ideal).
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
#include "imgui.h"
#include "imgui_impl_opengl2.h"
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
#include <stddef.h> // intptr_t
#else
#include <stdint.h> // intptr_t
#endif
#include <GL/glew.h>
// OpenGL Data
static GLuint g_FontTexture = 0;
// Functions
bool ImGui_ImplOpenGL2_Init()
{
return true;
}
void ImGui_ImplOpenGL2_Shutdown()
{
ImGui_ImplOpenGL2_DestroyDeviceObjects();
}
void ImGui_ImplOpenGL2_NewFrame()
{
if (!g_FontTexture)
ImGui_ImplOpenGL2_CreateDeviceObjects();
}
// OpenGL2 Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
ImGuiIO& io = ImGui::GetIO();
int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y);
if (fb_width == 0 || fb_height == 0)
return;
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
// We are using the OpenGL fixed pipeline to make the example code simpler to read!
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// Render command lists
ImVec2 pos = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos)));
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)));
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback (registered via ImDrawList::AddCallback)
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y);
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
{
// Apply scissor/clipping rectangle
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
}
}
idx_buffer += pcmd->ElemCount;
}
}
// Restore modified state
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
}
bool ImGui_ImplOpenGL2_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
void ImGui_ImplOpenGL2_DestroyFontsTexture()
{
if (g_FontTexture)
{
ImGuiIO& io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture);
io.Fonts->TexID = 0;
g_FontTexture = 0;
}
}
bool ImGui_ImplOpenGL2_CreateDeviceObjects()
{
return ImGui_ImplOpenGL2_CreateFontsTexture();
}
void ImGui_ImplOpenGL2_DestroyDeviceObjects()
{
ImGui_ImplOpenGL2_DestroyFontsTexture();
}

View File

@@ -0,0 +1,28 @@
// dear imgui: Renderer for OpenGL2 (legacy OpenGL, fixed pipeline)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
// **Prefer using the code in imgui_impl_opengl3.cpp**
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
// confuse your GPU driver.
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_Init();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_NewFrame();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data);
// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyDeviceObjects();

View File

@@ -1306,10 +1306,22 @@ void opengl_renderer::Bind_Material(material_handle const Material, TSubModel *s
model_ubs.param[entry.location][entry.offset + j] = src[j]; model_ubs.param[entry.location][entry.offset + j] = src[j];
} }
if (std::isnan(material.opacity)) if (m_blendingenabled)
model_ubs.opacity = m_blendingenabled ? -1.0f : 0.5f; {
model_ubs.opacity = -1.0f;
}
else else
model_ubs.opacity = m_blendingenabled ? -1.0f : material.opacity; {
if (!std::isnan(material.opacity))
model_ubs.opacity = material.opacity;
else
model_ubs.opacity = 0.5f;
}
if (sm)
model_ubs.alpha_mult = sm->fVisible;
else
model_ubs.alpha_mult = 1.0f;
if (GLEW_ARB_multi_bind) if (GLEW_ARB_multi_bind)
{ {
@@ -2140,29 +2152,11 @@ void opengl_renderer::Render(TSubModel *Submodel)
case rendermode::color: case rendermode::color:
case rendermode::reflections: case rendermode::reflections:
{ {
// NOTE: code disabled as normalization marking doesn't take into account scaling propagation down hierarchy chains
// for the time being we'll do with enforced worst-case scaling method, when speculars are enabled
#ifdef EU07_USE_OPTIMIZED_NORMALIZATION
switch (Submodel->m_normalizenormals)
{
case TSubModel::normalize:
{
::glEnable(GL_NORMALIZE);
break;
}
case TSubModel::rescale:
{
::glEnable(GL_RESCALE_NORMAL);
break;
}
default:
{
break;
}
}
#else
#endif
// material configuration: // material configuration:
// transparency hack
if (Submodel->fVisible < 1.0f)
setup_drawing(true);
// textures... // textures...
if (Submodel->m_material < 0) if (Submodel->m_material < 0)
{ // zmienialne skóry { // zmienialne skóry
@@ -2183,28 +2177,11 @@ void opengl_renderer::Render(TSubModel *Submodel)
// main draw call // main draw call
draw(Submodel->m_geometry); draw(Submodel->m_geometry);
// post-draw reset
model_ubs.emission = 0.0f; model_ubs.emission = 0.0f;
if (Submodel->fVisible < 1.0f)
setup_drawing(false);
#ifdef EU07_USE_OPTIMIZED_NORMALIZATION
switch (Submodel->m_normalizenormals)
{
case TSubModel::normalize:
{
::glDisable(GL_NORMALIZE);
break;
}
case TSubModel::rescale:
{
::glDisable(GL_RESCALE_NORMAL);
break;
}
default:
{
break;
}
}
#else
#endif
break; break;
} }
case rendermode::shadows: case rendermode::shadows:
@@ -2264,34 +2241,53 @@ void opengl_renderer::Render(TSubModel *Submodel)
float lightlevel = 1.f; // TODO, TBD: parameter to control light strength float lightlevel = 1.f; // TODO, TBD: parameter to control light strength
// view angle attenuation // view angle attenuation
float const anglefactor = clamp((Submodel->fCosViewAngle - Submodel->fCosFalloffAngle) / (Submodel->fCosHotspotAngle - Submodel->fCosFalloffAngle), 0.f, 1.f); float const anglefactor = clamp((Submodel->fCosViewAngle - Submodel->fCosFalloffAngle) / (Submodel->fCosHotspotAngle - Submodel->fCosFalloffAngle), 0.f, 1.f);
// distance attenuation lightlevel *= anglefactor;
// we're capping how much effect the distance attenuation can have, otherwise the lights get too tiny at regular distances float const precipitationfactor{interpolate(1.f, 0.25f, clamp(Global.Overcast * 0.75f - 0.5f, 0.f, 1.f))};
float const distancefactor = std::max(0.5f, (Submodel->fSquareMaxDist - TSubModel::fSquareDist) / Submodel->fSquareMaxDist); lightlevel *= precipitationfactor;
float const precipitationfactor = std::max(1.f, Global.Overcast - 1.f);
if (lightlevel > 0.f) if (lightlevel > 0.f)
{ {
// material configuration: // material configuration:
// distance attenuation. NOTE: since it's fixed pipeline with built-in gamma correction we're using linear attenuation
// we're capping how much effect the distance attenuation can have, otherwise the lights get too tiny at regular distances
float const distancefactor{std::max(0.5f, (Submodel->fSquareMaxDist - TSubModel::fSquareDist) / Submodel->fSquareMaxDist)};
auto const pointsize{std::max(3.f, 5.f * distancefactor * anglefactor)};
::glEnable(GL_BLEND); ::glEnable(GL_BLEND);
::glPushMatrix(); ::glPushMatrix();
::glLoadIdentity(); ::glLoadIdentity();
::glTranslatef(lightcenter.x, lightcenter.y, lightcenter.z); // początek układu zostaje bez zmian ::glTranslatef(lightcenter.x, lightcenter.y, lightcenter.z); // początek układu zostaje bez zmian
/*
setup_shadow_color( colors::white ); // limit impact of dense fog on the lights
*/ model_ubs.fog_density = 1.0f / std::min<float>(Global.fFogEnd, m_fogrange * 2);
glPointSize(std::max(3.f, 5.f * distancefactor * anglefactor) * 2.0f);
// main draw call // main draw call
model_ubs.param[0] = glm::vec4(glm::vec3(Submodel->f4Diffuse), 0.0f);
model_ubs.emission = std::min(1.f, lightlevel * anglefactor * precipitationfactor); model_ubs.emission = std::min(1.f, lightlevel * anglefactor * precipitationfactor);
m_freespot_shader->bind(); m_freespot_shader->bind();
if (Global.Overcast > 1.0f)
{
// fake fog halo
float const fogfactor{interpolate(2.f, 1.f, clamp<float>(Global.fFogEnd / 2000, 0.f, 1.f)) * std::max(1.f, Global.Overcast)};
glPointSize(pointsize * fogfactor * 2.0f);
model_ubs.param[0] = glm::vec4(glm::vec3(Submodel->f4Diffuse),
Submodel->fVisible * std::min(1.f, lightlevel) * 0.5f);
glDepthMask(GL_FALSE);
draw(Submodel->m_geometry);
glDepthMask(GL_TRUE);
}
glPointSize(pointsize * 2.0f);
model_ubs.param[0] = glm::vec4(glm::vec3(Submodel->f4Diffuse),
Submodel->fVisible * std::min(1.f, lightlevel));
draw(Submodel->m_geometry); draw(Submodel->m_geometry);
// post-draw reset // post-draw reset
model_ubs.emission = 0.0f; model_ubs.emission = 0.0f;
model_ubs.fog_density = 1.0f / m_fogrange;
glDisable(GL_BLEND); glDisable(GL_BLEND);
@@ -2353,8 +2349,7 @@ void opengl_renderer::Render(TSubModel *Submodel)
void opengl_renderer::Render(TTrack *Track) void opengl_renderer::Render(TTrack *Track)
{ {
if ((Track->m_material1 == 0) && (Track->m_material2 == 0) && (Track->eType != tt_Switch || Track->SwitchExtension->m_material3 == 0))
if ((Track->m_material1 == 0) && (Track->m_material2 == 0))
{ {
return; return;
} }
@@ -2382,6 +2377,11 @@ void opengl_renderer::Render(TTrack *Track)
Bind_Material(Track->m_material2); Bind_Material(Track->m_material2);
draw(std::begin(Track->Geometry2), std::end(Track->Geometry2)); draw(std::begin(Track->Geometry2), std::end(Track->Geometry2));
} }
if (Track->eType == tt_Switch && Track->SwitchExtension->m_material3 != 0)
{
Bind_Material(Track->SwitchExtension->m_material3);
draw(Track->SwitchExtension->Geometry3);
}
setup_environment_light(); setup_environment_light();
break; break;
} }
@@ -2399,6 +2399,8 @@ void opengl_renderer::Render(TTrack *Track)
draw(std::begin(Track->Geometry1), std::end(Track->Geometry1)); draw(std::begin(Track->Geometry1), std::end(Track->Geometry1));
draw(std::begin(Track->Geometry2), std::end(Track->Geometry2)); draw(std::begin(Track->Geometry2), std::end(Track->Geometry2));
if (Track->eType == tt_Switch)
draw(Track->SwitchExtension->Geometry3);
break; break;
} }
case rendermode::pickcontrols: case rendermode::pickcontrols:
@@ -2428,6 +2430,7 @@ void opengl_renderer::Render(scene::basic_cell::path_sequence::const_iterator Fi
} }
} }
// TODO: render auto generated trackbeds together with regular trackbeds in pass 1, and all rails in pass 2
// first pass, material 1 // first pass, material 1
for (auto first{First}; first != Last; ++first) for (auto first{First}; first != Last; ++first)
{ {
@@ -2486,7 +2489,6 @@ void opengl_renderer::Render(scene::basic_cell::path_sequence::const_iterator Fi
// second pass, material 2 // second pass, material 2
for (auto first{First}; first != Last; ++first) for (auto first{First}; first != Last; ++first)
{ {
auto const track{*first}; auto const track{*first};
if (track->m_material2 == 0) if (track->m_material2 == 0)
@@ -2535,6 +2537,64 @@ void opengl_renderer::Render(scene::basic_cell::path_sequence::const_iterator Fi
} }
} }
} }
// third pass, material 3
for (auto first{First}; first != Last; ++first)
{
auto const track{*first};
if (track->eType != tt_Switch)
{
continue;
}
if (track->SwitchExtension->m_material3 == 0)
{
continue;
}
if (false == track->m_visible)
{
continue;
}
switch (m_renderpass.draw_mode)
{
case rendermode::color:
case rendermode::reflections:
{
if (track->eEnvironment != e_flat)
{
setup_environment_light(track->eEnvironment);
}
Bind_Material(track->SwitchExtension->m_material3);
draw(track->SwitchExtension->Geometry3);
if (track->eEnvironment != e_flat)
{
// restore default lighting
setup_environment_light();
}
break;
}
case rendermode::shadows:
{
if ((std::abs(track->fTexHeight1) < 0.35f) || ((track->iCategoryFlag == 1) && (track->eType != tt_Normal)))
{
// shadows are only calculated for high enough trackbeds
continue;
}
Bind_Material_Shadow(track->SwitchExtension->m_material3);
draw(track->SwitchExtension->Geometry3);
break;
}
case rendermode::pickscenery: // pick scenery mode uses piece-by-piece approach
case rendermode::pickcontrols:
default:
{
break;
}
}
}
// post-render reset // post-render reset
switch (m_renderpass.draw_mode) switch (m_renderpass.draw_mode)
{ {
@@ -2794,7 +2854,7 @@ void opengl_renderer::Render_Alpha(TTraction *Traction)
auto const distance{static_cast<float>(std::sqrt(distancesquared))}; auto const distance{static_cast<float>(std::sqrt(distancesquared))};
auto const linealpha = 20.f * Traction->WireThickness / std::max(0.5f * Traction->radius() + 1.f, distance - (0.5f * Traction->radius())); auto const linealpha = 20.f * Traction->WireThickness / std::max(0.5f * Traction->radius() + 1.f, distance - (0.5f * Traction->radius()));
if (m_widelines_supported) if (m_widelines_supported)
glLineWidth(clamp(0.5f * linealpha + Traction->WireThickness * Traction->radius() / 1000.f, 1.f, 1.5f)); glLineWidth(clamp(0.5f * linealpha + Traction->WireThickness * Traction->radius() / 1000.f, 1.f, 1.75f));
// render // render
@@ -3014,29 +3074,6 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel)
{ {
case rendermode::color: case rendermode::color:
{ {
// NOTE: code disabled as normalization marking doesn't take into account scaling propagation down hierarchy chains
// for the time being we'll do with enforced worst-case scaling method, when speculars are enabled
#ifdef EU07_USE_OPTIMIZED_NORMALIZATION
switch (Submodel->m_normalizenormals)
{
case TSubModel::normalize:
{
::glEnable(GL_NORMALIZE);
break;
}
case TSubModel::rescale:
{
::glEnable(GL_RESCALE_NORMAL);
break;
}
default:
{
break;
}
}
#else
#endif
// material configuration: // material configuration:
// textures... // textures...
if (Submodel->m_material < 0) if (Submodel->m_material < 0)
@@ -3058,27 +3095,6 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel)
draw(Submodel->m_geometry); draw(Submodel->m_geometry);
model_ubs.emission = 0.0f; model_ubs.emission = 0.0f;
#ifdef EU07_USE_OPTIMIZED_NORMALIZATION
switch (Submodel->m_normalizenormals)
{
case TSubModel::normalize:
{
::glDisable(GL_NORMALIZE);
break;
}
case TSubModel::rescale:
{
::glDisable(GL_RESCALE_NORMAL);
break;
}
default:
{
break;
}
}
#else
#endif
break; break;
} }
case rendermode::cabshadows: case rendermode::cabshadows:
@@ -3112,16 +3128,17 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel)
static_cast<float>(TSubModel::fSquareDist / Submodel->fSquareMaxDist)); // pozycja punktu świecącego względem kamery static_cast<float>(TSubModel::fSquareDist / Submodel->fSquareMaxDist)); // pozycja punktu świecącego względem kamery
Submodel->fCosViewAngle = glm::dot(glm::normalize(modelview * glm::vec4(0.f, 0.f, -1.f, 1.f) - lightcenter), glm::normalize(-lightcenter)); Submodel->fCosViewAngle = glm::dot(glm::normalize(modelview * glm::vec4(0.f, 0.f, -1.f, 1.f) - lightcenter), glm::normalize(-lightcenter));
float glarelevel = 0.6f; // luminosity at night is at level of ~0.1, so the overall resulting transparency in clear conditions is ~0.5 at full 'brightness'
if (Submodel->fCosViewAngle > Submodel->fCosFalloffAngle) if (Submodel->fCosViewAngle > Submodel->fCosFalloffAngle)
{ {
// only bother if the viewer is inside the visibility cone // only bother if the viewer is inside the visibility cone
auto glarelevel{clamp<float>(0.6f - Global.fLuminance // reduce the glare in bright daylight // luminosity at night is at level of ~0.1, so the overall resulting transparency in clear conditions is ~0.5 at full 'brightness'
+ std::max(0.f, Global.Overcast - 1.f), // increase the glare in rainy/foggy conditions auto glarelevel{clamp(std::max<float>(0.6f - Global.fLuminance, // reduce the glare in bright daylight
Global.Overcast - 1.f), // ensure some glare in rainy/foggy conditions
0.f, 1.f)}; 0.f, 1.f)};
// view angle attenuation
float const anglefactor{clamp((Submodel->fCosViewAngle - Submodel->fCosFalloffAngle) / (Submodel->fCosHotspotAngle - Submodel->fCosFalloffAngle), 0.f, 1.f)};
// scale it down based on view angle glarelevel *= anglefactor;
glarelevel *= (Submodel->fCosViewAngle - Submodel->fCosFalloffAngle) / (1.0f - Submodel->fCosFalloffAngle);
if (glarelevel > 0.0f) if (glarelevel > 0.0f)
{ {
@@ -3135,7 +3152,7 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel)
m_billboard_shader->bind(); m_billboard_shader->bind();
Bind_Texture(0, m_glaretexture); Bind_Texture(0, m_glaretexture);
model_ubs.param[0] = glm::vec4(glm::vec3(Submodel->f4Diffuse), glarelevel); model_ubs.param[0] = glm::vec4(glm::vec3(Submodel->f4Diffuse), Submodel->fVisible * glarelevel);
// main draw call // main draw call
draw(m_billboardgeometry); draw(m_billboardgeometry);
@@ -3463,12 +3480,13 @@ void opengl_renderer::Update_Lights(light_array &Lights)
light_ubs.fog_color = Global.FogColor; light_ubs.fog_color = Global.FogColor;
if (Global.fFogEnd > 0) if (Global.fFogEnd > 0)
{ {
auto const adjustedfogrange{Global.fFogEnd / std::max(1.f, Global.Overcast * 2.f)}; m_fogrange = Global.fFogEnd / std::max(1.f, Global.Overcast * 2.f);
light_ubs.fog_density = 1.0f / adjustedfogrange; model_ubs.fog_density = 1.0f / m_fogrange;
} }
else else
light_ubs.fog_density = 0.0f; model_ubs.fog_density = 0.0f;
model_ubo->update(model_ubs);
light_ubo->update(light_ubs); light_ubo->update(light_ubs);
} }

View File

@@ -311,6 +311,8 @@ class opengl_renderer
float m_specularopaquescalefactor{1.f}; float m_specularopaquescalefactor{1.f};
float m_speculartranslucentscalefactor{1.f}; float m_speculartranslucentscalefactor{1.f};
float m_fogrange = 2000.0f;
renderpass_config m_renderpass; // parameters for current render pass renderpass_config m_renderpass; // parameters for current render pass
section_sequence m_sectionqueue; // list of sections in current render pass section_sequence m_sectionqueue; // list of sections in current render pass
cell_sequence m_cellqueue; cell_sequence m_cellqueue;

View File

@@ -1174,9 +1174,31 @@ basic_region::RadioStop( glm::dvec3 const &Location ) {
} }
} }
std::vector<std::string> switchtrackbedtextures {
"rozkrz8r150-1pods-new",
"rozkrz8r150-2pods-new",
"rozkrz34r150-tpbps-new2",
"rozkrz34r150-tpd1",
"rkpd34r190-tpd1",
"rkpd34r190-tpd2",
"rkpd34r190-tpd-oil2",
"zwr41r500",
"zwrot-tpd-oil1",
"zwrot34r300pods-new" };
void void
basic_region::insert( shape_node Shape, scratch_data &Scratchpad, bool const Transform ) { basic_region::insert( shape_node Shape, scratch_data &Scratchpad, bool const Transform ) {
if( Global.CreateSwitchTrackbeds ) {
auto const materialname{ GfxRenderer.Material( Shape.data().material ).name };
for( auto const &switchtrackbedtexture : switchtrackbedtextures ) {
if( materialname.find( switchtrackbedtexture ) != std::string::npos ) {
// geometry with blacklisted texture, part of old switch trackbed; ignore it
return;
}
}
}
// shape might need to be split into smaller pieces, so we create list of nodes instead of just single one // shape might need to be split into smaller pieces, so we create list of nodes instead of just single one
// using deque so we can do single pass iterating and addding generated pieces without invalidating anything // using deque so we can do single pass iterating and addding generated pieces without invalidating anything
std::deque<shape_node> shapes { Shape }; std::deque<shape_node> shapes { Shape };

View File

@@ -12,7 +12,7 @@ void main()
float dist2 = abs(x * x + y * y); float dist2 = abs(x * x + y * y);
if (dist2 > 0.5f * 0.5f) if (dist2 > 0.5f * 0.5f)
discard; discard;
gl_FragData[0] = vec4(param[0].rgb * emission, 1.0f); gl_FragData[0] = vec4(param[0].rgb * emission, param[0].a);
#if MOTIONBLUR_ENABLED #if MOTIONBLUR_ENABLED
{ {
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;; vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;

View File

@@ -61,7 +61,7 @@ void main()
result += light.color * (part.x * param[1].x + part.y * param[1].y); result += light.color * (part.x * param[1].x + part.y * param[1].y);
} }
gl_FragData[0] = vec4(apply_fog(result * tex_color.rgb), tex_color.a); gl_FragData[0] = vec4(apply_fog(result * tex_color.rgb), tex_color.a * alpha_mult);
#if MOTIONBLUR_ENABLED #if MOTIONBLUR_ENABLED
{ {
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;; vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;

View File

@@ -67,14 +67,14 @@ void main()
result += light.color * (part.x * param[1].x + part.y * param[1].y); result += light.color * (part.x * param[1].x + part.y * param[1].y);
} }
gl_FragData[0] = vec4(apply_fog(result * tex_color.rgb), tex_color.a); gl_FragData[0] = vec4(apply_fog(result * tex_color.rgb), tex_color.a * alpha_mult);
#if MOTIONBLUR_ENABLED #if MOTIONBLUR_ENABLED
{ {
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;; vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;; vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
gl_FragData[1] = vec4(a - b, 0.0f, tex_color.a); gl_FragData[1] = vec4(a - b, 0.0f, tex_color.a * alpha_mult);
} }
#endif #endif
} }

View File

@@ -72,7 +72,7 @@ void main()
result += light.color * (part.x * param[1].x + part.y * param[1].y); result += light.color * (part.x * param[1].x + part.y * param[1].y);
} }
gl_FragData[0] = vec4(apply_fog(result * tex_color.rgb), tex_color.a); gl_FragData[0] = vec4(apply_fog(result * tex_color.rgb), tex_color.a * alpha_mult);
#if MOTIONBLUR_ENABLED #if MOTIONBLUR_ENABLED
{ {

View File

@@ -70,7 +70,7 @@ void main()
result += light.color * (part.x * param[1].x + part.y * param[1].y); result += light.color * (part.x * param[1].x + part.y * param[1].y);
} }
gl_FragData[0] = vec4(apply_fog(result * tex_color.rgb), tex_color.a); gl_FragData[0] = vec4(apply_fog(result * tex_color.rgb), tex_color.a * alpha_mult);
#if MOTIONBLUR_ENABLED #if MOTIONBLUR_ENABLED
{ {

View File

@@ -7,11 +7,19 @@ uniform sampler2D tex1;
#include <common> #include <common>
in vec4 f_clip_pos;
in vec4 f_clip_future_pos;
void main() void main()
{ {
vec4 tex_color = texture(tex1, vec2(f_coord.x, f_coord.y + param[1].x)); vec4 tex_color = texture(tex1, vec2(f_coord.x, f_coord.y + param[1].x));
gl_FragData[0] = tex_color * param[0]; gl_FragData[0] = tex_color * param[0];
#if MOTIONBLUR_ENABLED #if MOTIONBLUR_ENABLED
gl_FragData[1] = vec4(0.0f); {
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;
gl_FragData[1] = vec4(a - b, 0.0f, tex_color.a * alpha_mult);
}
#endif #endif
} }

View File

@@ -165,7 +165,15 @@ state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratch
std::string token { Input.getToken<std::string>() }; std::string token { Input.getToken<std::string>() };
if( token != "endatmo" ) { if( token != "endatmo" ) {
// optional overcast parameter // optional overcast parameter
Global.Overcast = clamp( std::stof( token ), 0.f, 2.f ); Global.Overcast = std::stof( token );
if( Global.Overcast < 0.f ) {
// negative overcast means random value in range 0-abs(specified range)
Global.Overcast =
Random(
clamp(
std::abs( Global.Overcast ),
0.f, 2.f ) );
}
// overcast drives weather so do a calculation here // overcast drives weather so do a calculation here
// NOTE: ugly, clean it up when we're done with world refactoring // NOTE: ugly, clean it up when we're done with world refactoring
simulation::Environment.compute_weather(); simulation::Environment.compute_weather();
@@ -436,7 +444,16 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|| ( nodedata.type == "triangle_strip" ) || ( nodedata.type == "triangle_strip" )
|| ( nodedata.type == "triangle_fan" ) ) { || ( nodedata.type == "triangle_fan" ) ) {
if( false == Scratchpad.binary.terrain ) { auto const skip {
// all shapes will be loaded from the binary version of the file
( true == Scratchpad.binary.terrain )
// crude way to detect fixed switch trackbed geometry
|| ( ( true == Global.CreateSwitchTrackbeds )
&& ( Input.Name().size() >= 15 )
&& ( Input.Name().substr( 0, 11 ) == "scenery/zwr" )
&& ( Input.Name().substr( Input.Name().size() - 4 ) == ".inc" ) ) };
if( false == skip ) {
simulation::Region->insert( simulation::Region->insert(
scene::shape_node().import( scene::shape_node().import(
@@ -445,7 +462,6 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
true ); true );
} }
else { else {
// all shapes were already loaded from the binary version of the file
skip_until( Input, "endtri" ); skip_until( Input, "endtri" );
} }
} }

View File

@@ -54,7 +54,7 @@ init() {
"Devices: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%s%s\nPower transfers: %.0f@%.0f%s%s%s%.0f@%.0f", "Devices: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%s%s\nPower transfers: %.0f@%.0f%s%s%s%.0f@%.0f",
" radio: ", " radio: ",
" oil pressure: ", " oil pressure: ",
"Controllers:\n master: %d(%d), secondary: %s\nEngine output: %.1f, current: %.0f\nRevolutions:\n engine: %.0f, motors: %.0f, ventilators: %.0f, fans: %.0f+%.0f", "Controllers:\n master: %d(%d), secondary: %s\nEngine output: %.1f, current: %.0f\nRevolutions:\n engine: %.0f, motors: %.0f\n engine fans: %.0f, motor fans: %.0f+%.0f, cooling fans: %.0f+%.0f",
" (shunt mode)", " (shunt mode)",
"\nTemperatures:\n engine: %.2f, oil: %.2f, water: %.2f%c%.2f", "\nTemperatures:\n engine: %.2f, oil: %.2f, water: %.2f%c%.2f",
"Brakes:\n train: %.2f, independent: %.2f, delay: %s, load flag: %d\nBrake cylinder pressures:\n train: %.2f, independent: %.2f, status: 0x%.2x\nPipe pressures:\n brake: %.2f (hat: %.2f), main: %.2f, control: %.2f\nTank pressures:\n auxiliary: %.2f, main: %.2f, control: %.2f", "Brakes:\n train: %.2f, independent: %.2f, delay: %s, load flag: %d\nBrake cylinder pressures:\n train: %.2f, independent: %.2f, status: 0x%.2x\nPipe pressures:\n brake: %.2f (hat: %.2f), main: %.2f, control: %.2f\nTank pressures:\n auxiliary: %.2f, main: %.2f, control: %.2f",
@@ -97,6 +97,9 @@ init() {
"water circuits link", "water circuits link",
"fuel pump", "fuel pump",
"oil pump", "oil pump",
"motor blowers A",
"motor blowers B",
"all motor blowers",
"line breaker", "line breaker",
"line breaker", "line breaker",
"alerter", "alerter",
@@ -248,6 +251,9 @@ init() {
u8"zawór połaczenia obiegow wody", u8"zawór połaczenia obiegow wody",
u8"pompa paliwa", u8"pompa paliwa",
u8"pompa oleju", u8"pompa oleju",
u8"wentylatory silników trakcyjnych A",
u8"wentylatory silników trakcyjnych B",
u8"wszystkie wentylatory silników trakcyjnych",
u8"wyłącznik szybki", u8"wyłącznik szybki",
u8"wyłącznik szybki", u8"wyłącznik szybki",
u8"czuwak", u8"czuwak",
@@ -354,6 +360,9 @@ init() {
"watercircuitslink_sw:", "watercircuitslink_sw:",
"fuelpump_sw:", "fuelpump_sw:",
"oilpump_sw:", "oilpump_sw:",
"motorblowersfront_sw:",
"motorblowersrear_sw:",
"motorblowersalloff_sw:",
"main_off_bt:", "main_off_bt:",
"main_on_bt:", "main_on_bt:",
"security_reset_bt:", "security_reset_bt:",

View File

@@ -86,6 +86,9 @@ enum string {
cab_watercircuitslink_sw, cab_watercircuitslink_sw,
cab_fuelpump_sw, cab_fuelpump_sw,
cab_oilpump_sw, cab_oilpump_sw,
cab_motorblowersfront_sw,
cab_motorblowersrear_sw,
cab_motorblowersalloff_sw,
cab_main_off_bt, cab_main_off_bt,
cab_main_on_bt, cab_main_on_bt,
cab_security_reset_bt, cab_security_reset_bt,

View File

@@ -19,7 +19,11 @@ http://mozilla.org/MPL/2.0/.
#include "application.h" #include "application.h"
#include "imgui/imgui_impl_glfw.h" #include "imgui/imgui_impl_glfw.h"
#ifdef EU07_USEIMGUIIMPLOPENGL2
#include "imgui/imgui_impl_opengl2.h"
#else
#include "imgui/imgui_impl_opengl3.h" #include "imgui/imgui_impl_opengl3.h"
#endif
GLFWwindow *ui_layer::m_window{nullptr}; GLFWwindow *ui_layer::m_window{nullptr};
ImGuiIO *ui_layer::m_imguiio{nullptr}; ImGuiIO *ui_layer::m_imguiio{nullptr};
@@ -129,11 +133,16 @@ bool ui_layer::init(GLFWwindow *Window)
if (Global.map_enabled) if (Global.map_enabled)
m_map = std::make_unique<map>(); m_map = std::make_unique<map>();
ImGui_ImplGlfw_InitForOpenGL(m_window);
ImGui_ImplOpenGL3_Init("#version 130");
ImGui::StyleColorsClassic(); ImGui::StyleColorsClassic();
ImGui_ImplGlfw_InitForOpenGL(m_window);
#ifdef EU07_USEIMGUIIMPLOPENGL2
ImGui_ImplOpenGL2_Init();
ImGui_ImplOpenGL2_NewFrame();
#else
ImGui_ImplOpenGL3_Init("#version 130");
ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame();
#endif
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
@@ -144,7 +153,11 @@ void ui_layer::shutdown()
{ {
ImGui::EndFrame(); ImGui::EndFrame();
#ifdef EU07_USEIMGUIIMPLOPENGL2
ImGui_ImplOpenGL2_Shutdown();
#else
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
#endif
ImGui_ImplGlfw_Shutdown(); ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext(); ImGui::DestroyContext();
} }
@@ -229,9 +242,14 @@ void ui_layer::render()
ImGui::Render(); ImGui::Render();
Timer::subsystem.gfx_gui.stop(); Timer::subsystem.gfx_gui.stop();
#ifdef EU07_USEIMGUIIMPLOPENGL2
ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
ImGui_ImplOpenGL2_NewFrame();
#else
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame();
#endif
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
} }

View File

@@ -1 +1 @@
#define VERSION_INFO "M7 (GL3) 10.10.2018, based master-c7ef111, tmj-913541b" #define VERSION_INFO "M7 (GL3) 10.10.2018, based on master-52c8b40, tmj-8a904f4"