mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-23 16:49:18 +02:00
build 180923. basic precipitation visualization system, minor bug fixes
This commit is contained in:
88
Driver.cpp
88
Driver.cpp
@@ -238,9 +238,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
|
||||||
@@ -879,7 +886,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
|
||||||
@@ -1035,9 +1041,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;
|
||||||
@@ -1061,14 +1070,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
|
||||||
@@ -1094,36 +1104,42 @@ 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ł
|
||||||
// sprawdzanie eventów pasywnych miniętych
|
if( sSpeedTable[ i ].fDist < 0.0 ) {
|
||||||
if( (sSpeedTable[ i ].fDist < 0.0) && (SemNextIndex == i) )
|
// sprawdzanie eventów pasywnych miniętych
|
||||||
{
|
/*
|
||||||
if( Global.iWriteLogEnabled & 8 ) {
|
if( ( eSignNext != nullptr ) && ( sSpeedTable[ i ].evEvent == eSignNext ) ) {
|
||||||
WriteLog( "Speed table update for " + OwnerName() + ", passed semaphor " + sSpeedTable[ SemNextIndex ].GetName() );
|
VelSignalLast = sSpeedTable[ i ].fVelNext;
|
||||||
}
|
}
|
||||||
SemNextIndex = -1; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze zmiennej sprawdzającej dla skanowania w przód
|
*/
|
||||||
}
|
if( SemNextIndex == i ) {
|
||||||
if( (sSpeedTable[ i ].fDist < 0.0) && (SemNextStopIndex == i) )
|
|
||||||
{
|
|
||||||
if( Global.iWriteLogEnabled & 8 ) {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
if (sSpeedTable[i].fDist > 0.0 &&
|
|
||||||
sSpeedTable[i].IsProperSemaphor(OrderCurrentGet()))
|
|
||||||
{
|
|
||||||
if( SemNextIndex == -1 ) {
|
|
||||||
// jeśli jest mienięty poprzedni semafor a wcześniej
|
|
||||||
// byl nowy to go dorzucamy do zmiennej, żeby cały czas widział najbliższy
|
|
||||||
SemNextIndex = i;
|
|
||||||
if( Global.iWriteLogEnabled & 8 ) {
|
if( Global.iWriteLogEnabled & 8 ) {
|
||||||
WriteLog( "Speed table update for " + OwnerName() + ", next semaphor is " + 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
|
||||||
}
|
}
|
||||||
if( ( SemNextStopIndex == -1 )
|
if( SemNextStopIndex == i ) {
|
||||||
|| ( ( sSpeedTable[SemNextStopIndex].fVelNext != 0 )
|
if( Global.iWriteLogEnabled & 8 ) {
|
||||||
&& ( sSpeedTable[ i ].fVelNext == 0 ) ) ) {
|
WriteLog( "Speed table update for " + OwnerName() + ", passed semaphor " + sSpeedTable[ SemNextStopIndex ].GetName() );
|
||||||
SemNextStopIndex = i;
|
}
|
||||||
|
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 ) {
|
||||||
|
// check signals ahead
|
||||||
|
if( sSpeedTable[ i ].IsProperSemaphor( OrderCurrentGet() ) ) {
|
||||||
|
if( SemNextIndex == -1 ) {
|
||||||
|
// jeśli jest mienięty poprzedni semafor a wcześniej
|
||||||
|
// byl nowy to go dorzucamy do zmiennej, żeby cały czas widział najbliższy
|
||||||
|
SemNextIndex = i;
|
||||||
|
if( Global.iWriteLogEnabled & 8 ) {
|
||||||
|
WriteLog( "Speed table update for " + OwnerName() + ", next semaphor is " + sSpeedTable[ SemNextIndex ].GetName() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( ( SemNextStopIndex == -1 )
|
||||||
|
|| ( ( sSpeedTable[ SemNextStopIndex ].fVelNext != 0 )
|
||||||
|
&& ( sSpeedTable[ i ].fVelNext == 0 ) ) ) {
|
||||||
|
SemNextStopIndex = i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sSpeedTable[i].iFlags & spOutsideStation)
|
if (sSpeedTable[i].iFlags & spOutsideStation)
|
||||||
|
|||||||
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
|
||||||
|
|||||||
10
DynObj.cpp
10
DynObj.cpp
@@ -2014,7 +2014,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;
|
||||||
}
|
}
|
||||||
@@ -2396,12 +2396,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ę
|
||||||
@@ -2838,7 +2838,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;
|
||||||
|
|||||||
2
DynObj.h
2
DynObj.h
@@ -546,6 +546,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
|
||||||
|
|||||||
@@ -65,6 +65,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 };
|
||||||
|
|||||||
49
Train.cpp
49
Train.cpp
@@ -527,9 +527,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() ) );
|
||||||
@@ -4529,31 +4529,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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -5863,7 +5846,7 @@ 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 )
|
||||||
@@ -5875,6 +5858,7 @@ TTrain::update_sounds( double const Deltatime ) {
|
|||||||
// don't play the optional ending sound if the listener switches views
|
// don't play the optional ending sound if the listener switches views
|
||||||
rsRunningNoise.stop( true == FreeFlyModeFlag );
|
rsRunningNoise.stop( true == FreeFlyModeFlag );
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// hunting oscillation noise
|
// hunting oscillation noise
|
||||||
if( ( false == FreeFlyModeFlag )
|
if( ( false == FreeFlyModeFlag )
|
||||||
&& ( false == Global.CabWindowOpen )
|
&& ( false == Global.CabWindowOpen )
|
||||||
@@ -5882,6 +5866,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
|
||||||
|
|||||||
@@ -224,6 +224,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();
|
||||||
@@ -951,6 +953,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ą
|
||||||
|
|||||||
@@ -330,6 +330,9 @@
|
|||||||
<ClCompile Include="ref\imgui\imgui_widgets.cpp">
|
<ClCompile Include="ref\imgui\imgui_widgets.cpp">
|
||||||
<Filter>Source Files\imgui</Filter>
|
<Filter>Source Files\imgui</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="precipitation.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Globals.h">
|
<ClInclude Include="Globals.h">
|
||||||
@@ -608,6 +611,9 @@
|
|||||||
<ClInclude Include="editoruipanels.h">
|
<ClInclude Include="editoruipanels.h">
|
||||||
<Filter>Header Files\application\mode_editor</Filter>
|
<Filter>Header Files\application\mode_editor</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="precipitation.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="maszyna.rc">
|
<ResourceCompile Include="maszyna.rc">
|
||||||
|
|||||||
@@ -43,12 +43,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
|
||||||
}
|
}
|
||||||
|
|||||||
197
precipitation.cpp
Normal file
197
precipitation.cpp
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
if( Global.Weather == "rain:" ) {
|
||||||
|
m_texture = GfxRenderer.Fetch_Texture( "fx/rain_medium" );
|
||||||
|
m_moverateweathertypefactor = 2.f;
|
||||||
|
}
|
||||||
|
else if( Global.Weather == "snow:" ) {
|
||||||
|
m_texture = GfxRenderer.Fetch_Texture( "fx/snow_medium" );
|
||||||
|
m_moverateweathertypefactor = 1.25f;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 1.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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
basic_precipitation::render() {
|
||||||
|
|
||||||
|
GfxRenderer.Bind_Texture( m_texture );
|
||||||
|
|
||||||
|
// cache entry state
|
||||||
|
::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
|
||||||
|
|
||||||
|
if( m_vertexbuffer == -1 ) {
|
||||||
|
// 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 );
|
||||||
|
|
||||||
|
::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 );
|
||||||
|
|
||||||
|
::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
|
||||||
|
}
|
||||||
|
// positions
|
||||||
|
::glBindBuffer( GL_ARRAY_BUFFER, m_vertexbuffer );
|
||||||
|
::glVertexPointer( 3, GL_FLOAT, sizeof( glm::vec3 ), reinterpret_cast<void const*>( 0 ) );
|
||||||
|
::glEnableClientState( GL_VERTEX_ARRAY );
|
||||||
|
// uvs
|
||||||
|
::glBindBuffer( GL_ARRAY_BUFFER, m_uvbuffer );
|
||||||
|
::glClientActiveTexture( m_textureunit );
|
||||||
|
::glTexCoordPointer( 2, GL_FLOAT, sizeof( glm::vec2 ), reinterpret_cast<void const*>( 0 ) );
|
||||||
|
::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||||
|
// uv transformation matrix
|
||||||
|
::glMatrixMode( GL_TEXTURE );
|
||||||
|
::glLoadIdentity();
|
||||||
|
::glTranslatef( 0.f, m_textureoffset, 0.f );
|
||||||
|
// indices
|
||||||
|
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer );
|
||||||
|
::glDrawElements( GL_TRIANGLES, static_cast<GLsizei>( m_indices.size() ), GL_UNSIGNED_SHORT, reinterpret_cast<void const*>( 0 ) );
|
||||||
|
// cleanup
|
||||||
|
::glLoadIdentity();
|
||||||
|
::glMatrixMode( GL_MODELVIEW );
|
||||||
|
::glPopClientAttrib();
|
||||||
|
}
|
||||||
59
precipitation.h
Normal file
59
precipitation.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
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 "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
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
set_unit( GLint const Textureunit ) {
|
||||||
|
m_textureunit = Textureunit; }
|
||||||
|
bool
|
||||||
|
init();
|
||||||
|
void
|
||||||
|
update();
|
||||||
|
void
|
||||||
|
render();
|
||||||
|
|
||||||
|
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 };
|
||||||
|
GLint m_textureunit { 0 };
|
||||||
|
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 };
|
||||||
|
};
|
||||||
71
renderer.cpp
71
renderer.cpp
@@ -129,6 +129,7 @@ opengl_renderer::Init( GLFWwindow *Window ) {
|
|||||||
std::vector<GLint>{ m_normaltextureunit, m_diffusetextureunit } );
|
std::vector<GLint>{ m_normaltextureunit, m_diffusetextureunit } );
|
||||||
m_textures.assign_units( m_helpertextureunit, m_shadowtextureunit, m_normaltextureunit, m_diffusetextureunit ); // TODO: add reflections unit
|
m_textures.assign_units( m_helpertextureunit, m_shadowtextureunit, m_normaltextureunit, m_diffusetextureunit ); // TODO: add reflections unit
|
||||||
ui_layer::set_unit( m_diffusetextureunit );
|
ui_layer::set_unit( m_diffusetextureunit );
|
||||||
|
simulation::Environment.m_precipitation.set_unit( m_diffusetextureunit );
|
||||||
select_unit( m_diffusetextureunit );
|
select_unit( m_diffusetextureunit );
|
||||||
|
|
||||||
::glDepthFunc( GL_LEQUAL );
|
::glDepthFunc( GL_LEQUAL );
|
||||||
@@ -550,7 +551,9 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
|||||||
::glEnable( GL_TEXTURE_2D );
|
::glEnable( GL_TEXTURE_2D );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if( false == FreeFlyModeFlag ) {
|
// without rain/snow we can render the cab early to limit the overdraw
|
||||||
|
if( ( false == FreeFlyModeFlag )
|
||||||
|
&& ( Global.Overcast <= 1.f ) ) { // precipitation happens when overcast is in 1-2 range
|
||||||
switch_units( true, true, false );
|
switch_units( true, true, false );
|
||||||
setup_shadow_map( m_cabshadowtexture, m_cabshadowtexturematrix );
|
setup_shadow_map( m_cabshadowtexture, m_cabshadowtexturematrix );
|
||||||
// cache shadow colour in case we need to account for cab light
|
// cache shadow colour in case we need to account for cab light
|
||||||
@@ -570,8 +573,10 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
|||||||
// ...translucent parts
|
// ...translucent parts
|
||||||
setup_drawing( true );
|
setup_drawing( true );
|
||||||
Render_Alpha( simulation::Region );
|
Render_Alpha( simulation::Region );
|
||||||
|
// precipitation; done at the end, only before cab render
|
||||||
|
Render_precipitation();
|
||||||
|
// cab render
|
||||||
if( false == FreeFlyModeFlag ) {
|
if( false == FreeFlyModeFlag ) {
|
||||||
// cab render is performed without shadows, due to low resolution and number of models without windows :|
|
|
||||||
switch_units( true, true, false );
|
switch_units( true, true, false );
|
||||||
setup_shadow_map( m_cabshadowtexture, m_cabshadowtexturematrix );
|
setup_shadow_map( m_cabshadowtexture, m_cabshadowtexturematrix );
|
||||||
// cache shadow colour in case we need to account for cab light
|
// cache shadow colour in case we need to account for cab light
|
||||||
@@ -580,6 +585,12 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
|||||||
if( vehicle->InteriorLightLevel > 0.f ) {
|
if( vehicle->InteriorLightLevel > 0.f ) {
|
||||||
setup_shadow_color( glm::min( colors::white, shadowcolor + glm::vec4( vehicle->InteriorLight * vehicle->InteriorLightLevel, 1.f ) ) );
|
setup_shadow_color( glm::min( colors::white, shadowcolor + glm::vec4( vehicle->InteriorLight * vehicle->InteriorLightLevel, 1.f ) ) );
|
||||||
}
|
}
|
||||||
|
if( Global.Overcast > 1.f ) {
|
||||||
|
// 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 );
|
||||||
if( vehicle->InteriorLightLevel > 0.f ) {
|
if( vehicle->InteriorLightLevel > 0.f ) {
|
||||||
setup_shadow_color( shadowcolor );
|
setup_shadow_color( shadowcolor );
|
||||||
@@ -590,7 +601,8 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
|||||||
// restore default texture matrix for reflections cube map
|
// restore default texture matrix for reflections cube map
|
||||||
select_unit( m_helpertextureunit );
|
select_unit( m_helpertextureunit );
|
||||||
::glMatrixMode( GL_TEXTURE );
|
::glMatrixMode( GL_TEXTURE );
|
||||||
::glPopMatrix();
|
// ::glPopMatrix();
|
||||||
|
::glLoadIdentity();
|
||||||
select_unit( m_diffusetextureunit );
|
select_unit( m_diffusetextureunit );
|
||||||
::glMatrixMode( GL_MODELVIEW );
|
::glMatrixMode( GL_MODELVIEW );
|
||||||
}
|
}
|
||||||
@@ -1011,7 +1023,8 @@ opengl_renderer::setup_matrices() {
|
|||||||
// special case, for colour render pass setup texture matrix for reflections cube map
|
// special case, for colour render pass setup texture matrix for reflections cube map
|
||||||
select_unit( m_helpertextureunit );
|
select_unit( m_helpertextureunit );
|
||||||
::glMatrixMode( GL_TEXTURE );
|
::glMatrixMode( GL_TEXTURE );
|
||||||
::glPushMatrix();
|
// ::glPushMatrix();
|
||||||
|
::glLoadIdentity();
|
||||||
::glMultMatrixf( glm::value_ptr( glm::inverse( glm::mat4{ glm::mat3{ m_renderpass.camera.modelview() } } ) ) );
|
::glMultMatrixf( glm::value_ptr( glm::inverse( glm::mat4{ glm::mat3{ m_renderpass.camera.modelview() } } ) ) );
|
||||||
select_unit( m_diffusetextureunit );
|
select_unit( m_diffusetextureunit );
|
||||||
}
|
}
|
||||||
@@ -1459,7 +1472,7 @@ opengl_renderer::Render( world_environment *Environment ) {
|
|||||||
// sun
|
// sun
|
||||||
{
|
{
|
||||||
Bind_Texture( m_suntexture );
|
Bind_Texture( m_suntexture );
|
||||||
::glColor4f( suncolor.x, suncolor.y, suncolor.z, 1.0f );
|
::glColor4f( suncolor.x, suncolor.y, suncolor.z, clamp( 1.5f - Global.Overcast, 0.f, 1.f ) );
|
||||||
auto const sunvector = Environment->m_sun.getDirection();
|
auto const sunvector = Environment->m_sun.getDirection();
|
||||||
auto const sunposition = modelview * glm::vec4( sunvector.x, sunvector.y, sunvector.z, 1.0f );
|
auto const sunposition = modelview * glm::vec4( sunvector.x, sunvector.y, sunvector.z, 1.0f );
|
||||||
|
|
||||||
@@ -2807,6 +2820,54 @@ opengl_renderer::Render( TMemCell *Memcell ) {
|
|||||||
::glPopMatrix();
|
::glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
opengl_renderer::Render_precipitation() {
|
||||||
|
|
||||||
|
if( Global.Overcast <= 1.f ) { return; }
|
||||||
|
|
||||||
|
switch_units( true, false, false );
|
||||||
|
|
||||||
|
// ::glColor4fv( glm::value_ptr( glm::vec4( glm::min( glm::vec3( Global.fLuminance ), glm::vec3( 1 ) ), 1 ) ) );
|
||||||
|
::glColor4fv(
|
||||||
|
glm::value_ptr(
|
||||||
|
interpolate(
|
||||||
|
0.5f * ( Global.DayLight.diffuse + Global.DayLight.ambient ),
|
||||||
|
colors::white,
|
||||||
|
0.5f * clamp<float>( Global.fLuminance, 0.f, 1.f ) ) ) );
|
||||||
|
::glPushMatrix();
|
||||||
|
|
||||||
|
auto const velocity { simulation::Environment.m_precipitation.m_cameramove * -1.0 };
|
||||||
|
if( glm::length2( velocity ) > 0.0 ) {
|
||||||
|
auto const forward{ glm::normalize( velocity ) };
|
||||||
|
if( false == FreeFlyModeFlag ) {
|
||||||
|
// counter potential vehicle roll
|
||||||
|
auto const roll { simulation::Train->Dynamic()->Roll() };
|
||||||
|
if( roll != 0.0 ) {
|
||||||
|
::glRotated( roll, forward.x, 0.0, forward.z );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// TBD: leave lighting on to allow vehicle lights to affect it?
|
||||||
|
::glDisable( GL_LIGHTING );
|
||||||
|
// 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 );
|
||||||
|
::glEnable( GL_LIGHTING );
|
||||||
|
::glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
opengl_renderer::Render_Alpha( scene::basic_region *Region ) {
|
opengl_renderer::Render_Alpha( scene::basic_region *Region ) {
|
||||||
|
|
||||||
|
|||||||
@@ -294,6 +294,8 @@ private:
|
|||||||
Render_cab( TDynamicObject const *Dynamic, bool const Alpha = false );
|
Render_cab( TDynamicObject const *Dynamic, bool const Alpha = false );
|
||||||
void
|
void
|
||||||
Render( TMemCell *Memcell );
|
Render( TMemCell *Memcell );
|
||||||
|
void
|
||||||
|
Render_precipitation();
|
||||||
void
|
void
|
||||||
Render_Alpha( scene::basic_region *Region );
|
Render_Alpha( scene::basic_region *Region );
|
||||||
void
|
void
|
||||||
|
|||||||
35
scene.cpp
35
scene.cpp
@@ -986,6 +986,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 {
|
||||||
@@ -1062,7 +1093,9 @@ basic_region::deserialize( std::string const &Scenariofile ) {
|
|||||||
// 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 *§ion { m_sections[ 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( section == nullptr ) {
|
||||||
|
section = new basic_section();
|
||||||
|
}
|
||||||
section->deserialize( input );
|
section->deserialize( input );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
scene.h
4
scene.h
@@ -53,6 +53,7 @@ struct scratch_data {
|
|||||||
bool is_open { false };
|
bool is_open { false };
|
||||||
} trainset;
|
} trainset;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
bool initialized { false };
|
bool initialized { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -321,6 +322,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;
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -37,9 +37,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 );
|
||||||
@@ -266,6 +268,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();
|
||||||
|
|||||||
Reference in New Issue
Block a user