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

Merge remote-tracking branch 'refs/remotes/TMJ/master'

This commit is contained in:
Królik Uszasty
2019-04-15 20:19:45 +02:00
25 changed files with 545 additions and 199 deletions

View File

@@ -40,6 +40,7 @@ class powergridsource_table;
class instance_table; class instance_table;
class vehicle_table; class vehicle_table;
struct light_array; struct light_array;
struct dictionary_source;
namespace scene { namespace scene {
struct node_data; struct node_data;

View File

@@ -1375,7 +1375,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
if( ( mvOccupied->Vel < v ) if( ( mvOccupied->Vel < v )
|| ( v == 0.0 ) ) { || ( v == 0.0 ) ) {
// if we're going slower than the target velocity and there's enough room for safe stop, speed up // if we're going slower than the target velocity and there's enough room for safe stop, speed up
auto const brakingdistance = fBrakeDist * braking_distance_multiplier( v ); auto const brakingdistance { 1.2 * fBrakeDist * braking_distance_multiplier( v ) };
if( brakingdistance > 0.0 ) { if( brakingdistance > 0.0 ) {
// maintain desired acc while we have enough room to brake safely, when close enough start paying attention // maintain desired acc while we have enough room to brake safely, when close enough start paying attention
// try to make a smooth transition instead of sharp change // try to make a smooth transition instead of sharp change
@@ -2127,6 +2127,11 @@ bool TController::CheckVehicles(TOrders user)
&& ( ( p->MoverParameters->Couplers[ end::rear ].CouplingFlag & ( coupling::control ) ) == 0 ) ) { && ( ( p->MoverParameters->Couplers[ end::rear ].CouplingFlag & ( coupling::control ) ) == 0 ) ) {
// NOTE: don't set battery in the occupied vehicle, let the user/ai do it explicitly // NOTE: don't set battery in the occupied vehicle, let the user/ai do it explicitly
p->MoverParameters->BatterySwitch( true ); p->MoverParameters->BatterySwitch( true );
// enable heating and converter in carriages with can be heated
if( p->MoverParameters->HeatingPower > 0 ) {
p->MoverParameters->HeatingAllow = true;
p->MoverParameters->ConverterSwitch( true, range_t::local );
}
} }
if (p->asDestination == "none") if (p->asDestination == "none")
@@ -2358,6 +2363,7 @@ double TController::BrakeAccFactor() const
double Factor = 1.0; double Factor = 1.0;
if( ( fAccThreshold != 0.0 ) if( ( fAccThreshold != 0.0 )
&& ( AccDesired < 0.0 )
&& ( ( ActualProximityDist > fMinProximityDist ) && ( ( ActualProximityDist > fMinProximityDist )
|| ( mvOccupied->Vel > VelDesired + fVelPlus ) ) ) { || ( mvOccupied->Vel > VelDesired + fVelPlus ) ) ) {
Factor += ( fBrakeReaction * ( /*mvOccupied->BrakeCtrlPosR*/BrakeCtrlPosition < 0.5 ? 1.5 : 1 ) ) * mvOccupied->Vel / ( std::max( 0.0, ActualProximityDist ) + 1 ) * ( ( AccDesired - AbsAccS_pub ) / fAccThreshold ); Factor += ( fBrakeReaction * ( /*mvOccupied->BrakeCtrlPosR*/BrakeCtrlPosition < 0.5 ? 1.5 : 1 ) ) * mvOccupied->Vel / ( std::max( 0.0, ActualProximityDist ) + 1 ) * ( ( AccDesired - AbsAccS_pub ) / fAccThreshold );
@@ -2529,9 +2535,9 @@ bool TController::PrepareEngine()
} }
// sync virtual brake state with the 'real' one // sync virtual brake state with the 'real' one
std::unordered_map<int, int> const brakepositions { std::unordered_map<int, int> const brakepositions {
{ mvOccupied->Handle->GetPos( bh_RP ), gbh_RP }, { static_cast<int>( mvOccupied->Handle->GetPos( bh_RP ) ), gbh_RP },
{ mvOccupied->Handle->GetPos( bh_NP ), gbh_NP }, { static_cast<int>( mvOccupied->Handle->GetPos( bh_NP ) ), gbh_NP },
{ mvOccupied->Handle->GetPos( bh_FS ), gbh_FS } }; { static_cast<int>( mvOccupied->Handle->GetPos( bh_FS ) ), gbh_FS } };
auto const lookup { brakepositions.find( static_cast<int>( mvOccupied->fBrakeCtrlPos ) ) }; auto const lookup { brakepositions.find( static_cast<int>( mvOccupied->fBrakeCtrlPos ) ) };
if( lookup != brakepositions.end() ) { if( lookup != brakepositions.end() ) {
BrakeLevelSet( lookup->second ); // GBH BrakeLevelSet( lookup->second ); // GBH
@@ -3568,7 +3574,7 @@ void TController::Doors( bool const Open, int const Side ) {
} }
if( AIControllFlag ) { if( AIControllFlag ) {
if( ( true == mvOccupied->Doors.has_autowarning ) if( ( true == mvOccupied->Doors.has_warning )
&& ( false == mvOccupied->DepartureSignal ) && ( false == mvOccupied->DepartureSignal )
&& ( true == TestFlag( iDrivigFlags, moveDoorOpened ) ) ) { && ( true == TestFlag( iDrivigFlags, moveDoorOpened ) ) ) {
mvOccupied->signal_departure( true ); // załącenie bzyczka mvOccupied->signal_departure( true ); // załącenie bzyczka
@@ -3581,13 +3587,14 @@ void TController::Doors( bool const Open, int const Side ) {
|| ( false == AIControllFlag ) ) ) { || ( false == AIControllFlag ) ) ) {
// ai doesn't close the door until it's free to depart, but human driver has free reign to do stupid things // ai doesn't close the door until it's free to depart, but human driver has free reign to do stupid things
if( ( pVehicle->MoverParameters->Doors.close_control == control_t::conductor ) if( ( pVehicle->MoverParameters->Doors.close_control == control_t::conductor )
|| ( ( true == AIControllFlag ) || ( ( true == AIControllFlag ) ) ) {
&& ( ( pVehicle->MoverParameters->Doors.close_control == control_t::driver )
|| ( pVehicle->MoverParameters->Doors.close_control == control_t::mixed ) ) ) ) {
// if the door are controlled by the driver, we let the user operate them unless this user is an ai // if the door are controlled by the driver, we let the user operate them unless this user is an ai
// the train conductor, if present, handles door operation also for human-driven trains // the train conductor, if present, handles door operation also for human-driven trains
if( ( pVehicle->MoverParameters->Doors.close_control == control_t::driver )
|| ( pVehicle->MoverParameters->Doors.close_control == control_t::mixed ) ) {
pVehicle->MoverParameters->OperateDoors( side::right, false ); pVehicle->MoverParameters->OperateDoors( side::right, false );
pVehicle->MoverParameters->OperateDoors( side::left, false ); pVehicle->MoverParameters->OperateDoors( side::left, false );
}
if( pVehicle->MoverParameters->Doors.permit_needed ) { if( pVehicle->MoverParameters->Doors.permit_needed ) {
pVehicle->MoverParameters->PermitDoors( side::right, false ); pVehicle->MoverParameters->PermitDoors( side::right, false );
pVehicle->MoverParameters->PermitDoors( side::left, false ); pVehicle->MoverParameters->PermitDoors( side::left, false );
@@ -4687,11 +4694,11 @@ TController::UpdateSituation(double dt) {
// TODO: test if we can use the distances calculation from obey_train // TODO: test if we can use the distances calculation from obey_train
fMinProximityDist = std::min( 5 + iVehicles, 25 ); fMinProximityDist = std::min( 5 + iVehicles, 25 );
fMaxProximityDist = std::min( 10 + iVehicles, 50 ); fMaxProximityDist = std::min( 10 + iVehicles, 50 );
/* // HACK: modern vehicles might brake slower at low speeds, increase safety margin as crude counter
if( IsHeavyCargoTrain ) { if( mvControlling->EIMCtrlType > 0 ) {
fMaxProximityDist *= 1.5; fMinProximityDist += 5.0;
fMaxProximityDist += 5.0;
} }
*/
fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
// margines prędkości powodujący załączenie napędu // margines prędkości powodujący załączenie napędu
// były problemy z jazdą np. 3km/h podczas ładowania wagonów // były problemy z jazdą np. 3km/h podczas ładowania wagonów
@@ -5171,7 +5178,11 @@ TController::UpdateSituation(double dt) {
20.0 ) ); // others 20.0 ) ); // others
if( vel > VelDesired + fVelPlus ) { if( vel > VelDesired + fVelPlus ) {
// if going too fast force some prompt braking // if going too fast force some prompt braking
AccPreferred = std::min( -0.65, AccPreferred ); AccPreferred = std::min(
( ( mvOccupied->CategoryFlag & 2 ) ?
-0.65 : // cars
-0.30 ), // others
AccPreferred );
} }
} }
@@ -5683,11 +5694,11 @@ TController::UpdateSituation(double dt) {
|| ( VelNext > vel - 40.0 ) ) ? || ( VelNext > vel - 40.0 ) ) ?
fBrake_a0[ 0 ] * 0.8 : fBrake_a0[ 0 ] * 0.8 :
-fAccThreshold ) -fAccThreshold )
/ braking_distance_multiplier( VelNext ) ) { / ( 1.2 * braking_distance_multiplier( VelNext ) ) ) {
AccDesired = std::max( -0.06, AccDesired ); AccDesired = std::max( -0.06, AccDesired );
} }
} }
else { if( AccDesired < -0.1 ) {
// i orientuj się szybciej, jeśli hamujesz // i orientuj się szybciej, jeśli hamujesz
ReactionTime = 0.25; ReactionTime = 0.25;
} }
@@ -5786,11 +5797,11 @@ TController::UpdateSituation(double dt) {
} }
} }
} }
// yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej // yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej zwiekszanie predkosci
// zwiekszanie predkosci
// Ra 2F1H: jest konflikt histerezy pomiędzy nastawioną pozycją a uzyskiwanym // Ra 2F1H: jest konflikt histerezy pomiędzy nastawioną pozycją a uzyskiwanym
// przyspieszeniem - utrzymanie pozycji powoduje przekroczenie przyspieszenia // przyspieszeniem - utrzymanie pozycji powoduje przekroczenie przyspieszenia
if( ( AccDesired - AbsAccS > 0.01 ) ) { if( ( AccDesired > -0.06 ) // don't add power if not asked for actual speed-up
&& ( AccDesired - AbsAccS > 0.05 ) ) {
// jeśli przyspieszenie pojazdu jest mniejsze niż żądane oraz... // jeśli przyspieszenie pojazdu jest mniejsze niż żądane oraz...
if( vel < ( if( vel < (
VelDesired == 1.0 ? // work around for trains getting stuck on tracks with speed limit = 1 VelDesired == 1.0 ? // work around for trains getting stuck on tracks with speed limit = 1
@@ -5882,7 +5893,8 @@ TController::UpdateSituation(double dt) {
} }
} }
} }
if ((AccDesired < fAccGravity - 0.05) && (AbsAccS < AccDesired - fBrake_a1[0]*0.51)) { if ( ( AccDesired < fAccGravity - 0.05 )
&& ( ( AccDesired - fBrake_a1[0]*0.51 ) ) - AbsAccS > 0.05 ) {
// jak hamuje, to nie tykaj kranu za często // jak hamuje, to nie tykaj kranu za często
// yB: luzuje hamulec dopiero przy różnicy opóźnień rzędu 0.2 // yB: luzuje hamulec dopiero przy różnicy opóźnień rzędu 0.2
if( OrderCurrentGet() != Disconnect ) { if( OrderCurrentGet() != Disconnect ) {

View File

@@ -407,9 +407,9 @@ private:
// methods // methods
public: public:
std::string TrainName() const; std::string TrainName() const;
Mtable::TTrainParameters const * TrainTimetable() const;
private: private:
std::string Relation() const; std::string Relation() const;
Mtable::TTrainParameters const * TrainTimetable() const;
int StationIndex() const; int StationIndex() const;
int StationCount() const; int StationCount() const;
bool IsStop() const; bool IsStop() const;

View File

@@ -160,6 +160,39 @@ void TAnim::Parovoz(){
// animowanie tłoka i rozrządu parowozu // animowanie tłoka i rozrządu parowozu
}; };
*/ */
void TDynamicObject::destination_data::deserialize( cParser &Input ) {
while( true == deserialize_mapping( Input ) ) {
; // all work done by while()
}
}
bool TDynamicObject::destination_data::deserialize_mapping( cParser &Input ) {
// token can be a key or block end
auto const key { Input.getToken<std::string>( true, "\n\r\t ,;[]" ) };
if( ( true == key.empty() ) || ( key == "}" ) ) { return false; }
if( key == "{" ) {
script = Input.getToken<std::string>();
}
else if( key == "update:" ) {
auto const value { Input.getToken<std::string>() };
// TODO: implement
}
else if( key == "instance:" ) {
instancing = Input.getToken<std::string>();
}
else if( key == "parameters:" ) {
parameters = Input.getToken<std::string>();
}
return true;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
TDynamicObject * TDynamicObject::FirstFind(int &coupler_nr, int cf) TDynamicObject * TDynamicObject::FirstFind(int &coupler_nr, int cf)
{ // szukanie skrajnego połączonego pojazdu w pociagu { // szukanie skrajnego połączonego pojazdu w pociagu
@@ -919,6 +952,8 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
btEndSignalsTab2.Turn( true ); btEndSignalsTab2.Turn( true );
btnOn = true; btnOn = true;
} }
// destination signs
update_destinations();
// else btEndSignalsTab2.TurnOff(); // else btEndSignalsTab2.TurnOff();
// McZapkie-181002: krecenie wahaczem (korzysta z kata obrotu silnika) // McZapkie-181002: krecenie wahaczem (korzysta z kata obrotu silnika)
if (iAnimType[ANIM_LEVERS]) if (iAnimType[ANIM_LEVERS])
@@ -1946,6 +1981,10 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
init_sections( mdLowPolyInt, nameprefix ); init_sections( mdLowPolyInt, nameprefix );
} }
} }
// destination sign
if( mdModel ) {
init_destination( mdModel );
}
// 'external_load' is an optional special section in the main model, pointing to submodel of external load // 'external_load' is an optional special section in the main model, pointing to submodel of external load
if( mdModel ) { if( mdModel ) {
init_sections( mdModel, "external_load" ); init_sections( mdModel, "external_load" );
@@ -2069,6 +2108,16 @@ TDynamicObject::init_sections( TModel3d const *Model, std::string const &Namepre
return sectioncount; return sectioncount;
} }
bool
TDynamicObject::init_destination( TModel3d *Model ) {
if( Model->GetSMRoot() == nullptr ) { return false; }
std::tie( DestinationSign.sign, DestinationSign.has_light ) = Model->GetSMRoot()->find_replacable4();
return DestinationSign.sign != nullptr;
}
void void
TDynamicObject::create_controller( std::string const Type, bool const Trainset ) { TDynamicObject::create_controller( std::string const Type, bool const Trainset ) {
@@ -2553,6 +2602,27 @@ na sprzęgach, opóźnienie działania hamulca itp. Oczywiście musi mieć to pe
histerezę czasową, aby te tryby pracy nie przełączały się zbyt szybko. histerezę czasową, aby te tryby pracy nie przełączały się zbyt szybko.
*/ */
void TDynamicObject::update_destinations() {
if( DestinationSign.sign == nullptr ) { return; }
DestinationSign.sign->fLight = (
( ( DestinationSign.has_light ) && ( MoverParameters->Battery ) ) ?
2.0 :
-1.0 );
// jak są 4 tekstury wymienne, to nie zmieniać rozkładem
if( std::abs( m_materialdata.multi_textures ) >= 4 ) { return; }
// TODO: dedicated setting to discern electronic signs, instead of fallback on light presence
m_materialdata.replacable_skins[ 4 ] = (
( ( DestinationSign.destination != null_handle )
&& ( ( false == DestinationSign.has_light ) // physical destination signs remain up until manually changed
|| ( ( true == MoverParameters->Battery ) // lcd signs are off without power
&& ( ctOwner != nullptr ) ) ) ) ? // lcd signs are off for carriages without engine, potentially left on a siding
DestinationSign.destination :
DestinationSign.destination_off );
}
bool TDynamicObject::Update(double dt, double dt1) bool TDynamicObject::Update(double dt, double dt1)
{ {
if (dt1 == 0) if (dt1 == 0)
@@ -4017,6 +4087,10 @@ void TDynamicObject::RenderSounds() {
} }
if( volume > 0.05 ) { if( volume > 0.05 ) {
rscurve rscurve
.pitch(
true == rscurve.is_combined() ?
MoverParameters->Vel * 0.01f :
rscurve.m_frequencyoffset + rscurve.m_frequencyfactor * 1.f )
.gain( 2.5 * volume ) .gain( 2.5 * volume )
.play( sound_flags::exclusive | sound_flags::looping ); .play( sound_flags::exclusive | sound_flags::looping );
} }
@@ -4241,7 +4315,8 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
} }
// potentially set blank destination texture // potentially set blank destination texture
DestinationSet( {}, {} ); DestinationSign.destination_off = DestinationFind( "nowhere" );
// DestinationSet( {}, {} );
if( GfxRenderer.Material( m_materialdata.replacable_skins[ 1 ] ).has_alpha ) { if( GfxRenderer.Material( m_materialdata.replacable_skins[ 1 ] ).has_alpha ) {
// tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych // tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
@@ -5537,6 +5612,15 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
parser >> JointCabs; parser >> JointCabs;
} }
else if( token == "pydestinationsign:" ) {
DestinationSign.deserialize( parser );
// supply vehicle folder as script path if none is provided
if( ( false == DestinationSign.script.empty() )
&& ( substr_path( DestinationSign.script ).empty() ) ) {
DestinationSign.script = asBaseDir + DestinationSign.script;
}
}
} while( token != "" ); } while( token != "" );
} // internaldata: } // internaldata:
@@ -6093,45 +6177,92 @@ int TDynamicObject::RouteWish(TTrack *tr)
return Mechanik ? Mechanik->CrossRoute(tr) : 0; // wg AI albo prosto return Mechanik ? Mechanik->CrossRoute(tr) : 0; // wg AI albo prosto
}; };
void TDynamicObject::DestinationSet(std::string to, std::string numer) void TDynamicObject::DestinationSet(std::string to, std::string numer) {
{ // ustawienie stacji docelowej oraz wymiennej tekstury 4, jeśli istnieje plik // ustawienie stacji docelowej oraz wymiennej tekstury 4, jeśli istnieje plik
// w zasadzie, to każdy wagon mógłby mieć inną stację docelową // w zasadzie, to każdy wagon mógłby mieć inną stację docelową
// zwłaszcza w towarowych, pod kątem zautomatyzowania maewrów albo pracy górki // zwłaszcza w towarowych, pod kątem zautomatyzowania maewrów albo pracy górki
// ale to jeszcze potrwa, zanim będzie możliwe, na razie można wpisać stację z // ale to jeszcze potrwa, zanim będzie możliwe, na razie można wpisać stację z
// rozkładu // rozkładu
if( std::abs( m_materialdata.multi_textures ) >= 4 ) {
// jak są 4 tekstury wymienne, to nie zmieniać rozkładem asDestination = to;
if( std::abs( m_materialdata.multi_textures ) >= 4 ) { return; } // jak są 4 tekstury wymienne, to nie zmieniać rozkładem
if( DestinationSign.sign == nullptr ) { return; } // no sign submodel, no problem
// now see if we can find any version of the destination texture
std::vector<std::string> const destinations = {
numer, // try dedicated timetable sign first...
to }; // ...then generic destination sign
for( auto const &destination : destinations ) {
DestinationSign.destination = DestinationFind( destination );
if( DestinationSign.destination != null_handle ) {
// got what we wanted, we're done here
return; return;
} }
numer = Bezogonkow(numer);
asDestination = to;
to = Bezogonkow(to); // do szukania pliku obcinamy ogonki
if( true == to.empty() ) {
to = "nowhere";
} }
// if we didn't get static texture we might be able to make one
if( DestinationSign.script.empty() ) { return; } // no script so no way to make the texture
if( numer == "none" ) { return; } // blank or incomplete/malformed timetable, don't bother
std::string signrequest {
"make:"
+ DestinationSign.script + "?"
// timetable include
+ "$timetable=" + (
ctOwner == nullptr ?
MoverParameters->Name : // leading vehicle, can point to it directly
ctOwner->Vehicle()->MoverParameters->Name ) + "&" // owned vehicle, safer to point to owner as carriages can have identical names
// basic instancing string
// NOTE: underscore doesn't have any magic meaning for the time being, it's just less likely to conflict with regular dictionary keys
+ "_id1=" + (
ctOwner != nullptr ? ctOwner->TrainName() :
Mechanik != nullptr ? Mechanik->TrainName() :
"none" ) }; // shouldn't get here but, eh
// TBD, TODO: replace instancing with support for variables in extra parameters string?
if( false == DestinationSign.instancing.empty() ) {
signrequest +=
"&_id2=" + (
DestinationSign.instancing == "name" ? MoverParameters->Name :
DestinationSign.instancing == "type" ? MoverParameters->TypeName :
"none" );
}
// optionl extra parameters
if( false == DestinationSign.parameters.empty() ) {
signrequest += "&" + DestinationSign.parameters;
}
DestinationSign.destination = GfxRenderer.Fetch_Material( signrequest );
}
material_handle TDynamicObject::DestinationFind( std::string Destination ) {
if( Destination.empty() ) { return null_handle; }
Destination = Bezogonkow( Destination ); // do szukania pliku obcinamy ogonki
// destination textures are kept in the vehicle's directory so we point the current texture path there // destination textures are kept in the vehicle's directory so we point the current texture path there
auto const currenttexturepath { Global.asCurrentTexturePath }; auto const currenttexturepath { Global.asCurrentTexturePath };
Global.asCurrentTexturePath = asBaseDir; Global.asCurrentTexturePath = asBaseDir;
// now see if we can find any version of the texture // now see if we can find any version of the texture
std::vector<std::string> destinations = { std::vector<std::string> const destinations {
numer + '@' + MoverParameters->TypeName, Destination + '@' + MoverParameters->TypeName,
numer, Destination };
to + '@' + MoverParameters->TypeName,
to, auto destinationhandle { null_handle };
"nowhere" + '@' + MoverParameters->TypeName,
"nowhere" };
for( auto const &destination : destinations ) { for( auto const &destination : destinations ) {
auto material = TextureTest( ToLower( destination ) ); auto material = TextureTest( ToLower( destination ) );
if( false == material.empty() ) { if( false == material.empty() ) {
m_materialdata.replacable_skins[ 4 ] = GfxRenderer.Fetch_Material( material ); destinationhandle = GfxRenderer.Fetch_Material( material );
break; break;
} }
} }
// whether we got anything, restore previous texture path // whether we got anything, restore previous texture path
Global.asCurrentTexturePath = currenttexturepath; Global.asCurrentTexturePath = currenttexturepath;
};
return destinationhandle;
}
void TDynamicObject::OverheadTrack(float o) void TDynamicObject::OverheadTrack(float o)
{ // ewentualne wymuszanie jazdy { // ewentualne wymuszanie jazdy

View File

@@ -200,6 +200,20 @@ public:
TModel3d *mdLowPolyInt; // ABu 010305: wnetrze lowpoly TModel3d *mdLowPolyInt; // ABu 010305: wnetrze lowpoly
std::array<TSubModel *, 3> LowPolyIntCabs {}; // pointers to low fidelity version of individual driver cabs std::array<TSubModel *, 3> LowPolyIntCabs {}; // pointers to low fidelity version of individual driver cabs
bool JointCabs{ false }; // flag for vehicles with multiple virtual 'cabs' sharing location and 3d model(s) bool JointCabs{ false }; // flag for vehicles with multiple virtual 'cabs' sharing location and 3d model(s)
struct destination_data {
TSubModel *sign { nullptr }; // submodel mapped with replacable texture -4
bool has_light { false }; // the submodel was originally configured with self-illumination attribute
material_handle destination { null_handle }; // most recently assigned non-blank destination texture
material_handle destination_off { null_handle }; // blank destination sign
std::string script; // potential python script used to generate texture data
int update_rate { 0 }; // -1: per stop, 0: none, >0: fps // TBD, TODO: implement?
std::string instancing; // potential method to generate more than one texture per timetable
std::string parameters; // potential extra parameters supplied by mmd file
// methods
void deserialize( cParser &Input );
private:
bool deserialize_mapping( cParser &Input );
} DestinationSign;
float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?) float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?)
float LoadOffset { 0.f }; float LoadOffset { 0.f };
std::unordered_map<std::string, std::string> LoadModelOverrides; // potential overrides of default load visualization models std::unordered_map<std::string, std::string> LoadModelOverrides; // potential overrides of default load visualization models
@@ -517,6 +531,7 @@ private:
TTrack *Track, double fDist, std::string DriverType, double fVel, std::string TrainName, TTrack *Track, double fDist, std::string DriverType, double fVel, std::string TrainName,
float Load, std::string LoadType, bool Reversed, std::string); float Load, std::string LoadType, bool Reversed, std::string);
int init_sections( TModel3d const *Model, std::string const &Nameprefix ); int init_sections( TModel3d const *Model, std::string const &Nameprefix );
bool init_destination( TModel3d *Model );
void create_controller( std::string const Type, bool const Trainset ); void create_controller( std::string const Type, bool const Trainset );
void AttachPrev(TDynamicObject *Object, int iType = 1); void AttachPrev(TDynamicObject *Object, int iType = 1);
bool UpdateForce(double dt); bool UpdateForce(double dt);
@@ -531,6 +546,7 @@ private:
void update_load_visibility(); void update_load_visibility();
void update_load_offset(); void update_load_offset();
void shuffle_load_sections(); void shuffle_load_sections();
void update_destinations();
bool Update(double dt, double dt1); bool Update(double dt, double dt1);
bool FastUpdate(double dt); bool FastUpdate(double dt);
void Move(double fDistance); void Move(double fDistance);
@@ -633,6 +649,7 @@ private:
// zapytanie do AI, po którym segmencie skrzyżowania jechać // zapytanie do AI, po którym segmencie skrzyżowania jechać
int RouteWish(TTrack *tr); int RouteWish(TTrack *tr);
void DestinationSet(std::string to, std::string numer); void DestinationSet(std::string to, std::string numer);
material_handle DestinationFind( std::string Destination );
void OverheadTrack(float o); void OverheadTrack(float o);
double MED[9][8]; // lista zmiennych do debugowania hamulca ED double MED[9][8]; // lista zmiennych do debugowania hamulca ED

