16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 22:09:19 +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;
}
fBlinkTimer = double( Random( 1000 * fOffTime ) ) / ( 1000 * fOffTime );
// TODO: redo the random timer initialization
// fBlinkTimer = Random() * ( fOnTime + fOffTime );
pModel = TModelsManager::GetModel( asName );
return ( pModel != nullptr );
@@ -548,9 +549,73 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
if( Framestamp == m_framestamp ) { return; }
fBlinkTimer -= Timer::GetDeltaTime();
if( fBlinkTimer <= 0 )
fBlinkTimer += fOffTime;
auto const timedelta { Timer::GetDeltaTime() };
// 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ść
TAnimContainer *pCurrent;
@@ -569,17 +634,19 @@ void TAnimModel::RaPrepare()
bool state; // stan światła
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 ) {
case ls_On:
case ls_Off: {
// zapalony albo zgaszony
state = ( lightmode == ls_On );
break;
}
case ls_Off:
case ls_Blink: {
// migotanie
state = ( fBlinkTimer < fOnTime );
if (LightsOn[i]) {
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;
}
case ls_Dark: {
@@ -607,10 +674,16 @@ void TAnimModel::RaPrepare()
break;
}
}
if (LightsOn[i])
LightsOn[i]->iVisible = state;
if (LightsOff[i])
LightsOff[i]->iVisible = !state;
if( lightmode >= ls_Dark ) {
// crude as hell but for test will do :x
if (LightsOn[i]) {
LightsOn[i]->iVisible = state;
// TODO: set visibility for the entire submodel's children as well
LightsOn[i]->fVisible = m_lightopacities[i];
}
if (LightsOff[i])
LightsOff[i]->iVisible = !state;
}
}
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( this ); //żeby nie robić cudzych animacji
TSubModel::pasText = &asText; // przekazanie tekstu do wyświetlacza (!!!! do przemyślenia)
@@ -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)
{ // ustawienie światła (n) na wartość (v)
if (n >= iMaxNumLights)
if( n >= iMaxNumLights ) {
return; // przekroczony zakres
}
lsLights[ n ] = v;
};

View File

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

View File

