mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-23 08:39:18 +02:00
Merge branch 'milek-dev' into gfx-work
This commit is contained in:
@@ -585,7 +585,7 @@ void TAnimModel::RaPrepare()
|
|||||||
case ls_Dark: {
|
case ls_Dark: {
|
||||||
// zapalone, gdy ciemno
|
// zapalone, gdy ciemno
|
||||||
state = (
|
state = (
|
||||||
Global.fLuminance <= (
|
Global.fLuminance - std::max( 0.f, Global.Overcast - 1.f ) <= (
|
||||||
lsLights[ i ] == static_cast<float>( ls_Dark ) ?
|
lsLights[ i ] == static_cast<float>( ls_Dark ) ?
|
||||||
DefaultDarkThresholdLevel :
|
DefaultDarkThresholdLevel :
|
||||||
( lsLights[ i ] - static_cast<float>( ls_Dark ) ) ) );
|
( lsLights[ i ] - static_cast<float>( ls_Dark ) ) ) );
|
||||||
@@ -595,7 +595,7 @@ void TAnimModel::RaPrepare()
|
|||||||
// like ls_dark but off late at night
|
// like ls_dark but off late at night
|
||||||
auto const simulationhour { simulation::Time.data().wHour };
|
auto const simulationhour { simulation::Time.data().wHour };
|
||||||
state = (
|
state = (
|
||||||
Global.fLuminance <= (
|
Global.fLuminance - std::max( 0.f, Global.Overcast - 1.f ) <= (
|
||||||
lsLights[ i ] == static_cast<float>( ls_Home ) ?
|
lsLights[ i ] == static_cast<float>( ls_Home ) ?
|
||||||
DefaultDarkThresholdLevel :
|
DefaultDarkThresholdLevel :
|
||||||
( lsLights[ i ] - static_cast<float>( ls_Home ) ) ) );
|
( lsLights[ i ] - static_cast<float>( ls_Home ) ) ) );
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ set(SOURCES
|
|||||||
"scenenodegroups.cpp"
|
"scenenodegroups.cpp"
|
||||||
"simulationenvironment.cpp"
|
"simulationenvironment.cpp"
|
||||||
"simulationstateserializer.cpp"
|
"simulationstateserializer.cpp"
|
||||||
|
"precipitation.cpp"
|
||||||
|
"openglcolor.cpp"
|
||||||
|
|
||||||
"imgui/imgui.cpp"
|
"imgui/imgui.cpp"
|
||||||
"imgui/imgui_demo.cpp"
|
"imgui/imgui_demo.cpp"
|
||||||
|
|||||||
@@ -70,4 +70,6 @@ enum class TCommandType
|
|||||||
cm_Command // komenda pobierana z komórki
|
cm_Command // komenda pobierana z komórki
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using material_handle = int;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
54
Driver.cpp
54
Driver.cpp
@@ -235,9 +235,16 @@ void TSpeedPos::CommandCheck()
|
|||||||
case TCommandType::cm_PassengerStopPoint:
|
case TCommandType::cm_PassengerStopPoint:
|
||||||
// nie ma dostępu do rozkładu
|
// nie ma dostępu do rozkładu
|
||||||
// przystanek, najwyżej AI zignoruje przy analizie tabelki
|
// przystanek, najwyżej AI zignoruje przy analizie tabelki
|
||||||
// if ((iFlags & spPassengerStopPoint) == 0)
|
fVelNext = 0.0;
|
||||||
fVelNext = 0.0; // TrainParams->IsStop()?0.0:-1.0; //na razie tak
|
|
||||||
iFlags |= spPassengerStopPoint; // niestety nie da się w tym miejscu współpracować z rozkładem
|
iFlags |= spPassengerStopPoint; // niestety nie da się w tym miejscu współpracować z rozkładem
|
||||||
|
/*
|
||||||
|
// NOTE: not used for now as it might be unnecessary
|
||||||
|
// special case, potentially override any set speed limits if requested
|
||||||
|
// NOTE: we test it here because for the time being it's only used for passenger stops
|
||||||
|
if( TestFlag( iFlags, spDontApplySpeedLimit ) ) {
|
||||||
|
fVelNext = -1;
|
||||||
|
}
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
case TCommandType::cm_SetProximityVelocity:
|
case TCommandType::cm_SetProximityVelocity:
|
||||||
// musi zostać gdyż inaczej nie działają manewry
|
// musi zostać gdyż inaczej nie działają manewry
|
||||||
@@ -876,7 +883,6 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
|||||||
// TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie
|
// TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie
|
||||||
// jest dobry pomysł
|
// jest dobry pomysł
|
||||||
sSpeedTable[i].iFlags = 0; // nie liczy się już
|
sSpeedTable[i].iFlags = 0; // nie liczy się już
|
||||||
sSpeedTable[i].fVelNext = -1; // jechać
|
|
||||||
continue; // nie analizować prędkości
|
continue; // nie analizować prędkości
|
||||||
}
|
}
|
||||||
} // koniec obsługi przelotu na W4
|
} // koniec obsługi przelotu na W4
|
||||||
@@ -953,7 +959,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
|||||||
|
|
||||||
// perform loading/unloading
|
// perform loading/unloading
|
||||||
auto const platformside = static_cast<int>( std::floor( std::abs( sSpeedTable[ i ].evEvent->input_value( 2 ) ) ) ) % 10;
|
auto const platformside = static_cast<int>( std::floor( std::abs( sSpeedTable[ i ].evEvent->input_value( 2 ) ) ) ) % 10;
|
||||||
auto const exchangetime = simulation::Station.update_load( pVehicles[ 0 ], *TrainParams, platformside );
|
auto const exchangetime = std::max( 5.0, simulation::Station.update_load( pVehicles[ 0 ], *TrainParams, platformside ) );
|
||||||
WaitingSet( std::max( -fStopTime, exchangetime ) ); // na końcu rozkładu się ustawia 60s i tu by było skrócenie
|
WaitingSet( std::max( -fStopTime, exchangetime ) ); // na końcu rozkładu się ustawia 60s i tu by było skrócenie
|
||||||
|
|
||||||
if( TrainParams->CheckTrainLatency() < 0.0 ) {
|
if( TrainParams->CheckTrainLatency() < 0.0 ) {
|
||||||
@@ -1032,9 +1038,12 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
|||||||
iDrivigFlags |= moveStopCloser; // do następnego W4 podjechać blisko (z dociąganiem)
|
iDrivigFlags |= moveStopCloser; // do następnego W4 podjechać blisko (z dociąganiem)
|
||||||
sSpeedTable[i].iFlags = 0; // nie liczy się już zupełnie (nie wyśle SetVelocity)
|
sSpeedTable[i].iFlags = 0; // nie liczy się już zupełnie (nie wyśle SetVelocity)
|
||||||
sSpeedTable[i].fVelNext = -1; // można jechać za W4
|
sSpeedTable[i].fVelNext = -1; // można jechać za W4
|
||||||
|
if( ( sSpeedTable[ i ].fDist <= 0.0 ) && ( eSignNext == sSpeedTable[ i ].evEvent ) ) {
|
||||||
|
// sanity check, if we're held by this stop point, let us go
|
||||||
|
VelSignalLast = -1;
|
||||||
|
}
|
||||||
if (go == TCommandType::cm_Unknown) // jeśli nie było komendy wcześniej
|
if (go == TCommandType::cm_Unknown) // jeśli nie było komendy wcześniej
|
||||||
go = TCommandType::cm_Ready; // gotów do odjazdu z W4 (semafor może
|
go = TCommandType::cm_Ready; // gotów do odjazdu z W4 (semafor może zatrzymać)
|
||||||
// zatrzymać)
|
|
||||||
if( false == tsGuardSignal.empty() ) {
|
if( false == tsGuardSignal.empty() ) {
|
||||||
// jeśli mamy głos kierownika, to odegrać
|
// jeśli mamy głos kierownika, to odegrać
|
||||||
iDrivigFlags |= moveGuardSignal;
|
iDrivigFlags |= moveGuardSignal;
|
||||||
@@ -1058,14 +1067,15 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
|||||||
// if the consist can change direction through a simple cab change it doesn't need fiddling with recognition of passenger stops
|
// if the consist can change direction through a simple cab change it doesn't need fiddling with recognition of passenger stops
|
||||||
iDrivigFlags &= ~( moveStopPoint );
|
iDrivigFlags &= ~( moveStopPoint );
|
||||||
}
|
}
|
||||||
|
fLastStopExpDist = -1.0f; // nie ma rozkładu, nie ma usuwania stacji
|
||||||
sSpeedTable[i].iFlags = 0; // W4 nie liczy się już (nie wyśle SetVelocity)
|
sSpeedTable[i].iFlags = 0; // W4 nie liczy się już (nie wyśle SetVelocity)
|
||||||
sSpeedTable[i].fVelNext = -1; // można jechać za W4
|
sSpeedTable[i].fVelNext = -1; // można jechać za W4
|
||||||
fLastStopExpDist = -1.0f; // nie ma rozkładu, nie ma usuwania stacji
|
if( ( sSpeedTable[ i ].fDist <= 0.0 ) && ( eSignNext == sSpeedTable[ i ].evEvent ) ) {
|
||||||
// wykonanie kolejnego rozkazu (Change_direction albo Shunt)
|
// sanity check, if we're held by this stop point, let us go
|
||||||
// FIX: don't automatically advance if there's disconnect procedure in progress
|
VelSignalLast = -1;
|
||||||
if( false == TestFlag( OrderCurrentGet(), Disconnect ) ) {
|
|
||||||
JumpToNextOrder();
|
|
||||||
}
|
}
|
||||||
|
// wykonanie kolejnego rozkazu (Change_direction albo Shunt)
|
||||||
|
JumpToNextOrder();
|
||||||
// ma się nie ruszać aż do momentu podania sygnału
|
// ma się nie ruszać aż do momentu podania sygnału
|
||||||
iDrivigFlags |= moveStopHere | moveStartHorn;
|
iDrivigFlags |= moveStopHere | moveStartHorn;
|
||||||
continue; // nie analizować prędkości
|
continue; // nie analizować prędkości
|
||||||
@@ -1091,24 +1101,29 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
|||||||
}
|
}
|
||||||
else if (sSpeedTable[i].iFlags & spEvent) // W4 może się deaktywować
|
else if (sSpeedTable[i].iFlags & spEvent) // W4 może się deaktywować
|
||||||
{ // jeżeli event, może być potrzeba wysłania komendy, aby ruszył
|
{ // jeżeli event, może być potrzeba wysłania komendy, aby ruszył
|
||||||
|
if( sSpeedTable[ i ].fDist < 0.0 ) {
|
||||||
// sprawdzanie eventów pasywnych miniętych
|
// sprawdzanie eventów pasywnych miniętych
|
||||||
if( (sSpeedTable[ i ].fDist < 0.0) && (SemNextIndex == i) )
|
/*
|
||||||
{
|
if( ( eSignNext != nullptr ) && ( sSpeedTable[ i ].evEvent == eSignNext ) ) {
|
||||||
|
VelSignalLast = sSpeedTable[ i ].fVelNext;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if( SemNextIndex == i ) {
|
||||||
if( Global.iWriteLogEnabled & 8 ) {
|
if( Global.iWriteLogEnabled & 8 ) {
|
||||||
WriteLog( "Speed table update for " + OwnerName() + ", passed semaphor " + sSpeedTable[ SemNextIndex ].GetName() );
|
WriteLog( "Speed table update for " + OwnerName() + ", passed semaphor " + sSpeedTable[ SemNextIndex ].GetName() );
|
||||||
}
|
}
|
||||||
SemNextIndex = -1; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze zmiennej sprawdzającej dla skanowania w przód
|
SemNextIndex = -1; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze zmiennej sprawdzającej dla skanowania w przód
|
||||||
}
|
}
|
||||||
if( (sSpeedTable[ i ].fDist < 0.0) && (SemNextStopIndex == i) )
|
if( SemNextStopIndex == i ) {
|
||||||
{
|
|
||||||
if( Global.iWriteLogEnabled & 8 ) {
|
if( Global.iWriteLogEnabled & 8 ) {
|
||||||
WriteLog( "Speed table update for " + OwnerName() + ", passed semaphor " + sSpeedTable[ SemNextStopIndex ].GetName() );
|
WriteLog( "Speed table update for " + OwnerName() + ", passed semaphor " + sSpeedTable[ SemNextStopIndex ].GetName() );
|
||||||
}
|
}
|
||||||
SemNextStopIndex = -1; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze zmiennej sprawdzającej dla skanowania w przód
|
SemNextStopIndex = -1; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze zmiennej sprawdzającej dla skanowania w przód
|
||||||
}
|
}
|
||||||
if (sSpeedTable[i].fDist > 0.0 &&
|
}
|
||||||
sSpeedTable[i].IsProperSemaphor(OrderCurrentGet()))
|
if( sSpeedTable[ i ].fDist > 0.0 ) {
|
||||||
{
|
// check signals ahead
|
||||||
|
if( sSpeedTable[ i ].IsProperSemaphor( OrderCurrentGet() ) ) {
|
||||||
if( SemNextIndex == -1 ) {
|
if( SemNextIndex == -1 ) {
|
||||||
// jeśli jest mienięty poprzedni semafor a wcześniej
|
// jeśli jest mienięty poprzedni semafor a wcześniej
|
||||||
// byl nowy to go dorzucamy do zmiennej, żeby cały czas widział najbliższy
|
// byl nowy to go dorzucamy do zmiennej, żeby cały czas widział najbliższy
|
||||||
@@ -1118,11 +1133,12 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( ( SemNextStopIndex == -1 )
|
if( ( SemNextStopIndex == -1 )
|
||||||
|| ( ( sSpeedTable[SemNextStopIndex].fVelNext != 0 )
|
|| ( ( sSpeedTable[ SemNextStopIndex ].fVelNext != 0 )
|
||||||
&& ( sSpeedTable[ i ].fVelNext == 0 ) ) ) {
|
&& ( sSpeedTable[ i ].fVelNext == 0 ) ) ) {
|
||||||
SemNextStopIndex = i;
|
SemNextStopIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (sSpeedTable[i].iFlags & spOutsideStation)
|
if (sSpeedTable[i].iFlags & spOutsideStation)
|
||||||
{ // jeśli W5, to reakcja zależna od trybu jazdy
|
{ // jeśli W5, to reakcja zależna od trybu jazdy
|
||||||
if (OrderCurrentGet() & Obey_train)
|
if (OrderCurrentGet() & Obey_train)
|
||||||
|
|||||||
4
Driver.h
4
Driver.h
@@ -119,8 +119,8 @@ enum TSpeedPosFlag
|
|||||||
spSemaphor = 0x4000, // semafor pociągowy
|
spSemaphor = 0x4000, // semafor pociągowy
|
||||||
spRoadVel = 0x8000, // zadanie prędkości drogowej
|
spRoadVel = 0x8000, // zadanie prędkości drogowej
|
||||||
spSectionVel = 0x20000, // odcinek z ograniczeniem
|
spSectionVel = 0x20000, // odcinek z ograniczeniem
|
||||||
spProximityVelocity = 0x40000, // odcinek z ograniczeniem i podaną jego długościa
|
spProximityVelocity = 0x40000 // odcinek z ograniczeniem i podaną jego długościa
|
||||||
spEndOfTable = 0x10000 // zatkanie tabelki
|
// spDontApplySpeedLimit = 0x10000 // this point won't apply its speed limit. potentially set by the scanning vehicle
|
||||||
};
|
};
|
||||||
|
|
||||||
class TSpeedPos
|
class TSpeedPos
|
||||||
|
|||||||
36
DynObj.cpp
36
DynObj.cpp
@@ -2012,7 +2012,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
|||||||
auto const indexstart { 1 };
|
auto const indexstart { 1 };
|
||||||
auto const indexend { ActPar.find_first_not_of( "1234567890", indexstart ) };
|
auto const indexend { ActPar.find_first_not_of( "1234567890", indexstart ) };
|
||||||
auto const huntingchance { std::atoi( ActPar.substr( indexstart, indexend ).c_str() ) };
|
auto const huntingchance { std::atoi( ActPar.substr( indexstart, indexend ).c_str() ) };
|
||||||
MoverParameters->TruckHunting = ( Random( 0, 100 ) <= huntingchance );
|
MoverParameters->TruckHunting = ( Random( 0, 100 ) < huntingchance );
|
||||||
ActPar.erase( 0, indexend );
|
ActPar.erase( 0, indexend );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2155,7 +2155,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
|||||||
btShutters1.Init( "shutters1", mdModel, false );
|
btShutters1.Init( "shutters1", mdModel, false );
|
||||||
}
|
}
|
||||||
if( MoverParameters->dizel_heat.water_aux.config.shutters ) {
|
if( MoverParameters->dizel_heat.water_aux.config.shutters ) {
|
||||||
btShutters1.Init( "shutters2", mdModel, false );
|
btShutters2.Init( "shutters2", mdModel, false );
|
||||||
}
|
}
|
||||||
TurnOff(); // resetowanie zmiennych submodeli
|
TurnOff(); // resetowanie zmiennych submodeli
|
||||||
|
|
||||||
@@ -2394,12 +2394,12 @@ void TDynamicObject::Move(double fDistance)
|
|||||||
// normalizacja potrzebna z powodu pochylenia (vFront)
|
// normalizacja potrzebna z powodu pochylenia (vFront)
|
||||||
vUp = CrossProduct(vFront, vLeft); // wektor w górę, będzie jednostkowy
|
vUp = CrossProduct(vFront, vLeft); // wektor w górę, będzie jednostkowy
|
||||||
modelRot.z = atan2(-vFront.x, vFront.z); // kąt obrotu pojazdu [rad]; z ABuBogies()
|
modelRot.z = atan2(-vFront.x, vFront.z); // kąt obrotu pojazdu [rad]; z ABuBogies()
|
||||||
double a = ((Axle1.GetRoll() + Axle0.GetRoll())); // suma przechyłek
|
auto const roll { Roll() }; // suma przechyłek
|
||||||
if (a != 0.0)
|
if (roll != 0.0)
|
||||||
{ // wyznaczanie przechylenia tylko jeśli jest przechyłka
|
{ // wyznaczanie przechylenia tylko jeśli jest przechyłka
|
||||||
// można by pobrać wektory normalne z toru...
|
// można by pobrać wektory normalne z toru...
|
||||||
mMatrix.Identity(); // ta macierz jest potrzebna głównie do wyświetlania
|
mMatrix.Identity(); // ta macierz jest potrzebna głównie do wyświetlania
|
||||||
mMatrix.Rotation(a * 0.5, vFront); // obrót wzdłuż osi o przechyłkę
|
mMatrix.Rotation(roll * 0.5, vFront); // obrót wzdłuż osi o przechyłkę
|
||||||
vUp = mMatrix * vUp; // wektor w górę pojazdu (przekręcenie na przechyłce)
|
vUp = mMatrix * vUp; // wektor w górę pojazdu (przekręcenie na przechyłce)
|
||||||
// vLeft=mMatrix*DynamicObject->vLeft;
|
// vLeft=mMatrix*DynamicObject->vLeft;
|
||||||
// vUp=CrossProduct(vFront,vLeft); //wektor w górę
|
// vUp=CrossProduct(vFront,vLeft); //wektor w górę
|
||||||
@@ -2836,7 +2836,7 @@ bool TDynamicObject::Update(double dt, double dt1)
|
|||||||
// TTrackParam tp;
|
// TTrackParam tp;
|
||||||
tp.Width = MyTrack->fTrackWidth;
|
tp.Width = MyTrack->fTrackWidth;
|
||||||
// McZapkie-250202
|
// McZapkie-250202
|
||||||
tp.friction = MyTrack->fFriction * Global.fFriction;
|
tp.friction = MyTrack->fFriction * Global.fFriction * Global.FrictionWeatherFactor;
|
||||||
tp.CategoryFlag = MyTrack->iCategoryFlag & 15;
|
tp.CategoryFlag = MyTrack->iCategoryFlag & 15;
|
||||||
tp.DamageFlag = MyTrack->iDamageFlag;
|
tp.DamageFlag = MyTrack->iDamageFlag;
|
||||||
tp.QualityFlag = MyTrack->iQualityFlag;
|
tp.QualityFlag = MyTrack->iQualityFlag;
|
||||||
@@ -3985,6 +3985,19 @@ void TDynamicObject::RenderSounds() {
|
|||||||
sSmallCompressor.stop();
|
sSmallCompressor.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// heater sound
|
||||||
|
if( ( true == MoverParameters->Heating )
|
||||||
|
&& ( std::abs( MoverParameters->enrot ) > 0.01 ) ) {
|
||||||
|
// TBD: check whether heating should depend on 'engine rotations' for electric vehicles
|
||||||
|
sHeater
|
||||||
|
.pitch( true == sHeater.is_combined() ?
|
||||||
|
std::abs( MoverParameters->enrot ) * 60.f * 0.01f :
|
||||||
|
1.f )
|
||||||
|
.play( sound_flags::exclusive | sound_flags::looping );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sHeater.stop();
|
||||||
|
}
|
||||||
|
|
||||||
// brake system and braking sounds:
|
// brake system and braking sounds:
|
||||||
|
|
||||||
@@ -4004,8 +4017,7 @@ void TDynamicObject::RenderSounds() {
|
|||||||
}
|
}
|
||||||
else if( quantizedratiochange < 0 ) {
|
else if( quantizedratiochange < 0 ) {
|
||||||
m_brakecylinderpistonrecede
|
m_brakecylinderpistonrecede
|
||||||
.pitch(
|
.pitch( true == m_brakecylinderpistonrecede.is_combined() ?
|
||||||
true == m_brakecylinderpistonrecede.is_combined() ?
|
|
||||||
quantizedratio * 0.01f :
|
quantizedratio * 0.01f :
|
||||||
m_brakecylinderpistonrecede.m_frequencyoffset + m_brakecylinderpistonrecede.m_frequencyfactor * 1.f )
|
m_brakecylinderpistonrecede.m_frequencyoffset + m_brakecylinderpistonrecede.m_frequencyfactor * 1.f )
|
||||||
.play();
|
.play();
|
||||||
@@ -5410,6 +5422,12 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
|||||||
sConverter.owner( this );
|
sConverter.owner( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if( token == "heater:" ) {
|
||||||
|
// train heating device
|
||||||
|
sHeater.deserialize( parser, sound_type::single );
|
||||||
|
sHeater.owner( this );
|
||||||
|
}
|
||||||
|
|
||||||
else if( token == "turbo:" ) {
|
else if( token == "turbo:" ) {
|
||||||
// pliki z turbogeneratorem
|
// pliki z turbogeneratorem
|
||||||
m_powertrainsounds.engine_turbo.deserialize( parser, sound_type::multipart, sound_parameters::range );
|
m_powertrainsounds.engine_turbo.deserialize( parser, sound_type::multipart, sound_parameters::range );
|
||||||
@@ -5844,7 +5862,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
|||||||
// other engine compartment sounds
|
// other engine compartment sounds
|
||||||
auto const nullvector { glm::vec3() };
|
auto const nullvector { glm::vec3() };
|
||||||
std::vector<sound_source *> enginesounds = {
|
std::vector<sound_source *> enginesounds = {
|
||||||
&sConverter, &sCompressor, &sSmallCompressor
|
&sConverter, &sCompressor, &sSmallCompressor, &sHeater
|
||||||
};
|
};
|
||||||
for( auto sound : enginesounds ) {
|
for( auto sound : enginesounds ) {
|
||||||
if( sound->offset() == nullvector ) {
|
if( sound->offset() == nullvector ) {
|
||||||
|
|||||||
3
DynObj.h
3
DynObj.h
@@ -412,6 +412,7 @@ private:
|
|||||||
sound_source sConverter { sound_placement::engine };
|
sound_source sConverter { sound_placement::engine };
|
||||||
sound_source sCompressor { sound_placement::engine }; // NBMX wrzesien 2003
|
sound_source sCompressor { sound_placement::engine }; // NBMX wrzesien 2003
|
||||||
sound_source sSmallCompressor { sound_placement::engine };
|
sound_source sSmallCompressor { sound_placement::engine };
|
||||||
|
sound_source sHeater { sound_placement::engine };
|
||||||
// braking sounds
|
// braking sounds
|
||||||
sound_source dsbPneumaticRelay { sound_placement::external };
|
sound_source dsbPneumaticRelay { sound_placement::external };
|
||||||
sound_source rsBrake { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab
|
sound_source rsBrake { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab
|
||||||
@@ -549,6 +550,8 @@ private:
|
|||||||
return iAxleFirst ?
|
return iAxleFirst ?
|
||||||
Axle1.pPosition :
|
Axle1.pPosition :
|
||||||
Axle0.pPosition; };
|
Axle0.pPosition; };
|
||||||
|
inline double Roll() {
|
||||||
|
return ( ( Axle1.GetRoll() + Axle0.GetRoll() ) ); }
|
||||||
/*
|
/*
|
||||||
// TODO: check if scanning takes into account direction when selecting axle
|
// TODO: check if scanning takes into account direction when selecting axle
|
||||||
// if it does, replace the version above
|
// if it does, replace the version above
|
||||||
|
|||||||
@@ -1018,7 +1018,9 @@ logvalues_event::export_as_text_( std::ostream &Output ) const {
|
|||||||
void
|
void
|
||||||
multi_event::init() {
|
multi_event::init() {
|
||||||
|
|
||||||
init_targets( simulation::Memory, "memory cell" );
|
auto const conditiontchecksmemcell { m_conditions.flags & ( flags::text | flags::value_1 | flags::value_2 ) };
|
||||||
|
// not all multi-events have memory cell checks, for the ones which don't we can keep quiet about it
|
||||||
|
init_targets( simulation::Memory, "memory cell", ( false == conditiontchecksmemcell ) );
|
||||||
if( m_ignored ) {
|
if( m_ignored ) {
|
||||||
// legacy compatibility behaviour, instead of disabling the event we disable the memory cell comparison test
|
// legacy compatibility behaviour, instead of disabling the event we disable the memory cell comparison test
|
||||||
m_conditions.flags &= ~( flags::text | flags::value_1 | flags::value_2 );
|
m_conditions.flags &= ~( flags::text | flags::value_1 | flags::value_2 );
|
||||||
|
|||||||
51
Gauge.cpp
51
Gauge.cpp
@@ -28,11 +28,11 @@ TGauge::TGauge( sound_source const &Soundtemplate ) :
|
|||||||
m_soundfxdecrease = m_soundtemplate;
|
m_soundfxdecrease = m_soundtemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TGauge::Init(TSubModel *Submodel, TGaugeType Type, float Scale, float Offset, float Friction, float Value, float const Endvalue, float const Endscale, bool const Interpolatescale )
|
void TGauge::Init(TSubModel *Submodel, TGaugeAnimation Type, float Scale, float Offset, float Friction, float Value, float const Endvalue, float const Endscale, bool const Interpolatescale )
|
||||||
{ // ustawienie parametrów animacji submodelu
|
{ // ustawienie parametrów animacji submodelu
|
||||||
SubModel = Submodel;
|
SubModel = Submodel;
|
||||||
m_value = Value;
|
m_value = Value;
|
||||||
m_type = Type;
|
m_animation = Type;
|
||||||
m_scale = Scale;
|
m_scale = Scale;
|
||||||
m_offset = Offset;
|
m_offset = Offset;
|
||||||
m_friction = Friction;
|
m_friction = Friction;
|
||||||
@@ -45,7 +45,7 @@ void TGauge::Init(TSubModel *Submodel, TGaugeType Type, float Scale, float Offse
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( m_type == TGaugeType::gt_Digital ) {
|
if( m_animation == TGaugeAnimation::gt_Digital ) {
|
||||||
|
|
||||||
TSubModel *sm = SubModel->ChildGet();
|
TSubModel *sm = SubModel->ChildGet();
|
||||||
do {
|
do {
|
||||||
@@ -147,19 +147,19 @@ bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1,
|
|||||||
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"", logtype::model );
|
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"", logtype::model );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, TGaugeType> gaugetypes {
|
std::map<std::string, TGaugeAnimation> gaugetypes {
|
||||||
{ "rot", TGaugeType::gt_Rotate },
|
{ "rot", TGaugeAnimation::gt_Rotate },
|
||||||
{ "rotvar", TGaugeType::gt_Rotate },
|
{ "rotvar", TGaugeAnimation::gt_Rotate },
|
||||||
{ "mov", TGaugeType::gt_Move },
|
{ "mov", TGaugeAnimation::gt_Move },
|
||||||
{ "movvar", TGaugeType::gt_Move },
|
{ "movvar", TGaugeAnimation::gt_Move },
|
||||||
{ "wip", TGaugeType::gt_Wiper },
|
{ "wip", TGaugeAnimation::gt_Wiper },
|
||||||
{ "dgt", TGaugeType::gt_Digital }
|
{ "dgt", TGaugeAnimation::gt_Digital }
|
||||||
};
|
};
|
||||||
auto lookup = gaugetypes.find( gaugetypename );
|
auto lookup = gaugetypes.find( gaugetypename );
|
||||||
auto const type = (
|
auto const type = (
|
||||||
lookup != gaugetypes.end() ?
|
lookup != gaugetypes.end() ?
|
||||||
lookup->second :
|
lookup->second :
|
||||||
TGaugeType::gt_Unknown );
|
TGaugeAnimation::gt_Unknown );
|
||||||
|
|
||||||
Init( submodel, type, scale, offset, friction, 0, endvalue, endscale, interpolatescale );
|
Init( submodel, type, scale, offset, friction, 0, endvalue, endscale, interpolatescale );
|
||||||
|
|
||||||
@@ -170,10 +170,17 @@ bool
|
|||||||
TGauge::Load_mapping( cParser &Input ) {
|
TGauge::Load_mapping( cParser &Input ) {
|
||||||
|
|
||||||
// token can be a key or block end
|
// token can be a key or block end
|
||||||
std::string const key { Input.getToken<std::string>( true, "\n\r\t ,;" ) };
|
auto const key { Input.getToken<std::string>( true, "\n\r\t ,;" ) };
|
||||||
if( ( true == key.empty() ) || ( key == "}" ) ) { return false; }
|
if( ( true == key.empty() ) || ( key == "}" ) ) { return false; }
|
||||||
// if not block end then the key is followed by assigned value or sub-block
|
// if not block end then the key is followed by assigned value or sub-block
|
||||||
if( key == "soundinc:" ) {
|
if( key == "type:" ) {
|
||||||
|
auto const gaugetype { Input.getToken<std::string>( true, "\n\r\t ,;" ) };
|
||||||
|
m_type = (
|
||||||
|
gaugetype == "impulse" ? TGaugeType::push :
|
||||||
|
gaugetype == "return" ? TGaugeType::push :
|
||||||
|
TGaugeType::toggle ); // default
|
||||||
|
}
|
||||||
|
else if( key == "soundinc:" ) {
|
||||||
m_soundfxincrease.deserialize( Input, sound_type::single );
|
m_soundfxincrease.deserialize( Input, sound_type::single );
|
||||||
}
|
}
|
||||||
else if( key == "sounddec:" ) {
|
else if( key == "sounddec:" ) {
|
||||||
@@ -209,7 +216,7 @@ void
|
|||||||
TGauge::UpdateValue( float fNewDesired, sound_source *Fallbacksound ) {
|
TGauge::UpdateValue( float fNewDesired, sound_source *Fallbacksound ) {
|
||||||
|
|
||||||
auto const desiredtimes100 = static_cast<int>( std::round( 100.0 * fNewDesired ) );
|
auto const desiredtimes100 = static_cast<int>( std::round( 100.0 * fNewDesired ) );
|
||||||
if( desiredtimes100 == static_cast<int>( 100.0 * m_targetvalue ) ) {
|
if( desiredtimes100 == static_cast<int>( std::round( 100.0 * m_targetvalue ) ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_targetvalue = fNewDesired;
|
m_targetvalue = fNewDesired;
|
||||||
@@ -281,16 +288,16 @@ void TGauge::Update() {
|
|||||||
}
|
}
|
||||||
if( SubModel )
|
if( SubModel )
|
||||||
{ // warunek na wszelki wypadek, gdyby się submodel nie podłączył
|
{ // warunek na wszelki wypadek, gdyby się submodel nie podłączył
|
||||||
switch (m_type) {
|
switch (m_animation) {
|
||||||
case TGaugeType::gt_Rotate: {
|
case TGaugeAnimation::gt_Rotate: {
|
||||||
SubModel->SetRotate( float3( 0, 1, 0 ), GetScaledValue() * 360.0 );
|
SubModel->SetRotate( float3( 0, 1, 0 ), GetScaledValue() * 360.0 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TGaugeType::gt_Move: {
|
case TGaugeAnimation::gt_Move: {
|
||||||
SubModel->SetTranslate( float3( 0, 0, GetScaledValue() ) );
|
SubModel->SetTranslate( float3( 0, 0, GetScaledValue() ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TGaugeType::gt_Wiper: {
|
case TGaugeAnimation::gt_Wiper: {
|
||||||
auto const scaledvalue { GetScaledValue() };
|
auto const scaledvalue { GetScaledValue() };
|
||||||
SubModel->SetRotate( float3( 0, 1, 0 ), scaledvalue * 360.0 );
|
SubModel->SetRotate( float3( 0, 1, 0 ), scaledvalue * 360.0 );
|
||||||
auto *sm = SubModel->ChildGet();
|
auto *sm = SubModel->ChildGet();
|
||||||
@@ -302,7 +309,7 @@ void TGauge::Update() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TGaugeType::gt_Digital: {
|
case TGaugeAnimation::gt_Digital: {
|
||||||
// Ra 2014-07: licznik cyfrowy
|
// Ra 2014-07: licznik cyfrowy
|
||||||
auto *sm = SubModel->ChildGet();
|
auto *sm = SubModel->ChildGet();
|
||||||
/* std::string n = FormatFloat( "0000000000", floor( fValue ) ); // na razie tak trochę bez sensu
|
/* std::string n = FormatFloat( "0000000000", floor( fValue ) ); // na razie tak trochę bez sensu
|
||||||
@@ -389,3 +396,9 @@ TGauge::model_offset() const {
|
|||||||
SubModel->offset( 1.f ) :
|
SubModel->offset( 1.f ) :
|
||||||
glm::vec3() );
|
glm::vec3() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TGaugeType
|
||||||
|
TGauge::type() const {
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
13
Gauge.h
13
Gauge.h
@@ -12,7 +12,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "Classes.h"
|
#include "Classes.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
|
|
||||||
enum class TGaugeType {
|
enum class TGaugeAnimation {
|
||||||
// typ ruchu
|
// typ ruchu
|
||||||
gt_Unknown, // na razie nie znany
|
gt_Unknown, // na razie nie znany
|
||||||
gt_Rotate, // obrót
|
gt_Rotate, // obrót
|
||||||
@@ -21,6 +21,11 @@ enum class TGaugeType {
|
|||||||
gt_Digital // licznik cyfrowy, np. kilometrów
|
gt_Digital // licznik cyfrowy, np. kilometrów
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class TGaugeType {
|
||||||
|
toggle,
|
||||||
|
push
|
||||||
|
};
|
||||||
|
|
||||||
// animowany wskaźnik, mogący przyjmować wiele stanów pośrednich
|
// animowany wskaźnik, mogący przyjmować wiele stanów pośrednich
|
||||||
class TGauge {
|
class TGauge {
|
||||||
|
|
||||||
@@ -32,7 +37,7 @@ public:
|
|||||||
inline
|
inline
|
||||||
void Clear() {
|
void Clear() {
|
||||||
*this = TGauge(); }
|
*this = TGauge(); }
|
||||||
void Init(TSubModel *Submodel, TGaugeType Type, float Scale = 1, float Offset = 0, float Friction = 0, float Value = 0, float const Endvalue = -1.0, float const Endscale = -1.0, bool const Interpolate = false );
|
void Init(TSubModel *Submodel, TGaugeAnimation Type, float Scale = 1, float Offset = 0, float Friction = 0, float Value = 0, float const Endvalue = -1.0, float const Endscale = -1.0, bool const Interpolate = false );
|
||||||
bool Load(cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, TModel3d *md2 = nullptr, double mul = 1.0);
|
bool Load(cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, TModel3d *md2 = nullptr, double mul = 1.0);
|
||||||
void UpdateValue( float fNewDesired );
|
void UpdateValue( float fNewDesired );
|
||||||
void UpdateValue( float fNewDesired, sound_source &Fallbacksound );
|
void UpdateValue( float fNewDesired, sound_source &Fallbacksound );
|
||||||
@@ -46,6 +51,7 @@ public:
|
|||||||
void UpdateValue();
|
void UpdateValue();
|
||||||
// returns offset of submodel associated with the button from the model centre
|
// returns offset of submodel associated with the button from the model centre
|
||||||
glm::vec3 model_offset() const;
|
glm::vec3 model_offset() const;
|
||||||
|
TGaugeType type() const;
|
||||||
// members
|
// members
|
||||||
TSubModel *SubModel { nullptr }; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie
|
TSubModel *SubModel { nullptr }; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie
|
||||||
|
|
||||||
@@ -60,7 +66,8 @@ private:
|
|||||||
GetScaledValue() const;
|
GetScaledValue() const;
|
||||||
|
|
||||||
// members
|
// members
|
||||||
TGaugeType m_type { TGaugeType::gt_Unknown }; // typ ruchu
|
TGaugeAnimation m_animation { TGaugeAnimation::gt_Unknown }; // typ ruchu
|
||||||
|
TGaugeType m_type { TGaugeType::toggle }; // switch type
|
||||||
float m_friction { 0.f }; // hamowanie przy zliżaniu się do zadanej wartości
|
float m_friction { 0.f }; // hamowanie przy zliżaniu się do zadanej wartości
|
||||||
float m_targetvalue { 0.f }; // wartość docelowa
|
float m_targetvalue { 0.f }; // wartość docelowa
|
||||||
float m_value { 0.f }; // wartość obecna
|
float m_value { 0.f }; // wartość obecna
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ struct global_settings {
|
|||||||
bool RealisticControlMode{ false }; // controls ability to steer the vehicle from outside views
|
bool RealisticControlMode{ false }; // controls ability to steer the vehicle from outside views
|
||||||
bool bEnableTraction{ true };
|
bool bEnableTraction{ true };
|
||||||
float fFriction{ 1.f }; // mnożnik tarcia - KURS90
|
float fFriction{ 1.f }; // mnożnik tarcia - KURS90
|
||||||
|
float FrictionWeatherFactor { 1.f };
|
||||||
bool bLiveTraction{ true };
|
bool bLiveTraction{ true };
|
||||||
float Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
|
float Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
|
||||||
glm::vec3 FogColor = { 0.6f, 0.7f, 0.8f };
|
glm::vec3 FogColor = { 0.6f, 0.7f, 0.8f };
|
||||||
|
|||||||
@@ -624,6 +624,7 @@ struct TCoupling {
|
|||||||
struct fuel_pump {
|
struct fuel_pump {
|
||||||
|
|
||||||
bool is_enabled { false }; // device is allowed/requested to operate
|
bool is_enabled { false }; // device is allowed/requested to operate
|
||||||
|
bool is_disabled { false }; // device is requested to stop
|
||||||
bool is_active { false }; // device is working
|
bool is_active { false }; // device is working
|
||||||
start_t start_type { start_t::manual };
|
start_t start_type { start_t::manual };
|
||||||
};
|
};
|
||||||
@@ -633,6 +634,7 @@ struct fuel_pump {
|
|||||||
struct oil_pump {
|
struct oil_pump {
|
||||||
|
|
||||||
bool is_enabled { false }; // device is allowed/requested to operate
|
bool is_enabled { false }; // device is allowed/requested to operate
|
||||||
|
bool is_disabled { false }; // device is requested to stop
|
||||||
bool is_active { false }; // device is working
|
bool is_active { false }; // device is working
|
||||||
start_t start_type { start_t::manual };
|
start_t start_type { start_t::manual };
|
||||||
float resource_amount { 1.f };
|
float resource_amount { 1.f };
|
||||||
@@ -646,6 +648,7 @@ struct water_pump {
|
|||||||
|
|
||||||
bool breaker { true }; // device is allowed to operate
|
bool breaker { true }; // device is allowed to operate
|
||||||
bool is_enabled { false }; // device is requested to operate
|
bool is_enabled { false }; // device is requested to operate
|
||||||
|
bool is_disabled { false }; // device is requested to stop
|
||||||
bool is_active { false }; // device is working
|
bool is_active { false }; // device is working
|
||||||
start_t start_type { start_t::manual };
|
start_t start_type { start_t::manual };
|
||||||
};
|
};
|
||||||
@@ -1332,11 +1335,14 @@ public:
|
|||||||
bool DirectionBackward(void);/*! kierunek ruchu*/
|
bool DirectionBackward(void);/*! kierunek ruchu*/
|
||||||
bool WaterPumpBreakerSwitch( bool State, range_t const Notify = range_t::consist ); // water pump breaker state toggle
|
bool WaterPumpBreakerSwitch( bool State, range_t const Notify = range_t::consist ); // water pump breaker state toggle
|
||||||
bool WaterPumpSwitch( bool State, range_t const Notify = range_t::consist ); // water pump state toggle
|
bool WaterPumpSwitch( bool State, range_t const Notify = range_t::consist ); // water pump state toggle
|
||||||
|
bool WaterPumpSwitchOff( bool State, range_t const Notify = range_t::consist ); // water pump state toggle
|
||||||
bool WaterHeaterBreakerSwitch( bool State, range_t const Notify = range_t::consist ); // water heater breaker state toggle
|
bool WaterHeaterBreakerSwitch( bool State, range_t const Notify = range_t::consist ); // water heater breaker state toggle
|
||||||
bool WaterHeaterSwitch( bool State, range_t const Notify = range_t::consist ); // water heater state toggle
|
bool WaterHeaterSwitch( bool State, range_t const Notify = range_t::consist ); // water heater state toggle
|
||||||
bool WaterCircuitsLinkSwitch( bool State, range_t const Notify = range_t::consist ); // water circuits link state toggle
|
bool WaterCircuitsLinkSwitch( bool State, range_t const Notify = range_t::consist ); // water circuits link state toggle
|
||||||
bool FuelPumpSwitch( bool State, range_t const Notify = range_t::consist ); // fuel pump state toggle
|
bool FuelPumpSwitch( bool State, range_t const Notify = range_t::consist ); // fuel pump state toggle
|
||||||
|
bool FuelPumpSwitchOff( bool State, range_t const Notify = range_t::consist ); // fuel pump state toggle
|
||||||
bool OilPumpSwitch( bool State, range_t const Notify = range_t::consist ); // oil pump state toggle
|
bool OilPumpSwitch( bool State, range_t const Notify = range_t::consist ); // oil pump state toggle
|
||||||
|
bool OilPumpSwitchOff( bool State, range_t const Notify = range_t::consist ); // oil pump state toggle
|
||||||
bool MainSwitch( bool const State, range_t const Notify = range_t::consist );/*! wylacznik glowny*/
|
bool MainSwitch( bool const State, range_t const Notify = range_t::consist );/*! wylacznik glowny*/
|
||||||
bool ConverterSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl przetwornicy*/
|
bool ConverterSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl przetwornicy*/
|
||||||
bool CompressorSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl sprezarki*/
|
bool CompressorSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl sprezarki*/
|
||||||
@@ -1366,7 +1372,8 @@ public:
|
|||||||
bool MaxCurrentSwitch(bool State); //przelacznik pradu wysokiego rozruchu
|
bool MaxCurrentSwitch(bool State); //przelacznik pradu wysokiego rozruchu
|
||||||
bool MinCurrentSwitch(bool State); //przelacznik pradu automatycznego rozruchu
|
bool MinCurrentSwitch(bool State); //przelacznik pradu automatycznego rozruchu
|
||||||
bool AutoRelaySwitch(bool State); //przelacznik automatycznego rozruchu
|
bool AutoRelaySwitch(bool State); //przelacznik automatycznego rozruchu
|
||||||
bool AutoRelayCheck(void);//symulacja automatycznego rozruchu
|
bool AutoRelayCheck();//symulacja automatycznego rozruchu
|
||||||
|
bool MotorConnectorsCheck();
|
||||||
|
|
||||||
bool ResistorsFlagCheck(void) const; //sprawdzenie kontrolki oporow rozruchowych NBMX
|
bool ResistorsFlagCheck(void) const; //sprawdzenie kontrolki oporow rozruchowych NBMX
|
||||||
bool PantFront( bool const State, range_t const Notify = range_t::consist ); //obsluga pantografou przedniego
|
bool PantFront( bool const State, range_t const Notify = range_t::consist ); //obsluga pantografou przedniego
|
||||||
@@ -1441,4 +1448,4 @@ private:
|
|||||||
void BrakeSubsystemDecode(); //Q 20160719
|
void BrakeSubsystemDecode(); //Q 20160719
|
||||||
};
|
};
|
||||||
|
|
||||||
extern double Distance(TLocation Loc1, TLocation Loc2, TDimension Dim1, TDimension Dim2);
|
//double Distance(TLocation Loc1, TLocation Loc2, TDimension Dim1, TDimension Dim2);
|
||||||
|
|||||||
@@ -142,22 +142,6 @@ double TMoverParameters::Current(double n, double U)
|
|||||||
Mn = RList[ MainCtrlActualPos ].Mn * RList[ MainCtrlActualPos ].Bn;
|
Mn = RList[ MainCtrlActualPos ].Mn * RList[ MainCtrlActualPos ].Bn;
|
||||||
}
|
}
|
||||||
|
|
||||||
// writepaslog("#",
|
|
||||||
// "C++-----------------------------------------------------------------------------");
|
|
||||||
// writepaslog("MCAP ", IntToStr(MainCtrlActualPos));
|
|
||||||
// writepaslog("SCAP ", IntToStr(ScndCtrlActualPos));
|
|
||||||
// writepaslog("n ", FloatToStr(n));
|
|
||||||
// writepaslog("StLinFlag ", BoolToYN(StLinFlag));
|
|
||||||
// writepaslog("DelayCtrlFlag ", booltoYN(DelayCtrlFlag));
|
|
||||||
// writepaslog("Bn ", FloatToStr(Bn));
|
|
||||||
// writepaslog("R ", FloatToStr(R));
|
|
||||||
// writepaslog("Mn ", IntToStr(Mn));
|
|
||||||
// writepaslog("RList[MCAP].Bn ", FloatToStr(RList[MainCtrlActualPos].Bn));
|
|
||||||
// writepaslog("RList[MCAP].Mn ", FloatToStr(RList[MainCtrlActualPos].Mn));
|
|
||||||
// writepaslog("RList[MCAP].R ", FloatToStr(RList[MainCtrlActualPos].R));
|
|
||||||
|
|
||||||
// z Megapacka ... bylo tutaj zakomentowane Q: no to usuwam...
|
|
||||||
|
|
||||||
if (DynamicBrakeFlag && (!FuseFlag) && (DynamicBrakeType == dbrake_automatic) &&
|
if (DynamicBrakeFlag && (!FuseFlag) && (DynamicBrakeType == dbrake_automatic) &&
|
||||||
ConverterFlag && Mains) // hamowanie EP09 //TUHEX
|
ConverterFlag && Mains) // hamowanie EP09 //TUHEX
|
||||||
{
|
{
|
||||||
@@ -1298,7 +1282,7 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
|
|||||||
if (SetFlag(DamageFlag, dtrain_out))
|
if (SetFlag(DamageFlag, dtrain_out))
|
||||||
{
|
{
|
||||||
EventFlag = true;
|
EventFlag = true;
|
||||||
Mains = false;
|
MainSwitch( false, range_t::local );
|
||||||
RunningShape.R = 0;
|
RunningShape.R = 0;
|
||||||
if (TestFlag(Track.DamageFlag, dtrack_norail))
|
if (TestFlag(Track.DamageFlag, dtrack_norail))
|
||||||
DerailReason = 1; // Ra: powód wykolejenia: brak szyn
|
DerailReason = 1; // Ra: powód wykolejenia: brak szyn
|
||||||
@@ -1310,7 +1294,7 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
|
|||||||
if (SetFlag(DamageFlag, dtrain_out))
|
if (SetFlag(DamageFlag, dtrain_out))
|
||||||
{
|
{
|
||||||
EventFlag = true;
|
EventFlag = true;
|
||||||
Mains = false;
|
MainSwitch( false, range_t::local );
|
||||||
RunningShape.R = 0;
|
RunningShape.R = 0;
|
||||||
DerailReason = 3; // Ra: powód wykolejenia: za szeroki tor
|
DerailReason = 3; // Ra: powód wykolejenia: za szeroki tor
|
||||||
}
|
}
|
||||||
@@ -1320,7 +1304,7 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
|
|||||||
if (SetFlag(DamageFlag, dtrain_out))
|
if (SetFlag(DamageFlag, dtrain_out))
|
||||||
{
|
{
|
||||||
EventFlag = true;
|
EventFlag = true;
|
||||||
Mains = false;
|
MainSwitch( false, range_t::local );
|
||||||
DerailReason = 4; // Ra: powód wykolejenia: nieodpowiednia trajektoria
|
DerailReason = 4; // Ra: powód wykolejenia: nieodpowiednia trajektoria
|
||||||
}
|
}
|
||||||
if( ( true == TestFlag( DamageFlag, dtrain_out ) )
|
if( ( true == TestFlag( DamageFlag, dtrain_out ) )
|
||||||
@@ -1540,7 +1524,9 @@ void TMoverParameters::WaterPumpCheck( double const Timestep ) {
|
|||||||
WaterPump.is_active = (
|
WaterPump.is_active = (
|
||||||
( true == Battery )
|
( true == Battery )
|
||||||
&& ( true == WaterPump.breaker )
|
&& ( true == WaterPump.breaker )
|
||||||
&& ( ( true == WaterPump.is_enabled ) || ( WaterPump.start_type == start_t::battery ) ) );
|
&& ( false == WaterPump.is_disabled )
|
||||||
|
&& ( ( true == WaterPump.is_active )
|
||||||
|
|| ( true == WaterPump.is_enabled ) || ( WaterPump.start_type == start_t::battery ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// water heater status check
|
// water heater status check
|
||||||
@@ -1569,10 +1555,12 @@ void TMoverParameters::FuelPumpCheck( double const Timestep ) {
|
|||||||
|
|
||||||
FuelPump.is_active = (
|
FuelPump.is_active = (
|
||||||
( true == Battery )
|
( true == Battery )
|
||||||
&& ( FuelPump.start_type == start_t::manual ? ( FuelPump.is_enabled ) :
|
&& ( false == FuelPump.is_disabled )
|
||||||
|
&& ( ( FuelPump.is_active )
|
||||||
|
|| ( FuelPump.start_type == start_t::manual ? ( FuelPump.is_enabled ) :
|
||||||
FuelPump.start_type == start_t::automatic ? ( dizel_startup || Mains ) :
|
FuelPump.start_type == start_t::automatic ? ( dizel_startup || Mains ) :
|
||||||
FuelPump.start_type == start_t::manualwithautofallback ? ( FuelPump.is_enabled || dizel_startup || Mains ) :
|
FuelPump.start_type == start_t::manualwithautofallback ? ( FuelPump.is_enabled || dizel_startup || Mains ) :
|
||||||
false ) ); // shouldn't ever get this far but, eh
|
false ) ) ); // shouldn't ever get this far but, eh
|
||||||
}
|
}
|
||||||
|
|
||||||
// oil pump status update
|
// oil pump status update
|
||||||
@@ -1580,10 +1568,13 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) {
|
|||||||
|
|
||||||
OilPump.is_active = (
|
OilPump.is_active = (
|
||||||
( true == Battery )
|
( true == Battery )
|
||||||
&& ( OilPump.start_type == start_t::manual ? ( OilPump.is_enabled ) :
|
&& ( false == Mains )
|
||||||
OilPump.start_type == start_t::automatic ? ( dizel_startup || Mains ) :
|
&& ( false == OilPump.is_disabled )
|
||||||
OilPump.start_type == start_t::manualwithautofallback ? ( OilPump.is_enabled || dizel_startup || Mains ) :
|
&& ( ( OilPump.is_active )
|
||||||
false ) ); // shouldn't ever get this far but, eh
|
|| ( OilPump.start_type == start_t::manual ? ( OilPump.is_enabled ) :
|
||||||
|
OilPump.start_type == start_t::automatic ? ( dizel_startup ) :
|
||||||
|
OilPump.start_type == start_t::manualwithautofallback ? ( OilPump.is_enabled || dizel_startup ) :
|
||||||
|
false ) ) ); // shouldn't ever get this far but, eh
|
||||||
|
|
||||||
auto const maxrevolutions {
|
auto const maxrevolutions {
|
||||||
EngineType == TEngineType::DieselEngine ?
|
EngineType == TEngineType::DieselEngine ?
|
||||||
@@ -2417,6 +2408,31 @@ bool TMoverParameters::WaterPumpSwitch( bool State, range_t const Notify ) {
|
|||||||
return ( WaterPump.is_enabled != initialstate );
|
return ( WaterPump.is_enabled != initialstate );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// water pump state toggle
|
||||||
|
bool TMoverParameters::WaterPumpSwitchOff( bool State, range_t const Notify ) {
|
||||||
|
|
||||||
|
if( WaterPump.start_type == start_t::battery ) {
|
||||||
|
// automatic fuel pump ignores 'manual' state commands
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool const initialstate { WaterPump.is_disabled };
|
||||||
|
|
||||||
|
WaterPump.is_disabled = State;
|
||||||
|
|
||||||
|
if( Notify != range_t::local ) {
|
||||||
|
SendCtrlToNext(
|
||||||
|
"WaterPumpSwitchOff",
|
||||||
|
( WaterPump.is_disabled ? 1 : 0 ),
|
||||||
|
CabNo,
|
||||||
|
( Notify == range_t::unit ?
|
||||||
|
coupling::control | coupling::permanent :
|
||||||
|
coupling::control ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( WaterPump.is_disabled != initialstate );
|
||||||
|
}
|
||||||
|
|
||||||
// water heater breaker state toggle
|
// water heater breaker state toggle
|
||||||
bool TMoverParameters::WaterHeaterBreakerSwitch( bool State, range_t const Notify ) {
|
bool TMoverParameters::WaterHeaterBreakerSwitch( bool State, range_t const Notify ) {
|
||||||
/*
|
/*
|
||||||
@@ -2517,6 +2533,30 @@ bool TMoverParameters::FuelPumpSwitch( bool State, range_t const Notify ) {
|
|||||||
return ( FuelPump.is_enabled != initialstate );
|
return ( FuelPump.is_enabled != initialstate );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TMoverParameters::FuelPumpSwitchOff( bool State, range_t const Notify ) {
|
||||||
|
|
||||||
|
if( FuelPump.start_type == start_t::automatic ) {
|
||||||
|
// automatic fuel pump ignores 'manual' state commands
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool const initialstate { FuelPump.is_disabled };
|
||||||
|
|
||||||
|
FuelPump.is_disabled = State;
|
||||||
|
|
||||||
|
if( Notify != range_t::local ) {
|
||||||
|
SendCtrlToNext(
|
||||||
|
"FuelPumpSwitchOff",
|
||||||
|
( FuelPump.is_disabled ? 1 : 0 ),
|
||||||
|
CabNo,
|
||||||
|
( Notify == range_t::unit ?
|
||||||
|
coupling::control | coupling::permanent :
|
||||||
|
coupling::control ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( FuelPump.is_disabled != initialstate );
|
||||||
|
}
|
||||||
|
|
||||||
// oil pump state toggle
|
// oil pump state toggle
|
||||||
bool TMoverParameters::OilPumpSwitch( bool State, range_t const Notify ) {
|
bool TMoverParameters::OilPumpSwitch( bool State, range_t const Notify ) {
|
||||||
|
|
||||||
@@ -2542,6 +2582,30 @@ bool TMoverParameters::OilPumpSwitch( bool State, range_t const Notify ) {
|
|||||||
return ( OilPump.is_enabled != initialstate );
|
return ( OilPump.is_enabled != initialstate );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TMoverParameters::OilPumpSwitchOff( bool State, range_t const Notify ) {
|
||||||
|
|
||||||
|
if( OilPump.start_type == start_t::automatic ) {
|
||||||
|
// automatic pump ignores 'manual' state commands
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool const initialstate { OilPump.is_disabled };
|
||||||
|
|
||||||
|
OilPump.is_disabled = State;
|
||||||
|
|
||||||
|
if( Notify != range_t::local ) {
|
||||||
|
SendCtrlToNext(
|
||||||
|
"OilPumpSwitchOff",
|
||||||
|
( OilPump.is_disabled ? 1 : 0 ),
|
||||||
|
CabNo,
|
||||||
|
( Notify == range_t::unit ?
|
||||||
|
coupling::control | coupling::permanent :
|
||||||
|
coupling::control ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( OilPump.is_disabled != initialstate );
|
||||||
|
}
|
||||||
|
|
||||||
// *************************************************************************************************
|
// *************************************************************************************************
|
||||||
// Q: 20160713
|
// Q: 20160713
|
||||||
// włączenie / wyłączenie obwodu głownego
|
// włączenie / wyłączenie obwodu głownego
|
||||||
@@ -2575,6 +2639,9 @@ bool TMoverParameters::MainSwitch( bool const State, range_t const Notify )
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Mains = false;
|
Mains = false;
|
||||||
|
// potentially knock out the pumps if their switch doesn't force them on
|
||||||
|
WaterPump.is_active &= WaterPump.is_enabled;
|
||||||
|
FuelPump.is_active &= FuelPump.is_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ( TrainType == dt_EZT )
|
if( ( TrainType == dt_EZT )
|
||||||
@@ -4447,6 +4514,13 @@ double TMoverParameters::TractionForce( double dt ) {
|
|||||||
&& ( MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) ) ) ); // TODO: check whether we need to send this EMU-wide
|
&& ( MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) ) ) ); // TODO: check whether we need to send this EMU-wide
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case TEngineType::DieselElectric: {
|
||||||
|
// TODO: move this to the auto relay check when the electric engine code paths are unified
|
||||||
|
StLinFlag = MotorConnectorsCheck();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -4689,7 +4763,7 @@ double TMoverParameters::TractionForce( double dt ) {
|
|||||||
Voltage = 0;
|
Voltage = 0;
|
||||||
|
|
||||||
// przekazniki bocznikowania, kazdy inny dla kazdej pozycji
|
// przekazniki bocznikowania, kazdy inny dla kazdej pozycji
|
||||||
if ((MainCtrlPos == 0) || (ShuntMode))
|
if ((MainCtrlPos == 0) || (ShuntMode) || (false==Mains))
|
||||||
ScndCtrlPos = 0;
|
ScndCtrlPos = 0;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
@@ -5391,19 +5465,14 @@ bool TMoverParameters::AutoRelayCheck(void)
|
|||||||
bool OK = false; // b:int;
|
bool OK = false; // b:int;
|
||||||
bool ARC = false;
|
bool ARC = false;
|
||||||
|
|
||||||
|
auto const motorconnectors { MotorConnectorsCheck() };
|
||||||
|
|
||||||
// Ra 2014-06: dla SN61 nie działa prawidłowo
|
// Ra 2014-06: dla SN61 nie działa prawidłowo
|
||||||
// rozlaczanie stycznikow liniowych
|
// yBARC - rozlaczenie stycznikow liniowych
|
||||||
if( ( false == Mains )
|
if( false == motorconnectors ) {
|
||||||
|| ( true == FuseFlag )
|
StLinFlag = false;
|
||||||
|| ( true == StLinSwitchOff )
|
|
||||||
|| ( MainCtrlPos == 0 )
|
|
||||||
|| ( ( TrainType != dt_EZT ) && ( BrakePress > 2.1 ) )
|
|
||||||
|| ( ActiveDir == 0 ) ) // hunter-111211: wylacznik cisnieniowy
|
|
||||||
{
|
|
||||||
StLinFlag = false; // yBARC - rozlaczenie stycznikow liniowych
|
|
||||||
OK = false;
|
OK = false;
|
||||||
if (!DynamicBrakeFlag)
|
if( false == DynamicBrakeFlag ) {
|
||||||
{
|
|
||||||
Im = 0;
|
Im = 0;
|
||||||
Itot = 0;
|
Itot = 0;
|
||||||
ResistorsFlag = false;
|
ResistorsFlag = false;
|
||||||
@@ -5578,17 +5647,11 @@ bool TMoverParameters::AutoRelayCheck(void)
|
|||||||
else // not StLinFlag
|
else // not StLinFlag
|
||||||
{
|
{
|
||||||
OK = false;
|
OK = false;
|
||||||
// ybARC - tutaj sa wszystkie warunki, jakie musza byc spelnione, zeby mozna byla
|
// ybARC - zalaczenie stycznikow liniowych
|
||||||
// zalaczyc styczniki liniowe
|
if( true == motorconnectors ) {
|
||||||
if (((MainCtrlPos == 1) || ((TrainType == dt_EZT) && (MainCtrlPos > 0))) &&
|
|
||||||
(!FuseFlag) && (Mains) && ((BrakePress < 1.0) || (TrainType == dt_EZT)) &&
|
|
||||||
(MainCtrlActualPos == 0) && (ActiveDir != 0))
|
|
||||||
{ //^^ TODO: sprawdzic BUG, prawdopodobnie w CreateBrakeSys()
|
|
||||||
DelayCtrlFlag = true;
|
DelayCtrlFlag = true;
|
||||||
if( (LastRelayTime >= InitialCtrlDelay)
|
if( LastRelayTime >= InitialCtrlDelay ) {
|
||||||
&& ( false == StLinSwitchOff ) )
|
StLinFlag = true;
|
||||||
{
|
|
||||||
StLinFlag = true; // ybARC - zalaczenie stycznikow liniowych
|
|
||||||
MainCtrlActualPos = 1;
|
MainCtrlActualPos = 1;
|
||||||
DelayCtrlFlag = false;
|
DelayCtrlFlag = false;
|
||||||
SetFlag(SoundFlag, sound::relay | sound::loud);
|
SetFlag(SoundFlag, sound::relay | sound::loud);
|
||||||
@@ -5661,6 +5724,34 @@ bool TMoverParameters::AutoRelayCheck(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TMoverParameters::MotorConnectorsCheck() {
|
||||||
|
|
||||||
|
// hunter-111211: wylacznik cisnieniowy
|
||||||
|
auto const pressureswitch {
|
||||||
|
( TrainType != dt_EZT )
|
||||||
|
&& ( ( BrakePress > 2.0 )
|
||||||
|
|| ( PipePress < 3.6 ) ) };
|
||||||
|
|
||||||
|
if( pressureswitch ) { return false; }
|
||||||
|
|
||||||
|
auto const connectorsoff {
|
||||||
|
( false == Mains )
|
||||||
|
|| ( true == FuseFlag )
|
||||||
|
|| ( true == StLinSwitchOff )
|
||||||
|
|| ( MainCtrlPos == 0 )
|
||||||
|
|| ( ActiveDir == 0 ) };
|
||||||
|
|
||||||
|
if( connectorsoff ) { return false; }
|
||||||
|
|
||||||
|
auto const connectorson {
|
||||||
|
( true == StLinFlag )
|
||||||
|
|| ( ( MainCtrlActualPos == 0 )
|
||||||
|
&& ( ( MainCtrlPos == 1 )
|
||||||
|
|| ( ( TrainType == dt_EZT ) && ( MainCtrlPos > 0 ) ) ) ) };
|
||||||
|
|
||||||
|
return connectorson;
|
||||||
|
}
|
||||||
|
|
||||||
// *************************************************************************************************
|
// *************************************************************************************************
|
||||||
// Q: 20160713
|
// Q: 20160713
|
||||||
// Podnosi / opuszcza przedni pantograf. Returns: state of the pantograph after the operation
|
// Podnosi / opuszcza przedni pantograf. Returns: state of the pantograph after the operation
|
||||||
@@ -9136,6 +9227,14 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
|||||||
}
|
}
|
||||||
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||||
}
|
}
|
||||||
|
else if( Command == "WaterPumpSwitchOff" ) {
|
||||||
|
|
||||||
|
if( WaterPump.start_type != start_t::battery ) {
|
||||||
|
// automatic fuel pump ignores 'manual' state commands
|
||||||
|
WaterPump.is_disabled = ( CValue1 == 1 );
|
||||||
|
}
|
||||||
|
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||||
|
}
|
||||||
else if( Command == "WaterHeaterBreakerSwitch" ) {
|
else if( Command == "WaterHeaterBreakerSwitch" ) {
|
||||||
/*
|
/*
|
||||||
if( FuelPump.start_type != start::automatic ) {
|
if( FuelPump.start_type != start::automatic ) {
|
||||||
@@ -9172,6 +9271,13 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
|||||||
}
|
}
|
||||||
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||||
}
|
}
|
||||||
|
else if (Command == "FuelPumpSwitchOff") {
|
||||||
|
if( FuelPump.start_type != start_t::automatic ) {
|
||||||
|
// automatic fuel pump ignores 'manual' state commands
|
||||||
|
FuelPump.is_disabled = ( CValue1 == 1 );
|
||||||
|
}
|
||||||
|
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||||
|
}
|
||||||
else if (Command == "OilPumpSwitch") {
|
else if (Command == "OilPumpSwitch") {
|
||||||
if( OilPump.start_type != start_t::automatic ) {
|
if( OilPump.start_type != start_t::automatic ) {
|
||||||
// automatic pump ignores 'manual' state commands
|
// automatic pump ignores 'manual' state commands
|
||||||
@@ -9179,6 +9285,13 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
|||||||
}
|
}
|
||||||
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||||
}
|
}
|
||||||
|
else if (Command == "OilPumpSwitchOff") {
|
||||||
|
if( OilPump.start_type != start_t::automatic ) {
|
||||||
|
// automatic pump ignores 'manual' state commands
|
||||||
|
OilPump.is_disabled = ( CValue1 == 1 );
|
||||||
|
}
|
||||||
|
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||||
|
}
|
||||||
else if (Command == "MainSwitch")
|
else if (Command == "MainSwitch")
|
||||||
{
|
{
|
||||||
if (CValue1 == 1) {
|
if (CValue1 == 1) {
|
||||||
@@ -9193,6 +9306,9 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Mains = false;
|
Mains = false;
|
||||||
|
// potentially knock out the pumps if their switch doesn't force them on
|
||||||
|
WaterPump.is_active &= WaterPump.is_enabled;
|
||||||
|
FuelPump.is_active &= FuelPump.is_enabled;
|
||||||
}
|
}
|
||||||
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
|
|||||||
iVboPtr = Pos; // pozycja w VBO
|
iVboPtr = Pos; // pozycja w VBO
|
||||||
*/
|
*/
|
||||||
if (!parser.expectToken("type:"))
|
if (!parser.expectToken("type:"))
|
||||||
Error("Model type parse failure!");
|
ErrorLog("Bad model: expected submodel type definition not found while loading model \"" + Model->NameGet() + "\"" );
|
||||||
{
|
{
|
||||||
std::string type = parser.getToken<std::string>();
|
std::string type = parser.getToken<std::string>();
|
||||||
if (type == "mesh")
|
if (type == "mesh")
|
||||||
@@ -1252,6 +1252,8 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
auto const name { FileName };
|
auto const name { FileName };
|
||||||
|
// cache the file name, in case someone wants it later
|
||||||
|
m_filename = name;
|
||||||
|
|
||||||
asBinary = name + ".e3d";
|
asBinary = name + ".e3d";
|
||||||
if (FileExists(asBinary))
|
if (FileExists(asBinary))
|
||||||
@@ -1271,8 +1273,6 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// cache the file name, in case someone wants it later
|
|
||||||
m_filename = name;
|
|
||||||
bool const result =
|
bool const result =
|
||||||
Root ? (iSubModelsCount > 0) : false; // brak pliku albo problem z wczytaniem
|
Root ? (iSubModelsCount > 0) : false; // brak pliku albo problem z wczytaniem
|
||||||
if (false == result)
|
if (false == result)
|
||||||
|
|||||||
830
PyInt.cpp
830
PyInt.cpp
@@ -1,24 +1,56 @@
|
|||||||
|
/*
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "PyInt.h"
|
#include "PyInt.h"
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "parser.h"
|
#include "application.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
#include "Model3d.h"
|
|
||||||
#include "Train.h"
|
|
||||||
#include "Logs.h"
|
#include "Logs.h"
|
||||||
|
|
||||||
TPythonInterpreter *TPythonInterpreter::_instance = NULL;
|
|
||||||
|
|
||||||
//#define _PY_INT_MORE_LOG
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TPythonInterpreter::TPythonInterpreter()
|
void render_task::run() {
|
||||||
{
|
// call the renderer
|
||||||
WriteLog("Loading Python ...");
|
auto *output { PyObject_CallMethod( m_renderer, "render", "O", m_input ) };
|
||||||
|
Py_DECREF( m_input );
|
||||||
|
|
||||||
|
if( output != nullptr ) {
|
||||||
|
auto *outputwidth { PyObject_CallMethod( m_renderer, "get_width", nullptr ) };
|
||||||
|
auto *outputheight { PyObject_CallMethod( m_renderer, "get_height", nullptr ) };
|
||||||
|
// upload texture data
|
||||||
|
if( ( outputwidth != nullptr )
|
||||||
|
&& ( outputheight != nullptr ) ) {
|
||||||
|
|
||||||
|
GfxRenderer.Bind_Material( m_target );
|
||||||
|
// build texture
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D, 0,
|
||||||
|
GL_SRGB8_ALPHA8,
|
||||||
|
PyInt_AsLong( outputwidth ), PyInt_AsLong( outputheight ), 0,
|
||||||
|
GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLubyte const *>( PyString_AsString( output ) ) );
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
Py_DECREF( outputheight );
|
||||||
|
Py_DECREF( outputwidth );
|
||||||
|
Py_DECREF( output );
|
||||||
|
}
|
||||||
|
// clean up after yourself
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initializes the module. returns true on success
|
||||||
|
auto python_taskqueue::init() -> bool {
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (sizeof(void*) == 8)
|
if (sizeof(void*) == 8)
|
||||||
Py_SetPythonHome("python64");
|
Py_SetPythonHome("python64");
|
||||||
@@ -31,327 +63,261 @@ TPythonInterpreter::TPythonInterpreter()
|
|||||||
Py_SetPythonHome("linuxpython");
|
Py_SetPythonHome("linuxpython");
|
||||||
#endif
|
#endif
|
||||||
Py_Initialize();
|
Py_Initialize();
|
||||||
_main = PyImport_ImportModule("__main__");
|
PyEval_InitThreads();
|
||||||
if (_main == NULL)
|
|
||||||
{
|
PyObject *stringiomodule { nullptr };
|
||||||
WriteLog("Cannot import Python module __main__");
|
PyObject *stringioclassname { nullptr };
|
||||||
|
PyObject *stringioobject { nullptr };
|
||||||
|
|
||||||
|
// save a pointer to the main PyThreadState object
|
||||||
|
m_mainthread = PyThreadState_Get();
|
||||||
|
// do the setup work while we hold the lock
|
||||||
|
m_main = PyImport_ImportModule("__main__");
|
||||||
|
if (m_main == nullptr) {
|
||||||
|
ErrorLog( "Python Interpreter: __main__ module is missing" );
|
||||||
|
goto release_and_exit;
|
||||||
}
|
}
|
||||||
PyObject *cStringModule = PyImport_ImportModule("cStringIO");
|
|
||||||
_stdErr = NULL;
|
stringiomodule = PyImport_ImportModule( "cStringIO" );
|
||||||
if (cStringModule == NULL)
|
stringioclassname = (
|
||||||
return;
|
stringiomodule != nullptr ?
|
||||||
PyObject *cStringClassName = PyObject_GetAttrString(cStringModule, "StringIO");
|
PyObject_GetAttrString( stringiomodule, "StringIO" ) :
|
||||||
if (cStringClassName == NULL)
|
nullptr );
|
||||||
return;
|
stringioobject = (
|
||||||
PyObject *cString = PyObject_CallObject(cStringClassName, NULL);
|
stringioclassname != nullptr ?
|
||||||
if (cString == NULL)
|
PyObject_CallObject( stringioclassname, nullptr ) :
|
||||||
return;
|
nullptr );
|
||||||
if (PySys_SetObject("stderr", cString) != 0)
|
m_error = { (
|
||||||
return;
|
stringioobject == nullptr ? nullptr :
|
||||||
_stdErr = cString;
|
PySys_SetObject( "stderr", stringioobject ) != 0 ? nullptr :
|
||||||
|
stringioobject ) };
|
||||||
|
|
||||||
|
if( m_error == nullptr ) { goto release_and_exit; }
|
||||||
|
|
||||||
|
if( false == run_file( "abstractscreenrenderer" ) ) { goto release_and_exit; }
|
||||||
|
|
||||||
|
// release the lock
|
||||||
|
PyEval_ReleaseLock();
|
||||||
|
|
||||||
|
WriteLog( "Python Interpreter setup complete" );
|
||||||
|
|
||||||
|
// init workers
|
||||||
|
for( auto &worker : m_workers ) {
|
||||||
|
|
||||||
|
auto *openglcontextwindow { Application.window( -1 ) };
|
||||||
|
worker =
|
||||||
|
std::make_unique<std::thread>(
|
||||||
|
&python_taskqueue::run, this,
|
||||||
|
openglcontextwindow, std::ref( m_tasks ), std::ref( m_condition ), std::ref( m_exit ) );
|
||||||
|
|
||||||
|
if( worker == nullptr ) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
release_and_exit:
|
||||||
|
PyEval_ReleaseLock();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TPythonInterpreter *TPythonInterpreter::getInstance()
|
// shuts down the module
|
||||||
{
|
void python_taskqueue::exit() {
|
||||||
if (!_instance)
|
// let the workers know we're done with them
|
||||||
{
|
m_exit = true;
|
||||||
_instance = new TPythonInterpreter();
|
m_condition.notify_all();
|
||||||
|
// let them free up their shit before we proceed
|
||||||
|
for( auto const &worker : m_workers ) {
|
||||||
|
worker->join();
|
||||||
}
|
}
|
||||||
return _instance;
|
// get rid of the leftover tasks
|
||||||
|
// with the workers dead we don't have to worry about concurrent access anymore
|
||||||
|
for( auto *task : m_tasks.data ) {
|
||||||
|
delete task;
|
||||||
|
}
|
||||||
|
// take a bow
|
||||||
|
PyEval_AcquireLock();
|
||||||
|
PyThreadState_Swap( m_mainthread );
|
||||||
|
Py_Finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// adds specified task along with provided collection of data to the work queue. returns true on success
|
||||||
|
auto python_taskqueue::insert( task_request const &Task ) -> bool {
|
||||||
|
|
||||||
|
if( ( Task.renderer.empty() )
|
||||||
|
|| ( Task.input == nullptr )
|
||||||
|
|| ( Task.target == null_handle ) ) { return false; }
|
||||||
|
|
||||||
|
auto *renderer { fetch_renderer( Task.renderer ) };
|
||||||
|
if( renderer == nullptr ) { return false; }
|
||||||
|
// acquire a lock on the task queue and add a new task
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock( m_tasks.mutex );
|
||||||
|
m_tasks.data.emplace_back( new render_task( renderer, Task.input, Task.target ) );
|
||||||
|
}
|
||||||
|
// potentially wake a worker to handle the new task
|
||||||
|
m_condition.notify_one();
|
||||||
|
// all done
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// executes python script stored in specified file. returns true on success
|
||||||
|
auto python_taskqueue::run_file( std::string const &File, std::string const &Path ) -> bool {
|
||||||
|
|
||||||
|
auto const lookup { FileExists( { Path + File, "python/local/" + File }, { ".py" } ) };
|
||||||
|
if( lookup.first.empty() ) { return false; }
|
||||||
|
|
||||||
|
std::ifstream inputfile { lookup.first + lookup.second };
|
||||||
|
std::string input;
|
||||||
|
input.assign( std::istreambuf_iterator<char>( inputfile ), std::istreambuf_iterator<char>() );
|
||||||
|
|
||||||
|
if( PyRun_SimpleString( input.c_str() ) != 0 ) {
|
||||||
|
error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto python_taskqueue::fetch_renderer( std::string const Renderer ) ->PyObject * {
|
||||||
|
|
||||||
|
auto const lookup { m_renderers.find( Renderer ) };
|
||||||
|
if( lookup != std::end( m_renderers ) ) {
|
||||||
|
return lookup->second;
|
||||||
|
}
|
||||||
|
// try to load specified renderer class
|
||||||
|
auto const path { substr_path( Renderer ) };
|
||||||
|
auto const file { Renderer.substr( path.size() ) };
|
||||||
|
PyObject *renderer { nullptr };
|
||||||
|
PyObject *rendererarguments { nullptr };
|
||||||
|
PyObject *renderername { nullptr };
|
||||||
|
|
||||||
|
PyEval_AcquireLock();
|
||||||
|
|
||||||
|
if( m_main == nullptr ) {
|
||||||
|
ErrorLog( "Python Renderer: __main__ module is missing" );
|
||||||
|
goto cache_and_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if( false == run_file( file, path ) ) {
|
||||||
|
goto cache_and_return;
|
||||||
|
}
|
||||||
|
renderername = PyObject_GetAttrString( m_main, file.c_str() );
|
||||||
|
if( renderername == nullptr ) {
|
||||||
|
ErrorLog( "Python Renderer: class \"" + file + "\" not defined" );
|
||||||
|
goto cache_and_return;
|
||||||
|
}
|
||||||
|
rendererarguments = Py_BuildValue( "(s)", path.c_str() );
|
||||||
|
if( rendererarguments == nullptr ) {
|
||||||
|
ErrorLog( "Python Renderer: failed to create initialization arguments" );
|
||||||
|
goto cache_and_return;
|
||||||
|
}
|
||||||
|
renderer = PyObject_CallObject( renderername, rendererarguments );
|
||||||
|
|
||||||
|
if( PyErr_Occurred() != nullptr ) {
|
||||||
|
error();
|
||||||
|
renderer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_and_return:
|
||||||
|
// clean up after yourself
|
||||||
|
if( rendererarguments != nullptr ) {
|
||||||
|
Py_DECREF( rendererarguments );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PyEval_ReleaseLock();
|
||||||
|
// cache the failures as well so we don't try again on subsequent requests
|
||||||
|
m_renderers.emplace( Renderer, renderer );
|
||||||
|
return renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void python_taskqueue::run( GLFWwindow *Context, rendertask_sequence &Tasks, threading::condition_variable &Condition, std::atomic<bool> &Exit ) {
|
||||||
|
|
||||||
|
glfwMakeContextCurrent( Context );
|
||||||
|
// create a state object for this thread
|
||||||
|
PyEval_AcquireLock();
|
||||||
|
auto *threadstate { PyThreadState_New( m_mainthread->interp ) };
|
||||||
|
PyEval_ReleaseLock();
|
||||||
|
|
||||||
|
render_task *task { nullptr };
|
||||||
|
|
||||||
|
while( false == Exit.load() ) {
|
||||||
|
// regardless of the reason we woke up prime the spurious wakeup flag for the next time
|
||||||
|
Condition.spurious( true );
|
||||||
|
// keep working as long as there's any scheduled tasks
|
||||||
|
do {
|
||||||
|
task = nullptr;
|
||||||
|
// acquire a lock on the task queue and potentially grab a task from it
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock( Tasks.mutex );
|
||||||
|
if( false == Tasks.data.empty() ) {
|
||||||
|
// fifo
|
||||||
|
task = Tasks.data.front();
|
||||||
|
Tasks.data.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( task != nullptr ) {
|
||||||
|
// swap in my thread state
|
||||||
|
PyEval_AcquireLock();
|
||||||
|
PyThreadState_Swap( threadstate );
|
||||||
|
// execute python code
|
||||||
|
task->run();
|
||||||
|
error();
|
||||||
|
// clear the thread state
|
||||||
|
PyThreadState_Swap( nullptr );
|
||||||
|
PyEval_ReleaseLock();
|
||||||
|
}
|
||||||
|
// TBD, TODO: add some idle time between tasks in case we're on a single thread cpu?
|
||||||
|
} while( task != nullptr );
|
||||||
|
// if there's nothing left to do wait until there is
|
||||||
|
// but check every now and then on your own to minimize potential deadlock situations
|
||||||
|
Condition.wait_for( std::chrono::seconds( 5 ) );
|
||||||
|
}
|
||||||
|
// clean up thread state data
|
||||||
|
PyEval_AcquireLock();
|
||||||
|
PyThreadState_Swap( nullptr );
|
||||||
|
PyThreadState_Clear( threadstate );
|
||||||
|
PyThreadState_Delete( threadstate );
|
||||||
|
PyEval_ReleaseLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TPythonInterpreter::killInstance() {
|
python_taskqueue::error() {
|
||||||
|
|
||||||
delete _instance;
|
if( PyErr_Occurred() == nullptr ) { return; }
|
||||||
}
|
|
||||||
|
|
||||||
bool TPythonInterpreter::loadClassFile( std::string const &lookupPath, std::string const &className )
|
if( m_error != nullptr ) {
|
||||||
{
|
// std err pythona jest buforowane
|
||||||
std::set<std::string>::const_iterator it = _classes.find(className);
|
|
||||||
if (it == _classes.end())
|
|
||||||
{
|
|
||||||
FILE *sourceFile = _getFile(lookupPath, className);
|
|
||||||
if (sourceFile != nullptr)
|
|
||||||
{
|
|
||||||
fseek(sourceFile, 0, SEEK_END);
|
|
||||||
auto const fsize = ftell(sourceFile);
|
|
||||||
char *buffer = (char *)calloc(fsize + 1, sizeof(char));
|
|
||||||
fseek(sourceFile, 0, SEEK_SET);
|
|
||||||
auto const freaded = fread(buffer, sizeof(char), fsize, sourceFile);
|
|
||||||
buffer[freaded] = 0; // z jakiegos powodu czytamy troche mniej i trzczeba dodac konczace
|
|
||||||
// zero do bufora (mimo ze calloc teoretycznie powiniene zwrocic
|
|
||||||
// wyzerowana pamiec)
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
char buf[255];
|
|
||||||
sprintf(buf, "readed %d / %d characters for %s", freaded, fsize, className);
|
|
||||||
WriteLog(buf);
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
fclose(sourceFile);
|
|
||||||
if (PyRun_SimpleString(buffer) != 0)
|
|
||||||
{
|
|
||||||
handleError();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_classes.insert( className );
|
|
||||||
/*
|
|
||||||
char *classNameToRemember = (char *)calloc(strlen(className) + 1, sizeof(char));
|
|
||||||
strcpy(classNameToRemember, className);
|
|
||||||
_classes.insert(classNameToRemember);
|
|
||||||
*/
|
|
||||||
free(buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *TPythonInterpreter::newClass( std::string const &className )
|
|
||||||
{
|
|
||||||
return newClass(className, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *TPythonInterpreter::_getFile( std::string const &lookupPath, std::string const &className )
|
|
||||||
{
|
|
||||||
if( false == lookupPath.empty() ) {
|
|
||||||
std::string const sourcefilepath = lookupPath + className + ".py";
|
|
||||||
FILE *file = fopen( sourcefilepath.c_str(), "r" );
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog( sourceFilePath );
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
if( nullptr != file ) { return file; }
|
|
||||||
}
|
|
||||||
std::string sourcefilepath = "python/local/" + className + ".py";
|
|
||||||
FILE *file = fopen( sourcefilepath.c_str(), "r" );
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog( sourceFilePath );
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
return file; // either the file, or a nullptr on fail
|
|
||||||
/*
|
|
||||||
char *sourceFilePath;
|
|
||||||
if (lookupPath != NULL)
|
|
||||||
{
|
|
||||||
sourceFilePath = (char *)calloc(strlen(lookupPath) + strlen(className) + 4, sizeof(char));
|
|
||||||
strcat(sourceFilePath, lookupPath);
|
|
||||||
strcat(sourceFilePath, className);
|
|
||||||
strcat(sourceFilePath, ".py");
|
|
||||||
|
|
||||||
FILE *file = fopen(sourceFilePath, "r");
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog(sourceFilePath);
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
free(sourceFilePath);
|
|
||||||
if (file != NULL)
|
|
||||||
{
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char *basePath = "python/local/";
|
|
||||||
sourceFilePath = (char *)calloc(strlen(basePath) + strlen(className) + 4, sizeof(char));
|
|
||||||
strcat(sourceFilePath, basePath);
|
|
||||||
strcat(sourceFilePath, className);
|
|
||||||
strcat(sourceFilePath, ".py");
|
|
||||||
|
|
||||||
FILE *file = fopen(sourceFilePath, "r");
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog(sourceFilePath);
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
free(sourceFilePath);
|
|
||||||
if (file != NULL)
|
|
||||||
{
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonInterpreter::handleError()
|
|
||||||
{
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog("Python Error occured");
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
if (_stdErr != NULL)
|
|
||||||
{ // std err pythona jest buforowane
|
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
PyObject *bufferContent = PyObject_CallMethod(_stdErr, "getvalue", NULL);
|
auto *errortext { PyObject_CallMethod( m_error, "getvalue", nullptr ) };
|
||||||
PyObject_CallMethod(_stdErr, "truncate", "i", 0); // czyscimy bufor na kolejne bledy
|
ErrorLog( PyString_AsString( errortext ) );
|
||||||
WriteLog(PyString_AsString(bufferContent));
|
// czyscimy bufor na kolejne bledy
|
||||||
|
PyObject_CallMethod( m_error, "truncate", "i", 0 );
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{ // nie dziala buffor pythona
|
// nie dziala buffor pythona
|
||||||
if (PyErr_Occurred() != NULL)
|
PyObject *type, *value, *traceback;
|
||||||
{
|
PyErr_Fetch( &type, &value, &traceback );
|
||||||
PyObject *ptype, *pvalue, *ptraceback;
|
if( type == nullptr ) {
|
||||||
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
|
ErrorLog( "Python Interpreter: don't know how to handle null exception" );
|
||||||
if (ptype == NULL)
|
|
||||||
{
|
|
||||||
WriteLog("Don't konw how to handle NULL exception");
|
|
||||||
}
|
}
|
||||||
PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
|
PyErr_NormalizeException( &type, &value, &traceback );
|
||||||
if (ptype == NULL)
|
if( type == nullptr ) {
|
||||||
{
|
ErrorLog( "Python Interpreter: don't know how to handle null exception" );
|
||||||
WriteLog("Don't konw how to handle NULL exception");
|
|
||||||
}
|
}
|
||||||
PyObject *pStrType = PyObject_Str(ptype);
|
auto *typetext { PyObject_Str( type ) };
|
||||||
if (pStrType != NULL)
|
if( typetext != nullptr ) {
|
||||||
{
|
ErrorLog( PyString_AsString( typetext ) );
|
||||||
WriteLog(PyString_AsString(pStrType));
|
|
||||||
}
|
}
|
||||||
WriteLog(PyString_AsString(pvalue));
|
if( value != nullptr ) {
|
||||||
PyObject *pStrTraceback = PyObject_Str(ptraceback);
|
ErrorLog( PyString_AsString( value ) );
|
||||||
if (pStrTraceback != NULL)
|
|
||||||
{
|
|
||||||
WriteLog(PyString_AsString(pStrTraceback));
|
|
||||||
}
|
}
|
||||||
else
|
auto *tracebacktext { PyObject_Str( traceback ) };
|
||||||
{
|
if( tracebacktext != nullptr ) {
|
||||||
WriteLog("Python Traceback cannot be shown");
|
WriteLog( PyString_AsString( tracebacktext ) );
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
else
|
WriteLog( "Python Interpreter: failed to retrieve the stack traceback" );
|
||||||
{
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog("Called python error handler when no error occured!");
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PyObject *TPythonInterpreter::newClass(std::string const &className, PyObject *argsTuple)
|
|
||||||
{
|
|
||||||
if (_main == NULL)
|
|
||||||
{
|
|
||||||
WriteLog("main turned into null");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
PyObject *classNameObj = PyObject_GetAttrString(_main, className.c_str());
|
|
||||||
if (classNameObj == NULL)
|
|
||||||
{
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
char buf[255];
|
|
||||||
sprintf(buf, "Python class %s not defined!", className);
|
|
||||||
WriteLog(buf);
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
PyObject *object = PyObject_CallObject(classNameObj, argsTuple);
|
|
||||||
|
|
||||||
if (PyErr_Occurred() != NULL)
|
|
||||||
{
|
|
||||||
handleError();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
TPythonScreenRenderer::TPythonScreenRenderer(int textureId, PyObject *renderer)
|
|
||||||
{
|
|
||||||
_textureId = textureId;
|
|
||||||
_pyRenderer = renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreenRenderer::updateTexture()
|
|
||||||
{
|
|
||||||
int width, height;
|
|
||||||
if (_pyWidth == NULL || _pyHeight == NULL)
|
|
||||||
{
|
|
||||||
WriteLog("Unknown python texture size!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
width = PyInt_AsLong(_pyWidth);
|
|
||||||
height = PyInt_AsLong(_pyHeight);
|
|
||||||
if (_pyTexture != NULL)
|
|
||||||
{
|
|
||||||
char *textureData = PyString_AsString(_pyTexture);
|
|
||||||
if (textureData != NULL)
|
|
||||||
{
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
char buff[255];
|
|
||||||
sprintf(buff, "Sending texture id: %d w: %d h: %d", _textureId, width, height);
|
|
||||||
WriteLog(buff);
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
/*
|
|
||||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
|
||||||
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
|
|
||||||
*/
|
|
||||||
GfxRenderer.Bind_Material(_textureId);
|
|
||||||
// setup texture parameters
|
|
||||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
|
||||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
|
||||||
// build texture
|
|
||||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData );
|
|
||||||
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
GLenum status = glGetError();
|
|
||||||
switch (status)
|
|
||||||
{
|
|
||||||
case GL_INVALID_ENUM:
|
|
||||||
WriteLog("An unacceptable value is specified for an enumerated argument. The "
|
|
||||||
"offending function is ignored, having no side effect other than to set "
|
|
||||||
"the error flag.");
|
|
||||||
break;
|
|
||||||
case GL_INVALID_VALUE:
|
|
||||||
WriteLog("A numeric argument is out of range. The offending function is ignored, "
|
|
||||||
"having no side effect other than to set the error flag.");
|
|
||||||
break;
|
|
||||||
case GL_INVALID_OPERATION:
|
|
||||||
WriteLog("The specified operation is not allowed in the current state. The "
|
|
||||||
"offending function is ignored, having no side effect other than to set "
|
|
||||||
"the error flag.");
|
|
||||||
break;
|
|
||||||
case GL_NO_ERROR:
|
|
||||||
WriteLog("No error has been recorded. The value of this symbolic constant is "
|
|
||||||
"guaranteed to be zero.");
|
|
||||||
break;
|
|
||||||
case GL_STACK_OVERFLOW:
|
|
||||||
WriteLog("This function would cause a stack overflow. The offending function is "
|
|
||||||
"ignored, having no side effect other than to set the error flag.");
|
|
||||||
break;
|
|
||||||
case GL_STACK_UNDERFLOW:
|
|
||||||
WriteLog("This function would cause a stack underflow. The offending function is "
|
|
||||||
"ignored, having no side effect other than to set the error flag.");
|
|
||||||
break;
|
|
||||||
case GL_OUT_OF_MEMORY:
|
|
||||||
WriteLog("There is not enough memory left to execute the function. The state of "
|
|
||||||
"OpenGL is undefined, except for the state of the error flags, after this "
|
|
||||||
"error is recorded.");
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteLog("RAW python texture data is NULL!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteLog("Python texture object is NULL!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreenRenderer::render(PyObject *trainState)
|
|
||||||
{
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog("Python rendering texture ...");
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
_pyTexture = PyObject_CallMethod(_pyRenderer, "render", "O", trainState);
|
|
||||||
|
|
||||||
if (_pyTexture == NULL)
|
|
||||||
{
|
|
||||||
TPythonInterpreter::getInstance()->handleError();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_pyWidth = PyObject_CallMethod(_pyRenderer, "get_width", NULL);
|
|
||||||
if (_pyWidth == NULL)
|
|
||||||
{
|
|
||||||
TPythonInterpreter::getInstance()->handleError();
|
|
||||||
}
|
|
||||||
_pyHeight = PyObject_CallMethod(_pyRenderer, "get_height", NULL);
|
|
||||||
if (_pyHeight == NULL)
|
|
||||||
{
|
|
||||||
TPythonInterpreter::getInstance()->handleError();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,237 +325,3 @@ void TPythonScreenRenderer::render(PyObject *trainState)
|
|||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TPythonScreenRenderer::~TPythonScreenRenderer()
|
|
||||||
{
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog("PythonScreenRenderer descturctor called");
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
if (_pyRenderer != NULL)
|
|
||||||
{
|
|
||||||
Py_CLEAR(_pyRenderer);
|
|
||||||
}
|
|
||||||
cleanup();
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog("PythonScreenRenderer desctructor finished");
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreenRenderer::cleanup()
|
|
||||||
{
|
|
||||||
if (_pyTexture != NULL)
|
|
||||||
{
|
|
||||||
Py_CLEAR(_pyTexture);
|
|
||||||
_pyTexture = NULL;
|
|
||||||
}
|
|
||||||
if (_pyWidth != NULL)
|
|
||||||
{
|
|
||||||
Py_CLEAR(_pyWidth);
|
|
||||||
_pyWidth = NULL;
|
|
||||||
}
|
|
||||||
if (_pyHeight != NULL)
|
|
||||||
{
|
|
||||||
Py_CLEAR(_pyHeight);
|
|
||||||
_pyHeight = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreens::reset(void *train)
|
|
||||||
{
|
|
||||||
_terminationFlag = true;
|
|
||||||
if (_thread != NULL)
|
|
||||||
{
|
|
||||||
// WriteLog("Awaiting python thread to end");
|
|
||||||
_thread->join();
|
|
||||||
delete _thread;
|
|
||||||
_thread = nullptr;
|
|
||||||
}
|
|
||||||
_terminationFlag = false;
|
|
||||||
_cleanupReadyFlag = false;
|
|
||||||
_renderReadyFlag = false;
|
|
||||||
for (std::vector<TPythonScreenRenderer *>::iterator i = _screens.begin(); i != _screens.end();
|
|
||||||
++i)
|
|
||||||
{
|
|
||||||
delete *i;
|
|
||||||
}
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog("Clearing renderer vector");
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
_screens.clear();
|
|
||||||
_train = train;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreens::init(cParser &parser, TModel3d *model, std::string const &name, int const cab)
|
|
||||||
{
|
|
||||||
std::string asSubModelName, asPyClassName;
|
|
||||||
parser.getTokens( 2, false );
|
|
||||||
parser
|
|
||||||
>> asSubModelName
|
|
||||||
>> asPyClassName;
|
|
||||||
std::string subModelName = ToLower( asSubModelName );
|
|
||||||
std::string pyClassName = ToLower( asPyClassName );
|
|
||||||
TSubModel *subModel = model->GetFromName(subModelName);
|
|
||||||
if (subModel == NULL)
|
|
||||||
{
|
|
||||||
WriteLog( "Python Screen: submodel " + subModelName + " not found - Ignoring screen" );
|
|
||||||
return; // nie ma takiego sub modelu w danej kabinie pomijamy
|
|
||||||
}
|
|
||||||
auto textureId = subModel->GetMaterial();
|
|
||||||
if (textureId <= 0)
|
|
||||||
{
|
|
||||||
WriteLog( "Python Screen: invalid texture id " + std::to_string(textureId) + " - Ignoring screen" );
|
|
||||||
return; // sub model nie posiada tekstury lub tekstura wymienna - nie obslugiwana
|
|
||||||
}
|
|
||||||
TPythonInterpreter *python = TPythonInterpreter::getInstance();
|
|
||||||
python->loadClassFile(_lookupPath, pyClassName);
|
|
||||||
PyObject *args = Py_BuildValue("(ssi)", _lookupPath.c_str(), name.c_str(), cab);
|
|
||||||
if (args == NULL)
|
|
||||||
{
|
|
||||||
WriteLog("Python Screen: cannot create __init__ arguments");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PyObject *pyRenderer = python->newClass(pyClassName, args);
|
|
||||||
Py_CLEAR(args);
|
|
||||||
if (pyRenderer == NULL)
|
|
||||||
{
|
|
||||||
WriteLog( "Python Screen: null renderer for " + pyClassName + " - Ignoring screen" );
|
|
||||||
return; // nie mozna utworzyc obiektu Pythonowego
|
|
||||||
}
|
|
||||||
m_updaterate = Global.PythonScreenUpdateRate;
|
|
||||||
TPythonScreenRenderer *renderer = new TPythonScreenRenderer(textureId, pyRenderer);
|
|
||||||
_screens.push_back(renderer);
|
|
||||||
WriteLog( "Created python screen " + pyClassName + " on submodel " + subModelName + " (" + std::to_string(textureId) + ")" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreens::update()
|
|
||||||
{
|
|
||||||
if (!_renderReadyFlag)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_renderReadyFlag = false;
|
|
||||||
for (std::vector<TPythonScreenRenderer *>::iterator i = _screens.begin(); i != _screens.end();
|
|
||||||
++i)
|
|
||||||
{
|
|
||||||
(*i)->updateTexture();
|
|
||||||
}
|
|
||||||
_cleanupReadyFlag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreens::setLookupPath(std::string const &path)
|
|
||||||
{
|
|
||||||
_lookupPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
TPythonScreens::TPythonScreens()
|
|
||||||
{
|
|
||||||
TPythonInterpreter::getInstance()->loadClassFile("", "abstractscreenrenderer");
|
|
||||||
}
|
|
||||||
|
|
||||||
TPythonScreens::~TPythonScreens()
|
|
||||||
{
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog("Called python sceeens destructor");
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
reset(NULL);
|
|
||||||
/*
|
|
||||||
if (_lookupPath != NULL)
|
|
||||||
{
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog("Freeing lookup path");
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
free(_lookupPath);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreens::run()
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
m_updatestopwatch.start();
|
|
||||||
if (_terminationFlag)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TTrain *train = (TTrain *)_train;
|
|
||||||
_trainState = train->GetTrainState();
|
|
||||||
if (_terminationFlag)
|
|
||||||
{
|
|
||||||
_freeTrainState();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (std::vector<TPythonScreenRenderer *>::iterator i = _screens.begin();
|
|
||||||
i != _screens.end(); ++i)
|
|
||||||
{
|
|
||||||
(*i)->render(_trainState);
|
|
||||||
}
|
|
||||||
_freeTrainState();
|
|
||||||
if (_terminationFlag)
|
|
||||||
{
|
|
||||||
_cleanup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_renderReadyFlag = true;
|
|
||||||
m_updatestopwatch.stop();
|
|
||||||
while (!_cleanupReadyFlag && !_terminationFlag)
|
|
||||||
{
|
|
||||||
auto const sleeptime {
|
|
||||||
std::max(
|
|
||||||
100,
|
|
||||||
m_updaterate - static_cast<int>( m_updatestopwatch.average() ) ) };
|
|
||||||
#ifdef _WIN32
|
|
||||||
Sleep( sleeptime );
|
|
||||||
#elif __linux__
|
|
||||||
usleep( sleeptime * 1000 );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
if (_terminationFlag)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreens::finish()
|
|
||||||
{
|
|
||||||
// nothing to do here, proper clean up takes place afterwards
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenRendererThread(TPythonScreens* renderer)
|
|
||||||
{
|
|
||||||
renderer->run();
|
|
||||||
renderer->finish();
|
|
||||||
#ifdef _PY_INT_MORE_LOG
|
|
||||||
WriteLog("Python Screen Renderer Thread Ends");
|
|
||||||
#endif // _PY_INT_MORE_LOG
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreens::start()
|
|
||||||
{
|
|
||||||
if (_screens.size() > 0)
|
|
||||||
{
|
|
||||||
_thread = new std::thread(ScreenRendererThread, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreens::_cleanup()
|
|
||||||
{
|
|
||||||
_cleanupReadyFlag = false;
|
|
||||||
for (std::vector<TPythonScreenRenderer *>::iterator i = _screens.begin(); i != _screens.end();
|
|
||||||
++i)
|
|
||||||
{
|
|
||||||
(*i)->cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPythonScreens::_freeTrainState()
|
|
||||||
{
|
|
||||||
if (_trainState != NULL)
|
|
||||||
{
|
|
||||||
PyDict_Clear(_trainState);
|
|
||||||
Py_CLEAR(_trainState);
|
|
||||||
_trainState = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
135
PyInt.h
135
PyInt.h
@@ -1,5 +1,14 @@
|
|||||||
#ifndef PyIntH
|
/*
|
||||||
#define PyIntH
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PYINT_H
|
||||||
|
#define PYINT_H
|
||||||
|
|
||||||
#ifdef _POSIX_C_SOURCE
|
#ifdef _POSIX_C_SOURCE
|
||||||
#undef _POSIX_C_SOURCE
|
#undef _POSIX_C_SOURCE
|
||||||
@@ -17,78 +26,72 @@
|
|||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#endif
|
#endif
|
||||||
#include "Classes.h"
|
#include "Classes.h"
|
||||||
#include "Timer.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#define PyGetFloat(param) PyFloat_FromDouble(param >= 0 ? param : -param)
|
#define PyGetFloat(param) PyFloat_FromDouble(param >= 0 ? param : -param)
|
||||||
#define PyGetFloatS(param) PyFloat_FromDouble(param)
|
#define PyGetFloatS(param) PyFloat_FromDouble(param)
|
||||||
#define PyGetInt(param) PyInt_FromLong(param)
|
#define PyGetInt(param) PyInt_FromLong(param)
|
||||||
#define PyGetFloatS(param) PyFloat_FromDouble(param)
|
|
||||||
#define PyGetBool(param) param ? Py_True : Py_False
|
#define PyGetBool(param) param ? Py_True : Py_False
|
||||||
#define PyGetString(param) PyString_FromString(param)
|
#define PyGetString(param) PyString_FromString(param)
|
||||||
|
|
||||||
class TPythonInterpreter
|
// TODO: extract common base and inherit specialization from it
|
||||||
{
|
class render_task {
|
||||||
protected:
|
|
||||||
TPythonInterpreter();
|
|
||||||
~TPythonInterpreter() {}
|
|
||||||
static TPythonInterpreter *_instance;
|
|
||||||
std::set<std::string> _classes;
|
|
||||||
PyObject *_main;
|
|
||||||
PyObject *_stdErr;
|
|
||||||
FILE *_getFile( std::string const &lookupPath, std::string const &className );
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static TPythonInterpreter *getInstance();
|
// constructors
|
||||||
static void killInstance();
|
render_task( PyObject *Renderer, PyObject *Input, material_handle Target ) :
|
||||||
bool loadClassFile( std::string const &lookupPath, std::string const &className );
|
m_renderer( Renderer ), m_input( Input ), m_target( Target )
|
||||||
PyObject *newClass( std::string const &className );
|
{}
|
||||||
PyObject *newClass( std::string const &className, PyObject *argsTuple );
|
// methods
|
||||||
void handleError();
|
|
||||||
};
|
|
||||||
|
|
||||||
class TPythonScreenRenderer
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
PyObject *_pyRenderer;
|
|
||||||
PyObject *_pyTexture;
|
|
||||||
int _textureId;
|
|
||||||
PyObject *_pyWidth;
|
|
||||||
PyObject *_pyHeight;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TPythonScreenRenderer(int textureId, PyObject *renderer);
|
|
||||||
~TPythonScreenRenderer();
|
|
||||||
void render(PyObject *trainState);
|
|
||||||
void cleanup();
|
|
||||||
void updateTexture();
|
|
||||||
};
|
|
||||||
|
|
||||||
class TPythonScreens
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
bool _cleanupReadyFlag{ false };
|
|
||||||
bool _renderReadyFlag{ false };
|
|
||||||
bool _terminationFlag{ false };
|
|
||||||
std::thread *_thread{ nullptr };
|
|
||||||
std::vector<TPythonScreenRenderer *> _screens;
|
|
||||||
std::string _lookupPath;
|
|
||||||
void *_train;
|
|
||||||
void _cleanup();
|
|
||||||
void _freeTrainState();
|
|
||||||
PyObject *_trainState;
|
|
||||||
int m_updaterate { 200 };
|
|
||||||
Timer::stopwatch m_updatestopwatch;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void reset(void *train);
|
|
||||||
void setLookupPath(std::string const &path);
|
|
||||||
void init(cParser &parser, TModel3d *model, std::string const &name, int const cab);
|
|
||||||
void update();
|
|
||||||
TPythonScreens();
|
|
||||||
~TPythonScreens();
|
|
||||||
void run();
|
void run();
|
||||||
void start();
|
|
||||||
void finish();
|
private:
|
||||||
|
// members
|
||||||
|
PyObject *m_renderer {nullptr};
|
||||||
|
PyObject *m_input { nullptr };
|
||||||
|
material_handle m_target { null_handle };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PyIntH
|
class python_taskqueue {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// types
|
||||||
|
struct task_request {
|
||||||
|
|
||||||
|
std::string const &renderer;
|
||||||
|
PyObject *input;
|
||||||
|
material_handle target;
|
||||||
|
};
|
||||||
|
// constructors
|
||||||
|
python_taskqueue() = default;
|
||||||
|
// methods
|
||||||
|
// initializes the module. returns true on success
|
||||||
|
auto init() -> bool;
|
||||||
|
// shuts down the module
|
||||||
|
void exit();
|
||||||
|
// adds specified task along with provided collection of data to the work queue. returns true on success
|
||||||
|
auto insert( task_request const &Task ) -> bool;
|
||||||
|
// executes python script stored in specified file. returns true on success
|
||||||
|
auto run_file( std::string const &File, std::string const &Path = "" ) -> bool;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// types
|
||||||
|
static int const WORKERCOUNT { 1 };
|
||||||
|
using worker_array = std::array<std::unique_ptr<std::thread>, WORKERCOUNT >;
|
||||||
|
using rendertask_sequence = threading::lockable< std::deque<render_task *> >;
|
||||||
|
// methods
|
||||||
|
auto fetch_renderer( std::string const Renderer ) -> PyObject *;
|
||||||
|
void run( GLFWwindow *Context, rendertask_sequence &Tasks, threading::condition_variable &Condition, std::atomic<bool> &Exit );
|
||||||
|
void error();
|
||||||
|
// members
|
||||||
|
PyObject *m_main { nullptr };
|
||||||
|
PyObject *m_error { nullptr };
|
||||||
|
PyThreadState *m_mainthread{ nullptr };
|
||||||
|
worker_array m_workers;
|
||||||
|
threading::condition_variable m_condition; // wakes up the workers
|
||||||
|
std::atomic<bool> m_exit { false }; // signals the workers to quit
|
||||||
|
std::unordered_map<std::string, PyObject *> m_renderers; // cache of python classes
|
||||||
|
rendertask_sequence m_tasks;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
int const null_handle = 0;
|
|
||||||
|
|
||||||
enum class resource_state {
|
enum class resource_state {
|
||||||
none,
|
none,
|
||||||
loading,
|
loading,
|
||||||
|
|||||||
56
Segment.cpp
56
Segment.cpp
@@ -395,7 +395,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
|
|||||||
|
|
||||||
float m1, jmm1, m2, jmm2; // pozycje względne na odcinku 0...1 (ale nie parametr Beziera)
|
float m1, jmm1, m2, jmm2; // pozycje względne na odcinku 0...1 (ale nie parametr Beziera)
|
||||||
step = fStep;
|
step = fStep;
|
||||||
tv1 = 1.0; // Ra: to by można było wyliczać dla odcinka, wyglądało by lepiej
|
tv1 = 0.0; // Ra: to by można było wyliczać dla odcinka, wyglądało by lepiej
|
||||||
s = fStep * iSkip; // iSkip - ile odcinków z początku pominąć
|
s = fStep * iSkip; // iSkip - ile odcinków z początku pominąć
|
||||||
int i = iSkip; // domyślnie 0
|
int i = iSkip; // domyślnie 0
|
||||||
t = fTsBuffer[ i ]; // tabela wattości t dla segmentów
|
t = fTsBuffer[ i ]; // tabela wattości t dla segmentów
|
||||||
@@ -433,7 +433,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
|
|||||||
while( tv1 < 0.0 ) {
|
while( tv1 < 0.0 ) {
|
||||||
tv1 += 1.0;
|
tv1 += 1.0;
|
||||||
}
|
}
|
||||||
tv2 = tv1 - step / texturelength; // mapowanie na końcu segmentu
|
tv2 = tv1 + step / texturelength; // mapowanie na końcu segmentu
|
||||||
|
|
||||||
t = fTsBuffer[ i ]; // szybsze od GetTFromS(s);
|
t = fTsBuffer[ i ]; // szybsze od GetTFromS(s);
|
||||||
pos2 = glm::dvec3{ FastGetPoint( t ) - Origin };
|
pos2 = glm::dvec3{ FastGetPoint( t ) - Origin };
|
||||||
@@ -523,55 +523,3 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
void TSegment::Render()
|
|
||||||
{
|
|
||||||
Math3D::vector3 pt;
|
|
||||||
GfxRenderer.Bind_Material( null_handle );
|
|
||||||
|
|
||||||
//m7t
|
|
||||||
/*
|
|
||||||
if (bCurve)
|
|
||||||
{
|
|
||||||
glColor3f(0, 0, 1.0f);
|
|
||||||
glBegin(GL_LINE_STRIP);
|
|
||||||
glVertex3f(Point1.x, Point1.y, Point1.z);
|
|
||||||
glVertex3f(CPointOut.x, CPointOut.y, CPointOut.z);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glBegin(GL_LINE_STRIP);
|
|
||||||
glVertex3f(Point2.x, Point2.y, Point2.z);
|
|
||||||
glVertex3f(CPointIn.x, CPointIn.y, CPointIn.z);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glColor3f(1.0f, 0, 0);
|
|
||||||
glBegin(GL_LINE_STRIP);
|
|
||||||
for (int i = 0; i <= 8; i++)
|
|
||||||
{
|
|
||||||
pt = FastGetPoint(double(i) / 8.0f);
|
|
||||||
glVertex3f(pt.x, pt.y, pt.z);
|
|
||||||
}
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glColor3f(0, 0, 1.0f);
|
|
||||||
glBegin(GL_LINE_STRIP);
|
|
||||||
glVertex3f(Point1.x, Point1.y, Point1.z);
|
|
||||||
glVertex3f(Point1.x + CPointOut.x, Point1.y + CPointOut.y, Point1.z + CPointOut.z);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glBegin(GL_LINE_STRIP);
|
|
||||||
glVertex3f(Point2.x, Point2.y, Point2.z);
|
|
||||||
glVertex3f(Point2.x + CPointIn.x, Point2.y + CPointIn.y, Point2.z + CPointIn.z);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glColor3f(0.5f, 0, 0);
|
|
||||||
glBegin(GL_LINE_STRIP);
|
|
||||||
glVertex3f(Point1.x + CPointOut.x, Point1.y + CPointOut.y, Point1.z + CPointOut.z);
|
|
||||||
glVertex3f(Point2.x + CPointIn.x, Point2.y + CPointIn.y, Point2.z + CPointIn.z);
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|||||||
@@ -117,8 +117,10 @@ public:
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, gfx::basic_vertex const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, float fOffsetX = 0.f, glm::vec3 **p = nullptr, bool bRender = true);
|
RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, gfx::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);
|
||||||
|
/*
|
||||||
void
|
void
|
||||||
Render();
|
Render();
|
||||||
|
*/
|
||||||
inline
|
inline
|
||||||
double
|
double
|
||||||
GetLength() const {
|
GetLength() const {
|
||||||
|
|||||||
119
Track.cpp
119
Track.cpp
@@ -1269,8 +1269,10 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
case tt_Normal:
|
case tt_Normal:
|
||||||
if (m_material2)
|
if (m_material2)
|
||||||
{ // podsypka z podkładami jest tylko dla zwykłego toru
|
{ // podsypka z podkładami jest tylko dla zwykłego toru
|
||||||
|
// potentially retrieve texture length override from the assigned material
|
||||||
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
gfx::basic_vertex bpts1[ 8 ]; // punkty głównej płaszczyzny nie przydają się do robienia boków
|
gfx::basic_vertex bpts1[ 8 ]; // punkty głównej płaszczyzny nie przydają się do robienia boków
|
||||||
if( fTexLength == 4.f ) {
|
if( texturelength == 4.f ) {
|
||||||
// stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil
|
// stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil
|
||||||
auto const normalx = std::cos( glm::radians( 75.f ) );
|
auto const normalx = std::cos( glm::radians( 75.f ) );
|
||||||
auto const normaly = std::sin( glm::radians( 75.f ) );
|
auto const normaly = std::sin( glm::radians( 75.f ) );
|
||||||
@@ -1333,7 +1335,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa fTexLength
|
// mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa fTexLength
|
||||||
auto const max = fTexRatio2 * fTexLength; // szerokość proporcjonalna do długości
|
auto const max = fTexRatio2 * texturelength; // szerokość proporcjonalna do długości
|
||||||
auto const map11 = max > 0.f ? (fHTW + side) / max : 0.25f; // załamanie od strony 1
|
auto const map11 = max > 0.f ? (fHTW + side) / max : 0.25f; // załamanie od strony 1
|
||||||
auto const map12 = max > 0.f ? (fHTW + side + hypot1) / max : 0.5f; // brzeg od strony 1
|
auto const map12 = max > 0.f ? (fHTW + side + hypot1) / max : 0.5f; // brzeg od strony 1
|
||||||
if (iTrapezoid) {
|
if (iTrapezoid) {
|
||||||
@@ -1398,7 +1400,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -4 : 4, fTexLength);
|
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -4 : 4, texturelength);
|
||||||
if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) {
|
if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
}
|
}
|
||||||
@@ -1409,20 +1411,21 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
}
|
}
|
||||||
if (m_material1)
|
if (m_material1)
|
||||||
{ // szyny - generujemy dwie, najwyżej rysować się będzie jedną
|
{ // szyny - generujemy dwie, najwyżej rysować się będzie jedną
|
||||||
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) {
|
if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) {
|
||||||
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, texturelength );
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear(); // reuse the scratchpad
|
vertices.clear(); // reuse the scratchpad
|
||||||
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, texturelength );
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
}
|
}
|
||||||
if( ( Bank == 0 ) && ( false == Geometry1.empty() ) ) {
|
if( ( Bank == 0 ) && ( false == Geometry1.empty() ) ) {
|
||||||
// special variant, replace existing data for a turntable track
|
// special variant, replace existing data for a turntable track
|
||||||
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, texturelength );
|
||||||
GfxRenderer.Replace( vertices, Geometry1[ 0 ], GL_TRIANGLE_STRIP );
|
GfxRenderer.Replace( vertices, Geometry1[ 0 ], GL_TRIANGLE_STRIP );
|
||||||
vertices.clear(); // reuse the scratchpad
|
vertices.clear(); // reuse the scratchpad
|
||||||
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, texturelength );
|
||||||
GfxRenderer.Replace( vertices, Geometry1[ 1 ], GL_TRIANGLE_STRIP );
|
GfxRenderer.Replace( vertices, Geometry1[ 1 ], GL_TRIANGLE_STRIP );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1467,28 +1470,30 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
if( m_material1 ) {
|
if( m_material1 ) {
|
||||||
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
// fixed parts
|
// fixed parts
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength );
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength );
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, bladelength );
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength );
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
// left blade
|
// left blade
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, SwitchExtension->fOffset2 );
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, SwitchExtension->fOffset2 );
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
if( m_material2 ) {
|
if( m_material2 ) {
|
||||||
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
// fixed parts
|
// fixed parts
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength );
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength );
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, bladelength );
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength );
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
// right blade
|
// right blade
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 );
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 );
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
@@ -1497,28 +1502,30 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
{ // lewa działa lepiej niż prawa
|
{ // lewa działa lepiej niż prawa
|
||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
if( m_material1 ) {
|
if( m_material1 ) {
|
||||||
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
// fixed parts
|
// fixed parts
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength ); // lewa szyna normalna cała
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, bladelength ); // prawa szyna za iglicą
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength ); // prawa szyna za iglicą
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
// right blade
|
// right blade
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 );
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 );
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
if( m_material2 ) {
|
if( m_material2 ) {
|
||||||
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
// fixed parts
|
// fixed parts
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength ); // prawa szyna normalnie cała
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, bladelength ); // lewa szyna za iglicą
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength ); // lewa szyna za iglicą
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
// left blade
|
// left blade
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 );
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 );
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
@@ -1536,10 +1543,8 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
||||||
if (m_material1 || m_material2) {
|
if (m_material1 || m_material2) {
|
||||||
// punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
// punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
||||||
/*
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100%
|
auto const max = fTexRatio1 * texturelength; // test: szerokość proporcjonalna do długości
|
||||||
*/
|
|
||||||
auto const max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości
|
|
||||||
auto const map1 = max > 0.f ? fHTW / max : 0.5f; // obcięcie tekstury od strony 1
|
auto const map1 = max > 0.f ? fHTW / max : 0.5f; // obcięcie tekstury od strony 1
|
||||||
auto const map2 = max > 0.f ? fHTW2 / max : 0.5f; // obcięcie tekstury od strony 2
|
auto const map2 = max > 0.f ? fHTW2 / max : 0.5f; // obcięcie tekstury od strony 2
|
||||||
if (iTrapezoid) {
|
if (iTrapezoid) {
|
||||||
@@ -1576,12 +1581,14 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
}
|
}
|
||||||
if (m_material1) // jeśli podana była tekstura, generujemy trójkąty
|
if (m_material1) // jeśli podana była tekstura, generujemy trójkąty
|
||||||
{ // tworzenie trójkątów nawierzchni szosy
|
{ // tworzenie trójkątów nawierzchni szosy
|
||||||
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
|
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, texturelength);
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
}
|
}
|
||||||
if (m_material2)
|
if (m_material2)
|
||||||
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
|
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
|
||||||
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
gfx::basic_vertex
|
gfx::basic_vertex
|
||||||
rpts1[6],
|
rpts1[6],
|
||||||
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
||||||
@@ -1644,7 +1651,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
// mapowanie propocjonalne do szerokości chodnika
|
// mapowanie propocjonalne do szerokości chodnika
|
||||||
// krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy
|
// krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy
|
||||||
auto const d = -fTexHeight1 / 3.75f; // krawężnik o wysokości 150mm jest pochylony 40mm
|
auto const d = -fTexHeight1 / 3.75f; // krawężnik o wysokości 150mm jest pochylony 40mm
|
||||||
auto const max = fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości
|
auto const max = fTexRatio2 * texturelength; // test: szerokość proporcjonalna do długości
|
||||||
auto const map1l = (
|
auto const map1l = (
|
||||||
max > 0.f ?
|
max > 0.f ?
|
||||||
side / max :
|
side / max :
|
||||||
@@ -1741,24 +1748,24 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
||||||
// odcinka
|
// odcinka
|
||||||
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
|
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
|
||||||
Segment->RenderLoft( vertices, m_origin, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej
|
Segment->RenderLoft( vertices, m_origin, rpts1, -3, texturelength ); // tylko jeśli jest z prawej
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||||
Segment->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej
|
Segment->RenderLoft( vertices, m_origin, rpts2, -3, texturelength ); // tylko jeśli jest z lewej
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // pobocza zwykłe, brak przechyłki
|
else { // pobocza zwykłe, brak przechyłki
|
||||||
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
|
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
|
||||||
Segment->RenderLoft( vertices, m_origin, rpts1, 3, fTexLength );
|
Segment->RenderLoft( vertices, m_origin, rpts1, 3, texturelength );
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||||
Segment->RenderLoft( vertices, m_origin, rpts2, 3, fTexLength );
|
Segment->RenderLoft( vertices, m_origin, rpts2, 3, texturelength );
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
@@ -1818,7 +1825,8 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
||||||
if (m_material1 || m_material2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
if (m_material1 || m_material2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
||||||
{ // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100%
|
{ // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100%
|
||||||
auto const max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
|
auto const max = fTexRatio1 * texturelength; // test: szerokość proporcjonalna do długości
|
||||||
auto const map1 = max > 0.f ? fHTW / max : 0.5f; // obcięcie tekstury od strony 1
|
auto const map1 = max > 0.f ? fHTW / max : 0.5f; // obcięcie tekstury od strony 1
|
||||||
auto const map2 = max > 0.f ? fHTW2 / max : 0.5f; // obcięcie tekstury od strony 2
|
auto const map2 = max > 0.f ? fHTW2 / max : 0.5f; // obcięcie tekstury od strony 2
|
||||||
// if (iTrapezoid) //trapez albo przechyłki
|
// if (iTrapezoid) //trapez albo przechyłki
|
||||||
@@ -1848,6 +1856,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
// ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie w swoim czasie
|
// ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie w swoim czasie
|
||||||
if( m_material2 )
|
if( m_material2 )
|
||||||
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
|
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
|
||||||
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
gfx::basic_vertex
|
gfx::basic_vertex
|
||||||
rpts1[6],
|
rpts1[6],
|
||||||
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
||||||
@@ -1911,7 +1920,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
// mapowanie propocjonalne do szerokości chodnika
|
// mapowanie propocjonalne do szerokości chodnika
|
||||||
// krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy
|
// krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy
|
||||||
auto const d = -fTexHeight1 / 3.75f; // krawężnik o wysokości 150mm jest pochylony 40mm
|
auto const d = -fTexHeight1 / 3.75f; // krawężnik o wysokości 150mm jest pochylony 40mm
|
||||||
auto const max = fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości
|
auto const max = fTexRatio2 * texturelength; // test: szerokość proporcjonalna do długości
|
||||||
auto const map1l = (
|
auto const map1l = (
|
||||||
max > 0.f ?
|
max > 0.f ?
|
||||||
side / max :
|
side / max :
|
||||||
@@ -1991,22 +2000,22 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
if (SwitchExtension->iRoads == 4)
|
if (SwitchExtension->iRoads == 4)
|
||||||
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
|
||||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||||
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render );
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render );
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render );
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render );
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
@@ -2016,17 +2025,17 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
else {
|
else {
|
||||||
// punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe
|
// punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe
|
||||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||||
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4
|
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony)
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony)
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
@@ -2043,6 +2052,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( m_material1 ) {
|
if( m_material1 ) {
|
||||||
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
// jeśli podana tekstura nawierzchni
|
// jeśli podana tekstura nawierzchni
|
||||||
// we start with a vertex in the middle...
|
// we start with a vertex in the middle...
|
||||||
@@ -2054,8 +2064,8 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
glm::vec3{ 0.0f, 1.0f, 0.0f },
|
glm::vec3{ 0.0f, 1.0f, 0.0f },
|
||||||
glm::vec2{ 0.5f, 0.5f } );
|
glm::vec2{ 0.5f, 0.5f } );
|
||||||
// ...and add one extra vertex to close the fan...
|
// ...and add one extra vertex to close the fan...
|
||||||
u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + m_origin.x ) / fTexLength;
|
u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + m_origin.x ) / texturelength;
|
||||||
v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + m_origin.z ) / ( fTexRatio1 * fTexLength );
|
v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + m_origin.z ) / ( fTexRatio1 * texturelength );
|
||||||
vertices.emplace_back(
|
vertices.emplace_back(
|
||||||
glm::vec3 {
|
glm::vec3 {
|
||||||
SwitchExtension->vPoints[ 0 ].x,
|
SwitchExtension->vPoints[ 0 ].x,
|
||||||
@@ -2069,8 +2079,8 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
// ...then draw the precalculated rest
|
// ...then draw the precalculated rest
|
||||||
for (int i = pointcount + SwitchExtension->iRoads - 1; i >= 0; --i) {
|
for (int i = pointcount + SwitchExtension->iRoads - 1; i >= 0; --i) {
|
||||||
// mapowanie we współrzędnych scenerii
|
// mapowanie we współrzędnych scenerii
|
||||||
u = ( SwitchExtension->vPoints[ i ].x - oxz.x + m_origin.x ) / fTexLength;
|
u = ( SwitchExtension->vPoints[ i ].x - oxz.x + m_origin.x ) / texturelength;
|
||||||
v = ( SwitchExtension->vPoints[ i ].z - oxz.z + m_origin.z ) / ( fTexRatio1 * fTexLength );
|
v = ( SwitchExtension->vPoints[ i ].z - oxz.z + m_origin.z ) / ( fTexRatio1 * texturelength );
|
||||||
vertices.emplace_back(
|
vertices.emplace_back(
|
||||||
glm::vec3 {
|
glm::vec3 {
|
||||||
SwitchExtension->vPoints[ i ].x,
|
SwitchExtension->vPoints[ i ].x,
|
||||||
@@ -2522,28 +2532,32 @@ TTrack * TTrack::RaAnimate()
|
|||||||
if (SwitchExtension->RightSwitch)
|
if (SwitchExtension->RightSwitch)
|
||||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||||
if( m_material1 ) {
|
if( m_material1 ) {
|
||||||
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
// left blade
|
// left blade
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, SwitchExtension->fOffset2 );
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, SwitchExtension->fOffset2 );
|
||||||
GfxRenderer.Replace( vertices, Geometry1[ 2 ], GL_TRIANGLE_STRIP );
|
GfxRenderer.Replace( vertices, Geometry1[ 2 ], GL_TRIANGLE_STRIP );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
if( m_material2 ) {
|
if( m_material2 ) {
|
||||||
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
// right blade
|
// right blade
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 );
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 );
|
||||||
GfxRenderer.Replace( vertices, Geometry2[ 2 ], GL_TRIANGLE_STRIP );
|
GfxRenderer.Replace( vertices, Geometry2[ 2 ], GL_TRIANGLE_STRIP );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // lewa działa lepiej niż prawa
|
else { // lewa działa lepiej niż prawa
|
||||||
if( m_material1 ) {
|
if( m_material1 ) {
|
||||||
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
// right blade
|
// right blade
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 );
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 );
|
||||||
GfxRenderer.Replace( vertices, Geometry1[ 2 ], GL_TRIANGLE_STRIP );
|
GfxRenderer.Replace( vertices, Geometry1[ 2 ], GL_TRIANGLE_STRIP );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
if( m_material2 ) {
|
if( m_material2 ) {
|
||||||
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
// left blade
|
// left blade
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 );
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 );
|
||||||
GfxRenderer.Replace( vertices, Geometry2[ 2 ], GL_TRIANGLE_STRIP );
|
GfxRenderer.Replace( vertices, Geometry2[ 2 ], GL_TRIANGLE_STRIP );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
@@ -2883,6 +2897,19 @@ TTrack::export_as_text_( std::ostream &Output ) const {
|
|||||||
<< "\n";
|
<< "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
TTrack::texture_length( material_handle const Material ) {
|
||||||
|
|
||||||
|
if( Material == null_handle ) {
|
||||||
|
return fTexLength;
|
||||||
|
}
|
||||||
|
auto const texturelength { GfxRenderer.Material( Material ).size.y };
|
||||||
|
return (
|
||||||
|
texturelength < 0.f ?
|
||||||
|
fTexLength :
|
||||||
|
texturelength );
|
||||||
|
}
|
||||||
|
|
||||||
void TTrack::MovedUp1(float const dh)
|
void TTrack::MovedUp1(float const dh)
|
||||||
{ // poprawienie przechyłki wymaga wydłużenia podsypki
|
{ // poprawienie przechyłki wymaga wydłużenia podsypki
|
||||||
fTexHeight1 += dh;
|
fTexHeight1 += dh;
|
||||||
|
|||||||
3
Track.h
3
Track.h
@@ -299,7 +299,8 @@ private:
|
|||||||
void deserialize_( std::istream &Input );
|
void deserialize_( std::istream &Input );
|
||||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||||
void export_as_text_( std::ostream &Output ) const;
|
void export_as_text_( std::ostream &Output ) const;
|
||||||
|
// returns texture length for specified material
|
||||||
|
float texture_length( material_handle const Material );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
292
Train.cpp
292
Train.cpp
@@ -28,7 +28,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "DynObj.h"
|
#include "DynObj.h"
|
||||||
#include "mtable.h"
|
#include "mtable.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
#include "sound.h"
|
#include "application.h"
|
||||||
|
|
||||||
namespace input {
|
namespace input {
|
||||||
|
|
||||||
@@ -454,6 +454,7 @@ PyObject *TTrain::GetTrainState() {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyDict_SetItemString( dict, "name", PyGetString( DynamicObject->asName.c_str() ) );
|
||||||
PyDict_SetItemString( dict, "cab", PyGetInt( mover->ActiveCab ) );
|
PyDict_SetItemString( dict, "cab", PyGetInt( mover->ActiveCab ) );
|
||||||
// basic systems state data
|
// basic systems state data
|
||||||
PyDict_SetItemString( dict, "battery", PyGetBool( mvControlled->Battery ) );
|
PyDict_SetItemString( dict, "battery", PyGetBool( mvControlled->Battery ) );
|
||||||
@@ -482,6 +483,8 @@ PyObject *TTrain::GetTrainState() {
|
|||||||
else
|
else
|
||||||
bPN = false;
|
bPN = false;
|
||||||
PyDict_SetItemString( dict, "indir_brake", PyGetBool( bPN ) );
|
PyDict_SetItemString( dict, "indir_brake", PyGetBool( bPN ) );
|
||||||
|
PyDict_SetItemString( dict, "brake_delay_flag", PyGetInt( mvControlled->BrakeDelayFlag ));
|
||||||
|
PyDict_SetItemString( dict, "brake_op_mode_flag", PyGetInt( mvControlled->BrakeOpModeFlag ));
|
||||||
// other controls
|
// other controls
|
||||||
PyDict_SetItemString( dict, "ca", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) );
|
PyDict_SetItemString( dict, "ca", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) );
|
||||||
PyDict_SetItemString( dict, "shp", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ) );
|
PyDict_SetItemString( dict, "shp", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ) );
|
||||||
@@ -532,9 +535,9 @@ PyObject *TTrain::GetTrainState() {
|
|||||||
PyDict_SetItemString( dict, "unit_no", PyGetInt( iUnitNo ) );
|
PyDict_SetItemString( dict, "unit_no", PyGetInt( iUnitNo ) );
|
||||||
|
|
||||||
for( int i = 0; i < 20; i++ ) {
|
for( int i = 0; i < 20; i++ ) {
|
||||||
PyDict_SetItemString( dict, ( "doors_" + std::to_string( i + 1 ) ).c_str(), PyGetFloatS( bDoors[ i ][ 0 ] ) );
|
PyDict_SetItemString( dict, ( "doors_" + std::to_string( i + 1 ) ).c_str(), PyGetBool( bDoors[ i ][ 0 ] ) );
|
||||||
PyDict_SetItemString( dict, ( "doors_r_" + std::to_string( i + 1 ) ).c_str(), PyGetFloatS( bDoors[ i ][ 1 ] ) );
|
PyDict_SetItemString( dict, ( "doors_r_" + std::to_string( i + 1 ) ).c_str(), PyGetBool( bDoors[ i ][ 1 ] ) );
|
||||||
PyDict_SetItemString( dict, ( "doors_l_" + std::to_string( i + 1 ) ).c_str(), PyGetFloatS( bDoors[ i ][ 2 ] ) );
|
PyDict_SetItemString( dict, ( "doors_l_" + std::to_string( i + 1 ) ).c_str(), PyGetBool( bDoors[ i ][ 2 ] ) );
|
||||||
PyDict_SetItemString( dict, ( "doors_no_" + std::to_string( i + 1 ) ).c_str(), PyGetInt( iDoorNo[ i ] ) );
|
PyDict_SetItemString( dict, ( "doors_no_" + std::to_string( i + 1 ) ).c_str(), PyGetInt( iDoorNo[ i ] ) );
|
||||||
PyDict_SetItemString( dict, ( "code_" + std::to_string( i + 1 ) ).c_str(), PyGetString( ( std::to_string( iUnits[ i ] ) + cCode[ i ] ).c_str() ) );
|
PyDict_SetItemString( dict, ( "code_" + std::to_string( i + 1 ) ).c_str(), PyGetString( ( std::to_string( iUnits[ i ] ) + cCode[ i ] ).c_str() ) );
|
||||||
PyDict_SetItemString( dict, ( "car_name" + std::to_string( i + 1 ) ).c_str(), PyGetString( asCarName[ i ].c_str() ) );
|
PyDict_SetItemString( dict, ( "car_name" + std::to_string( i + 1 ) ).c_str(), PyGetString( asCarName[ i ].c_str() ) );
|
||||||
@@ -1327,8 +1330,10 @@ void TTrain::OnCommand_trainbrakeoperationmodeincrease(TTrain *Train, command_da
|
|||||||
// audio feedback
|
// audio feedback
|
||||||
Train->dsbPneumaticSwitch.play();
|
Train->dsbPneumaticSwitch.play();
|
||||||
// visual feedback
|
// visual feedback
|
||||||
// NOTE: there's no button for brake operation mode switch
|
Train->ggBrakeOperationModeCtrl.UpdateValue(
|
||||||
// TBD, TODO: add brake operation mode switch?
|
Train->mvOccupied->BrakeOpModeFlag > 0 ?
|
||||||
|
std::log2( Train->mvOccupied->BrakeOpModeFlag ) :
|
||||||
|
0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1343,8 +1348,10 @@ void TTrain::OnCommand_trainbrakeoperationmodedecrease(TTrain *Train, command_da
|
|||||||
// audio feedback
|
// audio feedback
|
||||||
Train->dsbPneumaticSwitch.play();
|
Train->dsbPneumaticSwitch.play();
|
||||||
// visual feedback
|
// visual feedback
|
||||||
// NOTE: there's no button for brake operation mode switch
|
Train->ggBrakeOperationModeCtrl.UpdateValue(
|
||||||
// TBD, TODO: add brake operation mode switch?
|
Train->mvOccupied->BrakeOpModeFlag > 0 ?
|
||||||
|
std::log2( Train->mvOccupied->BrakeOpModeFlag ) :
|
||||||
|
0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2116,8 +2123,17 @@ void TTrain::OnCommand_linebreakerclose( TTrain *Train, command_data const &Comm
|
|||||||
|
|
||||||
void TTrain::OnCommand_fuelpumptoggle( TTrain *Train, command_data const &Command ) {
|
void TTrain::OnCommand_fuelpumptoggle( TTrain *Train, command_data const &Command ) {
|
||||||
|
|
||||||
if( Command.action == GLFW_PRESS ) {
|
if( Command.action == GLFW_REPEAT ) { return; }
|
||||||
// only reacting to press, so the switch doesn't flip back and forth if key is held down
|
|
||||||
|
if( Train->ggFuelPumpButton.type() == TGaugeType::push ) {
|
||||||
|
// impulse switch
|
||||||
|
// currently there's no off button so we always try to turn it on
|
||||||
|
OnCommand_fuelpumpenable( Train, Command );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// two-state switch
|
||||||
|
if( Command.action == GLFW_RELEASE ) { return; }
|
||||||
|
|
||||||
if( false == Train->mvControlled->FuelPump.is_enabled ) {
|
if( false == Train->mvControlled->FuelPump.is_enabled ) {
|
||||||
// turn on
|
// turn on
|
||||||
OnCommand_fuelpumpenable( Train, Command );
|
OnCommand_fuelpumpenable( Train, Command );
|
||||||
@@ -2131,32 +2147,65 @@ void TTrain::OnCommand_fuelpumptoggle( TTrain *Train, command_data const &Comman
|
|||||||
|
|
||||||
void TTrain::OnCommand_fuelpumpenable( TTrain *Train, command_data const &Command ) {
|
void TTrain::OnCommand_fuelpumpenable( TTrain *Train, command_data const &Command ) {
|
||||||
|
|
||||||
|
if( Command.action == GLFW_REPEAT ) { return; }
|
||||||
|
|
||||||
|
if( Train->ggFuelPumpButton.type() == TGaugeType::push ) {
|
||||||
|
// impulse switch
|
||||||
if( Command.action == GLFW_PRESS ) {
|
if( Command.action == GLFW_PRESS ) {
|
||||||
// visual feedback
|
// visual feedback
|
||||||
Train->ggFuelPumpButton.UpdateValue( 1.0, Train->dsbSwitch );
|
Train->ggFuelPumpButton.UpdateValue( 1.0, Train->dsbSwitch );
|
||||||
|
|
||||||
if( true == Train->mvControlled->FuelPump.is_enabled ) { return; } // already enabled
|
|
||||||
|
|
||||||
Train->mvControlled->FuelPumpSwitch( true );
|
Train->mvControlled->FuelPumpSwitch( true );
|
||||||
}
|
}
|
||||||
|
else if( Command.action == GLFW_RELEASE ) {
|
||||||
|
// visual feedback
|
||||||
|
Train->ggFuelPumpButton.UpdateValue( 0.0, Train->dsbSwitch );
|
||||||
|
Train->mvControlled->FuelPumpSwitch( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// two-state switch, only cares about press events
|
||||||
|
if( Command.action == GLFW_PRESS ) {
|
||||||
|
// visual feedback
|
||||||
|
Train->ggFuelPumpButton.UpdateValue( 1.0, Train->dsbSwitch );
|
||||||
|
Train->mvControlled->FuelPumpSwitch( true );
|
||||||
|
Train->mvControlled->FuelPumpSwitchOff( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTrain::OnCommand_fuelpumpdisable( TTrain *Train, command_data const &Command ) {
|
void TTrain::OnCommand_fuelpumpdisable( TTrain *Train, command_data const &Command ) {
|
||||||
|
|
||||||
|
if( Command.action == GLFW_REPEAT ) { return; }
|
||||||
|
|
||||||
|
if( Train->ggFuelPumpButton.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 ) {
|
if( Command.action == GLFW_PRESS ) {
|
||||||
// visual feedback
|
// visual feedback
|
||||||
Train->ggFuelPumpButton.UpdateValue( 0.0, Train->dsbSwitch );
|
Train->ggFuelPumpButton.UpdateValue( 0.0, Train->dsbSwitch );
|
||||||
|
|
||||||
if( false == Train->mvControlled->FuelPump.is_enabled ) { return; } // already disabled
|
|
||||||
|
|
||||||
Train->mvControlled->FuelPumpSwitch( false );
|
Train->mvControlled->FuelPumpSwitch( false );
|
||||||
|
Train->mvControlled->FuelPumpSwitchOff( true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTrain::OnCommand_oilpumptoggle( TTrain *Train, command_data const &Command ) {
|
void TTrain::OnCommand_oilpumptoggle( TTrain *Train, command_data const &Command ) {
|
||||||
|
|
||||||
if( Command.action == GLFW_PRESS ) {
|
if( Command.action == GLFW_REPEAT ) { return; }
|
||||||
// only reacting to press, so the switch doesn't flip back and forth if key is held down
|
|
||||||
|
if( Train->ggOilPumpButton.type() == TGaugeType::push ) {
|
||||||
|
// impulse switch
|
||||||
|
// currently there's no off button so we always try to turn it on
|
||||||
|
OnCommand_oilpumpenable( Train, Command );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// two-state switch
|
||||||
|
if( Command.action == GLFW_RELEASE ) { return; }
|
||||||
|
|
||||||
if( false == Train->mvControlled->OilPump.is_enabled ) {
|
if( false == Train->mvControlled->OilPump.is_enabled ) {
|
||||||
// turn on
|
// turn on
|
||||||
OnCommand_oilpumpenable( Train, Command );
|
OnCommand_oilpumpenable( Train, Command );
|
||||||
@@ -2170,25 +2219,49 @@ void TTrain::OnCommand_oilpumptoggle( TTrain *Train, command_data const &Command
|
|||||||
|
|
||||||
void TTrain::OnCommand_oilpumpenable( TTrain *Train, command_data const &Command ) {
|
void TTrain::OnCommand_oilpumpenable( TTrain *Train, command_data const &Command ) {
|
||||||
|
|
||||||
|
if( Command.action == GLFW_REPEAT ) { return; }
|
||||||
|
|
||||||
|
if( Train->ggOilPumpButton.type() == TGaugeType::push ) {
|
||||||
|
// impulse switch
|
||||||
if( Command.action == GLFW_PRESS ) {
|
if( Command.action == GLFW_PRESS ) {
|
||||||
// visual feedback
|
// visual feedback
|
||||||
Train->ggOilPumpButton.UpdateValue( 1.0, Train->dsbSwitch );
|
Train->ggOilPumpButton.UpdateValue( 1.0, Train->dsbSwitch );
|
||||||
|
|
||||||
if( true == Train->mvControlled->OilPump.is_enabled ) { return; } // already enabled
|
|
||||||
|
|
||||||
Train->mvControlled->OilPumpSwitch( true );
|
Train->mvControlled->OilPumpSwitch( true );
|
||||||
}
|
}
|
||||||
|
else if( Command.action == GLFW_RELEASE ) {
|
||||||
|
// visual feedback
|
||||||
|
Train->ggOilPumpButton.UpdateValue( 0.0, Train->dsbSwitch );
|
||||||
|
Train->mvControlled->OilPumpSwitch( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// two-state switch, only cares about press events
|
||||||
|
if( Command.action == GLFW_PRESS ) {
|
||||||
|
// visual feedback
|
||||||
|
Train->ggOilPumpButton.UpdateValue( 1.0, Train->dsbSwitch );
|
||||||
|
Train->mvControlled->OilPumpSwitch( true );
|
||||||
|
Train->mvControlled->OilPumpSwitchOff( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTrain::OnCommand_oilpumpdisable( TTrain *Train, command_data const &Command ) {
|
void TTrain::OnCommand_oilpumpdisable( TTrain *Train, command_data const &Command ) {
|
||||||
|
|
||||||
|
if( Command.action == GLFW_REPEAT ) { return; }
|
||||||
|
|
||||||
|
if( Train->ggOilPumpButton.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 ) {
|
if( Command.action == GLFW_PRESS ) {
|
||||||
// visual feedback
|
// visual feedback
|
||||||
Train->ggOilPumpButton.UpdateValue( 0.0, Train->dsbSwitch );
|
Train->ggOilPumpButton.UpdateValue( 0.0, Train->dsbSwitch );
|
||||||
|
|
||||||
if( false == Train->mvControlled->OilPump.is_enabled ) { return; } // already disabled
|
|
||||||
|
|
||||||
Train->mvControlled->OilPumpSwitch( false );
|
Train->mvControlled->OilPumpSwitch( false );
|
||||||
|
Train->mvControlled->OilPumpSwitchOff( true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2311,8 +2384,17 @@ void TTrain::OnCommand_waterpumpbreakeropen( TTrain *Train, command_data const &
|
|||||||
|
|
||||||
void TTrain::OnCommand_waterpumptoggle( TTrain *Train, command_data const &Command ) {
|
void TTrain::OnCommand_waterpumptoggle( TTrain *Train, command_data const &Command ) {
|
||||||
|
|
||||||
if( Command.action == GLFW_PRESS ) {
|
if( Command.action == GLFW_REPEAT ) { return; }
|
||||||
// only reacting to press, so the switch doesn't flip back and forth if key is held down
|
|
||||||
|
if( Train->ggWaterPumpButton.type() == TGaugeType::push ) {
|
||||||
|
// impulse switch
|
||||||
|
// currently there's no off button so we always try to turn it on
|
||||||
|
OnCommand_waterpumpenable( Train, Command );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// two-state switch
|
||||||
|
if( Command.action == GLFW_RELEASE ) { return; }
|
||||||
|
|
||||||
if( false == Train->mvControlled->WaterPump.is_enabled ) {
|
if( false == Train->mvControlled->WaterPump.is_enabled ) {
|
||||||
// turn on
|
// turn on
|
||||||
OnCommand_waterpumpenable( Train, Command );
|
OnCommand_waterpumpenable( Train, Command );
|
||||||
@@ -2326,25 +2408,49 @@ void TTrain::OnCommand_waterpumptoggle( TTrain *Train, command_data const &Comma
|
|||||||
|
|
||||||
void TTrain::OnCommand_waterpumpenable( TTrain *Train, command_data const &Command ) {
|
void TTrain::OnCommand_waterpumpenable( TTrain *Train, command_data const &Command ) {
|
||||||
|
|
||||||
|
if( Command.action == GLFW_REPEAT ) { return; }
|
||||||
|
|
||||||
|
if( Train->ggWaterPumpButton.type() == TGaugeType::push ) {
|
||||||
|
// impulse switch
|
||||||
if( Command.action == GLFW_PRESS ) {
|
if( Command.action == GLFW_PRESS ) {
|
||||||
// visual feedback
|
// visual feedback
|
||||||
Train->ggWaterPumpButton.UpdateValue( 1.0, Train->dsbSwitch );
|
Train->ggWaterPumpButton.UpdateValue( 1.0, Train->dsbSwitch );
|
||||||
|
|
||||||
if( true == Train->mvControlled->WaterPump.is_enabled ) { return; } // already enabled
|
|
||||||
|
|
||||||
Train->mvControlled->WaterPumpSwitch( true );
|
Train->mvControlled->WaterPumpSwitch( true );
|
||||||
}
|
}
|
||||||
|
else if( Command.action == GLFW_RELEASE ) {
|
||||||
|
// visual feedback
|
||||||
|
Train->ggWaterPumpButton.UpdateValue( 0.0, Train->dsbSwitch );
|
||||||
|
Train->mvControlled->WaterPumpSwitch( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// two-state switch, only cares about press events
|
||||||
|
if( Command.action == GLFW_PRESS ) {
|
||||||
|
// visual feedback
|
||||||
|
Train->ggWaterPumpButton.UpdateValue( 1.0, Train->dsbSwitch );
|
||||||
|
Train->mvControlled->WaterPumpSwitch( true );
|
||||||
|
Train->mvControlled->WaterPumpSwitchOff( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTrain::OnCommand_waterpumpdisable( TTrain *Train, command_data const &Command ) {
|
void TTrain::OnCommand_waterpumpdisable( TTrain *Train, command_data const &Command ) {
|
||||||
|
|
||||||
|
if( Command.action == GLFW_REPEAT ) { return; }
|
||||||
|
|
||||||
|
if( Train->ggWaterPumpButton.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 ) {
|
if( Command.action == GLFW_PRESS ) {
|
||||||
// visual feedback
|
// visual feedback
|
||||||
Train->ggWaterPumpButton.UpdateValue( 0.0, Train->dsbSwitch );
|
Train->ggWaterPumpButton.UpdateValue( 0.0, Train->dsbSwitch );
|
||||||
|
|
||||||
if( false == Train->mvControlled->WaterPump.is_enabled ) { return; } // already disabled
|
|
||||||
|
|
||||||
Train->mvControlled->WaterPumpSwitch( false );
|
Train->mvControlled->WaterPumpSwitch( false );
|
||||||
|
Train->mvControlled->WaterPumpSwitchOff( true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4542,31 +4648,14 @@ void TTrain::UpdateMechPosition(double dt)
|
|||||||
2 :
|
2 :
|
||||||
DynamicObject->MoverParameters->ActiveCab );
|
DynamicObject->MoverParameters->ActiveCab );
|
||||||
if( !DebugModeFlag ) { // sprawdzaj więzy //Ra: nie tu!
|
if( !DebugModeFlag ) { // sprawdzaj więzy //Ra: nie tu!
|
||||||
if( pMechPosition.x < Cabine[ iCabn ].CabPos1.x )
|
|
||||||
pMechPosition.x = Cabine[ iCabn ].CabPos1.x;
|
|
||||||
if( pMechPosition.x > Cabine[ iCabn ].CabPos2.x )
|
|
||||||
pMechPosition.x = Cabine[ iCabn ].CabPos2.x;
|
|
||||||
if( pMechPosition.z < Cabine[ iCabn ].CabPos1.z )
|
|
||||||
pMechPosition.z = Cabine[ iCabn ].CabPos1.z;
|
|
||||||
if( pMechPosition.z > Cabine[ iCabn ].CabPos2.z )
|
|
||||||
pMechPosition.z = Cabine[ iCabn ].CabPos2.z;
|
|
||||||
if( pMechPosition.y > Cabine[ iCabn ].CabPos1.y + 1.8 )
|
|
||||||
pMechPosition.y = Cabine[ iCabn ].CabPos1.y + 1.8;
|
|
||||||
if( pMechPosition.y < Cabine[ iCabn ].CabPos1.y + 0.5 )
|
|
||||||
pMechPosition.y = Cabine[ iCabn ].CabPos2.y + 0.5;
|
|
||||||
|
|
||||||
if( pMechOffset.x < Cabine[ iCabn ].CabPos1.x )
|
pMechPosition.x = clamp( pMechPosition.x, Cabine[ iCabn ].CabPos1.x, Cabine[ iCabn ].CabPos2.x );
|
||||||
pMechOffset.x = Cabine[ iCabn ].CabPos1.x;
|
pMechPosition.y = clamp( pMechPosition.y, Cabine[ iCabn ].CabPos1.y + 0.5, Cabine[ iCabn ].CabPos2.y + 1.8 );
|
||||||
if( pMechOffset.x > Cabine[ iCabn ].CabPos2.x )
|
pMechPosition.z = clamp( pMechPosition.z, Cabine[ iCabn ].CabPos1.z, Cabine[ iCabn ].CabPos2.z );
|
||||||
pMechOffset.x = Cabine[ iCabn ].CabPos2.x;
|
|
||||||
if( pMechOffset.z < Cabine[ iCabn ].CabPos1.z )
|
pMechOffset.x = clamp( pMechOffset.x, Cabine[ iCabn ].CabPos1.x, Cabine[ iCabn ].CabPos2.x );
|
||||||
pMechOffset.z = Cabine[ iCabn ].CabPos1.z;
|
pMechOffset.y = clamp( pMechOffset.y, Cabine[ iCabn ].CabPos1.y + 0.5, Cabine[ iCabn ].CabPos2.y + 1.8 );
|
||||||
if( pMechOffset.z > Cabine[ iCabn ].CabPos2.z )
|
pMechOffset.z = clamp( pMechOffset.z, Cabine[ iCabn ].CabPos1.z, Cabine[ iCabn ].CabPos2.z );
|
||||||
pMechOffset.z = Cabine[ iCabn ].CabPos2.z;
|
|
||||||
if( pMechOffset.y > Cabine[ iCabn ].CabPos1.y + 1.8 )
|
|
||||||
pMechOffset.y = Cabine[ iCabn ].CabPos1.y + 1.8;
|
|
||||||
if( pMechOffset.y < Cabine[ iCabn ].CabPos1.y + 0.5 )
|
|
||||||
pMechOffset.y = Cabine[ iCabn ].CabPos2.y + 0.5;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -4706,7 +4795,6 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tor = DynamicObject->GetTrack(); // McZapkie-180203
|
|
||||||
// McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol
|
// McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol
|
||||||
auto const maxtacho { 3.0 };
|
auto const maxtacho { 3.0 };
|
||||||
fTachoVelocity = static_cast<float>( std::min( std::abs(11.31 * mvControlled->WheelDiameter * mvControlled->nrot), mvControlled->Vmax * 1.05) );
|
fTachoVelocity = static_cast<float>( std::min( std::abs(11.31 * mvControlled->WheelDiameter * mvControlled->nrot), mvControlled->Vmax * 1.05) );
|
||||||
@@ -5145,14 +5233,13 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
( true == mvControlled->ResistorsFlagCheck() )
|
( true == mvControlled->ResistorsFlagCheck() )
|
||||||
|| ( mvControlled->MainCtrlActualPos == 0 ) ); // do EU04
|
|| ( mvControlled->MainCtrlActualPos == 0 ) ); // do EU04
|
||||||
|
|
||||||
if( ( mvControlled->StLinFlag )
|
if( mvControlled->StLinFlag ) {
|
||||||
|| ( mvOccupied->BrakePress > 2.0 )
|
|
||||||
|| ( mvOccupied->PipePress < 3.6 ) ) {
|
|
||||||
// Ra: czy to jest udawanie działania styczników liniowych?
|
|
||||||
btLampkaStyczn.Turn( false );
|
btLampkaStyczn.Turn( false );
|
||||||
}
|
}
|
||||||
else if( mvOccupied->BrakePress < 1.0 )
|
else {
|
||||||
btLampkaStyczn.Turn( true ); // mozna prowadzic rozruch
|
// mozna prowadzic rozruch
|
||||||
|
btLampkaStyczn.Turn( mvOccupied->BrakePress < 1.0 );
|
||||||
|
}
|
||||||
if( ( ( TestFlag( mvControlled->Couplers[ side::rear ].CouplingFlag, coupling::control ) ) && ( mvControlled->CabNo == 1 ) )
|
if( ( ( TestFlag( mvControlled->Couplers[ side::rear ].CouplingFlag, coupling::control ) ) && ( mvControlled->CabNo == 1 ) )
|
||||||
|| ( ( TestFlag( mvControlled->Couplers[ side::front ].CouplingFlag, coupling::control ) ) && ( mvControlled->CabNo == -1 ) ) )
|
|| ( ( TestFlag( mvControlled->Couplers[ side::front ].CouplingFlag, coupling::control ) ) && ( mvControlled->CabNo == -1 ) ) )
|
||||||
btLampkaUkrotnienie.Turn( true );
|
btLampkaUkrotnienie.Turn( true );
|
||||||
@@ -5461,7 +5548,7 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
if (DynamicObject->Mechanik ?
|
if (DynamicObject->Mechanik ?
|
||||||
(DynamicObject->Mechanik->AIControllFlag ? false :
|
(DynamicObject->Mechanik->AIControllFlag ? false :
|
||||||
(Global.iFeedbackMode == 4 /*|| (Global.bMWDmasterEnable && Global.bMWDBreakEnable)*/)) :
|
(Global.iFeedbackMode == 4 /*|| (Global.bMWDmasterEnable && Global.bMWDBreakEnable)*/)) :
|
||||||
false) // nie blokujemy AI
|
false && Global.fCalibrateIn[ 0 ][ 1 ] != 0.0) // nie blokujemy AI
|
||||||
{ // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba
|
{ // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba
|
||||||
// Firleju: dlatego kasujemy i zastepujemy funkcją w Console
|
// Firleju: dlatego kasujemy i zastepujemy funkcją w Console
|
||||||
if (mvOccupied->BrakeHandle == TBrakeHandle::FV4a)
|
if (mvOccupied->BrakeHandle == TBrakeHandle::FV4a)
|
||||||
@@ -5494,7 +5581,7 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
if( ( DynamicObject->Mechanik != nullptr )
|
if( ( DynamicObject->Mechanik != nullptr )
|
||||||
&& ( false == DynamicObject->Mechanik->AIControllFlag ) // nie blokujemy AI
|
&& ( false == DynamicObject->Mechanik->AIControllFlag ) // nie blokujemy AI
|
||||||
&& ( mvOccupied->BrakeLocHandle == TBrakeHandle::FD1 )
|
&& ( mvOccupied->BrakeLocHandle == TBrakeHandle::FD1 )
|
||||||
&& ( ( Global.iFeedbackMode == 4 )
|
&& ( ( Global.iFeedbackMode == 4 ) && Global.fCalibrateIn[ 1 ][ 1 ] != 0.0
|
||||||
/*|| ( Global.bMWDmasterEnable && Global.bMWDBreakEnable )*/ ) ) {
|
/*|| ( Global.bMWDmasterEnable && Global.bMWDBreakEnable )*/ ) ) {
|
||||||
// Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba
|
// Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba
|
||||||
// Firleju: dlatego kasujemy i zastepujemy funkcją w Console
|
// Firleju: dlatego kasujemy i zastepujemy funkcją w Console
|
||||||
@@ -5521,6 +5608,7 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
ggBrakeProfileCtrl.Update();
|
ggBrakeProfileCtrl.Update();
|
||||||
ggBrakeProfileG.Update();
|
ggBrakeProfileG.Update();
|
||||||
ggBrakeProfileR.Update();
|
ggBrakeProfileR.Update();
|
||||||
|
ggBrakeOperationModeCtrl.Update();
|
||||||
ggMaxCurrentCtrl.Update();
|
ggMaxCurrentCtrl.Update();
|
||||||
// NBMX wrzesien 2003 - drzwi
|
// NBMX wrzesien 2003 - drzwi
|
||||||
ggDoorLeftButton.Update();
|
ggDoorLeftButton.Update();
|
||||||
@@ -5628,7 +5716,6 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
ggFuelPumpButton.Update();
|
ggFuelPumpButton.Update();
|
||||||
ggOilPumpButton.Update();
|
ggOilPumpButton.Update();
|
||||||
//------
|
//------
|
||||||
pyScreens.update();
|
|
||||||
}
|
}
|
||||||
// wyprowadzenie sygnałów dla haslera na PoKeys (zaznaczanie na taśmie)
|
// wyprowadzenie sygnałów dla haslera na PoKeys (zaznaczanie na taśmie)
|
||||||
btHaslerBrakes.Turn(DynamicObject->MoverParameters->BrakePress > 0.4); // ciśnienie w cylindrach
|
btHaslerBrakes.Turn(DynamicObject->MoverParameters->BrakePress > 0.4); // ciśnienie w cylindrach
|
||||||
@@ -5698,8 +5785,8 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
// NOTE: disabled while switch state isn't preserved while moving between compartments
|
|
||||||
// check whether we should raise the pantographs, based on volume in pantograph tank
|
// check whether we should raise the pantographs, based on volume in pantograph tank
|
||||||
|
// NOTE: disabled while switch state isn't preserved while moving between compartments
|
||||||
if( mvControlled->PantPress > (
|
if( mvControlled->PantPress > (
|
||||||
mvControlled->TrainType == dt_EZT ?
|
mvControlled->TrainType == dt_EZT ?
|
||||||
2.4 :
|
2.4 :
|
||||||
@@ -5714,7 +5801,15 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
// screens
|
||||||
|
fScreenTimer += Deltatime;
|
||||||
|
if( ( fScreenTimer > Global.PythonScreenUpdateRate * 0.001f )
|
||||||
|
&& ( false == FreeFlyModeFlag ) ) { // don't bother if we're outside
|
||||||
|
fScreenTimer = 0.f;
|
||||||
|
for( auto const &screen : m_screens ) {
|
||||||
|
Application.request( { screen.first, GetTrainState(), screen.second } );
|
||||||
|
}
|
||||||
|
}
|
||||||
// sounds
|
// sounds
|
||||||
update_sounds( Deltatime );
|
update_sounds( Deltatime );
|
||||||
|
|
||||||
@@ -5875,7 +5970,6 @@ TTrain::update_sounds( double const Deltatime ) {
|
|||||||
dsbSlipAlarm.stop();
|
dsbSlipAlarm.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// szum w czasie jazdy
|
// szum w czasie jazdy
|
||||||
if( ( false == FreeFlyModeFlag )
|
if( ( false == FreeFlyModeFlag )
|
||||||
&& ( false == Global.CabWindowOpen )
|
&& ( false == Global.CabWindowOpen )
|
||||||
@@ -5894,6 +5988,15 @@ TTrain::update_sounds( double const Deltatime ) {
|
|||||||
&& ( IsHunting ) ) {
|
&& ( IsHunting ) ) {
|
||||||
|
|
||||||
update_sounds_runningnoise( rsHuntingNoise );
|
update_sounds_runningnoise( rsHuntingNoise );
|
||||||
|
// modify calculated sound volume by hunting amount
|
||||||
|
auto const huntingamount =
|
||||||
|
interpolate(
|
||||||
|
0.0, 1.0,
|
||||||
|
clamp(
|
||||||
|
( mvOccupied->Vel - HuntingShake.fadein_begin ) / ( HuntingShake.fadein_end - HuntingShake.fadein_begin ),
|
||||||
|
0.0, 1.0 ) );
|
||||||
|
|
||||||
|
rsHuntingNoise.gain( rsHuntingNoise.gain() * huntingamount );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// don't play the optional ending sound if the listener switches views
|
// don't play the optional ending sound if the listener switches views
|
||||||
@@ -6273,6 +6376,8 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
|
|||||||
bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||||
{
|
{
|
||||||
m_controlmapper.clear();
|
m_controlmapper.clear();
|
||||||
|
// clear python screens
|
||||||
|
m_screens.clear();
|
||||||
// reset sound positions and owner
|
// reset sound positions and owner
|
||||||
auto const nullvector { glm::vec3() };
|
auto const nullvector { glm::vec3() };
|
||||||
std::vector<sound_source *> sounds = {
|
std::vector<sound_source *> sounds = {
|
||||||
@@ -6290,9 +6395,6 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
|||||||
pMechViewAngle = { 0.0, 0.0 };
|
pMechViewAngle = { 0.0, 0.0 };
|
||||||
Global.pCamera.Pitch = pMechViewAngle.x;
|
Global.pCamera.Pitch = pMechViewAngle.x;
|
||||||
Global.pCamera.Yaw = pMechViewAngle.y;
|
Global.pCamera.Yaw = pMechViewAngle.y;
|
||||||
|
|
||||||
pyScreens.reset(this);
|
|
||||||
pyScreens.setLookupPath(DynamicObject->asBaseDir);
|
|
||||||
bool parse = false;
|
bool parse = false;
|
||||||
int cabindex = 0;
|
int cabindex = 0;
|
||||||
DynamicObject->mdKabina = NULL; // likwidacja wskaźnika na dotychczasową kabinę
|
DynamicObject->mdKabina = NULL; // likwidacja wskaźnika na dotychczasową kabinę
|
||||||
@@ -6488,9 +6590,32 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
|||||||
// matched the token, grab the next one
|
// matched the token, grab the next one
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// TODO: add "pydestination:"
|
||||||
else if (token == "pyscreen:")
|
else if (token == "pyscreen:")
|
||||||
{
|
{
|
||||||
pyScreens.init(parser, DynamicObject->mdKabina, DynamicObject->name(), NewCabNo);
|
std::string submodelname, renderername;
|
||||||
|
parser.getTokens( 2 );
|
||||||
|
parser
|
||||||
|
>> submodelname
|
||||||
|
>> renderername;
|
||||||
|
|
||||||
|
auto const *submodel { DynamicObject->mdKabina->GetFromName( submodelname ) };
|
||||||
|
if( submodel == nullptr ) {
|
||||||
|
WriteLog( "Python Screen: submodel " + submodelname + " not found - Ignoring screen" );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto const material { submodel->GetMaterial() };
|
||||||
|
if( material <= 0 ) {
|
||||||
|
// sub model nie posiada tekstury lub tekstura wymienna - nie obslugiwana
|
||||||
|
WriteLog( "Python Screen: invalid texture id " + std::to_string( material ) + " - Ignoring screen" );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// record renderer and material binding for future update requests
|
||||||
|
m_screens.emplace_back(
|
||||||
|
( substr_path(renderername).empty() ? // supply vehicle folder as path if none is provided
|
||||||
|
DynamicObject->asBaseDir + renderername :
|
||||||
|
renderername ),
|
||||||
|
material );
|
||||||
}
|
}
|
||||||
// btLampkaUnknown.Init("unknown",mdKabina,false);
|
// btLampkaUnknown.Init("unknown",mdKabina,false);
|
||||||
} while (token != "");
|
} while (token != "");
|
||||||
@@ -6499,7 +6624,6 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
pyScreens.start();
|
|
||||||
if (DynamicObject->mdKabina)
|
if (DynamicObject->mdKabina)
|
||||||
{
|
{
|
||||||
// configure placement of sound emitters which aren't bound with any device model, and weren't placed manually
|
// configure placement of sound emitters which aren't bound with any device model, and weren't placed manually
|
||||||
@@ -6739,6 +6863,7 @@ void TTrain::clear_cab_controls()
|
|||||||
ggBrakeProfileCtrl.Clear();
|
ggBrakeProfileCtrl.Clear();
|
||||||
ggBrakeProfileG.Clear();
|
ggBrakeProfileG.Clear();
|
||||||
ggBrakeProfileR.Clear();
|
ggBrakeProfileR.Clear();
|
||||||
|
ggBrakeOperationModeCtrl.Clear();
|
||||||
ggMaxCurrentCtrl.Clear();
|
ggMaxCurrentCtrl.Clear();
|
||||||
ggMainOffButton.Clear();
|
ggMainOffButton.Clear();
|
||||||
ggMainOnButton.Clear();
|
ggMainOnButton.Clear();
|
||||||
@@ -7105,6 +7230,12 @@ void TTrain::set_cab_controls() {
|
|||||||
1.0 :
|
1.0 :
|
||||||
0.0 );
|
0.0 );
|
||||||
}
|
}
|
||||||
|
if (ggBrakeOperationModeCtrl.SubModel != nullptr) {
|
||||||
|
ggBrakeOperationModeCtrl.PutValue(
|
||||||
|
(mvOccupied->BrakeOpModeFlag > 0 ?
|
||||||
|
log2(mvOccupied->BrakeOpModeFlag) :
|
||||||
|
0));
|
||||||
|
}
|
||||||
// alarm chain
|
// alarm chain
|
||||||
ggAlarmChain.PutValue(
|
ggAlarmChain.PutValue(
|
||||||
mvControlled->AlarmChainFlag ?
|
mvControlled->AlarmChainFlag ?
|
||||||
@@ -7125,10 +7256,12 @@ void TTrain::set_cab_controls() {
|
|||||||
mvControlled->WaterPump.breaker ?
|
mvControlled->WaterPump.breaker ?
|
||||||
1.0 :
|
1.0 :
|
||||||
0.0 );
|
0.0 );
|
||||||
|
if( ggWaterPumpButton.type() != TGaugeType::push ) {
|
||||||
ggWaterPumpButton.PutValue(
|
ggWaterPumpButton.PutValue(
|
||||||
mvControlled->WaterPump.is_enabled ?
|
mvControlled->WaterPump.is_enabled ?
|
||||||
1.0 :
|
1.0 :
|
||||||
0.0 );
|
0.0 );
|
||||||
|
}
|
||||||
// water heater
|
// water heater
|
||||||
ggWaterHeaterBreakerButton.PutValue(
|
ggWaterHeaterBreakerButton.PutValue(
|
||||||
mvControlled->WaterHeater.breaker ?
|
mvControlled->WaterHeater.breaker ?
|
||||||
@@ -7143,15 +7276,19 @@ void TTrain::set_cab_controls() {
|
|||||||
1.0 :
|
1.0 :
|
||||||
0.0 );
|
0.0 );
|
||||||
// fuel pump
|
// fuel pump
|
||||||
|
if( ggFuelPumpButton.type() != TGaugeType::push ) {
|
||||||
ggFuelPumpButton.PutValue(
|
ggFuelPumpButton.PutValue(
|
||||||
mvControlled->FuelPump.is_enabled ?
|
mvControlled->FuelPump.is_enabled ?
|
||||||
1.0 :
|
1.0 :
|
||||||
0.0 );
|
0.0 );
|
||||||
|
}
|
||||||
// oil pump
|
// oil pump
|
||||||
|
if( ggOilPumpButton.type() != TGaugeType::push ) {
|
||||||
ggOilPumpButton.PutValue(
|
ggOilPumpButton.PutValue(
|
||||||
mvControlled->OilPump.is_enabled ?
|
mvControlled->OilPump.is_enabled ?
|
||||||
1.0 :
|
1.0 :
|
||||||
0.0 );
|
0.0 );
|
||||||
|
}
|
||||||
|
|
||||||
// we reset all indicators, as they're set during the update pass
|
// we reset all indicators, as they're set during the update pass
|
||||||
// TODO: when cleaning up break setting indicator state into a separate function, so we can reuse it
|
// TODO: when cleaning up break setting indicator state into a separate function, so we can reuse it
|
||||||
@@ -7296,6 +7433,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
|
|||||||
{ "brakeprofile_sw:", ggBrakeProfileCtrl },
|
{ "brakeprofile_sw:", ggBrakeProfileCtrl },
|
||||||
{ "brakeprofileg_sw:", ggBrakeProfileG },
|
{ "brakeprofileg_sw:", ggBrakeProfileG },
|
||||||
{ "brakeprofiler_sw:", ggBrakeProfileR },
|
{ "brakeprofiler_sw:", ggBrakeProfileR },
|
||||||
|
{ "brakeopmode_sw:", ggBrakeOperationModeCtrl },
|
||||||
{ "maxcurrent_sw:", ggMaxCurrentCtrl },
|
{ "maxcurrent_sw:", ggMaxCurrentCtrl },
|
||||||
{ "main_off_bt:", ggMainOffButton },
|
{ "main_off_bt:", ggMainOffButton },
|
||||||
{ "main_on_bt:", ggMainOnButton },
|
{ "main_on_bt:", ggMainOnButton },
|
||||||
@@ -7558,9 +7696,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
|
|||||||
if (Parser.getToken<std::string>() == "analog")
|
if (Parser.getToken<std::string>() == "analog")
|
||||||
{
|
{
|
||||||
// McZapkie-300302: zegarek
|
// McZapkie-300302: zegarek
|
||||||
ggClockSInd.Init(DynamicObject->mdKabina->GetFromName("ClockShand"), TGaugeType::gt_Rotate, 1.0/60.0);
|
ggClockSInd.Init(DynamicObject->mdKabina->GetFromName("ClockShand"), TGaugeAnimation::gt_Rotate, 1.0/60.0);
|
||||||
ggClockMInd.Init(DynamicObject->mdKabina->GetFromName("ClockMhand"), TGaugeType::gt_Rotate, 1.0/60.0);
|
ggClockMInd.Init(DynamicObject->mdKabina->GetFromName("ClockMhand"), TGaugeAnimation::gt_Rotate, 1.0/60.0);
|
||||||
ggClockHInd.Init(DynamicObject->mdKabina->GetFromName("ClockHhand"), TGaugeType::gt_Rotate, 1.0/12.0);
|
ggClockHInd.Init(DynamicObject->mdKabina->GetFromName("ClockHhand"), TGaugeAnimation::gt_Rotate, 1.0/12.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Label == "evoltage:")
|
else if (Label == "evoltage:")
|
||||||
|
|||||||
9
Train.h
9
Train.h
@@ -367,6 +367,7 @@ public: // reszta może by?publiczna
|
|||||||
TGauge ggBrakeProfileCtrl; // nastawiacz GPR - przelacznik obrotowy
|
TGauge ggBrakeProfileCtrl; // nastawiacz GPR - przelacznik obrotowy
|
||||||
TGauge ggBrakeProfileG; // nastawiacz GP - hebelek towarowy
|
TGauge ggBrakeProfileG; // nastawiacz GP - hebelek towarowy
|
||||||
TGauge ggBrakeProfileR; // nastawiacz PR - hamowanie dwustopniowe
|
TGauge ggBrakeProfileR; // nastawiacz PR - hamowanie dwustopniowe
|
||||||
|
TGauge ggBrakeOperationModeCtrl; //przełącznik trybu pracy PS/PN/EP/MED
|
||||||
|
|
||||||
TGauge ggMaxCurrentCtrl;
|
TGauge ggMaxCurrentCtrl;
|
||||||
|
|
||||||
@@ -628,12 +629,10 @@ private:
|
|||||||
float fConverterTimer; // hunter-261211: dla przekaznika
|
float fConverterTimer; // hunter-261211: dla przekaznika
|
||||||
float fMainRelayTimer; // hunter-141211: zalaczanie WSa z opoznieniem
|
float fMainRelayTimer; // hunter-141211: zalaczanie WSa z opoznieniem
|
||||||
float fCzuwakTestTimer; // hunter-091012: do testu czuwaka
|
float fCzuwakTestTimer; // hunter-091012: do testu czuwaka
|
||||||
float fLightsTimer; // yB 150617: timer do swiatel
|
float fScreenTimer { 0.f };
|
||||||
|
|
||||||
bool CAflag { false }; // hunter-131211: dla osobnego zbijania CA i SHP
|
bool CAflag { false }; // hunter-131211: dla osobnego zbijania CA i SHP
|
||||||
|
|
||||||
double fPoslizgTimer;
|
|
||||||
TTrack *tor;
|
|
||||||
// McZapkie-240302 - przyda sie do tachometru
|
// McZapkie-240302 - przyda sie do tachometru
|
||||||
float fTachoVelocity{ 0.0f };
|
float fTachoVelocity{ 0.0f };
|
||||||
float fTachoVelocityJump{ 0.0f }; // ze skakaniem
|
float fTachoVelocityJump{ 0.0f }; // ze skakaniem
|
||||||
@@ -659,10 +658,8 @@ private:
|
|||||||
bool bHeat[8]; // grzanie
|
bool bHeat[8]; // grzanie
|
||||||
// McZapkie: do syczenia
|
// McZapkie: do syczenia
|
||||||
float fPPress, fNPress;
|
float fPPress, fNPress;
|
||||||
// float fSPPress, fSNPress;
|
|
||||||
int iSekunda; // Ra: sekunda aktualizacji pr?dko?ci
|
|
||||||
int iRadioChannel { 1 }; // numer aktualnego kana?u radiowego
|
int iRadioChannel { 1 }; // numer aktualnego kana?u radiowego
|
||||||
TPythonScreens pyScreens;
|
std::vector<std::pair<std::string, material_handle>> m_screens;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
float fPress[20][3]; // cisnienia dla wszystkich czlonow
|
float fPress[20][3]; // cisnienia dla wszystkich czlonow
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "gamepadinput.h"
|
#include "gamepadinput.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
#include "simulation.h"
|
#include "simulation.h"
|
||||||
#include "PyInt.h"
|
|
||||||
#include "sceneeditor.h"
|
#include "sceneeditor.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
#include "uilayer.h"
|
#include "uilayer.h"
|
||||||
@@ -27,6 +26,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "screenshot.h"
|
#include "screenshot.h"
|
||||||
#include "translation.h"
|
#include "translation.h"
|
||||||
#include "Train.h"
|
#include "Train.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
#pragma comment (lib, "glu32.lib")
|
#pragma comment (lib, "glu32.lib")
|
||||||
#pragma comment (lib, "dsound.lib")
|
#pragma comment (lib, "dsound.lib")
|
||||||
@@ -136,6 +136,7 @@ eu07_application::init( int Argc, char *Argv[] ) {
|
|||||||
if( ( result = init_audio() ) != 0 ) {
|
if( ( result = init_audio() ) != 0 ) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
m_taskqueue.init();
|
||||||
if( ( result = init_modes() ) != 0 ) {
|
if( ( result = init_modes() ) != 0 ) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -147,7 +148,7 @@ int
|
|||||||
eu07_application::run() {
|
eu07_application::run() {
|
||||||
|
|
||||||
// main application loop
|
// main application loop
|
||||||
while (!glfwWindowShouldClose( m_window ) && !m_modestack.empty())
|
while (!glfwWindowShouldClose( m_windows.front() ) && !m_modestack.empty())
|
||||||
{
|
{
|
||||||
if (!m_modes[ m_modestack.top() ]->update())
|
if (!m_modes[ m_modestack.top() ]->update())
|
||||||
break;
|
break;
|
||||||
@@ -173,6 +174,12 @@ eu07_application::run() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
eu07_application::request( python_taskqueue::task_request const &Task ) {
|
||||||
|
|
||||||
|
return m_taskqueue.insert( Task );
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
eu07_application::exit() {
|
eu07_application::exit() {
|
||||||
|
|
||||||
@@ -181,10 +188,11 @@ eu07_application::exit() {
|
|||||||
|
|
||||||
ui_layer::shutdown();
|
ui_layer::shutdown();
|
||||||
|
|
||||||
glfwDestroyWindow( m_window );
|
for( auto *window : m_windows ) {
|
||||||
|
glfwDestroyWindow( window );
|
||||||
|
}
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
|
m_taskqueue.exit();
|
||||||
TPythonInterpreter::killInstance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -219,7 +227,7 @@ eu07_application::push_mode( eu07_application::mode const Mode ) {
|
|||||||
void
|
void
|
||||||
eu07_application::set_title( std::string const &Title ) {
|
eu07_application::set_title( std::string const &Title ) {
|
||||||
|
|
||||||
glfwSetWindowTitle( m_window, Title.c_str() );
|
glfwSetWindowTitle( m_windows.front(), Title.c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -239,15 +247,13 @@ eu07_application::set_cursor( int const Mode ) {
|
|||||||
void
|
void
|
||||||
eu07_application::set_cursor_pos( double const Horizontal, double const Vertical ) {
|
eu07_application::set_cursor_pos( double const Horizontal, double const Vertical ) {
|
||||||
|
|
||||||
if( m_window != nullptr ) {
|
glfwSetCursorPos( m_windows.front(), Horizontal, Vertical );
|
||||||
glfwSetCursorPos( m_window, Horizontal, Vertical );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::dvec2 eu07_application::get_cursor_pos() const {
|
glm::dvec2 eu07_application::get_cursor_pos() const {
|
||||||
glm::dvec2 pos;
|
glm::dvec2 pos;
|
||||||
if( m_window != nullptr ) {
|
if( !m_windows.empty() ) {
|
||||||
glfwGetCursorPos( m_window, &pos.x, &pos.y );
|
glfwGetCursorPos( m_windows.front(), &pos.x, &pos.y );
|
||||||
}
|
}
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
@@ -255,9 +261,7 @@ glm::dvec2 eu07_application::get_cursor_pos() const {
|
|||||||
void
|
void
|
||||||
eu07_application::get_cursor_pos( double &Horizontal, double &Vertical ) const {
|
eu07_application::get_cursor_pos( double &Horizontal, double &Vertical ) const {
|
||||||
|
|
||||||
if( m_window != nullptr ) {
|
glfwGetCursorPos( m_windows.front(), &Horizontal, &Vertical );
|
||||||
glfwGetCursorPos( m_window, &Horizontal, &Vertical );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -306,6 +310,24 @@ void eu07_application::on_char(unsigned int c) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLFWwindow *
|
||||||
|
eu07_application::window( int const Windowindex ) {
|
||||||
|
|
||||||
|
if( Windowindex >= 0 ) {
|
||||||
|
return (
|
||||||
|
Windowindex < m_windows.size() ?
|
||||||
|
m_windows[ Windowindex ] :
|
||||||
|
nullptr );
|
||||||
|
}
|
||||||
|
// for index -1 create a new child window
|
||||||
|
glfwWindowHint( GLFW_VISIBLE, GL_FALSE );
|
||||||
|
auto *childwindow = glfwCreateWindow( 1, 1, "eu07helper", nullptr, m_windows.front() );
|
||||||
|
if( childwindow != nullptr ) {
|
||||||
|
m_windows.emplace_back( childwindow );
|
||||||
|
}
|
||||||
|
return childwindow;
|
||||||
|
}
|
||||||
|
|
||||||
// private:
|
// private:
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -450,9 +472,7 @@ eu07_application::init_glfw() {
|
|||||||
else
|
else
|
||||||
Global.ControlPicking = true;
|
Global.ControlPicking = true;
|
||||||
|
|
||||||
// TBD, TODO: move the global pointer to a more appropriate place
|
m_windows.emplace_back( window );
|
||||||
|
|
||||||
m_window = window;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -460,17 +480,18 @@ eu07_application::init_glfw() {
|
|||||||
void
|
void
|
||||||
eu07_application::init_callbacks() {
|
eu07_application::init_callbacks() {
|
||||||
|
|
||||||
glfwSetFramebufferSizeCallback( m_window, window_resize_callback );
|
auto *window { m_windows.front() };
|
||||||
glfwSetCursorPosCallback( m_window, cursor_pos_callback );
|
glfwSetFramebufferSizeCallback( window, window_resize_callback );
|
||||||
glfwSetMouseButtonCallback( m_window, mouse_button_callback );
|
glfwSetCursorPosCallback( window, cursor_pos_callback );
|
||||||
glfwSetKeyCallback( m_window, key_callback );
|
glfwSetMouseButtonCallback( window, mouse_button_callback );
|
||||||
glfwSetScrollCallback( m_window, scroll_callback );
|
glfwSetKeyCallback( window, key_callback );
|
||||||
glfwSetCharCallback(m_window, char_callback);
|
glfwSetScrollCallback( window, scroll_callback );
|
||||||
glfwSetWindowFocusCallback( m_window, focus_callback );
|
glfwSetCharCallback(window, char_callback);
|
||||||
|
glfwSetWindowFocusCallback( window, focus_callback );
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
glfwGetFramebufferSize( m_window, &width, &height );
|
glfwGetFramebufferSize( window, &width, &height );
|
||||||
window_resize_callback( m_window, width, height );
|
window_resize_callback( window, width, height );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,10 +503,10 @@ eu07_application::init_gfx() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ui_layer::init(m_window))
|
if (!ui_layer::init(m_windows.front()))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!GfxRenderer.Init(m_window))
|
if (!GfxRenderer.Init(m_windows.front()))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "applicationmode.h"
|
#include "applicationmode.h"
|
||||||
|
#include "PyInt.h"
|
||||||
|
|
||||||
class eu07_application {
|
class eu07_application {
|
||||||
|
|
||||||
@@ -29,6 +30,8 @@ public:
|
|||||||
init( int Argc, char *Argv[] );
|
init( int Argc, char *Argv[] );
|
||||||
int
|
int
|
||||||
run();
|
run();
|
||||||
|
bool
|
||||||
|
request( python_taskqueue::task_request const &Task );
|
||||||
void
|
void
|
||||||
exit();
|
exit();
|
||||||
void
|
void
|
||||||
@@ -61,11 +64,9 @@ public:
|
|||||||
void
|
void
|
||||||
on_scroll( double const Xoffset, double const Yoffset );
|
on_scroll( double const Xoffset, double const Yoffset );
|
||||||
void on_char(unsigned int c);
|
void on_char(unsigned int c);
|
||||||
|
// gives access to specified window, creates a new window if index == -1
|
||||||
inline
|
|
||||||
GLFWwindow *
|
GLFWwindow *
|
||||||
window() {
|
window( int const Windowindex = 0 );
|
||||||
return m_window; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// types
|
// types
|
||||||
@@ -82,12 +83,13 @@ private:
|
|||||||
int init_audio();
|
int init_audio();
|
||||||
int init_modes();
|
int init_modes();
|
||||||
// members
|
// members
|
||||||
GLFWwindow * m_window { nullptr };
|
|
||||||
|
|
||||||
bool m_screenshot_queued = false;
|
bool m_screenshot_queued = false;
|
||||||
|
|
||||||
modeptr_array m_modes { nullptr }; // collection of available application behaviour modes
|
modeptr_array m_modes { nullptr }; // collection of available application behaviour modes
|
||||||
mode_stack m_modestack; // current behaviour mode
|
mode_stack m_modestack; // current behaviour mode
|
||||||
|
python_taskqueue m_taskqueue;
|
||||||
|
std::vector<GLFWwindow *> m_windows;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern eu07_application Application;
|
extern eu07_application Application;
|
||||||
|
|||||||
@@ -230,6 +230,8 @@ driver_mode::update() {
|
|||||||
|
|
||||||
update_camera( deltarealtime );
|
update_camera( deltarealtime );
|
||||||
|
|
||||||
|
simulation::Environment.update_precipitation(); // has to be launched after camera step to work properly
|
||||||
|
|
||||||
Timer::subsystem.sim_total.stop();
|
Timer::subsystem.sim_total.stop();
|
||||||
|
|
||||||
simulation::Region->update_sounds();
|
simulation::Region->update_sounds();
|
||||||
@@ -323,8 +325,10 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co
|
|||||||
Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false;
|
Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false;
|
||||||
Global.altState = ( Mods & GLFW_MOD_ALT ) ? true : false;
|
Global.altState = ( Mods & GLFW_MOD_ALT ) ? true : false;
|
||||||
|
|
||||||
|
bool anyModifier = Mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT);
|
||||||
|
|
||||||
// give the ui first shot at the input processing...
|
// give the ui first shot at the input processing...
|
||||||
if( true == m_userinterface->on_key( Key, Action ) ) { return; }
|
if( !anyModifier && true == m_userinterface->on_key( Key, Action ) ) { return; }
|
||||||
// ...if the input is left untouched, pass it on
|
// ...if the input is left untouched, pass it on
|
||||||
if( true == m_input.keyboard.key( Key, Action ) ) { return; }
|
if( true == m_input.keyboard.key( Key, Action ) ) { return; }
|
||||||
|
|
||||||
@@ -948,6 +952,7 @@ driver_mode::InOutKey( bool const Near )
|
|||||||
train->Dynamic()->ABuSetModelShake( { 0, 0, 0 } );
|
train->Dynamic()->ABuSetModelShake( { 0, 0, 0 } );
|
||||||
train->MechStop();
|
train->MechStop();
|
||||||
FollowView(); // na pozycję mecha
|
FollowView(); // na pozycję mecha
|
||||||
|
train->UpdateMechPosition( m_secondaryupdaterate );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
FreeFlyModeFlag = true; // nadal poza kabiną
|
FreeFlyModeFlag = true; // nadal poza kabiną
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
#include "uilayer.h"
|
#include "uilayer.h"
|
||||||
#include "Logs.h"
|
#include "Logs.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
mouse_slider::bind( user_command const &Command ) {
|
mouse_slider::bind( user_command const &Command ) {
|
||||||
|
|||||||
@@ -140,8 +140,10 @@ editor_mode::on_key( int const Key, int const Scancode, int const Action, int co
|
|||||||
Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false;
|
Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false;
|
||||||
Global.altState = ( Mods & GLFW_MOD_ALT ) ? true : false;
|
Global.altState = ( Mods & GLFW_MOD_ALT ) ? true : false;
|
||||||
|
|
||||||
|
bool anyModifier = Mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT);
|
||||||
|
|
||||||
// give the ui first shot at the input processing...
|
// give the ui first shot at the input processing...
|
||||||
if( true == m_userinterface->on_key( Key, Action ) ) { return; }
|
if( !anyModifier && true == m_userinterface->on_key( Key, Action ) ) { return; }
|
||||||
// ...if the input is left untouched, pass it on
|
// ...if the input is left untouched, pass it on
|
||||||
if( true == m_input.keyboard.key( Key, Action ) ) { return; }
|
if( true == m_input.keyboard.key( Key, Action ) ) { return; }
|
||||||
|
|
||||||
|
|||||||
11
material.cpp
11
material.cpp
@@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
#include "Logs.h"
|
#include "Logs.h"
|
||||||
|
#include "sn_utils.h"
|
||||||
|
|
||||||
opengl_material::opengl_material()
|
opengl_material::opengl_material()
|
||||||
{
|
{
|
||||||
@@ -171,12 +172,16 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c
|
|||||||
if( key == Global.Weather ) {
|
if( key == Global.Weather ) {
|
||||||
// weather textures override generic (pri 0) and seasonal (pri 1) textures
|
// weather textures override generic (pri 0) and seasonal (pri 1) textures
|
||||||
// seasonal weather textures (pri 1+2=3) override generic weather (pri 2) textures
|
// seasonal weather textures (pri 1+2=3) override generic weather (pri 2) textures
|
||||||
|
// skip the opening bracket
|
||||||
|
auto const value { Input.getToken<std::string>( true, "\n\r\t ;" ) };
|
||||||
while( true == deserialize_mapping( Input, Priority + 2, Loadnow ) ) {
|
while( true == deserialize_mapping( Input, Priority + 2, Loadnow ) ) {
|
||||||
; // all work is done in the header
|
; // all work is done in the header
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( key == Global.Season ) {
|
else if( key == Global.Season ) {
|
||||||
// seasonal textures override generic textures
|
// seasonal textures override generic textures
|
||||||
|
// skip the opening bracket
|
||||||
|
auto const value { Input.getToken<std::string>( true, "\n\r\t ;" ) };
|
||||||
while( true == deserialize_mapping( Input, 1, Loadnow ) ) {
|
while( true == deserialize_mapping( Input, 1, Loadnow ) ) {
|
||||||
; // all work is done in the header
|
; // all work is done in the header
|
||||||
}
|
}
|
||||||
@@ -244,6 +249,12 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c
|
|||||||
selfillum = std::stof(value); //m7t: handle exception
|
selfillum = std::stof(value); //m7t: handle exception
|
||||||
m_selfillum_priority = Priority;
|
m_selfillum_priority = Priority;
|
||||||
}
|
}
|
||||||
|
else if( key == "size:" ) {
|
||||||
|
Input.getTokens( 2 );
|
||||||
|
Input
|
||||||
|
>> size.x
|
||||||
|
>> size.y;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
auto const value = Input.getToken<std::string>( true, "\n\r\t ;" );
|
auto const value = Input.getToken<std::string>( true, "\n\r\t ;" );
|
||||||
if( value == "{" ) {
|
if( value == "{" ) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ struct opengl_material {
|
|||||||
float selfillum = std::numeric_limits<float>::quiet_NaN();
|
float selfillum = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
glm::vec2 size { -1.f, -1.f }; // 'physical' size of bound texture, in meters
|
||||||
|
|
||||||
// constructors
|
// constructors
|
||||||
opengl_material();
|
opengl_material();
|
||||||
|
|||||||
12
openglcolor.cpp
Normal file
12
openglcolor.cpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
opengl_color OpenGLColor;
|
||||||
69
openglcolor.h
Normal file
69
openglcolor.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// encapsulation of the fixed pipeline opengl color
|
||||||
|
class opengl_color {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// constructors:
|
||||||
|
opengl_color() = default;
|
||||||
|
|
||||||
|
// methods:
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
color3( glm::vec3 const &Color ) {
|
||||||
|
return color4( glm::vec4{ Color, 1.f } ); }
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
color3( float const Red, float const Green, float const Blue ) {
|
||||||
|
return color3( glm::vec3 { Red, Green, Blue } ); }
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
color3( float const *Value ) {
|
||||||
|
return color3( glm::make_vec3( Value ) ); }
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
color4( glm::vec4 const &Color ) {
|
||||||
|
if( ( Color != m_color ) ) {
|
||||||
|
m_color = Color;
|
||||||
|
::glColor4fv( glm::value_ptr( m_color ) ); } }
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
color4( float const Red, float const Green, float const Blue, float const Alpha ) {
|
||||||
|
return color4( glm::vec4{ Red, Green, Blue, Alpha } ); }
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
color4( float const *Value ) {
|
||||||
|
return color4( glm::make_vec4( Value ) );
|
||||||
|
}
|
||||||
|
inline
|
||||||
|
glm::vec4 const &
|
||||||
|
data() const {
|
||||||
|
return m_color; }
|
||||||
|
inline
|
||||||
|
float const *
|
||||||
|
data_array() const {
|
||||||
|
return glm::value_ptr( m_color ); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// members:
|
||||||
|
glm::vec4 m_color { -1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
extern opengl_color OpenGLColor;
|
||||||
|
|
||||||
|
// NOTE: standard opengl calls re-definitions
|
||||||
|
#define glColor3f OpenGLColor.color3
|
||||||
|
#define glColor3fv OpenGLColor.color3
|
||||||
|
#define glColor4f OpenGLColor.color4
|
||||||
|
#define glColor4fv OpenGLColor.color4
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
@@ -61,6 +61,10 @@ public:
|
|||||||
load(glm::mat4 const &Matrix) {
|
load(glm::mat4 const &Matrix) {
|
||||||
m_stack.top() = Matrix;
|
m_stack.top() = Matrix;
|
||||||
upload(); }
|
upload(); }
|
||||||
|
void
|
||||||
|
scale( glm::vec3 const &Scale ) {
|
||||||
|
m_stack.top() = glm::scale( m_stack.top(), Scale );
|
||||||
|
upload(); }
|
||||||
void
|
void
|
||||||
multiply( glm::mat4 const &Matrix ) {
|
multiply( glm::mat4 const &Matrix ) {
|
||||||
m_stack.top() *= Matrix;
|
m_stack.top() *= Matrix;
|
||||||
@@ -137,9 +141,9 @@ public:
|
|||||||
m_stacks[ m_mode ].rotate(
|
m_stacks[ m_mode ].rotate(
|
||||||
static_cast<float>(glm::radians(Angle)),
|
static_cast<float>(glm::radians(Angle)),
|
||||||
glm::vec3(
|
glm::vec3(
|
||||||
static_cast<float>(X),
|
static_cast<float>( X ),
|
||||||
static_cast<float>(Y),
|
static_cast<float>( Y ),
|
||||||
static_cast<float>(Z) ) ); }
|
static_cast<float>( Z ) ) ); }
|
||||||
template <typename Type_>
|
template <typename Type_>
|
||||||
void
|
void
|
||||||
translate( Type_ const X, Type_ const Y, Type_ const Z ) {
|
translate( Type_ const X, Type_ const Y, Type_ const Z ) {
|
||||||
@@ -149,6 +153,14 @@ public:
|
|||||||
static_cast<float>( Y ),
|
static_cast<float>( Y ),
|
||||||
static_cast<float>( Z ) ) ); }
|
static_cast<float>( Z ) ) ); }
|
||||||
template <typename Type_>
|
template <typename Type_>
|
||||||
|
void
|
||||||
|
scale( Type_ const X, Type_ const Y, Type_ const Z ) {
|
||||||
|
m_stacks[ m_mode ].scale(
|
||||||
|
glm::vec3(
|
||||||
|
static_cast<float>( X ),
|
||||||
|
static_cast<float>( Y ),
|
||||||
|
static_cast<float>( Z ) ) ); }
|
||||||
|
template <typename Type_>
|
||||||
void
|
void
|
||||||
multiply( Type_ const *Matrix ) {
|
multiply( Type_ const *Matrix ) {
|
||||||
m_stacks[ m_mode ].multiply(
|
m_stacks[ m_mode ].multiply(
|
||||||
@@ -213,7 +225,8 @@ extern opengl_matrices OpenGLMatrices;
|
|||||||
#define glRotatef OpenGLMatrices.rotate
|
#define glRotatef OpenGLMatrices.rotate
|
||||||
#define glTranslated OpenGLMatrices.translate
|
#define glTranslated OpenGLMatrices.translate
|
||||||
#define glTranslatef OpenGLMatrices.translate
|
#define glTranslatef OpenGLMatrices.translate
|
||||||
// NOTE: no scale override as we aren't using it anywhere
|
#define glScaled OpenGLMatrices.scale
|
||||||
|
#define glScalef OpenGLMatrices.scale
|
||||||
#define glMultMatrixd OpenGLMatrices.multiply
|
#define glMultMatrixd OpenGLMatrices.multiply
|
||||||
#define glMultMatrixf OpenGLMatrices.multiply
|
#define glMultMatrixf OpenGLMatrices.multiply
|
||||||
#define glOrtho OpenGLMatrices.ortho
|
#define glOrtho OpenGLMatrices.ortho
|
||||||
|
|||||||
200
precipitation.cpp
Normal file
200
precipitation.cpp
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "precipitation.h"
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "openglmatrixstack.h"
|
||||||
|
#include "renderer.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "simulation.h"
|
||||||
|
#include "Train.h"
|
||||||
|
|
||||||
|
basic_precipitation::~basic_precipitation() {
|
||||||
|
// TODO: release allocated resources
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
basic_precipitation::create( int const Tesselation ) {
|
||||||
|
|
||||||
|
auto const heightfactor { 10.f }; // height-to-radius factor
|
||||||
|
m_moverate *= heightfactor;
|
||||||
|
auto const verticaltexturestretchfactor { 1.5f }; // crude motion blur
|
||||||
|
|
||||||
|
// create geometry chunk
|
||||||
|
auto const latitudes { 3 }; // just a cylinder with end cones
|
||||||
|
auto const longitudes { Tesselation };
|
||||||
|
auto const longitudehalfstep { 0.5f * static_cast<float>( 2.0 * M_PI * 1.f / longitudes ) }; // for crude uv correction
|
||||||
|
|
||||||
|
std::uint16_t index = 0;
|
||||||
|
|
||||||
|
// auto const radius { 25.f }; // cylinder radius
|
||||||
|
std::vector<float> radii { 25.f, 10.f, 5.f, 1.f };
|
||||||
|
for( auto radius : radii ) {
|
||||||
|
|
||||||
|
for( int i = 0; i <= latitudes; ++i ) {
|
||||||
|
|
||||||
|
auto const latitude{ static_cast<float>( M_PI * ( -0.5f + (float)( i ) / latitudes ) ) };
|
||||||
|
auto const z{ std::sin( latitude ) };
|
||||||
|
auto const zr{ std::cos( latitude ) };
|
||||||
|
|
||||||
|
for( int j = 0; j <= longitudes; ++j ) {
|
||||||
|
// NOTE: for the first and last row half of the points we create end up unused but, eh
|
||||||
|
auto const longitude{ static_cast<float>( 2.0 * M_PI * (float)( j ) / longitudes ) };
|
||||||
|
auto const x{ std::cos( longitude ) };
|
||||||
|
auto const y{ std::sin( longitude ) };
|
||||||
|
// NOTE: cartesian to opengl swap would be: -x, -z, -y
|
||||||
|
m_vertices.emplace_back( glm::vec3( -x * zr, -z * heightfactor, -y * zr ) * radius );
|
||||||
|
// uvs
|
||||||
|
// NOTE: first and last row receives modified u values to deal with limitation of mapping onto triangles
|
||||||
|
auto u = (
|
||||||
|
i == 0 ? longitude + longitudehalfstep :
|
||||||
|
i == latitudes ? longitude - longitudehalfstep :
|
||||||
|
longitude );
|
||||||
|
m_uvs.emplace_back(
|
||||||
|
u / ( 2.0 * M_PI ) * radius,
|
||||||
|
1.f - (float)( i ) / latitudes * radius * heightfactor * 0.5f / verticaltexturestretchfactor );
|
||||||
|
|
||||||
|
if( ( i == 0 ) || ( j == 0 ) ) {
|
||||||
|
// initial edge of the dome, don't start indices yet
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// the end cones are built from one triangle of each quad, the middle rows use both
|
||||||
|
if( i < latitudes ) {
|
||||||
|
m_indices.emplace_back( index - 1 - ( longitudes + 1 ) );
|
||||||
|
m_indices.emplace_back( index - 1 );
|
||||||
|
m_indices.emplace_back( index );
|
||||||
|
}
|
||||||
|
if( i > 1 ) {
|
||||||
|
m_indices.emplace_back( index );
|
||||||
|
m_indices.emplace_back( index - ( longitudes + 1 ) );
|
||||||
|
m_indices.emplace_back( index - 1 - ( longitudes + 1 ) );
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
} // longitude
|
||||||
|
} // latitude
|
||||||
|
} // radius
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
basic_precipitation::init() {
|
||||||
|
|
||||||
|
create( 18 );
|
||||||
|
|
||||||
|
// TODO: select texture based on current overcast level
|
||||||
|
// TODO: when the overcast level dynamic change is in check the current level during render and pick the appropriate texture on the fly
|
||||||
|
std::string const densitysuffix { (
|
||||||
|
Global.Overcast < 1.35 ?
|
||||||
|
"_light" :
|
||||||
|
"_medium" ) };
|
||||||
|
if( Global.Weather == "rain:" ) {
|
||||||
|
m_moverateweathertypefactor = 2.f;
|
||||||
|
m_texture = GfxRenderer.Fetch_Texture( "fx/rain" + densitysuffix );
|
||||||
|
}
|
||||||
|
else if( Global.Weather == "snow:" ) {
|
||||||
|
m_moverateweathertypefactor = 1.25f;
|
||||||
|
m_texture = GfxRenderer.Fetch_Texture( "fx/snow" + densitysuffix );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
basic_precipitation::update() {
|
||||||
|
|
||||||
|
auto const timedelta { static_cast<float>( ( DebugModeFlag ? Timer::GetDeltaTime() : Timer::GetDeltaTime() ) ) };
|
||||||
|
|
||||||
|
if( timedelta == 0.0 ) { return; }
|
||||||
|
|
||||||
|
m_textureoffset += m_moverate * m_moverateweathertypefactor * timedelta;
|
||||||
|
m_textureoffset = clamp_circular( m_textureoffset, 10.f );
|
||||||
|
|
||||||
|
auto cameramove { glm::dvec3{ Global.pCamera.Pos - m_camerapos} };
|
||||||
|
cameramove.y = 0.0; // vertical movement messes up vector calculation
|
||||||
|
|
||||||
|
m_camerapos = Global.pCamera.Pos;
|
||||||
|
|
||||||
|
// intercept sudden user-induced camera jumps
|
||||||
|
if( m_freeflymode != FreeFlyModeFlag ) {
|
||||||
|
m_freeflymode = FreeFlyModeFlag;
|
||||||
|
if( true == m_freeflymode ) {
|
||||||
|
// cache last precipitation vector in the cab
|
||||||
|
m_cabcameramove = m_cameramove;
|
||||||
|
// don't carry previous precipitation vector to a new unrelated location
|
||||||
|
m_cameramove = glm::dvec3{ 0.0 };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// restore last cached precipitation vector
|
||||||
|
m_cameramove = m_cabcameramove;
|
||||||
|
}
|
||||||
|
cameramove = glm::dvec3{ 0.0 };
|
||||||
|
}
|
||||||
|
if( m_windowopen != Global.CabWindowOpen ) {
|
||||||
|
m_windowopen = Global.CabWindowOpen;
|
||||||
|
cameramove = glm::dvec3{ 0.0 };
|
||||||
|
}
|
||||||
|
if( ( simulation::Train != nullptr ) && ( simulation::Train->iCabn != m_activecab ) ) {
|
||||||
|
m_activecab = simulation::Train->iCabn;
|
||||||
|
cameramove = glm::dvec3{ 0.0 };
|
||||||
|
}
|
||||||
|
if( glm::length( cameramove ) > 100.0 ) {
|
||||||
|
cameramove = glm::dvec3{ 0.0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cameramove = m_cameramove * std::max( 0.0, 1.0 - 5.0 * timedelta ) + cameramove * ( 30.0 * timedelta );
|
||||||
|
if( std::abs( m_cameramove.x ) < 0.001 ) { m_cameramove.x = 0.0; }
|
||||||
|
if( std::abs( m_cameramove.y ) < 0.001 ) { m_cameramove.y = 0.0; }
|
||||||
|
if( std::abs( m_cameramove.z ) < 0.001 ) { m_cameramove.z = 0.0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
float basic_precipitation::get_textureoffset()
|
||||||
|
{
|
||||||
|
return m_textureoffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
basic_precipitation::render() {
|
||||||
|
|
||||||
|
GfxRenderer.Bind_Texture(0, m_texture);
|
||||||
|
|
||||||
|
if (!m_shader)
|
||||||
|
{
|
||||||
|
gl::shader vert("precipitation.vert");
|
||||||
|
gl::shader frag("precipitation.frag");
|
||||||
|
m_shader = std::make_unique<gl::program>(std::vector<std::reference_wrapper<const gl::shader>>({vert, frag}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_vertexbuffer == -1 ) {
|
||||||
|
m_vao = std::make_unique<gl::vao>();
|
||||||
|
|
||||||
|
// build the buffers
|
||||||
|
::glGenBuffers( 1, &m_vertexbuffer );
|
||||||
|
::glBindBuffer( GL_ARRAY_BUFFER, m_vertexbuffer );
|
||||||
|
::glBufferData( GL_ARRAY_BUFFER, m_vertices.size() * sizeof( glm::vec3 ), m_vertices.data(), GL_STATIC_DRAW );
|
||||||
|
m_vao->setup_attrib(0, 3, GL_FLOAT, sizeof(glm::vec3), 0);
|
||||||
|
|
||||||
|
::glGenBuffers( 1, &m_uvbuffer );
|
||||||
|
::glBindBuffer( GL_ARRAY_BUFFER, m_uvbuffer );
|
||||||
|
::glBufferData( GL_ARRAY_BUFFER, m_uvs.size() * sizeof( glm::vec2 ), m_uvs.data(), GL_STATIC_DRAW );
|
||||||
|
m_vao->setup_attrib(1, 2, GL_FLOAT, sizeof(glm::vec2), 0);
|
||||||
|
|
||||||
|
::glGenBuffers( 1, &m_indexbuffer );
|
||||||
|
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer );
|
||||||
|
::glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof( unsigned short ), m_indices.data(), GL_STATIC_DRAW );
|
||||||
|
// NOTE: vertex and index source data is superfluous past this point, but, eh
|
||||||
|
}
|
||||||
|
|
||||||
|
m_shader->bind();
|
||||||
|
m_vao->bind();
|
||||||
|
|
||||||
|
::glDrawElements( GL_TRIANGLES, static_cast<GLsizei>( m_indices.size() ), GL_UNSIGNED_SHORT, reinterpret_cast<void const*>( 0 ) );
|
||||||
|
}
|
||||||
60
precipitation.h
Normal file
60
precipitation.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "gl/vao.h"
|
||||||
|
#include "gl/shader.h"
|
||||||
|
#include "Texture.h"
|
||||||
|
|
||||||
|
// based on "Rendering Falling Rain and Snow"
|
||||||
|
// by Niniane Wang, Bretton Wade
|
||||||
|
|
||||||
|
class basic_precipitation {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// constructors
|
||||||
|
basic_precipitation() = default;
|
||||||
|
// destructor
|
||||||
|
~basic_precipitation();
|
||||||
|
// methods
|
||||||
|
bool
|
||||||
|
init();
|
||||||
|
void
|
||||||
|
update();
|
||||||
|
void
|
||||||
|
render();
|
||||||
|
float get_textureoffset();
|
||||||
|
|
||||||
|
glm::dvec3 m_cameramove{ 0.0 };
|
||||||
|
|
||||||
|
private:
|
||||||
|
// methods
|
||||||
|
void create( int const Tesselation );
|
||||||
|
|
||||||
|
// members
|
||||||
|
std::vector<glm::vec3> m_vertices;
|
||||||
|
std::vector<glm::vec2> m_uvs;
|
||||||
|
std::vector<std::uint16_t> m_indices;
|
||||||
|
GLuint m_vertexbuffer { (GLuint)-1 };
|
||||||
|
GLuint m_uvbuffer { (GLuint)-1 };
|
||||||
|
GLuint m_indexbuffer { (GLuint)-1 };
|
||||||
|
texture_handle m_texture { -1 };
|
||||||
|
float m_textureoffset { 0.f };
|
||||||
|
float m_moverate { 30 * 0.001f };
|
||||||
|
float m_moverateweathertypefactor { 1.f }; // medium-dependent; 1.0 for snow, faster for rain
|
||||||
|
glm::dvec3 m_camerapos { 0.0 };
|
||||||
|
bool m_freeflymode { true };
|
||||||
|
bool m_windowopen { true };
|
||||||
|
int m_activecab{ 0 };
|
||||||
|
glm::dvec3 m_cabcameramove{ 0.0 };
|
||||||
|
|
||||||
|
std::unique_ptr<gl::program> m_shader;
|
||||||
|
std::unique_ptr<gl::vao> m_vao;
|
||||||
|
};
|
||||||
120
renderer.cpp
120
renderer.cpp
@@ -342,15 +342,9 @@ bool opengl_renderer::Render()
|
|||||||
if (m_gllasttime)
|
if (m_gllasttime)
|
||||||
m_debugtimestext += "gpu: " + to_string((double)(m_gllasttime / 1000ULL) / 1000.0, 3) + "ms";
|
m_debugtimestext += "gpu: " + to_string((double)(m_gllasttime / 1000ULL) / 1000.0, 3) + "ms";
|
||||||
|
|
||||||
m_debugstatstext =
|
m_debugstatstext = "drawcalls: " + to_string(m_debugstats.drawcalls) + "\n" + " vehicles: " + to_string(m_debugstats.dynamics) + "\n" + " models: " + to_string(m_debugstats.models) + "\n" +
|
||||||
"drawcalls: " + to_string( m_debugstats.drawcalls ) + "\n"
|
" submodels: " + to_string(m_debugstats.submodels) + "\n" + " paths: " + to_string(m_debugstats.paths) + "\n" + " shapes: " + to_string(m_debugstats.shapes) + "\n" +
|
||||||
+ " vehicles: " + to_string( m_debugstats.dynamics ) + "\n"
|
" traction: " + to_string(m_debugstats.traction) + "\n" + " lines: " + to_string(m_debugstats.lines);
|
||||||
+ " models: " + to_string( m_debugstats.models ) + "\n"
|
|
||||||
+ " submodels: " + to_string( m_debugstats.submodels ) + "\n"
|
|
||||||
+ " paths: " + to_string( m_debugstats.paths ) + "\n"
|
|
||||||
+ " shapes: " + to_string( m_debugstats.shapes ) + "\n"
|
|
||||||
+ " traction: " + to_string( m_debugstats.traction ) + "\n"
|
|
||||||
+ " lines: " + to_string( m_debugstats.lines );
|
|
||||||
|
|
||||||
if (DebugModeFlag)
|
if (DebugModeFlag)
|
||||||
m_debugtimestext += m_textures.info();
|
m_debugtimestext += m_textures.info();
|
||||||
@@ -364,7 +358,7 @@ void opengl_renderer::SwapBuffers()
|
|||||||
{
|
{
|
||||||
Timer::subsystem.gfx_swap.start();
|
Timer::subsystem.gfx_swap.start();
|
||||||
glfwSwapBuffers(m_window);
|
glfwSwapBuffers(m_window);
|
||||||
// swapbuffers() will unbind current buffers so we prepare for it on our end
|
// swapbuffers() could unbind current buffers so we prepare for it on our end
|
||||||
gfx::opengl_vbogeometrybank::reset();
|
gfx::opengl_vbogeometrybank::reset();
|
||||||
Timer::subsystem.gfx_swap.stop();
|
Timer::subsystem.gfx_swap.stop();
|
||||||
}
|
}
|
||||||
@@ -402,7 +396,6 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
|||||||
else
|
else
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
|
||||||
|
|
||||||
setup_shadow_map(nullptr, m_renderpass);
|
setup_shadow_map(nullptr, m_renderpass);
|
||||||
setup_env_map(nullptr);
|
setup_env_map(nullptr);
|
||||||
|
|
||||||
@@ -465,7 +458,9 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
|||||||
// opaque parts...
|
// opaque parts...
|
||||||
setup_drawing(false);
|
setup_drawing(false);
|
||||||
|
|
||||||
if (false == FreeFlyModeFlag)
|
// without rain/snow we can render the cab early to limit the overdraw
|
||||||
|
// precipitation happens when overcast is in 1-2 range
|
||||||
|
if (!FreeFlyModeFlag && Global.Overcast <= 1.0f)
|
||||||
{
|
{
|
||||||
glDebug("render cab opaque");
|
glDebug("render cab opaque");
|
||||||
if (Global.gfx_shadowmap_enabled)
|
if (Global.gfx_shadowmap_enabled)
|
||||||
@@ -488,15 +483,26 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
|||||||
glDebug("render translucent region");
|
glDebug("render translucent region");
|
||||||
setup_drawing(true);
|
setup_drawing(true);
|
||||||
Render_Alpha(simulation::Region);
|
Render_Alpha(simulation::Region);
|
||||||
|
|
||||||
|
// precipitation; done at end, only before cab render
|
||||||
|
Render_precipitation();
|
||||||
|
|
||||||
|
// cab render
|
||||||
if (false == FreeFlyModeFlag)
|
if (false == FreeFlyModeFlag)
|
||||||
{
|
{
|
||||||
glDebug("render translucent cab");
|
glDebug("render translucent cab");
|
||||||
model_ubs.future = glm::mat4();
|
model_ubs.future = glm::mat4();
|
||||||
// cab render is performed without shadows, due to low resolution and number of models without windows :|
|
|
||||||
if (Global.gfx_shadowmap_enabled)
|
if (Global.gfx_shadowmap_enabled)
|
||||||
setup_shadow_map(m_cabshadows_tex.get(), m_cabshadowpass);
|
setup_shadow_map(m_cabshadows_tex.get(), m_cabshadowpass);
|
||||||
// cache shadow colour in case we need to account for cab light
|
// cache shadow colour in case we need to account for cab light
|
||||||
auto const *vehicle{simulation::Train->Dynamic()};
|
auto const *vehicle{simulation::Train->Dynamic()};
|
||||||
|
if (Global.Overcast > 1.0f)
|
||||||
|
{
|
||||||
|
// with active precipitation draw the opaque cab parts here to mask rain/snow placed 'inside' the cab
|
||||||
|
setup_drawing(false);
|
||||||
|
Render_cab(vehicle, false);
|
||||||
|
setup_drawing(true);
|
||||||
|
}
|
||||||
Render_cab(vehicle, true);
|
Render_cab(vehicle, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1152,13 +1158,16 @@ bool opengl_renderer::Render(world_environment *Environment)
|
|||||||
model_ubo->update(model_ubs);
|
model_ubo->update(model_ubs);
|
||||||
|
|
||||||
// skydome
|
// skydome
|
||||||
|
// drawn with 500m radius to blend in if the fog range is low
|
||||||
|
glPushMatrix();
|
||||||
|
glScalef(500.0f, 500.0f, 500.0f);
|
||||||
Environment->m_skydome.Render();
|
Environment->m_skydome.Render();
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
// skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh
|
// skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh
|
||||||
gfx::opengl_vbogeometrybank::reset();
|
gfx::opengl_vbogeometrybank::reset();
|
||||||
|
|
||||||
// celestial bodies
|
// celestial bodies
|
||||||
float const duskfactor = 1.0f - clamp(std::abs(Environment->m_sun.getAngle()), 0.0f, 12.0f) / 12.0f;
|
|
||||||
glm::vec3 suncolor = interpolate(glm::vec3(255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f), glm::vec3(235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f), duskfactor);
|
|
||||||
|
|
||||||
opengl_texture::reset_unit_cache();
|
opengl_texture::reset_unit_cache();
|
||||||
|
|
||||||
@@ -1182,6 +1191,10 @@ bool opengl_renderer::Render(world_environment *Environment)
|
|||||||
m_sunlight.apply_angle();
|
m_sunlight.apply_angle();
|
||||||
m_sunlight.apply_intensity();
|
m_sunlight.apply_intensity();
|
||||||
|
|
||||||
|
auto const fogfactor{clamp<float>(Global.fFogEnd / 2000.f, 0.f, 1.f)}; // stronger fog reduces opacity of the celestial bodies
|
||||||
|
float const duskfactor = 1.0f - clamp(std::abs(Environment->m_sun.getAngle()), 0.0f, 12.0f) / 12.0f;
|
||||||
|
glm::vec3 suncolor = interpolate(glm::vec3(255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f), glm::vec3(235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f), duskfactor);
|
||||||
|
|
||||||
// clouds
|
// clouds
|
||||||
if (Environment->m_clouds.mdCloud)
|
if (Environment->m_clouds.mdCloud)
|
||||||
{
|
{
|
||||||
@@ -1832,7 +1845,7 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
|
|||||||
++m_debugstats.dynamics;
|
++m_debugstats.dynamics;
|
||||||
|
|
||||||
// setup
|
// setup
|
||||||
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( Dynamic ); //żeby nie robić cudzych animacji
|
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>(Dynamic); //żeby nie robić cudzych animacji
|
||||||
glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.camera.position();
|
glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.camera.position();
|
||||||
// lod visibility ranges are defined for base (x 1.0) viewing distance. for render we adjust them for actual range multiplier and zoom
|
// lod visibility ranges are defined for base (x 1.0) viewing distance. for render we adjust them for actual range multiplier and zoom
|
||||||
float squaredistance;
|
float squaredistance;
|
||||||
@@ -1902,7 +1915,7 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
|
|||||||
Render(Dynamic->mdModel, Dynamic->Material(), squaredistance);
|
Render(Dynamic->mdModel, Dynamic->Material(), squaredistance);
|
||||||
|
|
||||||
if (Dynamic->mdLoad) // renderowanie nieprzezroczystego ładunku
|
if (Dynamic->mdLoad) // renderowanie nieprzezroczystego ładunku
|
||||||
Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
|
Render_Alpha(Dynamic->mdLoad, Dynamic->Material(), squaredistance, {0.f, Dynamic->LoadOffset, 0.f}, {});
|
||||||
|
|
||||||
// post-render cleanup
|
// post-render cleanup
|
||||||
// calc_motion = false;
|
// calc_motion = false;
|
||||||
@@ -2251,9 +2264,10 @@ void opengl_renderer::Render(TSubModel *Submodel)
|
|||||||
float lightlevel = 1.f; // TODO, TBD: parameter to control light strength
|
float lightlevel = 1.f; // TODO, TBD: parameter to control light strength
|
||||||
// view angle attenuation
|
// view angle attenuation
|
||||||
float const anglefactor = clamp((Submodel->fCosViewAngle - Submodel->fCosFalloffAngle) / (Submodel->fCosHotspotAngle - Submodel->fCosFalloffAngle), 0.f, 1.f);
|
float const anglefactor = clamp((Submodel->fCosViewAngle - Submodel->fCosFalloffAngle) / (Submodel->fCosHotspotAngle - Submodel->fCosFalloffAngle), 0.f, 1.f);
|
||||||
// distance attenuation. NOTE: since it's fixed pipeline with built-in gamma correction we're using linear attenuation
|
// distance attenuation
|
||||||
// we're capping how much effect the distance attenuation can have, otherwise the lights get too tiny at regular distances
|
// 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 distancefactor = std::max(0.5f, (Submodel->fSquareMaxDist - TSubModel::fSquareDist) / Submodel->fSquareMaxDist);
|
||||||
|
float const precipitationfactor = std::max(1.f, Global.Overcast - 1.f);
|
||||||
|
|
||||||
if (lightlevel > 0.f)
|
if (lightlevel > 0.f)
|
||||||
{
|
{
|
||||||
@@ -2271,7 +2285,7 @@ void opengl_renderer::Render(TSubModel *Submodel)
|
|||||||
|
|
||||||
// main draw call
|
// main draw call
|
||||||
model_ubs.param[0] = glm::vec4(glm::vec3(Submodel->f4Diffuse), 0.0f);
|
model_ubs.param[0] = glm::vec4(glm::vec3(Submodel->f4Diffuse), 0.0f);
|
||||||
model_ubs.emission = lightlevel * anglefactor;
|
model_ubs.emission = std::min(1.f, lightlevel * anglefactor * precipitationfactor);
|
||||||
m_freespot_shader->bind();
|
m_freespot_shader->bind();
|
||||||
|
|
||||||
draw(Submodel->m_geometry);
|
draw(Submodel->m_geometry);
|
||||||
@@ -2569,6 +2583,55 @@ void opengl_renderer::Render(TMemCell *Memcell)
|
|||||||
::glPopMatrix();
|
::glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void opengl_renderer::Render_precipitation()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Global.Overcast <= 1.f)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
::glPushMatrix();
|
||||||
|
// tilt the precipitation cone against the velocity vector for crude motion blur
|
||||||
|
auto const velocity{simulation::Environment.m_precipitation.m_cameramove * -1.0};
|
||||||
|
if (glm::length2(velocity) > 0.0)
|
||||||
|
{
|
||||||
|
auto const forward{glm::normalize(velocity)};
|
||||||
|
auto left{glm::cross(forward, {0.0, 1.0, 0.0})};
|
||||||
|
auto const rotationangle{std::min(45.0, (FreeFlyModeFlag ? 5 * glm::length(velocity) : simulation::Train->Dynamic()->GetVelocity() * 0.2))};
|
||||||
|
::glRotated(rotationangle, left.x, 0.0, left.z);
|
||||||
|
}
|
||||||
|
if (false == FreeFlyModeFlag)
|
||||||
|
{
|
||||||
|
// counter potential vehicle roll
|
||||||
|
auto const roll{0.5 * glm::degrees(simulation::Train->Dynamic()->Roll())};
|
||||||
|
if (roll != 0.0)
|
||||||
|
{
|
||||||
|
auto const forward{simulation::Train->Dynamic()->VectorFront()};
|
||||||
|
auto const vehicledirection = simulation::Train->Dynamic()->DirectionGet();
|
||||||
|
::glRotated(roll, forward.x, 0.0, forward.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Global.Weather == "rain:")
|
||||||
|
{
|
||||||
|
// oddly enough random streaks produce more natural looking rain than ones the eye can follow
|
||||||
|
::glRotated(Random() * 360, 0.0, 1.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_ubo->update(model_ubs);
|
||||||
|
|
||||||
|
// momentarily disable depth write, to allow vehicle cab drawn afterwards to mask it instead of leaving it 'inside'
|
||||||
|
::glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
simulation::Environment.m_precipitation.render();
|
||||||
|
|
||||||
|
::glDepthMask(GL_TRUE);
|
||||||
|
::glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
void opengl_renderer::Render_Alpha(scene::basic_region *Region)
|
void opengl_renderer::Render_Alpha(scene::basic_region *Region)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -3040,8 +3103,7 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel)
|
|||||||
}
|
}
|
||||||
else if (Submodel->eType == TP_FREESPOTLIGHT)
|
else if (Submodel->eType == TP_FREESPOTLIGHT)
|
||||||
{
|
{
|
||||||
|
if (Global.fLuminance < Submodel->fLight || Global.Overcast > 1.0f)
|
||||||
if (Global.fLuminance < Submodel->fLight)
|
|
||||||
{
|
{
|
||||||
// NOTE: we're forced here to redo view angle calculations etc, because this data isn't instanced but stored along with the single mesh
|
// NOTE: we're forced here to redo view angle calculations etc, because this data isn't instanced but stored along with the single mesh
|
||||||
// TODO: separate instance data from reusable geometry
|
// TODO: separate instance data from reusable geometry
|
||||||
@@ -3054,15 +3116,12 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel)
|
|||||||
if (Submodel->fCosViewAngle > Submodel->fCosFalloffAngle)
|
if (Submodel->fCosViewAngle > Submodel->fCosFalloffAngle)
|
||||||
{
|
{
|
||||||
// only bother if the viewer is inside the visibility cone
|
// only bother if the viewer is inside the visibility cone
|
||||||
if (Global.Overcast > 1.0)
|
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
|
||||||
// increase the glare in rainy/foggy conditions
|
0.f, 1.f)};
|
||||||
glarelevel += std::max(0.f, 0.5f * (Global.Overcast - 1.f));
|
|
||||||
}
|
|
||||||
// scale it down based on view angle
|
// scale it down based on view angle
|
||||||
glarelevel *= (Submodel->fCosViewAngle - Submodel->fCosFalloffAngle) / (1.0f - Submodel->fCosFalloffAngle);
|
glarelevel *= (Submodel->fCosViewAngle - Submodel->fCosFalloffAngle) / (1.0f - Submodel->fCosFalloffAngle);
|
||||||
// reduce the glare in bright daylight
|
|
||||||
glarelevel = clamp(glarelevel - static_cast<float>(Global.fLuminance), 0.f, 1.f);
|
|
||||||
|
|
||||||
if (glarelevel > 0.0f)
|
if (glarelevel > 0.0f)
|
||||||
{
|
{
|
||||||
@@ -3403,7 +3462,10 @@ void opengl_renderer::Update_Lights(light_array &Lights)
|
|||||||
|
|
||||||
light_ubs.fog_color = Global.FogColor;
|
light_ubs.fog_color = Global.FogColor;
|
||||||
if (Global.fFogEnd > 0)
|
if (Global.fFogEnd > 0)
|
||||||
light_ubs.fog_density = 1.0f / Global.fFogEnd;
|
{
|
||||||
|
auto const adjustedfogrange{Global.fFogEnd / std::max(1.f, Global.Overcast * 2.f)};
|
||||||
|
light_ubs.fog_density = 1.0f / adjustedfogrange;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
light_ubs.fog_density = 0.0f;
|
light_ubs.fog_density = 0.0f;
|
||||||
|
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ class opengl_renderer
|
|||||||
void Render(scene::basic_cell::path_sequence::const_iterator First, scene::basic_cell::path_sequence::const_iterator Last);
|
void Render(scene::basic_cell::path_sequence::const_iterator First, scene::basic_cell::path_sequence::const_iterator Last);
|
||||||
bool Render_cab(TDynamicObject const *Dynamic, bool const Alpha = false);
|
bool Render_cab(TDynamicObject const *Dynamic, bool const Alpha = false);
|
||||||
void Render(TMemCell *Memcell);
|
void Render(TMemCell *Memcell);
|
||||||
|
void Render_precipitation();
|
||||||
void Render_Alpha(scene::basic_region *Region);
|
void Render_Alpha(scene::basic_region *Region);
|
||||||
void Render_Alpha(cell_sequence::reverse_iterator First, cell_sequence::reverse_iterator Last);
|
void Render_Alpha(cell_sequence::reverse_iterator First, cell_sequence::reverse_iterator Last);
|
||||||
void Render_Alpha(TAnimModel *Instance);
|
void Render_Alpha(TAnimModel *Instance);
|
||||||
|
|||||||
42
scene.cpp
42
scene.cpp
@@ -233,7 +233,8 @@ basic_cell::deserialize( std::istream &Input ) {
|
|||||||
}
|
}
|
||||||
// cell activation flag
|
// cell activation flag
|
||||||
m_active = (
|
m_active = (
|
||||||
( false == m_shapesopaque.empty() )
|
( true == m_active )
|
||||||
|
|| ( false == m_shapesopaque.empty() )
|
||||||
|| ( false == m_shapestranslucent.empty() )
|
|| ( false == m_shapestranslucent.empty() )
|
||||||
|| ( false == m_lines.empty() ) );
|
|| ( false == m_lines.empty() ) );
|
||||||
}
|
}
|
||||||
@@ -1004,6 +1005,37 @@ basic_region::update_traction( TDynamicObject *Vehicle, int const Pantographinde
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checks whether specified file is a valid region data file
|
||||||
|
bool
|
||||||
|
basic_region::is_scene( std::string const &Scenariofile ) const {
|
||||||
|
|
||||||
|
auto filename { Scenariofile };
|
||||||
|
while( filename[ 0 ] == '$' ) {
|
||||||
|
// trim leading $ char rainsted utility may add to the base name for modified .scn files
|
||||||
|
filename.erase( 0, 1 );
|
||||||
|
}
|
||||||
|
erase_extension( filename );
|
||||||
|
filename = Global.asCurrentSceneryPath + filename;
|
||||||
|
filename += EU07_FILEEXTENSION_REGION;
|
||||||
|
|
||||||
|
if( false == FileExists( filename ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// file type and version check
|
||||||
|
std::ifstream input( filename, std::ios::binary );
|
||||||
|
|
||||||
|
uint32_t headermain{ sn_utils::ld_uint32( input ) };
|
||||||
|
uint32_t headertype{ sn_utils::ld_uint32( input ) };
|
||||||
|
|
||||||
|
if( ( headermain != EU07_FILEHEADER
|
||||||
|
|| ( headertype != EU07_FILEVERSION_REGION ) ) ) {
|
||||||
|
// wrong file type
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// stores content of the class in file with specified name
|
// stores content of the class in file with specified name
|
||||||
void
|
void
|
||||||
basic_region::serialize( std::string const &Scenariofile ) const {
|
basic_region::serialize( std::string const &Scenariofile ) const {
|
||||||
@@ -1078,10 +1110,12 @@ basic_region::deserialize( std::string const &Scenariofile ) {
|
|||||||
auto sectioncount { sn_utils::ld_uint32( input ) };
|
auto sectioncount { sn_utils::ld_uint32( input ) };
|
||||||
while( sectioncount-- ) {
|
while( sectioncount-- ) {
|
||||||
// section index, followed by section data size, followed by section data
|
// section index, followed by section data size, followed by section data
|
||||||
auto *§ion { m_sections[ sn_utils::ld_uint32( input ) ] };
|
auto const sectionindex { sn_utils::ld_uint32( input ) };
|
||||||
auto const sectionsize { sn_utils::ld_uint32( input ) };
|
auto const sectionsize { sn_utils::ld_uint32( input ) };
|
||||||
section = new basic_section();
|
if( m_sections[ sectionindex ] == nullptr ) {
|
||||||
section->deserialize( input );
|
m_sections[ sectionindex ] = new basic_section();
|
||||||
|
}
|
||||||
|
m_sections[ sectionindex ]->deserialize( input );
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
4
scene.h
4
scene.h
@@ -54,6 +54,7 @@ struct scratch_data {
|
|||||||
bool is_open { false };
|
bool is_open { false };
|
||||||
} trainset;
|
} trainset;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
bool initialized { false };
|
bool initialized { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -330,6 +331,9 @@ public:
|
|||||||
// legacy method, updates sounds around camera
|
// legacy method, updates sounds around camera
|
||||||
void
|
void
|
||||||
update_sounds();
|
update_sounds();
|
||||||
|
// checks whether specified file is a valid region data file
|
||||||
|
bool
|
||||||
|
is_scene( std::string const &Scenariofile ) const;
|
||||||
// stores content of the class in file with specified name
|
// stores content of the class in file with specified name
|
||||||
void
|
void
|
||||||
serialize( std::string const &Scenariofile ) const;
|
serialize( std::string const &Scenariofile ) const;
|
||||||
|
|||||||
17
shaders/precipitation.frag
Normal file
17
shaders/precipitation.frag
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
in vec2 f_coord;
|
||||||
|
|
||||||
|
#texture (tex1, 0, sRGB_A)
|
||||||
|
uniform sampler2D tex1;
|
||||||
|
|
||||||
|
#include <common>
|
||||||
|
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
20
shaders/precipitation.vert
Normal file
20
shaders/precipitation.vert
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 v_vert;
|
||||||
|
layout(location = 1) in vec2 v_coord;
|
||||||
|
|
||||||
|
out vec2 f_coord;
|
||||||
|
|
||||||
|
out vec4 f_clip_pos;
|
||||||
|
out vec4 f_clip_future_pos;
|
||||||
|
|
||||||
|
#include <common>
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
f_clip_pos = (projection * modelview) * vec4(v_vert, 1.0f);
|
||||||
|
f_clip_future_pos = (projection * future * modelview) * vec4(v_vert, 1.0f);
|
||||||
|
|
||||||
|
gl_Position = f_clip_pos;
|
||||||
|
f_coord = v_coord;
|
||||||
|
}
|
||||||
@@ -62,8 +62,8 @@ void
|
|||||||
world_environment::compute_weather() const {
|
world_environment::compute_weather() const {
|
||||||
|
|
||||||
Global.Weather = (
|
Global.Weather = (
|
||||||
Global.Overcast < 0.25 ? "clear:" :
|
Global.Overcast <= 0.25 ? "clear:" :
|
||||||
Global.Overcast < 1.0 ? "cloudy:" :
|
Global.Overcast <= 1.0 ? "cloudy:" :
|
||||||
( Global.Season != "winter:" ?
|
( Global.Season != "winter:" ?
|
||||||
"rain:" :
|
"rain:" :
|
||||||
"snow:" ) );
|
"snow:" ) );
|
||||||
@@ -76,6 +76,9 @@ world_environment::init() {
|
|||||||
m_moon.init();
|
m_moon.init();
|
||||||
m_stars.init();
|
m_stars.init();
|
||||||
m_clouds.Init();
|
m_clouds.Init();
|
||||||
|
m_precipitation.init();
|
||||||
|
|
||||||
|
m_precipitationsound.deserialize( "rain-sound-loop", sound_type::single );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -147,6 +150,24 @@ world_environment::update() {
|
|||||||
// but quite effective way to make the distant items blend with background better
|
// but quite effective way to make the distant items blend with background better
|
||||||
// NOTE: base brightness calculation provides scaled up value, so we bring it back to 'real' one here
|
// NOTE: base brightness calculation provides scaled up value, so we bring it back to 'real' one here
|
||||||
Global.FogColor = m_skydome.GetAverageHorizonColor();
|
Global.FogColor = m_skydome.GetAverageHorizonColor();
|
||||||
|
|
||||||
|
// weather-related simulation factors
|
||||||
|
// TODO: dynamic change of air temperature and overcast levels
|
||||||
|
if( Global.Weather == "rain:" ) {
|
||||||
|
// reduce friction in rain
|
||||||
|
Global.FrictionWeatherFactor = 0.85f;
|
||||||
|
m_precipitationsound.play( sound_flags::exclusive | sound_flags::looping );
|
||||||
|
}
|
||||||
|
else if( Global.Weather == "snow:" ) {
|
||||||
|
// reduce friction due to snow
|
||||||
|
Global.FrictionWeatherFactor = 0.75f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
world_environment::update_precipitation() {
|
||||||
|
|
||||||
|
m_precipitation.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "moon.h"
|
#include "moon.h"
|
||||||
#include "stars.h"
|
#include "stars.h"
|
||||||
#include "skydome.h"
|
#include "skydome.h"
|
||||||
|
#include "precipitation.h"
|
||||||
|
#include "sound.h"
|
||||||
|
|
||||||
class opengl_renderer;
|
class opengl_renderer;
|
||||||
|
|
||||||
@@ -26,6 +28,7 @@ public:
|
|||||||
// methods
|
// methods
|
||||||
void init();
|
void init();
|
||||||
void update();
|
void update();
|
||||||
|
void update_precipitation();
|
||||||
void time( int const Hour = -1, int const Minute = -1, int const Second = -1 );
|
void time( int const Hour = -1, int const Minute = -1, int const Second = -1 );
|
||||||
// switches between static and dynamic daylight calculation
|
// switches between static and dynamic daylight calculation
|
||||||
void toggle_daylight();
|
void toggle_daylight();
|
||||||
@@ -41,6 +44,9 @@ private:
|
|||||||
cSun m_sun;
|
cSun m_sun;
|
||||||
cMoon m_moon;
|
cMoon m_moon;
|
||||||
TSky m_clouds;
|
TSky m_clouds;
|
||||||
|
basic_precipitation m_precipitation;
|
||||||
|
|
||||||
|
sound_source m_precipitationsound { sound_placement::external, -1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace simulation {
|
namespace simulation {
|
||||||
|
|||||||
@@ -35,9 +35,11 @@ state_serializer::deserialize( std::string const &Scenariofile ) {
|
|||||||
// TODO: check first for presence of serialized binary files
|
// TODO: check first for presence of serialized binary files
|
||||||
// if this fails, fall back on the legacy text format
|
// if this fails, fall back on the legacy text format
|
||||||
scene::scratch_data importscratchpad;
|
scene::scratch_data importscratchpad;
|
||||||
|
importscratchpad.name = Scenariofile;
|
||||||
if( Scenariofile != "$.scn" ) {
|
if( Scenariofile != "$.scn" ) {
|
||||||
// compilation to binary file isn't supported for rainsted-created overrides
|
// compilation to binary file isn't supported for rainsted-created overrides
|
||||||
importscratchpad.binary.terrain = Region->deserialize( Scenariofile );
|
// NOTE: we postpone actual loading of the scene until we process time, season and weather data
|
||||||
|
importscratchpad.binary.terrain = Region->is_scene( Scenariofile ) ;
|
||||||
}
|
}
|
||||||
// NOTE: for the time being import from text format is a given, since we don't have full binary serialization
|
// NOTE: for the time being import from text format is a given, since we don't have full binary serialization
|
||||||
cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global.asCurrentSceneryPath, Global.bLoadTraction );
|
cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global.asCurrentSceneryPath, Global.bLoadTraction );
|
||||||
@@ -277,6 +279,12 @@ state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Sc
|
|||||||
|
|
||||||
if( true == Scratchpad.initialized ) { return; }
|
if( true == Scratchpad.initialized ) { return; }
|
||||||
|
|
||||||
|
if( true == Scratchpad.binary.terrain ) {
|
||||||
|
// at this stage it should be safe to import terrain from the binary scene file
|
||||||
|
// TBD: postpone loading furter and only load required blocks during the simulation?
|
||||||
|
Region->deserialize( Scratchpad.name );
|
||||||
|
}
|
||||||
|
|
||||||
simulation::Paths.InitTracks();
|
simulation::Paths.InitTracks();
|
||||||
simulation::Traction.InitTraction();
|
simulation::Traction.InitTraction();
|
||||||
simulation::Events.InitEvents();
|
simulation::Events.InitEvents();
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Sch
|
|||||||
|
|
||||||
if( parameters.LoadType.name.empty() ) {
|
if( parameters.LoadType.name.empty() ) {
|
||||||
// (try to) set the cargo type for empty cars
|
// (try to) set the cargo type for empty cars
|
||||||
|
parameters.LoadAmount = 0.f; // safety measure against edge cases
|
||||||
parameters.AssignLoad( "passengers" );
|
parameters.AssignLoad( "passengers" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3
stdafx.h
3
stdafx.h
@@ -99,10 +99,13 @@
|
|||||||
#include <glm/gtx/norm.hpp>
|
#include <glm/gtx/norm.hpp>
|
||||||
#include <glm/gtx/string_cast.hpp>
|
#include <glm/gtx/string_cast.hpp>
|
||||||
|
|
||||||
|
int const null_handle = 0;
|
||||||
|
|
||||||
#include "openglmatrixstack.h"
|
#include "openglmatrixstack.h"
|
||||||
#define STRINGIZE_DETAIL(x) #x
|
#define STRINGIZE_DETAIL(x) #x
|
||||||
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
|
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
|
||||||
#define glDebug(x) if (GLEW_GREMEDY_string_marker) glStringMarkerGREMEDY(0, __FILE__ ":" STRINGIZE(__LINE__) ": " x);
|
#define glDebug(x) if (GLEW_GREMEDY_string_marker) glStringMarkerGREMEDY(0, __FILE__ ":" STRINGIZE(__LINE__) ": " x);
|
||||||
|
#include "openglcolor.h"
|
||||||
|
|
||||||
#ifdef DBG_NEW
|
#ifdef DBG_NEW
|
||||||
#pragma push_macro("new")
|
#pragma push_macro("new")
|
||||||
|
|||||||
@@ -170,6 +170,11 @@ bool ui_layer::on_key(int const Key, int const Action)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Key == GLFW_KEY_F10) {
|
||||||
|
m_quit_active = !m_quit_active;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_quit_active)
|
if (m_quit_active)
|
||||||
{
|
{
|
||||||
if (Key == GLFW_KEY_Y) {
|
if (Key == GLFW_KEY_Y) {
|
||||||
@@ -319,7 +324,7 @@ void ui_layer::render_menu_contents()
|
|||||||
if (ImGui::BeginMenu(LOC_STR(ui_general)))
|
if (ImGui::BeginMenu(LOC_STR(ui_general)))
|
||||||
{
|
{
|
||||||
ImGui::MenuItem(LOC_STR(ui_debug_mode), nullptr, &DebugModeFlag);
|
ImGui::MenuItem(LOC_STR(ui_debug_mode), nullptr, &DebugModeFlag);
|
||||||
ImGui::MenuItem(LOC_STR(ui_quit), nullptr, &m_quit_active);
|
ImGui::MenuItem(LOC_STR(ui_quit), "F10", &m_quit_active);
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
if (ImGui::BeginMenu(LOC_STR(ui_tools)))
|
if (ImGui::BeginMenu(LOC_STR(ui_tools)))
|
||||||
|
|||||||
59
utilities.h
59
utilities.h
@@ -313,3 +313,62 @@ glm::dvec3 LoadPoint( class cParser &Input );
|
|||||||
// extracts a group of tokens from provided data stream
|
// extracts a group of tokens from provided data stream
|
||||||
std::string
|
std::string
|
||||||
deserialize_random_set( cParser &Input, char const *Break = "\n\r\t ;" );
|
deserialize_random_set( cParser &Input, char const *Break = "\n\r\t ;" );
|
||||||
|
|
||||||
|
namespace threading {
|
||||||
|
|
||||||
|
// simple POD pairing of a data item and a mutex
|
||||||
|
// NOTE: doesn't do any locking itself, it's merely for cleaner argument arrangement and passing
|
||||||
|
template <typename Type_>
|
||||||
|
struct lockable {
|
||||||
|
|
||||||
|
Type_ data;
|
||||||
|
std::mutex mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
// basic wrapper simplifying use of std::condition_variable for most typical cases.
|
||||||
|
// has its own mutex and secondary variable to ignore spurious wakeups
|
||||||
|
class condition_variable {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// methods
|
||||||
|
void
|
||||||
|
wait() {
|
||||||
|
std::unique_lock<std::mutex> lock( m_mutex );
|
||||||
|
m_condition.wait(
|
||||||
|
lock,
|
||||||
|
[ this ]() {
|
||||||
|
return m_spurious == false; } ); }
|
||||||
|
template< class Rep_, class Period_ >
|
||||||
|
void
|
||||||
|
wait_for( const std::chrono::duration<Rep_, Period_> &Time ) {
|
||||||
|
std::unique_lock<std::mutex> lock( m_mutex );
|
||||||
|
m_condition.wait_for(
|
||||||
|
lock,
|
||||||
|
Time,
|
||||||
|
[ this ]() {
|
||||||
|
return m_spurious == false; } ); }
|
||||||
|
void
|
||||||
|
notify_one() {
|
||||||
|
spurious( false );
|
||||||
|
m_condition.notify_one();
|
||||||
|
}
|
||||||
|
void
|
||||||
|
notify_all() {
|
||||||
|
spurious( false );
|
||||||
|
m_condition.notify_all();
|
||||||
|
}
|
||||||
|
void
|
||||||
|
spurious( bool const Spurious ) {
|
||||||
|
std::lock_guard<std::mutex> lock( m_mutex );
|
||||||
|
m_spurious = Spurious; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// members
|
||||||
|
mutable std::mutex m_mutex;
|
||||||
|
std::condition_variable m_condition;
|
||||||
|
bool m_spurious { true };
|
||||||
|
};
|
||||||
|
|
||||||
|
} // threading
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user