View File

@@ -70,7 +70,6 @@ struct global_settings {
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 };
double fFogStart{ 1700 };
double fFogEnd{ 2000 }; double fFogEnd{ 2000 };
std::string Season{}; // season of the year, based on simulation date std::string Season{}; // season of the year, based on simulation date
std::string Weather{ "cloudy:" }; // current weather std::string Weather{ "cloudy:" }; // current weather

View File

@@ -1354,6 +1354,7 @@ public:
std::string StLinSwitchType; std::string StLinSwitchType;
bool Heating = false; //ogrzewanie 'Winger 020304 bool Heating = false; //ogrzewanie 'Winger 020304
bool HeatingAllow { false }; // heating switch // TODO: wrap heating in a basic device
int DoubleTr = 1; //trakcja ukrotniona - przedni pojazd 'Winger 160304 int DoubleTr = 1; //trakcja ukrotniona - przedni pojazd 'Winger 160304
bool PhysicActivation = true; bool PhysicActivation = true;
@@ -1500,6 +1501,7 @@ public:
/*-funkcje typowe dla lokomotywy elektrycznej*/ /*-funkcje typowe dla lokomotywy elektrycznej*/
void ConverterCheck( double const Timestep ); // przetwornica void ConverterCheck( double const Timestep ); // przetwornica
void HeatingCheck( double const Timestep );
void WaterPumpCheck( double const Timestep ); void WaterPumpCheck( double const Timestep );
void WaterHeaterCheck( double const Timestep ); void WaterHeaterCheck( double const Timestep );
void FuelPumpCheck( double const Timestep ); void FuelPumpCheck( double const Timestep );