@@ -115,9 +115,17 @@ set(SOURCES
"imgui/imgui_demo.cpp"
"imgui/imgui_draw.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 "")
if (WIN32)

View File

@@ -339,8 +339,8 @@ std::string TSpeedPos::TableText() const
{ // pozycja tabelki pr?dko?ci
if (iFlags & spEnabled)
{ // o ile pozycja istotna
return "Flags:" + to_hex_str(iFlags, 8) + ", Dist:" + to_string(fDist, 1, 6) +
", Vel:" + (fVelNext == -1.0 ? " - " : to_string(static_cast<int>(fVelNext), 0, 3)) + ", Name:" + GetName();
return to_hex_str(iFlags, 8) + " " + to_string(fDist, 1, 6) +
" " + (fVelNext == -1.0 ? " -" : to_string(static_cast<int>(fVelNext), 0, 3)) + " " + GetName();
}
return "Empty";
}
@@ -2437,6 +2437,11 @@ bool TController::PrepareEngine()
mvOccupied->ConverterSwitch( true );
// w EN57 sprężarka w ra jest zasilana z silnikowego
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
@@ -4254,123 +4259,6 @@ TController::UpdateSituation(double dt) {
fMaxProximityDist = 10.0; //[m]
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
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;
}
case Shunt: {
@@ -4585,10 +4473,13 @@ TController::UpdateSituation(double dt) {
}
// ustalanie zadanej predkosci
if (iDrivigFlags & moveActive) // 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
if (iDrivigFlags & moveActive) {
SetDriverPsyche(); // ustawia AccPreferred (potrzebne tu?)
// 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)
VelDesired = fVelMax; // wstępnie prędkość maksymalna dla pojazdu(-ów), będzie
// 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
VelDesired = min_speed( VelDesired, TrainParams->TTVmax );
}
SetDriverPsyche(); // ustawia AccPreferred (potrzebne tu?)
// szukanie optymalnych wartości
AccDesired = AccPreferred; // AccPreferred wynika z osobowości mechanika
VelNext = VelDesired; // maksymalna prędkość wynikająca z innych czynników niż trajektoria ruchu
@@ -4647,6 +4535,126 @@ TController::UpdateSituation(double dt) {
default:
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 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 AIdriver = true;
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
extern bool WriteLogFlag; // logowanie parametrów fizycznych
static const int BrakeAccTableSize = 20;

View File

@@ -2687,7 +2687,7 @@ void TDynamicObject::LoadUpdate() {
}
else if( MoverParameters->LoadAmount == 0 ) {
// nie ma ładunku
MoverParameters->AssignLoad( "" );
// MoverParameters->AssignLoad( "" );
mdLoad = nullptr;
// erase bindings between lowpoly sections and potential load chunks placed inside them
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:" ) {
// 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 );
@@ -5621,10 +5650,13 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
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
sound_source motor { sound_placement::external }; // generally traction motor
sound_source motorblower { sound_placement::engine }; // associated motor blowers
// add entry to the list
auto const location { glm::vec3 { 0.f, 0.f, offset } };
motor.offset( location );
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 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
if( Vehicle.EngineType == TEngineType::ElectricInductionMotor ) {
if( Vehicle.InverterFrequency > 0.1 ) {
@@ -7034,7 +7087,7 @@ vehicle_table::erase_disabled() {
if( ( simulation::Train != nullptr )
&& ( simulation::Train->Dynamic() == vehicle ) ) {
// clear potential train binding
// TBD, TODO: manually eject the driver first ?
// TBD, TODO: kill vehicle sounds
SafeDelete( simulation::Train );
}
// remove potential entries in the light array

View File

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

View File

@@ -349,6 +349,11 @@ global_settings::ConfigParse(cParser &Parser) {
Parser >> splinefidelity;
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" ) {
Parser.getTokens();

View File

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

View File

@@ -166,6 +166,7 @@ enum class start_t {
manual,
automatic,
manualwithautofallback,
converter,
battery
};
// recognized vehicle light locations and types; can be combined
@@ -619,107 +620,122 @@ struct TCoupling {
int sounds { 0 }; // sounds emitted by the coupling devices
};
// basic approximation of a fuel pump
// TODO: fuel consumption, optional automatic engine start after activation
struct fuel_pump {
bool is_enabled { false }; // device is allowed/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 };
};
// basic approximation of a fuel pump
// TODO: fuel consumption, optional automatic engine start after activation
struct oil_pump {
bool is_enabled { false }; // device is allowed/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 };
float resource_amount { 1.f };
float pressure_minimum { 0.f }; // lowest acceptable working pressure
float pressure_maximum { 0.65f }; // oil pressure at maximum engine revolutions
float pressure_target { 0.f };
float pressure_present { 0.f };
};
struct water_pump {
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 {
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 {
float temp_min { -1 }; // lowest accepted temperature
float temp_max { -1 }; // highest accepted temperature
} config;
};
struct heat_data {
// input, state of relevant devices
bool cooling { false }; // TODO: user controlled device, implement
// bool okienko { true }; // window in the engine compartment
// system configuration
bool auxiliary_water_circuit { false }; // cooling system has an extra water circuit
double fan_speed { 0.075 }; // cooling fan rpm; either fraction of engine rpm, or absolute value if negative
// heat exchange factors
double kw { 0.35 };
double kv { 0.6 };
double kfe { 1.0 };
double kfs { 80.0 };
double kfo { 25.0 };
double kfo2 { 25.0 };
// system parts
struct fluid_circuit_t {
struct circuit_config_t {
float temp_min { -1 }; // lowest accepted temperature
float temp_max { -1 }; // highest accepted temperature
float temp_cooling { -1 }; // active cooling activation point
float temp_flow { -1 }; // fluid flow activation point
bool shutters { false }; // the radiator has shutters to assist the cooling
} config;
bool is_cold { false }; // fluid is too cold
bool is_warm { false }; // fluid is too hot
bool is_hot { false }; // fluid temperature crossed cooling threshold
bool is_flowing { false }; // fluid is being pushed through the circuit
} water,
water_aux,
oil;
// output, state of affected devices
bool PA { false }; // malfunction flag
float rpmw { 0.0 }; // current main circuit fan revolutions
float rpmwz { 0.0 }; // desired main circuit fan revolutions
bool zaluzje1 { false };
float rpmw2 { 0.0 }; // current auxiliary circuit fan revolutions
float rpmwz2 { 0.0 }; // desired auxiliary circuit fan revolutions
bool zaluzje2 { false };
// output, temperatures
float Te { 15.0 }; // ambient temperature TODO: get it from environment data
// NOTE: by default the engine is initialized in warm, startup-ready state
float Ts { 50.0 }; // engine temperature
float To { 45.0 }; // oil temperature
float Tsr { 50.0 }; // main circuit radiator temperature (?)
float Twy { 50.0 }; // main circuit water temperature
float Tsr2 { 40.0 }; // secondary circuit radiator temperature (?)
float Twy2 { 40.0 }; // secondary circuit water temperature
float temperatura1 { 50.0 };
float temperatura2 { 40.0 };
};
class TMoverParameters
{ // Ra: wrapper na kod pascalowy, przejmujący jego funkcje Q: 20160824 - juz nie wrapper a klasa bazowa :)
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_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
};
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
struct fuel_pump : public basic_device {
// TODO: fuel consumption, optional automatic engine start after activation
};
// basic approximation of an oil pump
struct oil_pump : public basic_device {
// config
float pressure_minimum { 0.f }; // lowest acceptable working pressure
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 };
// ld outputs
float pressure { 0.f }; // current pressure
};
// 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
};
struct water_heater {
// config
struct heater_config_t {
float temp_min { -1 }; // lowest accepted temperature
float temp_max { -1 }; // highest accepted temperature
} 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 {
// input, state of relevant devices
bool cooling { false }; // TODO: user controlled device, implement
// bool okienko { true }; // window in the engine compartment
// system configuration
bool auxiliary_water_circuit { false }; // cooling system has an extra water circuit
double fan_speed { 0.075 }; // cooling fan rpm; either fraction of engine rpm, or absolute value if negative
// heat exchange factors
double kw { 0.35 };
double kv { 0.6 };
double kfe { 1.0 };
double kfs { 80.0 };
double kfo { 25.0 };
double kfo2 { 25.0 };
// system parts
struct fluid_circuit_t {
struct circuit_config_t {
float temp_min { -1 }; // lowest accepted temperature
float temp_max { -1 }; // highest accepted temperature
float temp_cooling { -1 }; // active cooling activation point
float temp_flow { -1 }; // fluid flow activation point
bool shutters { false }; // the radiator has shutters to assist the cooling
} config;
bool is_cold { false }; // fluid is too cold
bool is_warm { false }; // fluid is too hot
bool is_hot { false }; // fluid temperature crossed cooling threshold
bool is_flowing { false }; // fluid is being pushed through the circuit
} water,
water_aux,
oil;
// output, state of affected devices
bool PA { false }; // malfunction flag
float rpmw { 0.0 }; // current main circuit fan revolutions
float rpmwz { 0.0 }; // desired main circuit fan revolutions
bool zaluzje1 { false };
float rpmw2 { 0.0 }; // current auxiliary circuit fan revolutions
float rpmwz2 { 0.0 }; // desired auxiliary circuit fan revolutions
bool zaluzje2 { false };
// output, temperatures
float Te { 15.0 }; // ambient temperature TODO: get it from environment data
// NOTE: by default the engine is initialized in warm, startup-ready state
float Ts { 50.0 }; // engine temperature
float To { 45.0 }; // oil temperature
float Tsr { 50.0 }; // main circuit radiator temperature (?)
float Twy { 50.0 }; // main circuit water temperature
float Tsr2 { 40.0 }; // secondary circuit radiator temperature (?)
float Twy2 { 40.0 }; // secondary circuit water temperature
float temperatura1 { 50.0 };
float temperatura2 { 40.0 };
};
public:
double dMoveLen = 0.0;
@@ -1040,6 +1056,7 @@ public:
water_heater WaterHeater;
bool WaterCircuitsLink { false }; // optional connection between water circuits
heat_data dizel_heat;
std::array<cooling_fan, 2> MotorBlowers;
int BrakeCtrlPos = -2; /*nastawa hamulca zespolonego*/
double BrakeCtrlPosR = 0.0; /*nastawa hamulca zespolonego - plynna dla FV4a*/
@@ -1126,7 +1143,7 @@ public:
bool StLinSwitchOff{ false }; // state of the button forcing motor connectors open
bool ResistorsFlag = false; /*!o jazda rezystorowa*/
double RventRot = 0.0; /*!s obroty wentylatorow rozruchowych*/
bool UnBrake = false; /*w EZT - nacisniete odhamowywanie*/
bool UnBrake = false; /*w EZT - nacisniete odhamowywanie*/
double PantPress = 0.0; /*Cisnienie w zbiornikach pantografow*/
bool PantPressSwitchActive{ false }; // state of the pantograph pressure switch. gets primed at defined pressure level in pantograph air system
bool PantPressLockActive{ false }; // pwr system state flag. fires when pressure switch activates by pantograph pressure dropping below defined level
@@ -1343,6 +1360,8 @@ public:
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 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 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*/
@@ -1353,6 +1372,7 @@ public:
void WaterHeaterCheck( double const Timestep );
void FuelPumpCheck( double const Timestep );
void OilPumpCheck( double const Timestep );
void MotorBlowersCheck( double const Timestep );
bool FuseOn(void); //bezpiecznik nadamiary
bool FuseFlagCheck(void) const; // sprawdzanie flagi nadmiarowego
void FuseOff(void); // wylaczenie nadmiarowego

View File

@@ -1436,6 +1436,8 @@ void TMoverParameters::compute_movement_( double const Deltatime ) {
SetFlag( SoundFlag, sound::relay );
}
}
// traction motors
MotorBlowersCheck( Deltatime );
// uklady hamulcowe:
ConverterCheck( Deltatime );
if (VeselVolume > 0)
@@ -1532,6 +1534,11 @@ void TMoverParameters::WaterPumpCheck( double const Timestep ) {
// water heater status check
void TMoverParameters::WaterHeaterCheck( double const Timestep ) {
WaterHeater.is_damaged = (
( true == WaterHeater.is_damaged )
|| ( ( true == WaterHeater.is_active )
&& ( false == WaterPump.is_active ) ) );
WaterHeater.is_active = (
( false == WaterHeater.is_damaged )
&& ( true == Battery )
@@ -1543,11 +1550,6 @@ void TMoverParameters::WaterHeaterCheck( double const Timestep ) {
&& ( dizel_heat.temperatura1 > WaterHeater.config.temp_max ) ) {
WaterHeater.is_active = false;
}
WaterHeater.is_damaged = (
( true == WaterHeater.is_damaged )
|| ( ( true == WaterHeater.is_active )
&& ( false == WaterPump.is_active ) ) );
}
// 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
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
OilPump.pressure_present =
OilPump.pressure =
std::min<float>(
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 ) {
OilPump.pressure_present =
if( OilPump.pressure > OilPump.pressure_target ) {
OilPump.pressure =
std::max<float>(
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 );
}
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
// włączenie / wyłączenie obwodu głownego
@@ -6020,7 +6113,7 @@ bool TMoverParameters::dizel_StartupCheck() {
}
// test the oil pump
if( ( false == OilPump.is_active )
|| ( OilPump.pressure_present < OilPump.pressure_minimum ) ) {
|| ( OilPump.pressure < OilPump.pressure_minimum ) ) {
engineisready = false;
if( OilPump.start_type == start_t::manual ) {
// 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() ) {
// empty the vehicle
// empty the vehicle if requested
LoadType = load_attributes();
LoadAmount = 0.f;
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 ) {
if( Name == loadattributes.name ) {
@@ -8211,59 +8303,54 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) {
}
extract_value( ConverterStartDelay, "ConverterStartDelay", line, "" );
// devices
std::map<std::string, start_t> starts {
{ "Manual", start_t::manual },
{ "Automatic", start_t::automatic },
{ "Mixed", start_t::manualwithautofallback },
{ "Battery", start_t::battery },
{ "Converter", start_t::converter } };
// compressor
{
std::map<std::string, start_t> starts {
{ "Manual", start_t::manual },
{ "Automatic", start_t::automatic }
};
auto lookup = starts.find( extract_value( "CompressorStart", line ) );
CompressorStart =
lookup != starts.end() ?
lookup->second :
start_t::manual;
}
// 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 ) );
FuelPump.start_type =
lookup != starts.end() ?
lookup->second :
start_t::manual;
}
// 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 ) );
OilPump.start_type =
lookup != starts.end() ?
lookup->second :
start_t::manual;
}
// 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 ) );
WaterPump.start_type =
lookup != starts.end() ?
lookup->second :
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) {
@@ -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_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 ) {
@@ -9292,7 +9383,39 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
}
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
}
else if (Command == "MainSwitch")
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")
{
if (CValue1 == 1) {

View File

@@ -72,6 +72,23 @@ void TSubModel::Name(std::string const &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
void
TSubModel::SetLightLevel( float const Level, bool const Includechildren, bool const Includesiblings ) {
@@ -1340,7 +1357,8 @@ void TSubModel::serialize(std::ostream &s,
else
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::s_vec4(s, f4Ambient);
@@ -1460,7 +1478,8 @@ void TSubModel::deserialize(std::istream &s)
tVboPtr = 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);
f4Ambient = sn_utils::d_vec4(s);

View File

@@ -100,7 +100,6 @@ private:
int iNumVerts { -1 }; // ilość wierzchołków (1 dla FreeSpotLight)
int tVboPtr; // początek na liście wierzchołków albo indeksów
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
glm::vec4
f4Ambient { 1.0f,1.0f,1.0f,1.0f },
@@ -142,7 +141,8 @@ public: // chwilowo
float4x4 *mAnimMatrix{ nullptr }; // macierz do animacji kwaternionowych (należy do AnimContainer)
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
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 pName; // robocza nazwa
private:
@@ -195,6 +195,8 @@ public:
uint32_t Flags() const { return iFlags; };
void UnFlagNext() { iFlags &= 0x00FFFFFF; };
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
void SetLightLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
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 } ) + ")" );
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
@@ -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
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 = (
pOwner->eType == tt_Switch ?
6 * Global.SplineFidelity :
static_cast<int>( std::ceil( fLength / fStep ) ) ); // potrzebne do VBO
*/
fStep = fLength / iSegCount; // update step to equalize size of individual pieces
fTsBuffer.resize( iSegCount + 1 );
@@ -376,7 +372,7 @@ Math3D::vector3 TSegment::FastGetPoint(double const t) const
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
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
// 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(
pt,
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 )
@@ -477,7 +473,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
Output.emplace_back(
pt,
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 )
@@ -501,7 +497,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
Output.emplace_back(
pt,
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.y += ShapePoints[ j ].position.y;
@@ -512,7 +508,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
Output.emplace_back(
pt,
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; }
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
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
float fVelocity = -1.0; // maksymalne ograniczenie prędkości (ustawianej eventem)
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
@@ -134,7 +136,7 @@ private:
// members
int iAxles { 0 }; // ilość osi na odcinkach obsługiwanych przez obiekt
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
};
@@ -222,6 +224,7 @@ public:
void ConnectPrevNext(TTrack *pNewPrev, int typ);
void ConnectNextPrev(TTrack *pNewNext, int typ);
void ConnectNextNext(TTrack *pNewNext, int typ);
material_handle copy_adjacent_trackbed_material( TTrack const *Exclude = nullptr );
inline double Length() const {
return Segment->GetLength(); };
inline std::shared_ptr<TSegment> CurrentSegment() const {
@@ -289,6 +292,7 @@ public:
void VelocitySet(float v);
double VelocityGet();
void ConnectionsLog();
bool DoubleSlip() const;
private:
// radius() subclass details, calculates node's bounding radius
@@ -301,6 +305,13 @@ private:
void export_as_text_( std::ostream &Output ) const;
// returns texture length for specified 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.g *= Global.DayLight.ambient[ 1 ];
color.b *= Global.DayLight.ambient[ 2 ];
color *= 0.5f;
color *= 0.35f;
}
else {
// 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::compressordisable, &TTrain::OnCommand_compressordisable },
{ 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::motorconnectorsclose, &TTrain::OnCommand_motorconnectorsclose },
{ user_command::motordisconnect, &TTrain::OnCommand_motordisconnect },
@@ -448,7 +451,9 @@ bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d)
PyObject *TTrain::GetTrainState() {
auto const *mover = DynamicObject->MoverParameters;
PyEval_AcquireLock();
auto *dict = PyDict_New();
PyEval_ReleaseLock();
if( ( dict == nullptr )
|| ( mover == 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 ) {
command_data Command = cmd;
void TTrain::OnCommand_motorblowerstogglefront( TTrain *Train, command_data const &Command ) {
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
if( Train->ggStLinOffButton.SubModel == nullptr ) {
if( Command.action == GLFW_PRESS ) {
@@ -5055,7 +5245,7 @@ bool TTrain::Update( double const Deltatime )
ggWater1TempB.Update();
}
if( ggOilPressB.SubModel ) {
ggOilPressB.UpdateValue( tmp->MoverParameters->OilPump.pressure_present );
ggOilPressB.UpdateValue( tmp->MoverParameters->OilPump.pressure );
ggOilPressB.Update();
}
}
@@ -5356,7 +5546,7 @@ bool TTrain::Update( double const Deltatime )
btLampkaRearRightEndLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::redmarker_right ) != 0 );
// others
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 {
// wylaczone
@@ -5715,6 +5905,9 @@ bool TTrain::Update( double const Deltatime )
ggWaterCircuitsLinkButton.Update();
ggFuelPumpButton.Update();
ggOilPumpButton.Update();
ggMotorBlowersFrontButton.Update();
ggMotorBlowersRearButton.Update();
ggMotorBlowersAllOffButton.Update();
//------
}
// wyprowadzenie sygnałów dla haslera na PoKeys (zaznaczanie na taśmie)
@@ -6945,6 +7138,9 @@ void TTrain::clear_cab_controls()
ggWaterCircuitsLinkButton.Clear();
ggFuelPumpButton.Clear();
ggOilPumpButton.Clear();
ggMotorBlowersFrontButton.Clear();
ggMotorBlowersRearButton.Clear();
ggMotorBlowersAllOffButton.Clear();
btLampkaPrzetw.Clear();
btLampkaPrzetwB.Clear();
@@ -7289,6 +7485,26 @@ void TTrain::set_cab_controls() {
1.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
// 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 },
{ "oilpump_sw:", ggOilPumpButton },
{ "oilpressb:", ggOilPressB },
{ "motorblowersfront_sw:", ggMotorBlowersFrontButton },
{ "motorblowersrear_sw:", ggMotorBlowersRearButton },
{ "motorblowersalloff_sw:", ggMotorBlowersAllOffButton },
{ "radio_sw:", ggRadioButton },
{ "radiochannel_sw:", ggRadioChannelSelector },
{ "radiochannelprev_sw:", ggRadioChannelPrevious },
@@ -7648,7 +7867,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
// oil pressure
auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka
gauge.Load( Parser, DynamicObject, DynamicObject->mdKabina, nullptr );
gauge.AssignFloat( &mvControlled->OilPump.pressure_present );
gauge.AssignFloat( &mvControlled->OilPump.pressure );
}
else if( Label == "oiltemp:" ) {
// 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_compressordisable( 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_motorconnectorsclose( 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_generictoggle( TTrain *Train, command_data const &Command );
// members
TDynamicObject *DynamicObject { nullptr }; // przestawia zmiana pojazdu [F5]
TMoverParameters *mvControlled { nullptr }; // człon, w którym sterujemy silnikiem
@@ -351,7 +359,7 @@ public: // reszta może by?publiczna
TGauge ggI3B;
TGauge ggItotalB;
TGauge ggOilPressB;
TGauge ggOilPressB; // other unit oil pressure indicator
TGauge ggWater1TempB;
// McZapkie: definicje regulatorow
@@ -459,6 +467,9 @@ public: // reszta może by?publiczna
TGauge ggWaterCircuitsLinkButton;
TGauge ggFuelPumpButton; // 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 btLampkaStyczn;

View File

@@ -214,10 +214,13 @@ commanddescription_sequence Commands_descriptions = {
{ "generictoggle9", command_target::vehicle, command_mode::oneoff },
{ "batterytoggle", 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()
{

View File

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

View File

@@ -217,6 +217,10 @@ driverkeyboard_input::default_bindings() {
{ user_command::batterytoggle, GLFW_KEY_J },
// batteryenable,
// 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
if( ( simulation::Train == nullptr ) && ( false == FreeFlyModeFlag ) ) {
// intercept cases when the driven train got removed after entering portal
InOutKey();
}
if( Global.changeDynObj ) {
// ABu zmiana pojazdu - przejście do innego
ChangeDynamic();

View File

@@ -499,6 +499,15 @@ drivermouse_input::default_bindings() {
{ "oilpump_sw:", {
user_command::oilpumptoggle,
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:", {
user_command::linebreakeropen,
user_command::none } },

View File

@@ -353,7 +353,10 @@ debug_panel::render() {
render_section( "Vehicle AI", m_ailines );
render_section( "Vehicle Scan Table", m_scantablelines );
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( "Gfx Renderer", m_rendererlines );
// 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.CompressorGovernorLock ? '!' : '.' ),
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
mover.Couplers[ side::front ].power_high.voltage,
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.nrot ) * mover.Transmision.Ratio * 60,
mover.RventRot * 60,
mover.MotorBlowers[side::front].revolutions,
mover.MotorBlowers[side::rear].revolutions,
mover.dizel_heat.rpmw,
mover.dizel_heat.rpmw2 );
@@ -759,6 +764,8 @@ debug_panel::update_section_scantable( std::vector<text_line> &Output ) {
if( m_input.mechanik == nullptr ) { return; }
Output.emplace_back( "Flags: Dist: Vel: Name:", Global.UITextColor );
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 );
@@ -768,8 +775,8 @@ debug_panel::update_section_scantable( std::vector<text_line> &Output ) {
Output.emplace_back( Bezogonkow( scanline ), Global.UITextColor );
++i;
} while( i < speedtablesize );
if( Output.empty() ) {
Output.emplace_back( "(no points of interest)", Global.UITextColor );
if( Output.size() == 1 ) {
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 );
// 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 += "(*)"; }
textline += "\nAir temperature: " + to_string( Global.AirTemperature, 1 ) + " deg C";
@@ -794,32 +802,33 @@ debug_panel::update_section_eventqueue( std::vector<text_line> &Output ) {
std::string textline;
// current event queue
auto const time { Timer::GetTime() };
auto const *event { simulation::Events.begin() };
auto eventtableindex{ 0 };
while( ( event != nullptr )
&& ( eventtableindex < 30 ) ) {
// current event queue
auto const time { Timer::GetTime() };
auto const *event { simulation::Events.begin() };
if( ( false == event->m_ignored )
&& ( false == event->m_passive ) ) {
Output.emplace_back( "Delay: Event:", Global.UITextColor );
auto const delay { " " + to_string( std::max( 0.0, event->m_launchtime - time ), 1 ) };
textline =
"Delay: " + delay.substr( delay.length() - 6 )
+ ", Event: " + event->m_name
+ ( event->m_activator ? " (by: " + event->m_activator->asName + ")" : "" )
+ ( event->m_sibling ? " (joint event)" : "" );
while( ( event != nullptr )
&& ( Output.size() < 30 ) ) {
Output.emplace_back( textline, Global.UITextColor );
++eventtableindex;
}
event = event->m_next;
}
if( Output.empty() ) {
textline = "(no queued events)";
Output.emplace_back( textline, Global.UITextColor );
}
if( ( false == event->m_ignored )
&& ( 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 ) };
textline = delay.substr( delay.length() - 6 )
+ " " + event->m_name
+ ( event->m_activator ? " (by: " + event->m_activator->asName + ")" : "" )
+ ( event->m_sibling ? " (joint event)" : "" );
Output.emplace_back( textline, Global.UITextColor );
}
event = event->m_next;
}
if( Output.size() == 1 ) {
Output.front().data = "(no queued events)";
}
}
void
@@ -880,15 +889,16 @@ debug_panel::update_section_renderer( std::vector<text_line> &Output ) {
Output.emplace_back( GfxRenderer.info_stats(), Global.UITextColor );
}
void
bool
debug_panel::render_section( std::string const &Header, std::vector<text_line> const &Lines ) {
if( Lines.empty() ) { return; }
if( false == ImGui::CollapsingHeader( Header.c_str() ) ) { return; }
if( true == Lines.empty() ) { return false; }
if( false == ImGui::CollapsingHeader( Header.c_str() ) ) { return false; }
for( auto const &line : Lines ) {
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
}
return true;
}
void

View File

@@ -72,7 +72,7 @@ private:
std::string update_vehicle_coupler( int const Side );
std::string update_vehicle_brake() const;
// 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
std::array<char, 1024> m_buffer;
input_data m_input;
@@ -88,6 +88,7 @@ private:
int tprev { 0 }; // poprzedni czas
double VelPrev { 0.0 }; // poprzednia prędkość
double Acc { 0.0 }; // przyspieszenie styczne
bool m_eventqueueactivevehicleonly { false };
};
class transcripts_panel : public ui_panel {

View File

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

View File

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

@@ -965,7 +965,7 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
// modelview
camera.position() = Global.pCamera.Pos;
Global.pCamera.SetMatrix(viewmatrix);
// projection
// projection
float znear = 0.1f * Global.ZoomFactor;
float zfar = Config.draw_range * Global.fDistanceFactor;
camera.projection() = perspective_projection(fovy, aspect, znear, zfar);
@@ -980,7 +980,7 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
glm::dvec3 const cubefaceupvectors[6] = {{0.0, -1.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}, {0.0, -1.0, 0.0}, {0.0, -1.0, 0.0}};
auto const cubefaceindex = m_environmentcubetextureface;
viewmatrix *= glm::lookAt(camera.position(), camera.position() + cubefacetargetvectors[cubefaceindex], cubefaceupvectors[cubefaceindex]);
// projection
// projection
float znear = 0.1f * Global.ZoomFactor;
float zfar = Config.draw_range * Global.fDistanceFactor;
camera.projection() = perspective_projection(glm::radians(90.f), 1.f, znear, zfar);
@@ -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];
}
if (std::isnan(material.opacity))
model_ubs.opacity = m_blendingenabled ? -1.0f : 0.5f;
if (m_blendingenabled)
{
model_ubs.opacity = -1.0f;
}
else
{
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.opacity = m_blendingenabled ? -1.0f : material.opacity;
model_ubs.alpha_mult = 1.0f;
if (GLEW_ARB_multi_bind)
{
@@ -2140,29 +2152,11 @@ void opengl_renderer::Render(TSubModel *Submodel)
case rendermode::color:
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:
// transparency hack
if (Submodel->fVisible < 1.0f)
setup_drawing(true);
// textures...
if (Submodel->m_material < 0)
{ // zmienialne skóry
@@ -2183,28 +2177,11 @@ void opengl_renderer::Render(TSubModel *Submodel)
// main draw call
draw(Submodel->m_geometry);
// post-draw reset
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;
}
case rendermode::shadows:
@@ -2264,34 +2241,53 @@ void opengl_renderer::Render(TSubModel *Submodel)
float lightlevel = 1.f; // TODO, TBD: parameter to control light strength
// view angle attenuation
float const anglefactor = clamp((Submodel->fCosViewAngle - Submodel->fCosFalloffAngle) / (Submodel->fCosHotspotAngle - Submodel->fCosFalloffAngle), 0.f, 1.f);
// distance 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);
float const precipitationfactor = std::max(1.f, Global.Overcast - 1.f);
lightlevel *= anglefactor;
float const precipitationfactor{interpolate(1.f, 0.25f, clamp(Global.Overcast * 0.75f - 0.5f, 0.f, 1.f))};
lightlevel *= precipitationfactor;
if (lightlevel > 0.f)
{
// 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);
::glPushMatrix();
::glLoadIdentity();
::glTranslatef(lightcenter.x, lightcenter.y, lightcenter.z); // początek układu zostaje bez zmian
/*
setup_shadow_color( colors::white );
*/
glPointSize(std::max(3.f, 5.f * distancefactor * anglefactor) * 2.0f);
// limit impact of dense fog on the lights
model_ubs.fog_density = 1.0f / std::min<float>(Global.fFogEnd, m_fogrange * 2);
// 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();
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);
// post-draw reset
model_ubs.emission = 0.0f;
model_ubs.fog_density = 1.0f / m_fogrange;
glDisable(GL_BLEND);
@@ -2353,8 +2349,7 @@ void opengl_renderer::Render(TSubModel *Submodel)
void opengl_renderer::Render(TTrack *Track)
{
if ((Track->m_material1 == 0) && (Track->m_material2 == 0))
if ((Track->m_material1 == 0) && (Track->m_material2 == 0) && (Track->eType != tt_Switch || Track->SwitchExtension->m_material3 == 0))
{
return;
}
@@ -2382,6 +2377,11 @@ void opengl_renderer::Render(TTrack *Track)
Bind_Material(Track->m_material2);
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();
break;
}
@@ -2399,6 +2399,8 @@ void opengl_renderer::Render(TTrack *Track)
draw(std::begin(Track->Geometry1), std::end(Track->Geometry1));
draw(std::begin(Track->Geometry2), std::end(Track->Geometry2));
if (Track->eType == tt_Switch)
draw(Track->SwitchExtension->Geometry3);
break;
}
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
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
for (auto first{First}; first != Last; ++first)
{
auto const track{*first};
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
switch (m_renderpass.draw_mode)
{
@@ -2620,7 +2680,7 @@ void opengl_renderer::Render_precipitation()
model_ubs.set_modelview(OpenGLMatrices.data(GL_MODELVIEW));
model_ubs.param[0] = interpolate(0.5f * (Global.DayLight.diffuse + Global.DayLight.ambient), colors::white, 0.5f * clamp<float>(Global.fLuminance, 0.f, 1.f));
model_ubs.param[1].x = simulation::Environment.m_precipitation.get_textureoffset();
model_ubs.param[1].x = simulation::Environment.m_precipitation.get_textureoffset();
model_ubo->update(model_ubs);
// momentarily disable depth write, to allow vehicle cab drawn afterwards to mask it instead of leaving it 'inside'
@@ -2794,7 +2854,7 @@ void opengl_renderer::Render_Alpha(TTraction *Traction)
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()));
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
@@ -3014,29 +3074,6 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel)
{
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:
// textures...
if (Submodel->m_material < 0)
@@ -3058,27 +3095,6 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel)
draw(Submodel->m_geometry);
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;
}
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
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)
{
// only bother if the viewer is inside the visibility cone
auto glarelevel{clamp<float>(0.6f - Global.fLuminance // reduce the glare in bright daylight
+ std::max(0.f, Global.Overcast - 1.f), // increase the glare in rainy/foggy conditions
0.f, 1.f)};
// luminosity at night is at level of ~0.1, so the overall resulting transparency in clear conditions is ~0.5 at full 'brightness'
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)};
// 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 *= (Submodel->fCosViewAngle - Submodel->fCosFalloffAngle) / (1.0f - Submodel->fCosFalloffAngle);
glarelevel *= anglefactor;
if (glarelevel > 0.0f)
{
@@ -3135,7 +3152,7 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel)
m_billboard_shader->bind();
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
draw(m_billboardgeometry);
@@ -3463,12 +3480,13 @@ void opengl_renderer::Update_Lights(light_array &Lights)
light_ubs.fog_color = Global.FogColor;
if (Global.fFogEnd > 0)
{
auto const adjustedfogrange{Global.fFogEnd / std::max(1.f, Global.Overcast * 2.f)};
light_ubs.fog_density = 1.0f / adjustedfogrange;
m_fogrange = Global.fFogEnd / std::max(1.f, Global.Overcast * 2.f);
model_ubs.fog_density = 1.0f / m_fogrange;
}
else
light_ubs.fog_density = 0.0f;
model_ubs.fog_density = 0.0f;
model_ubo->update(model_ubs);
light_ubo->update(light_ubs);
}

View File

@@ -311,6 +311,8 @@ class opengl_renderer
float m_specularopaquescalefactor{1.f};
float m_speculartranslucentscalefactor{1.f};
float m_fogrange = 2000.0f;
renderpass_config m_renderpass; // parameters for current render pass
section_sequence m_sectionqueue; // list of sections in current render pass
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
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
// using deque so we can do single pass iterating and addding generated pieces without invalidating anything
std::deque<shape_node> shapes { Shape };

View File

@@ -12,7 +12,7 @@ void main()
float dist2 = abs(x * x + y * y);
if (dist2 > 0.5f * 0.5f)
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
{
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);
}
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
{
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);
}
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
{
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);
gl_FragData[1] = vec4(a - b, 0.0f, tex_color.a * alpha_mult);
}
#endif
}

View File

@@ -72,7 +72,7 @@ void main()
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
{

View File

@@ -70,7 +70,7 @@ void main()
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
{

View File

@@ -7,11 +7,19 @@ uniform sampler2D tex1;
#include <common>
in vec4 f_clip_pos;
in vec4 f_clip_future_pos;
void main()
{
vec4 tex_color = texture(tex1, vec2(f_coord.x, f_coord.y + param[1].x));
gl_FragData[0] = tex_color * param[0];
#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
}

View File

@@ -165,7 +165,15 @@ state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratch
std::string token { Input.getToken<std::string>() };
if( token != "endatmo" ) {
// 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
// NOTE: ugly, clean it up when we're done with world refactoring
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_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(
scene::shape_node().import(
@@ -445,7 +462,6 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
true );
}
else {
// all shapes were already loaded from the binary version of the file
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",
" radio: ",
" 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)",
"\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",
@@ -97,6 +97,9 @@ init() {
"water circuits link",
"fuel pump",
"oil pump",
"motor blowers A",
"motor blowers B",
"all motor blowers",
"line breaker",
"line breaker",
"alerter",
@@ -248,6 +251,9 @@ init() {
u8"zawór połaczenia obiegow wody",
u8"pompa paliwa",
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"czuwak",
@@ -354,6 +360,9 @@ init() {
"watercircuitslink_sw:",
"fuelpump_sw:",
"oilpump_sw:",
"motorblowersfront_sw:",
"motorblowersrear_sw:",
"motorblowersalloff_sw:",
"main_off_bt:",
"main_on_bt:",
"security_reset_bt:",

View File

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

View File

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