mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-18 01:59:19 +02:00
external cargo included in the vehicle load visualization system, cargo model offset parameter
This commit is contained in:
122
DynObj.cpp
122
DynObj.cpp
@@ -621,26 +621,26 @@ TDynamicObject::toggle_lights() {
|
||||
|
||||
if( true == SectionLightsActive ) {
|
||||
// switch all lights off
|
||||
for( auto §ionlight : SectionLightLevels ) {
|
||||
sectionlight.level = 0.0f;
|
||||
for( auto §ion : Sections ) {
|
||||
section.light_level = 0.0f;
|
||||
}
|
||||
SectionLightsActive = false;
|
||||
}
|
||||
else {
|
||||
// set lights with probability depending on the compartment type. TODO: expose this in .mmd file
|
||||
for( auto §ionlight : SectionLightLevels ) {
|
||||
for( auto §ion : Sections ) {
|
||||
|
||||
std::string const &compartmentname = sectionlight.compartment->pName;
|
||||
if( ( compartmentname.find( "corridor" ) == 0 )
|
||||
|| ( compartmentname.find( "korytarz" ) == 0 ) ) {
|
||||
auto const sectionname { section.compartment->pName };
|
||||
if( ( sectionname.find( "corridor" ) == 0 )
|
||||
|| ( sectionname.find( "korytarz" ) == 0 ) ) {
|
||||
// corridors are lit 100% of time
|
||||
sectionlight.level = 0.75f;
|
||||
section.light_level = 0.75f;
|
||||
}
|
||||
else if(
|
||||
( compartmentname.find( "compartment" ) == 0 )
|
||||
|| ( compartmentname.find( "przedzial" ) == 0 ) ) {
|
||||
( sectionname.find( "compartment" ) == 0 )
|
||||
|| ( sectionname.find( "przedzial" ) == 0 ) ) {
|
||||
// compartments are lit with 75% probability
|
||||
sectionlight.level = ( Random() < 0.75 ? 0.75f : 0.15f );
|
||||
section.light_level = ( Random() < 0.75 ? 0.75f : 0.15f );
|
||||
}
|
||||
}
|
||||
SectionLightsActive = true;
|
||||
@@ -1024,10 +1024,10 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
|
||||
// else btHeadSignals23.TurnOff();
|
||||
}
|
||||
// interior light levels
|
||||
for( auto const §ion : SectionLightLevels ) {
|
||||
section.compartment->SetLightLevel( section.level, true );
|
||||
for( auto const §ion : Sections ) {
|
||||
section.compartment->SetLightLevel( section.light_level, true );
|
||||
if( section.load != nullptr ) {
|
||||
section.load->SetLightLevel( section.level, true );
|
||||
section.load->SetLightLevel( section.light_level, true );
|
||||
}
|
||||
}
|
||||
// load chunks visibility
|
||||
@@ -2161,35 +2161,21 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
// check the low poly interior for potential compartments of interest, ie ones which can be individually lit
|
||||
// TODO: definition of relevant compartments in the .mmd file
|
||||
TSubModel *submodel { nullptr };
|
||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab1" ) ) != nullptr ) { SectionLightLevels.push_back( { submodel, nullptr, 0.0f } ); }
|
||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab2" ) ) != nullptr ) { SectionLightLevels.push_back( { submodel, nullptr, 0.0f } ); }
|
||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab0" ) ) != nullptr ) { SectionLightLevels.push_back( { submodel, nullptr, 0.0f } ); }
|
||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab1" ) ) != nullptr ) { Sections.push_back( { submodel, nullptr, 0.0f } ); }
|
||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab2" ) ) != nullptr ) { Sections.push_back( { submodel, nullptr, 0.0f } ); }
|
||||
if( ( submodel = mdLowPolyInt->GetFromName( "cab0" ) ) != nullptr ) { Sections.push_back( { submodel, nullptr, 0.0f } ); }
|
||||
// passenger car compartments
|
||||
std::vector<std::string> nameprefixes = { "corridor", "korytarz", "compartment", "przedzial" };
|
||||
int compartmentindex;
|
||||
std::string compartmentname;
|
||||
for( auto const &nameprefix : nameprefixes ) {
|
||||
compartmentindex = 0;
|
||||
do {
|
||||
compartmentname =
|
||||
nameprefix + (
|
||||
compartmentindex < 10 ?
|
||||
"0" + std::to_string( compartmentindex ) :
|
||||
std::to_string( compartmentindex ) );
|
||||
submodel = mdLowPolyInt->GetFromName( compartmentname );
|
||||
if( submodel != nullptr ) {
|
||||
SectionLightLevels.push_back( {
|
||||
submodel,
|
||||
nullptr, // pointers to load sections are generated afterwards
|
||||
0.0f } );
|
||||
}
|
||||
++compartmentindex;
|
||||
} while( ( submodel != nullptr )
|
||||
|| ( compartmentindex < 2 ) ); // chain can start from prefix00 or prefix01
|
||||
init_sections( mdLowPolyInt, nameprefix );
|
||||
}
|
||||
update_load_sections();
|
||||
update_load_visibility();
|
||||
}
|
||||
// 'external_load' is an optional special section in the main model, pointing to submodel of external load
|
||||
if( mdModel ) {
|
||||
init_sections( mdModel, "external_load" );
|
||||
}
|
||||
update_load_sections();
|
||||
update_load_visibility();
|
||||
// wyszukiwanie zderzakow
|
||||
if( mdModel ) {
|
||||
// jeśli ma w czym szukać
|
||||
@@ -2277,6 +2263,35 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
return MoverParameters->Dim.L;
|
||||
}
|
||||
|
||||
int
|
||||
TDynamicObject::init_sections( TModel3d const *Model, std::string const &Nameprefix ) {
|
||||
|
||||
std::string sectionname;
|
||||
auto sectioncount = 0;
|
||||
auto sectionindex = 0;
|
||||
TSubModel *sectionsubmodel { nullptr };
|
||||
|
||||
do {
|
||||
sectionname =
|
||||
Nameprefix + (
|
||||
sectionindex < 10 ?
|
||||
"0" + std::to_string( sectionindex ) :
|
||||
std::to_string( sectionindex ) );
|
||||
sectionsubmodel = Model->GetFromName( sectionname );
|
||||
if( sectionsubmodel != nullptr ) {
|
||||
Sections.push_back( {
|
||||
sectionsubmodel,
|
||||
nullptr, // pointers to load sections are generated afterwards
|
||||
0.0f } );
|
||||
++sectioncount;
|
||||
}
|
||||
++sectionindex;
|
||||
} while( ( sectionsubmodel != nullptr )
|
||||
|| ( sectionindex < 2 ) ); // chain can start from prefix00 or prefix01
|
||||
|
||||
return sectioncount;
|
||||
}
|
||||
|
||||
void
|
||||
TDynamicObject::create_controller( std::string const Type, bool const Trainset ) {
|
||||
|
||||
@@ -2580,6 +2595,9 @@ void TDynamicObject::LoadExchange( int const Disembark, int const Embark, int co
|
||||
// update state of load exchange operation
|
||||
void TDynamicObject::update_exchange( double const Deltatime ) {
|
||||
|
||||
// TODO: move offset calculation after initial check, when the loading system is all unified
|
||||
update_load_offset();
|
||||
|
||||
if( ( m_exchange.unload_count < 0.01 ) && ( m_exchange.load_count < 0.01 ) ) { return; }
|
||||
|
||||
if( ( MoverParameters->Vel < 2.0 )
|
||||
@@ -2686,7 +2704,7 @@ TDynamicObject::update_load_sections() {
|
||||
|
||||
SectionLoadVisibility.clear();
|
||||
|
||||
for( auto §ion : SectionLightLevels ) {
|
||||
for( auto §ion : Sections ) {
|
||||
|
||||
section.load = (
|
||||
mdLoad != nullptr ?
|
||||
@@ -2737,6 +2755,19 @@ TDynamicObject::update_load_visibility() {
|
||||
} } );
|
||||
}
|
||||
|
||||
void
|
||||
TDynamicObject::update_load_offset() {
|
||||
|
||||
if( MoverParameters->LoadMinOffset == 0.f ) { return; }
|
||||
|
||||
auto const loadpercentage { (
|
||||
MoverParameters->MaxLoad == 0.0 ?
|
||||
0.0 :
|
||||
100.0 * MoverParameters->Load / MoverParameters->MaxLoad ) };
|
||||
|
||||
LoadOffset = interpolate( MoverParameters->LoadMinOffset, 0.f, clamp( 0.0, 1.0, loadpercentage * 0.01 ) );
|
||||
}
|
||||
|
||||
void
|
||||
TDynamicObject::shuffle_load_sections() {
|
||||
|
||||
@@ -2748,6 +2779,8 @@ TDynamicObject::shuffle_load_sections() {
|
||||
return (
|
||||
( section.submodel->pName.find( "compartment" ) == 0 )
|
||||
|| ( section.submodel->pName.find( "przedzial" ) == 0 ) ); } );
|
||||
// NOTE: potentially we're left with a mix of corridor and external section loads
|
||||
// but that's not necessarily a wrong outcome, so we leave it this way for the time being
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3807,10 +3840,11 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
MoverParameters->DerailReason = 0; //żeby tylko raz
|
||||
}
|
||||
|
||||
update_exchange( dt );
|
||||
if (MoverParameters->LoadStatus)
|
||||
if( MoverParameters->LoadStatus ) {
|
||||
LoadUpdate(); // zmiana modelu ładunku
|
||||
|
||||
}
|
||||
update_exchange( dt );
|
||||
|
||||
return true; // Ra: chyba tak?
|
||||
}
|
||||
|
||||
@@ -3848,9 +3882,11 @@ bool TDynamicObject::FastUpdate(double dt)
|
||||
// ResetdMoveLen();
|
||||
FastMove(dDOMoveLen);
|
||||
|
||||
update_exchange( dt );
|
||||
if (MoverParameters->LoadStatus)
|
||||
if( MoverParameters->LoadStatus ) {
|
||||
LoadUpdate(); // zmiana modelu ładunku
|
||||
}
|
||||
update_exchange( dt );
|
||||
|
||||
return true; // Ra: chyba tak?
|
||||
}
|
||||
|
||||
|
||||
11
DynObj.h
11
DynObj.h
@@ -196,16 +196,17 @@ public:
|
||||
TModel3d *mdLoad; // model zmiennego ładunku
|
||||
TModel3d *mdKabina; // model kabiny dla użytkownika; McZapkie-030303: to z train.h
|
||||
TModel3d *mdLowPolyInt; // ABu 010305: wnetrze lowpoly
|
||||
float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?)
|
||||
float LoadOffset { 0.f };
|
||||
glm::vec3 InteriorLight { 0.9f * 255.f / 255.f, 0.9f * 216.f / 255.f, 0.9f * 176.f / 255.f }; // tungsten light. TODO: allow definition of light type?
|
||||
float InteriorLightLevel { 0.0f }; // current level of interior lighting
|
||||
struct section_light {
|
||||
struct vehicle_section {
|
||||
TSubModel *compartment;
|
||||
TSubModel *load;
|
||||
float level;
|
||||
float light_level;
|
||||
};
|
||||
std::vector<section_light> SectionLightLevels; // table of light levels for specific compartments of associated 3d model
|
||||
std::vector<vehicle_section> Sections; // table of recognized vehicle sections
|
||||
bool SectionLightsActive { false }; // flag indicating whether section lights were set.
|
||||
float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?)
|
||||
struct section_visibility {
|
||||
TSubModel *submodel;
|
||||
bool visible;
|
||||
@@ -517,6 +518,7 @@ private:
|
||||
std::string Name, std::string BaseDir, std::string asReplacableSkin, std::string Type_Name,
|
||||
TTrack *Track, double fDist, std::string DriverType, double fVel, std::string TrainName,
|
||||
float Load, std::string LoadType, bool Reversed, std::string);
|
||||
int init_sections( TModel3d const *Model, std::string const &Nameprefix );
|
||||
void create_controller( std::string const Type, bool const Trainset );
|
||||
void AttachPrev(TDynamicObject *Object, int iType = 1);
|
||||
bool UpdateForce(double dt, double dt1, bool FullVer);
|
||||
@@ -525,6 +527,7 @@ private:
|
||||
void LoadUpdate();
|
||||
void update_load_sections();
|
||||
void update_load_visibility();
|
||||
void update_load_offset();
|
||||
void shuffle_load_sections();
|
||||
bool Update(double dt, double dt1);
|
||||
bool FastUpdate(double dt);
|
||||
|
||||
@@ -947,6 +947,7 @@ public:
|
||||
float MaxLoad = 0.f; /*masa w T lub ilosc w sztukach - ladownosc*/
|
||||
std::string LoadAccepted; std::string LoadQuantity; /*co moze byc zaladowane, jednostki miary*/
|
||||
double OverLoadFactor = 0.0; /*ile razy moze byc przekroczona ladownosc*/
|
||||
float LoadMinOffset { 0.f }; // offset applied to cargo model when load amount is 0
|
||||
float LoadSpeed = 0.f; float UnLoadSpeed = 0.f;/*szybkosc na- i rozladunku jednostki/s*/
|
||||
int DoorOpenCtrl = 0; int DoorCloseCtrl = 0; /*0: przez pasazera, 1: przez maszyniste, 2: samoczynne (zamykanie)*/
|
||||
double DoorStayOpen = 0.0; /*jak dlugo otwarte w przypadku DoorCloseCtrl=2*/
|
||||
|
||||
@@ -6624,12 +6624,9 @@ TMoverParameters::signal_departure( bool const State, range_t const Notify ) {
|
||||
void
|
||||
TMoverParameters::update_autonomous_doors( double const Deltatime ) {
|
||||
|
||||
if( ( DoorCloseCtrl != control_t::autonomous )
|
||||
|| ( ( false == DoorLeftOpened )
|
||||
&& ( false == DoorRightOpened ) ) ) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
if( DoorCloseCtrl != control_t::autonomous ) { return; }
|
||||
if( ( false == DoorLeftOpened )
|
||||
&& ( false == DoorRightOpened ) ) { return; }
|
||||
|
||||
if( DoorStayOpen > 0.0 ) {
|
||||
// update door timers if the door close after defined time
|
||||
@@ -6641,18 +6638,19 @@ TMoverParameters::update_autonomous_doors( double const Deltatime ) {
|
||||
if( true == DoorLeftOpened ) { DoorLeftOpenTimer = DoorStayOpen; }
|
||||
if( true == DoorRightOpened ) { DoorRightOpenTimer = DoorStayOpen; }
|
||||
}
|
||||
// the door are closed if their timer goes below 0, or if the vehicle is moving at > 5 km/h
|
||||
// the door are closed if their timer goes below 0, or if the vehicle is moving at > 10 km/h
|
||||
auto const closingspeed { 10.0 };
|
||||
// NOTE: timer value of 0 is 'special' as it means the door will stay open until vehicle is moving
|
||||
if( true == DoorLeftOpened ) {
|
||||
if( ( ( DoorStayOpen > 0.0 ) && ( DoorLeftOpenTimer < 0.0 ) )
|
||||
|| ( Vel > 5.0 ) ) {
|
||||
|| ( Vel > closingspeed ) ) {
|
||||
// close the door and set the timer to expired state (closing may happen sooner if vehicle starts moving)
|
||||
DoorLeft( false, range_t::local );
|
||||
}
|
||||
}
|
||||
if( true == DoorRightOpened ) {
|
||||
if( ( ( DoorStayOpen > 0.0 ) && ( DoorRightOpenTimer < 0.0 ) )
|
||||
|| ( Vel > 5.0 ) ) {
|
||||
|| ( Vel > closingspeed ) ) {
|
||||
// close the door and set the timer to expired state (closing may happen sooner if vehicle starts moving)
|
||||
DoorRight( false, range_t::local );
|
||||
}
|
||||
@@ -7576,6 +7574,8 @@ void TMoverParameters::LoadFIZ_Load( std::string const &line ) {
|
||||
extract_value( OverLoadFactor, "OverLoadFactor", line, "" );
|
||||
extract_value( LoadSpeed, "LoadSpeed", line, "" );
|
||||
extract_value( UnLoadSpeed, "UnLoadSpeed", line, "" );
|
||||
|
||||
extract_value( LoadMinOffset, "LoadMinOffset", line, "" );
|
||||
}
|
||||
|
||||
void TMoverParameters::LoadFIZ_Dimensions( std::string const &line ) {
|
||||
|
||||
@@ -1154,7 +1154,7 @@ void TModel3d::AddTo(TSubModel *tmp, TSubModel *SubModel) {
|
||||
iFlags |= 0x0200; // submodele są oddzielne
|
||||
};
|
||||
|
||||
TSubModel *TModel3d::GetFromName(std::string const &Name)
|
||||
TSubModel *TModel3d::GetFromName(std::string const &Name) const
|
||||
{ // wyszukanie submodelu po nazwie
|
||||
if (Name.empty())
|
||||
return Root; // potrzebne do terenu z E3D
|
||||
|
||||
@@ -241,7 +241,7 @@ public:
|
||||
Root->m_boundingradius :
|
||||
0.f ); }
|
||||
inline TSubModel * GetSMRoot() { return (Root); };
|
||||
TSubModel * GetFromName(std::string const &Name);
|
||||
TSubModel * GetFromName(std::string const &Name) const;
|
||||
TSubModel * AddToNamed(const char *Name, TSubModel *SubModel);
|
||||
void AddTo(TSubModel *tmp, TSubModel *SubModel);
|
||||
void LoadFromTextFile(std::string const &FileName, bool dynamic);
|
||||
|
||||
@@ -2151,7 +2151,7 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
|
||||
Render( Dynamic->mdModel, Dynamic->Material(), squaredistance );
|
||||
|
||||
if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku
|
||||
Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance );
|
||||
Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
|
||||
|
||||
// post-render cleanup
|
||||
m_renderspecular = false;
|
||||
@@ -3096,7 +3096,7 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) {
|
||||
Render_Alpha( Dynamic->mdModel, Dynamic->Material(), squaredistance );
|
||||
|
||||
if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku
|
||||
Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance );
|
||||
Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
|
||||
|
||||
// post-render cleanup
|
||||
m_renderspecular = false;
|
||||
|
||||
Reference in New Issue
Block a user