View File

@@ -1075,11 +1075,13 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
for( int side = 0; side < 2; ++side ) { for( int side = 0; side < 2; ++side ) {
// przekazywanie napiec // przekazywanie napiec
auto const oppositeside = ( side == end::front ? end::rear : end::front ); auto const oppositeside { ( side == end::front ? end::rear : end::front ) };
auto const liveconnection{
( Couplers[ side ].CouplingFlag & ctrain_power )
|| ( ( Couplers[ side ].CouplingFlag & ctrain_heating )
&& ( Couplers[ side ].Connected->Heating ) ) };
if( ( Couplers[ side ].CouplingFlag & ctrain_power ) if( liveconnection ) {
|| ( ( Heating )
&& ( Couplers[ side ].CouplingFlag & ctrain_heating ) ) ) {
auto const &connectedcoupler = Couplers[ side ].Connected->Couplers[ Couplers[ side ].ConnectedNr ]; auto const &connectedcoupler = Couplers[ side ].Connected->Couplers[ Couplers[ side ].ConnectedNr ];
Couplers[ oppositeside ].power_high.voltage = Couplers[ oppositeside ].power_high.voltage =
std::max( std::max(
@@ -1103,8 +1105,8 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
Couplers[ side ].power_high.local = false; // power, if any, will be from external source Couplers[ side ].power_high.local = false; // power, if any, will be from external source
if( ( Couplers[ side ].CouplingFlag & ctrain_power ) if( ( Couplers[ side ].CouplingFlag & ctrain_power )
|| ( ( Heating ) || ( ( Couplers[ side ].CouplingFlag & ctrain_heating )
&& ( Couplers[ side ].CouplingFlag & ctrain_heating ) ) ) { && ( Couplers[ side ].Connected->Heating ) ) ) {
auto const &connectedcoupler = auto const &connectedcoupler =
Couplers[ side ].Connected->Couplers[ Couplers[ side ].Connected->Couplers[
( Couplers[ side ].ConnectedNr == end::front ? ( Couplers[ side ].ConnectedNr == end::front ?
@@ -1127,8 +1129,8 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
Couplers[ side ].power_high.local = true; // power is coming from local pantographs Couplers[ side ].power_high.local = true; // power is coming from local pantographs
if( ( Couplers[ side ].CouplingFlag & ctrain_power ) if( ( Couplers[ side ].CouplingFlag & ctrain_power )
|| ( ( Heating ) || ( ( Couplers[ side ].CouplingFlag & ctrain_heating )
&& ( Couplers[ side ].CouplingFlag & ctrain_heating ) ) ) { && ( Couplers[ side ].Connected->Heating ) ) ) {
auto const &connectedcoupler = auto const &connectedcoupler =
Couplers[ side ].Connected->Couplers[ Couplers[ side ].Connected->Couplers[
( Couplers[ side ].ConnectedNr == end::front ? ( Couplers[ side ].ConnectedNr == end::front ?
@@ -1409,6 +1411,8 @@ void TMoverParameters::compute_movement_( double const Deltatime ) {
// w rozrządczym nie (jest błąd w FIZ!) - Ra 2014-07: teraz we wszystkich // w rozrządczym nie (jest błąd w FIZ!) - Ra 2014-07: teraz we wszystkich
UpdatePantVolume( Deltatime ); // Ra 2014-07: obsługa zbiornika rozrządu oraz pantografów UpdatePantVolume( Deltatime ); // Ra 2014-07: obsługa zbiornika rozrządu oraz pantografów
} }
// heating
HeatingCheck( Deltatime );
UpdateBrakePressure(Deltatime); UpdateBrakePressure(Deltatime);
UpdatePipePressure(Deltatime); UpdatePipePressure(Deltatime);
@@ -1462,7 +1466,8 @@ void TMoverParameters::ConverterCheck( double const Timestep ) {
if( ( ConverterAllow ) if( ( ConverterAllow )
&& ( ConverterAllowLocal ) && ( ConverterAllowLocal )
&& ( false == PantPressLockActive ) && ( false == PantPressLockActive )
&& ( Mains ) ) { && ( ( Mains )
|| ( GetTrainsetVoltage() > 0 ) ) ) {
// delay timer can be optionally configured, and is set anew whenever converter goes off // delay timer can be optionally configured, and is set anew whenever converter goes off
if( ConverterStartDelayTimer <= 0.0 ) { if( ConverterStartDelayTimer <= 0.0 ) {
ConverterFlag = true; ConverterFlag = true;
@@ -1477,6 +1482,17 @@ void TMoverParameters::ConverterCheck( double const Timestep ) {
} }
}; };
// heating system status check
void TMoverParameters::HeatingCheck( double const Timestep ) {
Heating = (
( true == HeatingAllow )
// powered vehicles are generally required to activate their power source to provide heating
// passive vehicles get a pass in this regard
&& ( ( Power < 0.1 )
|| ( true == Mains ) ) );
}
// water pump status check // water pump status check
void TMoverParameters::WaterPumpCheck( double const Timestep ) { void TMoverParameters::WaterPumpCheck( double const Timestep ) {
// NOTE: breaker override with start type is sm42 specific hack, replace with ability to define the presence of the breaker // NOTE: breaker override with start type is sm42 specific hack, replace with ability to define the presence of the breaker
@@ -7055,9 +7071,14 @@ TMoverParameters::update_doors( double const Deltatime ) {
door.local_close = door.local_close && ( false == door.is_closed ); door.local_close = door.local_close && ( false == door.is_closed );
door.remote_close = door.remote_close && ( false == door.is_closed ); door.remote_close = door.remote_close && ( false == door.is_closed );
auto const autoopenrequest {
( Doors.open_control == control_t::autonomous )
&& ( ( false == Doors.permit_needed ) || door.open_permit )
};
auto const openrequest { auto const openrequest {
( localopencontrol && door.local_open ) ( localopencontrol && door.local_open )
|| ( remoteopencontrol && door.remote_open ) }; || ( remoteopencontrol && door.remote_open )
|| ( autoopenrequest && ( false == door.is_open ) ) };
auto const autocloserequest { auto const autocloserequest {
( ( Doors.auto_velocity != -1.f ) && ( Vel > Doors.auto_velocity ) ) ( ( Doors.auto_velocity != -1.f ) && ( Vel > Doors.auto_velocity ) )
@@ -7279,14 +7300,14 @@ double TMoverParameters::GetTrainsetVoltage(void)
return std::max( return std::max(
( ( ( Couplers[end::front].Connected ) ( ( ( Couplers[end::front].Connected )
&& ( ( Couplers[ end::front ].CouplingFlag & ctrain_power ) && ( ( Couplers[ end::front ].CouplingFlag & ctrain_power )
|| ( ( Heating ) || ( ( Couplers[ end::front ].CouplingFlag & ctrain_heating )
&& ( Couplers[ end::front ].CouplingFlag & ctrain_heating ) ) ) ) ? && ( Couplers[ end::front ].Connected->Heating ) ) ) ) ?
Couplers[end::front].Connected->Couplers[ Couplers[end::front].ConnectedNr ].power_high.voltage : Couplers[end::front].Connected->Couplers[ Couplers[end::front].ConnectedNr ].power_high.voltage :
0.0 ), 0.0 ),
( ( ( Couplers[end::rear].Connected ) ( ( ( Couplers[end::rear].Connected )
&& ( ( Couplers[ end::rear ].CouplingFlag & ctrain_power ) && ( ( Couplers[ end::rear ].CouplingFlag & ctrain_power )
|| ( ( Heating ) || ( ( Couplers[ end::rear ].CouplingFlag & ctrain_heating )
&& ( Couplers[ end::rear ].CouplingFlag & ctrain_heating ) ) ) ) ? && ( Couplers[ end::rear ].Connected->Heating ) ) ) ) ?
Couplers[ end::rear ].Connected->Couplers[ Couplers[ end::rear ].ConnectedNr ].power_high.voltage : Couplers[ end::rear ].Connected->Couplers[ Couplers[ end::rear ].ConnectedNr ].power_high.voltage :
0.0 ) ); 0.0 ) );
} }
@@ -8344,12 +8365,6 @@ void TMoverParameters::LoadFIZ_Doors( std::string const &line ) {
lookup != doorcontrols.end() ? lookup != doorcontrols.end() ?
lookup->second : lookup->second :
control_t::passenger; control_t::passenger;
if( Doors.close_control == control_t::autonomous ) {
// convert legacy method
Doors.close_control = control_t::passenger;
Doors.auto_velocity = 10.0;
}
} }
// automatic closing conditions // automatic closing conditions
extract_value( Doors.auto_duration, "DoorStayOpen", line, "" ); extract_value( Doors.auto_duration, "DoorStayOpen", line, "" );

View File

@@ -789,6 +789,27 @@ int TSubModel::count_children() {
1 + Child->count_siblings() ); 1 + Child->count_siblings() );
} }
// locates submodel mapped with replacable -4
std::tuple<TSubModel *, bool>
TSubModel::find_replacable4() {
if( m_material == -4 ) {
return std::make_tuple( this, ( fLight != -1.0 ) );
}
if( Next != nullptr ) {
auto lookup { Next->find_replacable4() };
if( std::get<TSubModel *>( lookup ) != nullptr ) { return lookup; }
}
if( Child != nullptr ) {
auto lookup { Child->find_replacable4() };
if( std::get<TSubModel *>( lookup ) != nullptr ) { return lookup; }
}
return std::make_tuple( nullptr, false );
}
int TSubModel::FlagsCheck() int TSubModel::FlagsCheck()
{ // analiza koniecznych zmian pomiędzy submodelami { // analiza koniecznych zmian pomiędzy submodelami
// samo pomijanie glBindTexture() nie poprawi wydajności // samo pomijanie glBindTexture() nie poprawi wydajności

View File

@@ -166,6 +166,8 @@ public:
TSubModel * ChildGet() { return Child; }; TSubModel * ChildGet() { return Child; };
int count_siblings(); int count_siblings();
int count_children(); int count_children();
// locates submodel mapped with replacable -4
std::tuple<TSubModel *, bool> find_replacable4();
int TriangleAdd(TModel3d *m, material_handle tex, int tri); int TriangleAdd(TModel3d *m, material_handle tex, int tri);
void SetRotate(float3 vNewRotateAxis, float fNewAngle); void SetRotate(float3 vNewRotateAxis, float fNewAngle);
void SetRotateXYZ( Math3D::vector3 vNewAngles); void SetRotateXYZ( Math3D::vector3 vNewAngles);

View File

@@ -10,9 +10,8 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h" #include "stdafx.h"
#include "PyInt.h" #include "PyInt.h"
#include "Globals.h" #include "dictionary.h"
#include "application.h" #include "application.h"
#include "renderer.h"
#include "Logs.h" #include "Logs.h"
void render_task::run() { void render_task::run() {

18
PyInt.h
View File

@@ -23,24 +23,6 @@ http://mozilla.org/MPL/2.0/.
#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)
// collection of keyword-value pairs
// NOTE: since our python dictionary operates on a few types, most of the class was hardcoded for simplicity
struct dictionary_source {
// types
template <typename Type_>
using keyvaluepair_sequence = std::vector<std::pair<std::string, Type_>>;
// members
keyvaluepair_sequence<double> floats;
keyvaluepair_sequence<int> integers;
keyvaluepair_sequence<bool> bools;
keyvaluepair_sequence<std::string> strings;
// methods
inline void insert( std::string const &Key, double const Value ) { floats.emplace_back( Key, Value ); }
inline void insert( std::string const &Key, int const Value ) { integers.emplace_back( Key, Value ); }
inline void insert( std::string const &Key, bool const Value ) { bools.emplace_back( Key, Value ); }
inline void insert( std::string const &Key, std::string const Value ) { strings.emplace_back( Key, Value ); }
};
// TODO: extract common base and inherit specialization from it // TODO: extract common base and inherit specialization from it
class render_task { class render_task {

View File

@@ -20,11 +20,13 @@ http://mozilla.org/MPL/2.0/.
#include "GL/glew.h" #include "GL/glew.h"
#include "application.h" #include "application.h"
#include "utilities.h" #include "dictionary.h"
#include "Globals.h" #include "Globals.h"
#include "Logs.h" #include "Logs.h"
#include "utilities.h"
#include "sn_utils.h" #include "sn_utils.h"
#define EU07_DEFERRED_TEXTURE_UPLOAD #define EU07_DEFERRED_TEXTURE_UPLOAD
texture_manager::texture_manager() { texture_manager::texture_manager() {
@@ -96,17 +98,9 @@ void
opengl_texture::make_request() { opengl_texture::make_request() {
auto const components { Split( name, '?' ) }; auto const components { Split( name, '?' ) };
auto const query { Split( components.back(), '&' ) };
auto *dictionary { new dictionary_source }; auto *dictionary { new dictionary_source( components.back() ) };
if( dictionary != nullptr ) { if( dictionary == nullptr ) { return; }
for( auto const &querypair : query ) {
auto const valuepos { querypair.find( '=' ) };
dictionary->insert(
ToLower( querypair.substr( 0, valuepos ) ),
querypair.substr( valuepos + 1 ) );
}
}
Application.request( { ToLower( components.front() ), dictionary, id } ); Application.request( { ToLower( components.front() ), dictionary, id } );
} }

102
Train.cpp
View File

@@ -30,6 +30,7 @@ http://mozilla.org/MPL/2.0/.
#include "Console.h" #include "Console.h"
#include "application.h" #include "application.h"
#include "renderer.h" #include "renderer.h"
#include "dictionary.h"
/* /*
namespace input { namespace input {
@@ -543,31 +544,8 @@ dictionary_source *TTrain::GetTrainState() {
dict->insert( "velnext", driver->VelNext ); dict->insert( "velnext", driver->VelNext );
dict->insert( "actualproximitydist", driver->ActualProximityDist ); dict->insert( "actualproximitydist", driver->ActualProximityDist );
// train data // train data
auto const *timetable{ driver->TrainTimetable() }; driver->TrainTimetable()->serialize( dict );
dict->insert( "train_stationstart", driver->iStationStart );
dict->insert( "trainnumber", driver->TrainName() );
dict->insert( "train_brakingmassratio", timetable->BrakeRatio );
dict->insert( "train_enginetype", timetable->LocSeries );
dict->insert( "train_engineload", timetable->LocLoad );
dict->insert( "train_stationindex", driver->iStationStart );
auto const stationcount { driver->StationCount() };
dict->insert( "train_stationcount", stationcount );
if( stationcount > 0 ) {
// timetable stations data, if there's any
for( auto stationidx = 1; stationidx <= stationcount; ++stationidx ) {
auto const stationlabel { "train_station" + std::to_string( stationidx ) + "_" };
auto const &timetableline { timetable->TimeTable[ stationidx ] };
dict->insert( ( stationlabel + "name" ), Bezogonkow( timetableline.StationName ) );
dict->insert( ( stationlabel + "fclt" ), Bezogonkow( timetableline.StationWare ) );
dict->insert( ( stationlabel + "lctn" ), timetableline.km );
dict->insert( ( stationlabel + "vmax" ), timetableline.vmax );
dict->insert( ( stationlabel + "ah" ), timetableline.Ah );
dict->insert( ( stationlabel + "am" ), timetableline.Am );
dict->insert( ( stationlabel + "dh" ), timetableline.Dh );
dict->insert( ( stationlabel + "dm" ), timetableline.Dm );
}
}
dict->insert( "train_atpassengerstop", driver->IsAtPassengerStop ); dict->insert( "train_atpassengerstop", driver->IsAtPassengerStop );
// world state data // world state data
dict->insert( "scenario", Global.SceneryFile ); dict->insert( "scenario", Global.SceneryFile );
@@ -4153,7 +4131,7 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command
if( Command.action == GLFW_PRESS ) { if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down // only reacting to press, so the switch doesn't flip back and forth if key is held down
if( false == Train->mvControlled->Heating ) { if( false == Train->mvControlled->HeatingAllow ) {
// turn on // turn on
OnCommand_heatingenable( Train, Command ); OnCommand_heatingenable( Train, Command );
} }
@@ -4167,24 +4145,20 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command
void TTrain::OnCommand_heatingenable( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_heatingenable( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_PRESS ) { if( Command.action == GLFW_PRESS ) {
Train->mvControlled->HeatingAllow = true;
// visual feedback // visual feedback
Train->ggTrainHeatingButton.UpdateValue( 1.0, Train->dsbSwitch ); Train->ggTrainHeatingButton.UpdateValue( 1.0, Train->dsbSwitch );
if( true == Train->mvControlled->Heating ) { return; } // already enabled
Train->mvControlled->Heating = true;
} }
} }
void TTrain::OnCommand_heatingdisable( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_heatingdisable( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_PRESS ) { if( Command.action == GLFW_PRESS ) {
Train->mvControlled->HeatingAllow = false;
// visual feedback // visual feedback
Train->ggTrainHeatingButton.UpdateValue( 0.0, Train->dsbSwitch ); Train->ggTrainHeatingButton.UpdateValue( 0.0, Train->dsbSwitch );
if( false == Train->mvControlled->Heating ) { return; } // already disabled
Train->mvControlled->Heating = false;
} }
} }
@@ -4315,39 +4289,75 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman
void TTrain::OnCommand_doorpermitleft( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_doorpermitleft( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_REPEAT ) { return; }
if( Command.action == GLFW_PRESS ) { if( Command.action == GLFW_PRESS ) {
Train->mvOccupied->PermitDoors( auto const side { (
( Train->mvOccupied->ActiveCab == 1 ? Train->mvOccupied->ActiveCab == 1 ?
side::left : side::left :
side::right ) ); side::right ) };
if( Train->ggDoorLeftPermitButton.type() == TGaugeType::push ) {
// impulse switch
Train->mvOccupied->PermitDoors( side );
// visual feedback // visual feedback
Train->ggDoorLeftPermitButton.UpdateValue( 1.0, Train->dsbSwitch ); Train->ggDoorLeftPermitButton.UpdateValue( 1.0, Train->dsbSwitch );
} }
else {
// two-state switch
auto const newstate { !( Train->mvOccupied->Doors.instances[ side ].open_permit ) };
Train->mvOccupied->PermitDoors( side, newstate );
// visual feedback
Train->ggDoorLeftPermitButton.UpdateValue( ( newstate ? 1.0 : 0.0 ), Train->dsbSwitch );
}
}
else if( Command.action == GLFW_RELEASE ) { else if( Command.action == GLFW_RELEASE ) {
if( Train->ggDoorLeftPermitButton.type() == TGaugeType::push ) {
// impulse switch
// visual feedback // visual feedback
Train->ggDoorLeftPermitButton.UpdateValue( 0.0, Train->dsbSwitch ); Train->ggDoorLeftPermitButton.UpdateValue( 0.0, Train->dsbSwitch );
} }
} }
}
void TTrain::OnCommand_doorpermitright( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_doorpermitright( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_REPEAT ) { return; }
if( Command.action == GLFW_PRESS ) { if( Command.action == GLFW_PRESS ) {
Train->mvOccupied->PermitDoors( auto const side { (
( Train->mvOccupied->ActiveCab == 1 ? Train->mvOccupied->ActiveCab == 1 ?
side::right : side::right :
side::left ) ); side::left ) };
if( Train->ggDoorRightPermitButton.type() == TGaugeType::push ) {
// impulse switch
Train->mvOccupied->PermitDoors( side );
// visual feedback // visual feedback
Train->ggDoorRightPermitButton.UpdateValue( 1.0, Train->dsbSwitch ); Train->ggDoorRightPermitButton.UpdateValue( 1.0, Train->dsbSwitch );
} }
else {
// two-state switch
auto const newstate { !( Train->mvOccupied->Doors.instances[ side ].open_permit ) };
Train->mvOccupied->PermitDoors( side, newstate );
// visual feedback
Train->ggDoorRightPermitButton.UpdateValue( ( newstate ? 1.0 : 0.0 ), Train->dsbSwitch );
}
}
else if( Command.action == GLFW_RELEASE ) { else if( Command.action == GLFW_RELEASE ) {
if( Train->ggDoorRightPermitButton.type() == TGaugeType::push ) {
// impulse switch
// visual feedback // visual feedback
Train->ggDoorRightPermitButton.UpdateValue( 0.0, Train->dsbSwitch ); Train->ggDoorRightPermitButton.UpdateValue( 0.0, Train->dsbSwitch );
} }
} }
}
void TTrain::OnCommand_doorpermitpresetactivatenext( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_doorpermitpresetactivatenext( TTrain *Train, command_data const &Command ) {
@@ -6027,7 +6037,6 @@ bool TTrain::Update( double const Deltatime )
//--------- //---------
// hunter-080812: poprawka na ogrzewanie w elektrykach - usuniete uzaleznienie od przetwornicy // hunter-080812: poprawka na ogrzewanie w elektrykach - usuniete uzaleznienie od przetwornicy
if( ( mvControlled->Heating == true ) if( ( mvControlled->Heating == true )
&& ( mvControlled->Mains == true )
&& ( mvControlled->ConvOvldFlag == false ) ) && ( mvControlled->ConvOvldFlag == false ) )
btLampkaOgrzewanieSkladu.Turn( true ); btLampkaOgrzewanieSkladu.Turn( true );
else else
@@ -7612,7 +7621,12 @@ void TTrain::set_cab_controls( int const Cab ) {
1.f : 1.f :
0.f ) ); 0.f ) );
// doors // doors
// NOTE: for the time being permit switches are presumed to be impulse switches if( ggDoorLeftPermitButton.type() != TGaugeType::push ) {
ggDoorLeftPermitButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::left : side::right ) ].open_permit ? 1.f : 0.f );
}
if( ggDoorRightPermitButton.type() != TGaugeType::push ) {
ggDoorRightPermitButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::right : side::left ) ].open_permit ? 1.f : 0.f );
}
ggDoorPermitPresetButton.PutValue( mvOccupied->Doors.permit_preset ); ggDoorPermitPresetButton.PutValue( mvOccupied->Doors.permit_preset );
ggDoorLeftButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::left : side::right ) ].is_closed ? 0.f : 1.f ); ggDoorLeftButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::left : side::right ) ].is_closed ? 0.f : 1.f );
ggDoorRightButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::right : side::left ) ].is_closed ? 0.f : 1.f ); ggDoorRightButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::right : side::left ) ].is_closed ? 0.f : 1.f );
@@ -7841,8 +7855,8 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co
} }
// TODO: move viable dedicated lights to the automatic light array // TODO: move viable dedicated lights to the automatic light array
std::unordered_map<std::string, bool *> const autolights = { std::unordered_map<std::string, bool *> const autolights = {
{ "i-doorpermit_left:", &mvOccupied->Doors.instances[side::left].open_permit }, { "i-doorpermit_left:", &mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::left : side::right ) ].open_permit },
{ "i-doorpermit_right:", &mvOccupied->Doors.instances[ side::right ].open_permit }, { "i-doorpermit_right:", &mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::right : side::left ) ].open_permit },
{ "i-doorstep:", &mvOccupied->Doors.step_enabled } { "i-doorstep:", &mvOccupied->Doors.step_enabled }
}; };
{ {

View File

@@ -81,12 +81,12 @@ openal_buffer::openal_buffer( std::string const &Filename ) :
auto const samplecount { stb_vorbis_decode_filename( Filename.c_str(), &channels, &samplerate, &filedata ) }; auto const samplecount { stb_vorbis_decode_filename( Filename.c_str(), &channels, &samplerate, &filedata ) };
if( samplecount > 0 ) { if( samplecount > 0 ) {
rate = samplerate; rate = samplerate;
data.resize( samplecount ); data.resize( samplecount * channels );
std::copy( filedata, filedata + samplecount, std::begin( data ) ); std::copy( filedata, filedata + data.size(), std::begin( data ) );
free( filedata ); free( filedata );
if( channels > 1 ) { if( channels > 1 ) {
narrow_to_mono( channels ); narrow_to_mono( channels );
data.resize( samplecount / channels ); data.resize( samplecount );
} }
} }
else { else {
@@ -109,7 +109,7 @@ void
openal_buffer::narrow_to_mono( std::uint16_t const Channelcount ) { openal_buffer::narrow_to_mono( std::uint16_t const Channelcount ) {
std::size_t monodataindex { 0 }; std::size_t monodataindex { 0 };
std::int32_t accumulator { 0 }; std::int64_t accumulator { 0 };
auto channelcount { Channelcount }; auto channelcount { Channelcount };
for( auto const channeldata : data ) { for( auto const channeldata : data ) {
@@ -117,7 +117,7 @@ openal_buffer::narrow_to_mono( std::uint16_t const Channelcount ) {
accumulator += channeldata; accumulator += channeldata;
if( --channelcount == 0 ) { if( --channelcount == 0 ) {
data[ monodataindex++ ] = accumulator / Channelcount; data[ monodataindex++ ] = static_cast<std::int16_t>( accumulator / Channelcount );
accumulator = 0; accumulator = 0;
channelcount = Channelcount; channelcount = Channelcount;
} }

55
dictionary.cpp Normal file
View File

@@ -0,0 +1,55 @@
/*
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 "dictionary.h"
#include "simulation.h"
#include "utilities.h"
#include "DynObj.h"
#include "Driver.h"
#include "mtable.h"
dictionary_source::dictionary_source( std::string const &Input ) {
auto const keyvaluepairs { Split( Input, '&' ) };
for( auto const &keyvaluepair : keyvaluepairs ) {
auto const valuepos { keyvaluepair.find( '=' ) };
if( keyvaluepair[ 0 ] != '$' ) {
// regular key, value pairs
insert(
ToLower( keyvaluepair.substr( 0, valuepos ) ),
keyvaluepair.substr( valuepos + 1 ) );
}
else {
// special case, $key indicates request to include certain dataset clarified by value
auto const key { ToLower( keyvaluepair.substr( 0, valuepos ) ) };
auto const value { keyvaluepair.substr( valuepos + 1 ) };
if( key == "$timetable" ) {
// timetable pulled from (preferably) the owner/direct controller of specified vehicle
auto const *vehicle { simulation::Vehicles.find( value ) };
auto const *controller { (
vehicle == nullptr ? nullptr :
vehicle->ctOwner == nullptr ? vehicle->Mechanik :
vehicle->ctOwner ) };
auto const *timetable { (
controller != nullptr ?
controller->TrainTimetable() :
nullptr ) };
if( timetable != nullptr ) {
timetable->serialize( this );
}
}
}
}
}

31
dictionary.h Normal file
View File

@@ -0,0 +1,31 @@
/*
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
// collection of keyword-value pairs
// NOTE: since our python dictionary operates on a few types, most of the class was hardcoded for simplicity
struct dictionary_source {
// types
template <typename Type_>
using keyvaluepair_sequence = std::vector<std::pair<std::string, Type_>>;
// members
keyvaluepair_sequence<double> floats;
keyvaluepair_sequence<int> integers;
keyvaluepair_sequence<bool> bools;
keyvaluepair_sequence<std::string> strings;
// constructors
dictionary_source() = default;
dictionary_source( std::string const &Input );
// methods
inline void insert( std::string const &Key, double const Value ) { floats.emplace_back( Key, Value ); }
inline void insert( std::string const &Key, int const Value ) { integers.emplace_back( Key, Value ); }
inline void insert( std::string const &Key, bool const Value ) { bools.emplace_back( Key, Value ); }
inline void insert( std::string const &Key, std::string const Value ) { strings.emplace_back( Key, Value ); }
};

View File

@@ -21,7 +21,7 @@ http://mozilla.org/MPL/2.0/.
#include "uilayer.h" #include "uilayer.h"
#include "Logs.h" #include "Logs.h"
auto const EU07_CONTROLLER_MOUSESLIDERSIZE{ 0.65 }; auto const EU07_CONTROLLER_MOUSESLIDERSIZE{ 0.6 };
void void
mouse_slider::bind( user_command const &Command ) { mouse_slider::bind( user_command const &Command ) {

View File

@@ -339,6 +339,9 @@
<ClCompile Include="ref\stb\stb_vorbis.c"> <ClCompile Include="ref\stb\stb_vorbis.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="dictionary.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Globals.h"> <ClInclude Include="Globals.h">
@@ -623,6 +626,9 @@
<ClInclude Include="openglcolor.h"> <ClInclude Include="openglcolor.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="dictionary.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="maszyna.rc"> <ResourceCompile Include="maszyna.rc">

View File

@@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/.
#include "Globals.h" #include "Globals.h"
#include "simulationtime.h" #include "simulationtime.h"
#include "dictionary.h"
#include "utilities.h" #include "utilities.h"
double TTrainParameters::CheckTrainLatency() double TTrainParameters::CheckTrainLatency()
@@ -523,3 +524,31 @@ bool TTrainParameters::DirectionChange()
return true; return true;
return false; return false;
} }
void TTrainParameters::serialize( dictionary_source *Output ) const {
Output->insert( "trainnumber", TrainName );
Output->insert( "train_brakingmassratio", BrakeRatio );
Output->insert( "train_enginetype", LocSeries );
Output->insert( "train_engineload", LocLoad );
Output->insert( "train_stationfrom", Relation1 );
Output->insert( "train_stationto", Relation2 );
Output->insert( "train_stationindex", StationIndex );
Output->insert( "train_stationcount", StationCount );
if( StationCount > 0 ) {
// timetable stations data, if there's any
for( auto stationidx = 1; stationidx <= StationCount; ++stationidx ) {
auto const stationlabel { "train_station" + std::to_string( stationidx ) + "_" };
auto const &timetableline { TimeTable[ stationidx ] };
Output->insert( ( stationlabel + "name" ), Bezogonkow( timetableline.StationName ) );
Output->insert( ( stationlabel + "fclt" ), Bezogonkow( timetableline.StationWare ) );
Output->insert( ( stationlabel + "lctn" ), timetableline.km );
Output->insert( ( stationlabel + "vmax" ), timetableline.vmax );
Output->insert( ( stationlabel + "ah" ), timetableline.Ah );
Output->insert( ( stationlabel + "am" ), timetableline.Am );
Output->insert( ( stationlabel + "dh" ), timetableline.Dh );
Output->insert( ( stationlabel + "dm" ), timetableline.Dm );
}
}
}

View File

@@ -83,6 +83,7 @@ class TTrainParameters
bool LoadTTfile(std::string scnpath, int iPlus, double vmax); bool LoadTTfile(std::string scnpath, int iPlus, double vmax);
bool DirectionChange(); bool DirectionChange();
void StationIndexInc(); void StationIndexInc();
void serialize( dictionary_source *Output ) const;
}; };
class TMTableTime class TMTableTime

View File

@@ -1,4 +1,4 @@
// Ogg Vorbis audio decoder - v1.14 - public domain // Ogg Vorbis audio decoder - v1.16 - public domain
// http://nothings.org/stb_vorbis/ // http://nothings.org/stb_vorbis/
// //
// Original version written by Sean Barrett in 2007. // Original version written by Sean Barrett in 2007.
@@ -33,6 +33,8 @@
// Timur Gagiev // Timur Gagiev
// //
// Partial history: // Partial history:
// 1.16 - 2019-03-04 - fix warnings
// 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found
// 1.14 - 2018-02-11 - delete bogus dealloca usage // 1.14 - 2018-02-11 - delete bogus dealloca usage
// 1.13 - 2018-01-29 - fix truncation of last frame (hopefully) // 1.13 - 2018-01-29 - fix truncation of last frame (hopefully)
// 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files // 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
@@ -253,7 +255,7 @@ extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
// create an ogg vorbis decoder from an open FILE *, looking for a stream at // create an ogg vorbis decoder from an open FILE *, looking for a stream at
// the _current_ seek point (ftell). on failure, returns NULL and sets *error. // the _current_ seek point (ftell). on failure, returns NULL and sets *error.
// note that stb_vorbis must "own" this stream; if you seek it in between // note that stb_vorbis must "own" this stream; if you seek it in between
// calls to stb_vorbis, it will become confused. Morever, if you attempt to // calls to stb_vorbis, it will become confused. Moreover, if you attempt to
// perform stb_vorbis_seek_*() operations on this file, it will assume it // perform stb_vorbis_seek_*() operations on this file, it will assume it
// owns the _entire_ rest of the file after the start point. Use the next // owns the _entire_ rest of the file after the start point. Use the next
// function, stb_vorbis_open_file_section(), to limit it. // function, stb_vorbis_open_file_section(), to limit it.
@@ -374,7 +376,8 @@ enum STBVorbisError
VORBIS_invalid_first_page, VORBIS_invalid_first_page,
VORBIS_bad_packet_type, VORBIS_bad_packet_type,
VORBIS_cant_find_last_page, VORBIS_cant_find_last_page,
VORBIS_seek_failed VORBIS_seek_failed,
VORBIS_ogg_skeleton_not_supported
}; };
@@ -1073,7 +1076,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
assert(z >= 0 && z < 32); assert(z >= 0 && z < 32);
available[z] = 0; available[z] = 0;
add_entry(c, bit_reverse(res), i, m++, len[i], values); add_entry(c, bit_reverse(res), i, m++, len[i], values);
// propogate availability up the tree // propagate availability up the tree
if (z != len[i]) { if (z != len[i]) {
assert(len[i] >= 0 && len[i] < 32); assert(len[i] >= 0 && len[i] < 32);
for (y=len[i]; y > z; --y) { for (y=len[i]; y > z; --y) {
@@ -2637,7 +2640,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype)
// once I combined the passes. // once I combined the passes.
// so there's a missing 'times 2' here (for adding X to itself). // so there's a missing 'times 2' here (for adding X to itself).
// this propogates through linearly to the end, where the numbers // this propagates through linearly to the end, where the numbers
// are 1/2 too small, and need to be compensated for. // are 1/2 too small, and need to be compensated for.
{ {
@@ -3578,7 +3581,22 @@ static int start_decoder(vorb *f)
if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page); if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page);
// check for expected packet length // check for expected packet length
if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page); if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page);
if (f->segments[0] != 30) return error(f, VORBIS_invalid_first_page); if (f->segments[0] != 30) {
// check for the Ogg skeleton fishead identifying header to refine our error
if (f->segments[0] == 64 &&
getn(f, header, 6) &&
header[0] == 'f' &&
header[1] == 'i' &&
header[2] == 's' &&
header[3] == 'h' &&
header[4] == 'e' &&
header[5] == 'a' &&
get8(f) == 'd' &&
get8(f) == '\0') return error(f, VORBIS_ogg_skeleton_not_supported);
else
return error(f, VORBIS_invalid_first_page);
}
// read packet // read packet
// check packet header // check packet header
if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page); if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page);
@@ -4566,7 +4584,7 @@ static int get_seek_page_info(stb_vorbis *f, ProbedPage *z)
return 1; return 1;
} }
// rarely used function to seek back to the preceeding page while finding the // rarely used function to seek back to the preceding page while finding the
// start of a packet // start of a packet
static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset) static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset)
{ {
@@ -4973,7 +4991,13 @@ stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, con
stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc) stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc)
{ {
FILE *f = fopen(filename, "rb"); FILE *f;
#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__)
if (0 != fopen_s(&f, filename, "rb"))
f = NULL;
#else
f = fopen(filename, "rb");
#endif
if (f) if (f)
return stb_vorbis_open_file(f, TRUE, error, alloc); return stb_vorbis_open_file(f, TRUE, error, alloc);
if (error) *error = VORBIS_file_open_failure; if (error) *error = VORBIS_file_open_failure;

View File

@@ -32,17 +32,18 @@ int const EU07_ENVIRONMENTBUFFERSIZE { 256 }; // size of (square) environmental
void void
opengl_light::apply_intensity( float const Factor ) { opengl_light::apply_intensity( float const Factor ) {
if( Factor == 1.0 ) { if( Factor == 1.f ) {
::glLightfv( id, GL_AMBIENT, glm::value_ptr( ambient ) ); ::glLightfv( id, GL_AMBIENT, glm::value_ptr( ambient ) );
::glLightfv( id, GL_DIFFUSE, glm::value_ptr( diffuse ) ); ::glLightfv( id, GL_DIFFUSE, glm::value_ptr( diffuse ) );
::glLightfv( id, GL_SPECULAR, glm::value_ptr( specular ) ); ::glLightfv( id, GL_SPECULAR, glm::value_ptr( specular ) );
} }
else { else {
auto const factor{ clamp( Factor, 0.05f, 1.f ) };
// temporary light scaling mechanics (ultimately this work will be left to the shaders // temporary light scaling mechanics (ultimately this work will be left to the shaders
glm::vec4 scaledambient( ambient.r * Factor, ambient.g * Factor, ambient.b * Factor, ambient.a ); glm::vec4 scaledambient( ambient.r * factor, ambient.g * factor, ambient.b * factor, ambient.a );
glm::vec4 scaleddiffuse( diffuse.r * Factor, diffuse.g * Factor, diffuse.b * Factor, diffuse.a ); glm::vec4 scaleddiffuse( diffuse.r * factor, diffuse.g * factor, diffuse.b * factor, diffuse.a );
glm::vec4 scaledspecular( specular.r * Factor, specular.g * Factor, specular.b * Factor, specular.a ); glm::vec4 scaledspecular( specular.r * factor, specular.g * factor, specular.b * factor, specular.a );
glLightfv( id, GL_AMBIENT, glm::value_ptr( scaledambient ) ); glLightfv( id, GL_AMBIENT, glm::value_ptr( scaledambient ) );
glLightfv( id, GL_DIFFUSE, glm::value_ptr( scaleddiffuse ) ); glLightfv( id, GL_DIFFUSE, glm::value_ptr( scaleddiffuse ) );
glLightfv( id, GL_SPECULAR, glm::value_ptr( scaledspecular ) ); glLightfv( id, GL_SPECULAR, glm::value_ptr( scaledspecular ) );
@@ -2170,34 +2171,36 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
m_renderspecular = true; // vehicles are rendered with specular component. static models without, at least for the time being m_renderspecular = true; // vehicles are rendered with specular component. static models without, at least for the time being
// render // render
if( Dynamic->mdLowPolyInt ) { if( Dynamic->mdLowPolyInt ) {
// low poly interior // HACK: reduce light level for vehicle interior if there's strong global lighting source
/* auto const luminance { static_cast<float>( 0.5 * ( std::max( 0.3, Global.fLuminance - Global.Overcast ) ) ) };
if( ( true == FreeFlyModeFlag ) m_sunlight.apply_intensity(
|| ( ( Dynamic->mdKabina == nullptr ) || ( false == Dynamic->bDisplayCab ) ) ) { clamp( (
*/ Dynamic->fShade > 0.f ?
/* Dynamic->fShade :
// enable cab light if needed 1.f )
if( Dynamic->InteriorLightLevel > 0.0f ) { - luminance,
0.f, 1.f ) );
// crude way to light the cabin, until we have something more complete in place // low poly interior
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr( Dynamic->InteriorLight * Dynamic->InteriorLightLevel ) );
}
*/
Render( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance ); Render( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance );
/* // HACK: if the model has low poly interior, we presume the load is placed inside and also affected by reduced light level
if( Dynamic->InteriorLightLevel > 0.0f ) { if( Dynamic->mdLoad ) {
// reset the overall ambient // renderowanie nieprzezroczystego ładunku
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr( m_baseambient ) );
}
*/
/*
}
*/
}
if( Dynamic->mdModel )
Render( Dynamic->mdModel, Dynamic->Material(), squaredistance );
if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku
Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} ); Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
}
m_sunlight.apply_intensity( Dynamic->fShade > 0.f ? Dynamic->fShade : 1.f );
}
else {
// HACK: if the model lacks low poly interior, we presume the load is placed outside
if( Dynamic->mdLoad ) {
// renderowanie nieprzezroczystego ładunku
Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
}
}
if( Dynamic->mdModel ) {
Render( Dynamic->mdModel, Dynamic->Material(), squaredistance );
}
// post-render cleanup // post-render cleanup
m_renderspecular = false; m_renderspecular = false;
if( Dynamic->fShade > 0.0f ) { if( Dynamic->fShade > 0.0f ) {

View File

@@ -164,16 +164,24 @@ state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratch
// atmosphere color; legacy parameter, no longer used // atmosphere color; legacy parameter, no longer used
Input.getTokens( 3 ); Input.getTokens( 3 );
// fog range // fog range
{
double fograngestart, fograngeend;
Input.getTokens( 2 ); Input.getTokens( 2 );
Input Input
>> Global.fFogStart >> fograngestart
>> Global.fFogEnd; >> fograngeend;
if( Global.fFogEnd > 0.0 ) { if( Global.fFogEnd != 0.0 ) {
// fog colour; optional legacy parameter, no longer used // fog colour; optional legacy parameter, no longer used
Input.getTokens( 3 ); Input.getTokens( 3 );
} }
Global.fFogEnd =
clamp(
Random( fograngestart, fograngeend ),
100.0, 2000.0 );
}
std::string token { Input.getToken<std::string>() }; std::string token { Input.getToken<std::string>() };
if( token != "endatmo" ) { if( token != "endatmo" ) {
// optional overcast parameter // optional overcast parameter

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#define VERSION_MAJOR 19 #define VERSION_MAJOR 19
#define VERSION_MINOR 327 #define VERSION_MINOR 406
#define VERSION_REVISION 0 #define VERSION_REVISION 0