16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-23 03:59:18 +02:00

Merge branch 'milek-dev' into gfx-work

This commit is contained in:
milek7
2018-12-03 23:43:02 +01:00
40 changed files with 987 additions and 571 deletions

View File

@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
#include "Button.h"
#include "parser.h"
#include "Model3d.h"
#include "DynObj.h"
#include "Console.h"
#include "Logs.h"
#include "renderer.h"
@@ -25,17 +26,19 @@ void TButton::Clear(int i)
Update(); // kasowanie bitu Feedback, o ile jakiś ustawiony
};
void TButton::Init( std::string const &asName, TModel3d *pModel, bool bNewOn ) {
bool TButton::Init( std::string const &asName, TModel3d const *pModel, bool bNewOn ) {
if( pModel == nullptr ) { return; }
if( pModel == nullptr ) { return false; }
pModelOn = pModel->GetFromName( asName + "_on" );
pModelOff = pModel->GetFromName( asName + "_off" );
m_state = bNewOn;
Update();
return( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) );
};
void TButton::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *pModel1, TModel3d *pModel2 ) {
void TButton::Load( cParser &Parser, TDynamicObject const *Owner ) {
std::string submodelname;
@@ -57,21 +60,17 @@ void TButton::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *pMod
m_soundfxincrease.owner( Owner );
m_soundfxdecrease.owner( Owner );
if( pModel1 ) {
// poszukiwanie submodeli w modelu
Init( submodelname, pModel1, false );
std::array<TModel3d *, 3> sources { Owner->mdKabina, Owner->mdLowPolyInt, Owner->mdModel };
for( auto const *source : sources ) {
if( true == Init( submodelname, source, false ) ) {
// got what we wanted, bail out
break;
}
}
if( ( pModelOn == nullptr )
&& ( pModelOff == nullptr )
&& ( pModel2 != nullptr ) ) {
// poszukiwanie submodeli w modelu
Init( submodelname, pModel2, false );
}
if( ( pModelOn == nullptr )
&& ( pModelOff == nullptr ) ) {
// if we failed to locate even one state submodel, cry
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + ( pModel1 != nullptr ? pModel1->NameGet() : pModel2 != nullptr ? pModel2->NameGet() : "NULL" ) + "\"", logtype::model );
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model(s) of \"" + Owner->name() + "\"", logtype::model );
}
// pass submodel location to defined sounds

View File

@@ -31,8 +31,8 @@ public:
return ( ( pModelOn != nullptr )
|| ( pModelOff != nullptr ) ); }
void Update();
void Init( std::string const &asName, TModel3d *pModel, bool bNewOn = false );
void Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *pModel1, TModel3d *pModel2 = nullptr );
bool Init( std::string const &asName, TModel3d const *pModel, bool bNewOn = false );
void Load( cParser &Parser, TDynamicObject const *Owner );
void AssignBool(bool const *bValue);
// returns offset of submodel associated with the button from the model centre
glm::vec3 model_offset() const;

View File

@@ -44,6 +44,7 @@ struct light_array;
namespace scene {
struct node_data;
class basic_node;
using group_handle = std::size_t;
}
namespace Mtable

View File

@@ -964,8 +964,8 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
// perform loading/unloading
auto const platformside = static_cast<int>( std::floor( std::abs( sSpeedTable[ i ].evEvent->input_value( 2 ) ) ) ) % 10;
auto const exchangetime = std::max( 5.0, simulation::Station.update_load( pVehicles[ 0 ], *TrainParams, platformside ) );
WaitingSet( std::max( -fStopTime, exchangetime ) ); // na końcu rozkładu się ustawia 60s i tu by było skrócenie
auto const exchangetime = simulation::Station.update_load( pVehicles[ 0 ], *TrainParams, platformside );
WaitingSet( exchangetime );
if( TrainParams->CheckTrainLatency() < 0.0 ) {
// odnotowano spóźnienie
@@ -1007,6 +1007,21 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
continue;
}
}
else {
// sitting at passenger stop
if( fStopTime < 0 ) {
// verify progress of load exchange
auto exchangetime { 0.f };
auto *vehicle { pVehicles[ 0 ] };
while( vehicle != nullptr ) {
exchangetime = std::max( exchangetime, vehicle->LoadExchangeTime() );
vehicle = vehicle->Next();
}
if( exchangetime > 0 ) {
WaitingSet( exchangetime );
}
}
}
if (OrderCurrentGet() & Shunt) {
OrderNext(Obey_train); // uruchomić jazdę pociągową
@@ -2055,6 +2070,14 @@ bool TController::CheckVehicles(TOrders user)
p = pVehicles[0];
while (p)
{
// HACK: wagony muszą mieć baterię załączoną do otwarcia drzwi...
if( ( p != pVehicle )
&& ( ( p->MoverParameters->Couplers[ side::front ].CouplingFlag & ( coupling::control | coupling::permanent ) ) == 0 )
&& ( ( p->MoverParameters->Couplers[ side::rear ].CouplingFlag & ( coupling::control | coupling::permanent ) ) == 0 ) ) {
// NOTE: don't set battery in the occupied vehicle, let the user/ai do it explicitly
p->MoverParameters->BatterySwitch( true );
}
if (p->asDestination == "none")
p->DestinationSet(TrainParams->Relation2, TrainParams->TrainName); // relacja docelowa, jeśli nie było
if (AIControllFlag) // jeśli prowadzi komputer
@@ -3195,8 +3218,6 @@ void TController::Doors( bool const Open, int const Side ) {
// tu będzie jeszcze długość peronu zaokrąglona do 10m (20m bezpieczniej, bo nie modyfikuje bitu 1)
auto *vehicle = pVehicles[0]; // pojazd na czole składu
while( vehicle != nullptr ) {
// wagony muszą mieć baterię załączoną do otwarcia drzwi...
vehicle->MoverParameters->BatterySwitch( true );
// otwieranie drzwi w pojazdach - flaga zezwolenia była by lepsza
if( vehicle->MoverParameters->DoorOpenCtrl != control_t::passenger ) {
// if the door are controlled by the driver, we let the user operate them...

View File

@@ -647,16 +647,14 @@ TDynamicObject::toggle_lights() {
}
void
TDynamicObject::set_cab_lights( float const Level ) {
if( Level == InteriorLightLevel ) { return; }
InteriorLightLevel = Level;
TDynamicObject::set_cab_lights( int const Cab, float const Level ) {
for( auto &section : Sections ) {
// cab compartments are placed at the beginning of the list, so we can bail out as soon as we find different compartment type
auto const sectionname { section.compartment->pName };
if( sectionname.size() < 4 ) { return; }
if( sectionname.find( "cab" ) != 0 ) { return; }
if( sectionname[ 3 ] != Cab + '0' ) { continue; } // match the cab with correct index
section.light_level = Level;
}
@@ -984,7 +982,8 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
btnOn = true;
}
if( ( Mechanik != nullptr )
if( ( false == bDisplayCab ) // edge case, lowpoly may act as a stand-in for the hi-fi cab, so make sure not to show the driver when inside
&& ( Mechanik != nullptr )
&& ( ( Mechanik->GetAction() != TAction::actSleep )
|| ( MoverParameters->Battery ) ) ) {
// rysowanie figurki mechanika
@@ -1039,10 +1038,19 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
// else btHeadSignals23.TurnOff();
}
// interior light levels
auto sectionlightcolor { glm::vec4( 1.f ) };
for( auto const &section : Sections ) {
section.compartment->SetLightLevel( section.light_level, true );
/*
sectionlightcolor = glm::vec4( InteriorLight, section.light_level );
*/
sectionlightcolor = glm::vec4(
( ( ( section.light_level == 0.f ) || ( Global.fLuminance > section.compartment->fLight ) ) ?
glm::vec3( 240.f / 255.f ) : // TBD: save and restore initial submodel diffuse instead of enforcing one?
InteriorLight ), // TODO: per-compartment (type) light color
section.light_level );
section.compartment->SetLightLevel( sectionlightcolor, true );
if( section.load != nullptr ) {
section.load->SetLightLevel( section.light_level, true );
section.load->SetLightLevel( sectionlightcolor, true );
}
}
// load chunks visibility
@@ -1061,7 +1069,17 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
sectionchunk = sectionchunk->NextGet();
}
}
// driver cabs visibility
for( int cabidx = 0; cabidx < LowPolyIntCabs.size(); ++cabidx ) {
if( LowPolyIntCabs[ cabidx ] == nullptr ) { continue; }
LowPolyIntCabs[ cabidx ]->iVisible = (
mdKabina == nullptr ? true : // there's no hi-fi cab
bDisplayCab == false ? true : // we're in external view
simulation::Train == nullptr ? true : // not a player-driven vehicle, implies external view
simulation::Train->Dynamic() != this ? true : // not a player-driven vehicle, implies external view
JointCabs ? false : // internal view, all cabs share the model so hide them 'all'
( simulation::Train->iCabn != cabidx ) ); // internal view, hide occupied cab and show others
}
}
// ABu 29.01.05 koniec przeklejenia *************************************
@@ -1355,8 +1373,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2,
MoverParameters->Couplers[ Side ].Connected,
coupling::coupler ) ) {
// tmp->MoverParameters->Couplers[CouplNr].Render=true; //podłączony sprzęg będzie widoczny
m_couplersounds[ Side ].dsbCouplerAttach.play();
// one coupling type per key press
return;
}
@@ -1374,9 +1390,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2,
MoverParameters->Couplers[ Side ].Connected,
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::brakehose ) ) ) {
// TODO: dedicated sound for connecting cable-type connections
m_couplersounds[ Side ].dsbCouplerDetach.play();
SetPneumatic( Side != 0, true );
if( Side == side::front ) {
PrevConnected->SetPneumatic( Side != 0, true );
@@ -1398,9 +1411,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2,
MoverParameters->Couplers[ Side ].Connected,
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::mainhose ) ) ) {
// TODO: dedicated sound for connecting cable-type connections
m_couplersounds[ Side ].dsbCouplerDetach.play();
SetPneumatic( Side != 0, false );
if( Side == side::front ) {
PrevConnected->SetPneumatic( Side != 0, false );
@@ -1422,8 +1432,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2,
MoverParameters->Couplers[ Side ].Connected,
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::control ) ) ) {
// TODO: dedicated sound for connecting cable-type connections
m_couplersounds[ Side ].dsbCouplerAttach.play();
// one coupling type per key press
return;
}
@@ -1438,8 +1446,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2,
MoverParameters->Couplers[ Side ].Connected,
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::gangway ) ) ) {
// TODO: dedicated gangway sound
m_couplersounds[ Side ].dsbCouplerAttach.play();
// one coupling type per key press
return;
}
@@ -1454,9 +1460,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2,
MoverParameters->Couplers[ Side ].Connected,
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::heating ) ) ) {
// TODO: dedicated 'click' sound for connecting cable-type connections
m_couplersounds[ Side ].dsbCouplerDetach.play();
// one coupling type per key press
return;
}
@@ -1475,11 +1478,6 @@ TDynamicObject::uncouple( int const Side ) {
}
// jeżeli sprzęg niezablokowany, jest co odczepić i się da
auto const couplingflag { Dettach( Side ) };
if( couplingflag == coupling::faux ) {
// dźwięk odczepiania
m_couplersounds[ Side ].dsbCouplerAttach.play();
m_couplersounds[ Side ].dsbCouplerDetach.play();
}
return couplingflag;
}
@@ -2183,9 +2181,18 @@ 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 ) { 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 } ); }
if( ( submodel = mdLowPolyInt->GetFromName( "cab0" ) ) != nullptr ) {
Sections.push_back( { submodel, nullptr, 0.0f } );
LowPolyIntCabs[ 0 ] = submodel;
}
if( ( submodel = mdLowPolyInt->GetFromName( "cab1" ) ) != nullptr ) {
Sections.push_back( { submodel, nullptr, 0.0f } );
LowPolyIntCabs[ 1 ] = submodel;
}
if( ( submodel = mdLowPolyInt->GetFromName( "cab2" ) ) != nullptr ) {
Sections.push_back( { submodel, nullptr, 0.0f } );
LowPolyIntCabs[ 2 ] = submodel;
}
// passenger car compartments
std::vector<std::string> nameprefixes = { "corridor", "korytarz", "compartment", "przedzial" };
for( auto const &nameprefix : nameprefixes ) {
@@ -2536,9 +2543,9 @@ void TDynamicObject::AttachPrev(TDynamicObject *Object, int iType)
loc.Z=Object->vPosition.y;
Object->MoverParameters->Loc=loc; //ustawienie dodawanego pojazdu
*/
MoverParameters->Attach(iDirection, Object->iDirection ^ 1, Object->MoverParameters, iType, true);
MoverParameters->Attach(iDirection, Object->iDirection ^ 1, Object->MoverParameters, iType, true, false);
MoverParameters->Couplers[iDirection].Render = false;
Object->MoverParameters->Attach(Object->iDirection ^ 1, iDirection, MoverParameters, iType, true);
Object->MoverParameters->Attach(Object->iDirection ^ 1, iDirection, MoverParameters, iType, true, false);
Object->MoverParameters->Couplers[Object->iDirection ^ 1].Render = true; // rysowanie sprzęgu w dołączanym
if (iDirection)
{ //łączenie standardowe
@@ -2607,13 +2614,39 @@ void TDynamicObject::LoadExchange( int const Disembark, int const Embark, int co
}
m_exchange.unload_count += Disembark;
m_exchange.load_count += Embark;
m_exchange.speed_factor = (
Platform == 3 ?
2.0 :
1.0 );
m_exchange.platforms = Platform;
m_exchange.time = 0.0;
}
// calculates time needed to complete current load change
float TDynamicObject::LoadExchangeTime() const {
if( ( m_exchange.unload_count < 0.01 ) && ( m_exchange.load_count < 0.01 ) ) { return 0.f; }
auto const baseexchangetime { m_exchange.unload_count / MoverParameters->UnLoadSpeed + m_exchange.load_count / MoverParameters->LoadSpeed };
auto const nominalexchangespeedfactor { ( m_exchange.platforms == 3 ? 2.f : 1.f ) };
auto const actualexchangespeedfactor { LoadExchangeSpeed() };
return baseexchangetime / ( actualexchangespeedfactor > 0.f ? actualexchangespeedfactor : nominalexchangespeedfactor );
}
// calculates current load exchange rate
float TDynamicObject::LoadExchangeSpeed() const {
// platforms (1:left, 2:right, 3:both)
// with exchange performed on both sides waiting times are halved
auto exchangespeedfactor { 0.f };
auto const lewe { ( DirectionGet() > 0 ) ? 1 : 2 };
auto const prawe { 3 - lewe };
if( m_exchange.platforms & lewe ) {
exchangespeedfactor += ( MoverParameters->DoorLeftOpened ? 1.f : 0.f );
}
if( m_exchange.platforms & prawe ) {
exchangespeedfactor += ( MoverParameters->DoorRightOpened ? 1.f : 0.f );
}
return exchangespeedfactor;
}
// update state of load exchange operation
void TDynamicObject::update_exchange( double const Deltatime ) {
@@ -2631,7 +2664,7 @@ void TDynamicObject::update_exchange( double const Deltatime ) {
&& ( m_exchange.time >= 1.0 ) ) {
m_exchange.time -= 1.0;
auto const exchangesize = std::min( m_exchange.unload_count, MoverParameters->UnLoadSpeed * m_exchange.speed_factor );
auto const exchangesize = std::min( m_exchange.unload_count, MoverParameters->UnLoadSpeed * LoadExchangeSpeed() );
m_exchange.unload_count -= exchangesize;
MoverParameters->LoadStatus = 1;
MoverParameters->LoadAmount = std::max( 0.f, MoverParameters->LoadAmount - exchangesize );
@@ -2645,7 +2678,7 @@ void TDynamicObject::update_exchange( double const Deltatime ) {
&& ( m_exchange.time >= 1.0 ) ) {
m_exchange.time -= 1.0;
auto const exchangesize = std::min( m_exchange.load_count, MoverParameters->LoadSpeed * m_exchange.speed_factor );
auto const exchangesize = std::min( m_exchange.load_count, MoverParameters->LoadSpeed * LoadExchangeSpeed() );
m_exchange.load_count -= exchangesize;
MoverParameters->LoadStatus = 2;
MoverParameters->LoadAmount = std::min( MoverParameters->MaxLoad, MoverParameters->LoadAmount + exchangesize ); // std::max not strictly needed but, eh
@@ -4464,6 +4497,11 @@ void TDynamicObject::RenderSounds() {
auto &coupler { MoverParameters->Couplers[ couplerindex ] };
if( coupler.sounds == sound::none ) {
++couplerindex;
continue;
}
if( true == TestFlag( coupler.sounds, sound::bufferclash ) ) {
// zderzaki uderzaja o siebie
if( true == TestFlag( coupler.sounds, sound::loud ) ) {
@@ -4488,6 +4526,7 @@ void TDynamicObject::RenderSounds() {
.play( sound_flags::exclusive );
}
}
if( true == TestFlag( coupler.sounds, sound::couplerstretch ) ) {
// sprzegi sie rozciagaja
if( true == TestFlag( coupler.sounds, sound::loud ) ) {
@@ -4513,8 +4552,22 @@ void TDynamicObject::RenderSounds() {
}
}
coupler.sounds = 0;
// TODO: dedicated sound for each connection type
// until then, play legacy placeholders:
if( ( coupler.sounds & ( sound::attachcoupler | sound::attachcontrol | sound::attachgangway ) ) != 0 ) {
m_couplersounds[ couplerindex ].dsbCouplerAttach.play();
}
if( ( coupler.sounds & ( sound::attachbrakehose | sound::attachmainhose | sound::attachheating ) ) != 0 ) {
m_couplersounds[ couplerindex ].dsbCouplerDetach.play();
}
if( true == TestFlag( coupler.sounds, sound::detachall ) ) {
// TODO: dedicated disconnect sounds
m_couplersounds[ couplerindex ].dsbCouplerAttach.play();
m_couplersounds[ couplerindex ].dsbCouplerDetach.play();
}
++couplerindex;
coupler.sounds = 0;
}
MoverParameters->SoundFlag = 0;
@@ -5916,6 +5969,10 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
>> HuntingShake.fadein_end;
}
else if( token == "jointcabs:" ) {
parser.getTokens();
parser >> JointCabs;
}
} while( token != "" );

View File

@@ -201,6 +201,8 @@ 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
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)
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?
@@ -290,7 +292,7 @@ private:
struct exchange_data {
float unload_count { 0.f }; // amount to unload
float load_count { 0.f }; // amount to load
float speed_factor { 1.f }; // operation speed modifier
int platforms { 0 }; // platforms which may take part in the exchange
float time { 0.f }; // time spent on the operation
};
@@ -530,6 +532,10 @@ private:
bool UpdateForce(double dt, double dt1, bool FullVer);
// initiates load change by specified amounts, with a platform on specified side
void LoadExchange( int const Disembark, int const Embark, int const Platform );
// calculates time needed to complete current load change
float LoadExchangeTime() const;
// calculates current load exchange factor, where 1 = nominal rate, higher = faster
float LoadExchangeSpeed() const; // TODO: make private when cleaning up
void LoadUpdate();
void update_load_sections();
void update_load_visibility();
@@ -619,7 +625,7 @@ private:
void Damage(char flag);
void RaLightsSet(int head, int rear);
int LightList( side const Side ) const { return iInventory[ Side ]; }
void set_cab_lights( float const Level );
void set_cab_lights( int const Cab, float const Level );
TDynamicObject * FirstFind(int &coupler_nr, int cf = 1);
float GetEPP(); // wyliczanie sredniego cisnienia w PG
int DirectionSet(int d); // ustawienie kierunku w składzie

View File

@@ -1019,7 +1019,7 @@ multi_event::init() {
auto const conditiontchecksmemcell { m_conditions.flags & ( flags::text | flags::value_1 | flags::value_2 ) };
// not all multi-events have memory cell checks, for the ones which don't we can keep quiet about it
init_targets( simulation::Memory, "memory cell", ( false == conditiontchecksmemcell ) );
init_targets( simulation::Memory, "memory cell", conditiontchecksmemcell );
if( m_ignored ) {
// legacy compatibility behaviour, instead of disabling the event we disable the memory cell comparison test
m_conditions.flags &= ~( flags::text | flags::value_1 | flags::value_2 );

View File

@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
#include "Gauge.h"
#include "parser.h"
#include "Model3d.h"
#include "DynObj.h"
#include "Timer.h"
#include "Logs.h"
#include "renderer.h"
@@ -76,7 +77,7 @@ void TGauge::Init(TSubModel *Submodel, TGaugeAnimation Type, float Scale, float
}
};
bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, TModel3d *md2, double mul ) {
void TGauge::Load( cParser &Parser, TDynamicObject const *Owner, double const mul ) {
std::string submodelname, gaugetypename;
float scale, endscale, endvalue, offset, friction;
@@ -138,13 +139,17 @@ bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1,
if( interpolatescale ) {
endscale *= mul;
}
TSubModel *submodel = md1->GetFromName( submodelname );
if (submodel) // jeśli nie znaleziony
md2 = nullptr; // informacja, że znaleziony
else if (md2) // a jest podany drugi model (np. zewnętrzny)
submodel = md2->GetFromName(submodelname); // to może tam będzie, co za różnica gdzie
TSubModel *submodel { nullptr };
std::array<TModel3d *, 2> sources { Owner->mdKabina, Owner->mdLowPolyInt };
for( auto const *source : sources ) {
if( ( source != nullptr )
&& ( submodel = source->GetFromName( submodelname ) ) != nullptr ) {
// got what we wanted, bail out
break;
}
}
if( submodel == nullptr ) {
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"", logtype::model );
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model(s) of \"" + Owner->name() + "\"", logtype::model );
}
std::map<std::string, TGaugeAnimation> gaugetypes {
@@ -163,7 +168,7 @@ bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1,
Init( submodel, type, scale, offset, friction, 0, endvalue, endscale, interpolatescale );
return md2 != nullptr; // true, gdy podany model zewnętrzny, a w kabinie nie było
// return md2 != nullptr; // true, gdy podany model zewnętrzny, a w kabinie nie było
};
bool

View File

@@ -38,7 +38,7 @@ public:
void Clear() {
*this = TGauge(); }
void Init(TSubModel *Submodel, TGaugeAnimation Type, float Scale = 1, float Offset = 0, float Friction = 0, float Value = 0, float const Endvalue = -1.0, float const Endscale = -1.0, bool const Interpolate = false );
bool Load(cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, TModel3d *md2 = nullptr, double mul = 1.0);
void Load(cParser &Parser, TDynamicObject const *Owner, double const mul = 1.0);
void UpdateValue( float fNewDesired );
void UpdateValue( float fNewDesired, sound_source &Fallbacksound );
void PutValue(float fNewDesired);

View File

@@ -209,13 +209,20 @@ static int const s_CAtest = 128;
/*dzwieki*/
enum sound {
none,
loud = 0x1,
couplerstretch = 0x2,
bufferclash = 0x4,
relay = 0x10,
parallel = 0x20,
shuntfield = 0x40,
pneumatic = 0x80
loud = 1 << 0,
couplerstretch = 1 << 1,
bufferclash = 1 << 2,
relay = 1 << 3,
parallel = 1 << 4,
shuntfield = 1 << 5,
pneumatic = 1 << 6,
detachall = 1 << 7,
attachcoupler = 1 << 8,
attachbrakehose = 1 << 9,
attachmainhose = 1 << 10,
attachcontrol = 1 << 11,
attachgangway = 1 << 12,
attachheating = 1 << 13
};
//szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType
@@ -1245,7 +1252,7 @@ public:
double Distance(const TLocation &Loc1, const TLocation &Loc2, const TDimension &Dim1, const TDimension &Dim2);
/* double Distance(const vector3 &Loc1, const vector3 &Loc2, const vector3 &Dim1, const vector3 &Dim2);
*/ //bool AttachA(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false);
bool Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false);
bool Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false, bool Audible = true);
int DettachStatus(int ConnectNo);
bool Dettach(int ConnectNo);
void SetCoupleDist();

View File

@@ -406,7 +406,7 @@ double TMoverParameters::CouplerDist(int Coupler)
return Couplers[ Coupler ].CoupleDist;
};
bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced)
bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced, bool Audible)
{ //łączenie do swojego sprzęgu (ConnectNo) pojazdu (ConnectTo) stroną (ConnectToNr)
// Ra: zwykle wykonywane dwukrotnie, dla każdego pojazdu oddzielnie
// Ra: trzeba by odróżnić wymóg dociśnięcia od uszkodzenia sprzęgu przy podczepianiu AI do
@@ -433,12 +433,32 @@ bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *
coupler.Render = true; // tego rysować
othercoupler.Render = false; // a tego nie
};
auto const couplingchange { CouplingType ^ coupler.CouplingFlag };
coupler.CouplingFlag = CouplingType; // ustawienie typu sprzęgu
// if (CouplingType!=ctrain_virtual) //Ra: wirtualnego nie łączymy zwrotnie!
//{//jeśli łączenie sprzęgiem niewirtualnym, ustawiamy połączenie zwrotne
othercoupler.CouplingFlag = CouplingType;
othercoupler.Connected = this;
othercoupler.CoupleDist = coupler.CoupleDist;
if( ( true == Audible ) && ( couplingchange != 0 ) ) {
// set sound event flag
int soundflag{ sound::none };
std::vector<std::pair<coupling, sound>> const soundmappings = {
{ coupling::coupler, sound::attachcoupler },
{ coupling::brakehose, sound::attachbrakehose },
{ coupling::mainhose, sound::attachmainhose },
{ coupling::control, sound::attachcontrol},
{ coupling::gangway, sound::attachgangway},
{ coupling::heating, sound::attachheating} };
for( auto const &soundmapping : soundmappings ) {
if( ( couplingchange & soundmapping.first ) != 0 ) {
soundflag |= soundmapping.second;
}
}
SetFlag( coupler.sounds, soundflag );
}
return true;
//}
// podłączenie nie udało się - jest wirtualne
@@ -489,6 +509,10 @@ bool TMoverParameters::Dettach(int ConnectNo)
Couplers[ConnectNo].Connected->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag =
0; // pozostaje sprzęg wirtualny
Couplers[ConnectNo].CouplingFlag = 0; // pozostaje sprzęg wirtualny
// set sound event flag
SetFlag( Couplers[ ConnectNo ].sounds, sound::detachall );
return true;
}
else if (i > 0)
@@ -4405,7 +4429,8 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
// sprzeganie wagonow z samoczynnymi sprzegami}
// CouplingFlag:=ctrain_coupler+ctrain_pneumatic+ctrain_controll+ctrain_passenger+ctrain_scndpneumatic;
// EN57
Couplers[ CouplerN ].CouplingFlag = coupling::coupler | coupling::brakehose | coupling::mainhose | coupling::control;
Couplers[ CouplerN ].CouplingFlag = coupling::coupler /*| coupling::brakehose | coupling::mainhose | coupling::control*/;
SetFlag( Couplers[ CouplerN ].sounds, sound::attachcoupler );
}
}
}
@@ -4857,9 +4882,13 @@ double TMoverParameters::TractionForce( double dt ) {
EnginePower = Voltage * Im / 1000.0;
/*
// NOTE: this part is experimentally disabled, as it generated early traction force drop for undetermined purpose
if ((tmpV > 2) && (EnginePower < tmp))
Ft = Ft * EnginePower / tmp;
// power curve drop
// NOTE: disabled for the time being due to side-effects
if( ( tmpV > 1 ) && ( EnginePower < tmp ) ) {
Ft = interpolate(
Ft, EnginePower / tmp,
clamp( tmpV - 1.0, 0.0, 1.0 ) );
}
*/
}

View File

@@ -110,9 +110,12 @@ TSubModel::SetVisibilityLevel( float const Level, bool const Includechildren, bo
// sets light level (alpha component of illumination color) to specified value
void
TSubModel::SetLightLevel( float const Level, bool const Includechildren, bool const Includesiblings ) {
f4Emision.a = Level;
TSubModel::SetLightLevel( glm::vec4 const &Level, bool const Includechildren, bool const Includesiblings ) {
/*
f4Emision = Level;
*/
f4Diffuse = { Level.r, Level.g, Level.b, f4Diffuse.a };
f4Emision.a = Level.a;
if( true == Includesiblings ) {
auto sibling { this };
while( ( sibling = sibling->Next ) != nullptr ) {

View File

@@ -201,7 +201,7 @@ public:
// sets visibility level (alpha component) to specified value
void SetVisibilityLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
// sets light level (alpha component of illumination color) to specified value
void SetLightLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
void SetLightLevel( glm::vec4 const &Level, bool const Includechildren = false, bool const Includesiblings = false );
inline float3 Translation1Get() {
return fMatrix ? *(fMatrix->TranslationGet()) + v_TransVector : v_TransVector; }
inline float3 Translation2Get() {

View File

@@ -372,7 +372,7 @@ Math3D::vector3 TSegment::FastGetPoint(double const t) const
interpolate( Point1, Point2, t ) );
}
bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, const gfx::vertex_array &ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, std::pair<float, float> fOffsetX, glm::vec3 **p, bool bRender)
bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, const gfx::vertex_array &ShapePoints, bool const Transition, double fTextureLength, double Texturescale, int iSkip, int iEnd, std::pair<float, float> fOffsetX, glm::vec3 **p, bool bRender)
{ // generowanie trójkątów dla odcinka trajektorii ruchu
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
// po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli podany jest przekrój końcowy
@@ -382,8 +382,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
glm::vec3 pos1, pos2, dir, parallel1, parallel2, pt, norm;
float s, step, fOffset, tv1, tv2, t, fEnd;
bool const trapez = iNumShapePoints < 0; // sygnalizacja trapezowatości
iNumShapePoints = std::abs( iNumShapePoints );
auto const iNumShapePoints = Transition ? ShapePoints.size() / 2 : ShapePoints.size();
float const texturelength = fTextureLength * Texturescale;
float const texturescale = Texturescale;
@@ -448,7 +447,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
parallel2 = glm::normalize( parallel2 );
// TODO: refactor the loop, there's no need to calculate starting points for each segment when we can copy the end points of the previous one
if( trapez ) {
if( Transition ) {
for( int j = 0; j < iNumShapePoints; ++j ) {
pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].position.x - fOffsetX.first ) + m1 * ( ShapePoints[ j + iNumShapePoints ].position.x - fOffsetX.second ) ) + pos1;
pt.y += jmm1 * ShapePoints[ j ].position.y + m1 * ShapePoints[ j + iNumShapePoints ].position.y;

View File

@@ -116,7 +116,7 @@ public:
r2 = fRoll2; }
bool
RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, gfx::vertex_array const &ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, std::pair<float, float> fOffsetX = {0.f, 0.f}, glm::vec3 **p = nullptr, bool bRender = true );
RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, gfx::vertex_array const &ShapePoints, bool const Transition, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, std::pair<float, float> fOffsetX = {0.f, 0.f}, glm::vec3 **p = nullptr, bool bRender = true );
/*
void
Render();

211
Track.cpp
View File

@@ -192,8 +192,7 @@ void TTrack::Init()
bool
TTrack::sort_by_material( TTrack const *Left, TTrack const *Right ) {
return ( ( Left->m_material1 < Right->m_material1 )
&& ( Left->m_material2 < Right->m_material2 ) );
return std::tie( Left->m_material1, Left->m_material2 ) < std::tie( Right->m_material1, Right->m_material2 );
}
TTrack * TTrack::Create400m(int what, double dx)
@@ -586,7 +585,7 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
if (eType == tt_Table) // obrotnica ma doklejkę
{ // SwitchExtension=new TSwitchExtension(this,1); //dodatkowe zmienne dla obrotnicy
SwitchExtension->Segments[0]->Init(p1, p2, segsize); // kopia oryginalnego toru
SwitchExtension->Segments[0]->Init(p1, p2, segsize, r1, r2 ); // kopia oryginalnego toru
}
else if (iCategoryFlag & 2)
if (m_material1 && fTexLength)
@@ -1122,11 +1121,10 @@ void TTrack::RaAssign( TAnimModel *am, basic_event *done, basic_event *joined )
{
SwitchExtension->pModel = am;
SwitchExtension->evMinus = done; // event zakończenia animacji (zadanie nowej przedłuża)
SwitchExtension->evPlus =
joined; // event potwierdzenia połączenia (gdy nie znajdzie, to się nie połączy)
if (am)
if (am->GetContainer()) // może nie być?
am->GetContainer()->EventAssign(done); // zdarzenie zakończenia animacji
SwitchExtension->evPlus = joined; // event potwierdzenia połączenia (gdy nie znajdzie, to się nie połączy)
if( ( am != nullptr ) && ( am->GetContainer() ) ) {// może nie być?
am->GetContainer()->EventAssign( done ); // zdarzenie zakończenia animacji
}
}
};
@@ -1159,7 +1157,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
create_track_bed_profile( bpts1, trPrev, trNext );
auto const texturelength { texture_length( m_material2 ) };
gfx::vertex_array vertices;
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -5 : 5, texturelength);
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid > 0, texturelength);
if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
}
@@ -1174,18 +1172,18 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
auto const texturelength { texture_length( m_material1 ) };
gfx::vertex_array vertices;
if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) {
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, texturelength );
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid > 0, texturelength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); // reuse the scratchpad
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, texturelength );
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid > 0, texturelength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
}
if( ( Bank == 0 ) && ( false == Geometry1.empty() ) ) {
// special variant, replace existing data for a turntable track
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, texturelength );
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid > 0, texturelength );
GfxRenderer.Replace( vertices, Geometry1[ 0 ], GL_TRIANGLE_STRIP );
vertices.clear(); // reuse the scratchpad
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, texturelength );
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid > 0, texturelength );
GfxRenderer.Replace( vertices, Geometry1[ 1 ], GL_TRIANGLE_STRIP );
}
}
@@ -1196,8 +1194,12 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
gfx::vertex_array rpts3, rpts4;
create_track_blade_profile( rpts3, rpts4 );
// TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers
auto const bladelength { static_cast<int>( std::ceil( SwitchExtension->Segments[ 0 ]->RaSegCount() * 0.65 ) ) };
auto const nnumPts { track_rail_profile( m_profile1.second ).size() / 2 };
auto const bladelength { static_cast<int>( std::ceil( SwitchExtension->Segments[ 0 ]->RaSegCount() * 0.65 ) ) };
// positive jointlength: the switch is typically used along the main track, negative: along the diverging track
// TODO: determine this from names of textures assigned to the tracks
// auto const jointlength { static_cast<int>( std::ceil( SwitchExtension->Segments[ 0 ]->RaSegCount() * 0.15 ) ) };
auto const jointlength { 0 }; // temporary until implementation of the above
if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
gfx::vertex_array vertices;
@@ -1205,15 +1207,22 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
auto const texturelength { texture_length( m_material1 ) };
// left blade
// composed from two parts: transition from blade to regular rail, and regular rail
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { SwitchExtension->fOffset2, SwitchExtension->fOffset2 / 2 } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { SwitchExtension->fOffset2 / 2, 0.f } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, true, texturelength, 1.0, 0, bladelength / 2, { SwitchExtension->fOffset2, SwitchExtension->fOffset2 / 2 } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength / 2, bladelength, { SwitchExtension->fOffset2 / 2, 0.f } );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
// fixed parts
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength );
if( jointlength > 0 ) {
// part of the diverging rail touched by wheels of vehicle going straight
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, 0, jointlength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
// other rail, full length
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
@@ -1221,15 +1230,16 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
auto const texturelength { texture_length( m_material2 ) };
// right blade
// composed from two parts: transition from blade to regular rail, and regular rail
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { -fMaxOffset + SwitchExtension->fOffset1, ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2 } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2, 0.f } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, true, texturelength, 1.0, 0, bladelength / 2, { -fMaxOffset + SwitchExtension->fOffset1, ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2 } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength / 2, bladelength, { ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2, 0.f } );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
// fixed parts
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength );
// diverging rail, potentially minus part touched by wheels of vehicle going straight
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, jointlength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
@@ -1241,15 +1251,23 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
auto const texturelength { texture_length( m_material1 ) };
// right blade
// composed from two parts: transition from blade to regular rail, and regular rail
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { -SwitchExtension->fOffset2, -SwitchExtension->fOffset2 / 2 } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { -SwitchExtension->fOffset2 / 2, 0.f } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, true, texturelength, 1.0, 0, bladelength / 2, { -SwitchExtension->fOffset2, -SwitchExtension->fOffset2 / 2 } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength / 2, bladelength, { -SwitchExtension->fOffset2 / 2, 0.f } );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
// fixed parts
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength ); // prawa szyna za iglicą
// prawa szyna za iglicą
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength ); // lewa szyna normalna cała
if( jointlength > 0 ) {
// part of the diverging rail touched by wheels of vehicle going straight
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, 0, jointlength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
// other rail, full length
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
@@ -1257,15 +1275,17 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
auto const texturelength { texture_length( m_material2 ) };
// left blade
// composed from two parts: transition from blade to regular rail, and regular rail
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { fMaxOffset - SwitchExtension->fOffset1, ( fMaxOffset - SwitchExtension->fOffset1 ) / 2 } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { ( fMaxOffset - SwitchExtension->fOffset1 ) / 2, 0.f } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, true, texturelength, 1.0, 0, bladelength / 2, { fMaxOffset - SwitchExtension->fOffset1, ( fMaxOffset - SwitchExtension->fOffset1 ) / 2 } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength / 2, bladelength, { ( fMaxOffset - SwitchExtension->fOffset1 ) / 2, 0.f } );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
// fixed parts
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength ); // lewa szyna za iglicą
// lewa szyna za iglicą
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength ); // prawa szyna normalnie cała
// diverging rail, potentially minus part touched by wheels of vehicle going straight
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, jointlength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
@@ -1297,7 +1317,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
{ // tworzenie trójkątów nawierzchni szosy
auto const texturelength { texture_length( m_material1 ) };
gfx::vertex_array vertices;
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, texturelength);
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid > 0, texturelength);
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
}
if (m_material2)
@@ -1308,31 +1328,17 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
gfx::vertex_array rpts1, rpts2; // współrzędne przekroju i mapowania dla prawej i lewej strony
create_road_side_profile( rpts1, rpts2, bpts1 );
gfx::vertex_array vertices;
if( iTrapezoid ) // trapez albo przechyłki
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
// odcinka
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
Segment->RenderLoft( vertices, m_origin, rpts1, -3, texturelength ); // tylko jeśli jest z prawej
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
Segment->RenderLoft( vertices, m_origin, rpts2, -3, texturelength ); // tylko jeśli jest z lewej
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
// tylko jeśli jest z prawej
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid > 0, texturelength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
else { // pobocza zwykłe, brak przechyłki
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
Segment->RenderLoft( vertices, m_origin, rpts1, 3, texturelength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
Segment->RenderLoft( vertices, m_origin, rpts2, 3, texturelength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
// tylko jeśli jest z lewej
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid > 0, texturelength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
}
break;
@@ -1406,22 +1412,22 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
if (SwitchExtension->iRoads == 4)
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render );
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render );
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render );
SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render );
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render );
SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render );
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render );
SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render );
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
@@ -1431,17 +1437,17 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
else {
// punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render ); // z P2 do P4
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render ); // z P2 do P4
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render ); // z P4 do P3=P1 (odwrócony)
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render ); // z P4 do P3=P1 (odwrócony)
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render ); // z P1 do P2
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render ); // z P1 do P2
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
@@ -1516,7 +1522,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
if (m_material1) // jeśli podana była tekstura, generujemy trójkąty
{ // tworzenie trójkątów nawierzchni szosy
gfx::vertex_array vertices;
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid > 0, fTexLength);
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
}
if (m_material2)
@@ -1524,24 +1530,12 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
gfx::vertex_array rpts1, rpts2; // współrzędne przekroju i mapowania dla prawej i lewej strony
create_road_side_profile( rpts1, rpts2, bpts1 );
gfx::vertex_array vertices;
if (iTrapezoid) // trapez albo przechyłki
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
Segment->RenderLoft(vertices, m_origin, rpts1, -3, fTexLength);
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
Segment->RenderLoft(vertices, m_origin, rpts2, -3, fTexLength);
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
else
{ // pobocza zwykłe, brak przechyłki
Segment->RenderLoft(vertices, m_origin, rpts1, 3, fTexLength);
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
Segment->RenderLoft(vertices, m_origin, rpts2, 3, fTexLength);
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid > 0, fTexLength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid > 0, fTexLength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
}
}
@@ -1816,8 +1810,8 @@ TTrack * TTrack::RaAnimate()
auto const texturelength { texture_length( m_material1 ) };
// left blade
// composed from two parts: transition from blade to regular rail, and regular rail
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { SwitchExtension->fOffset2, SwitchExtension->fOffset2 / 2 } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { SwitchExtension->fOffset2 / 2, 0.f } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, true, texturelength, 1.0, 0, bladelength / 2, { SwitchExtension->fOffset2, SwitchExtension->fOffset2 / 2 } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength / 2, bladelength, { SwitchExtension->fOffset2 / 2, 0.f } );
GfxRenderer.Replace( vertices, Geometry1[ 0 ], GL_TRIANGLE_STRIP );
vertices.clear();
}
@@ -1825,8 +1819,8 @@ TTrack * TTrack::RaAnimate()
auto const texturelength { texture_length( m_material2 ) };
// right blade
// composed from two parts: transition from blade to regular rail, and regular rail
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { -fMaxOffset + SwitchExtension->fOffset1, ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2 } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2, 0.f } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, true, texturelength, 1.0, 0, bladelength / 2, { -fMaxOffset + SwitchExtension->fOffset1, ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2 } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength / 2, bladelength, { ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2, 0.f } );
GfxRenderer.Replace( vertices, Geometry2[ 0 ], GL_TRIANGLE_STRIP );
vertices.clear();
}
@@ -1836,8 +1830,8 @@ TTrack * TTrack::RaAnimate()
auto const texturelength { texture_length( m_material1 ) };
// right blade
// composed from two parts: transition from blade to regular rail, and regular rail
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { -SwitchExtension->fOffset2, -SwitchExtension->fOffset2 / 2 } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { -SwitchExtension->fOffset2 / 2, 0.f } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, true, texturelength, 1.0, 0, bladelength / 2, { -SwitchExtension->fOffset2, -SwitchExtension->fOffset2 / 2 } );
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength / 2, bladelength, { -SwitchExtension->fOffset2 / 2, 0.f } );
GfxRenderer.Replace( vertices, Geometry1[ 0 ], GL_TRIANGLE_STRIP );
vertices.clear();
}
@@ -1845,8 +1839,8 @@ TTrack * TTrack::RaAnimate()
auto const texturelength { texture_length( m_material2 ) };
// left blade
// composed from two parts: transition from blade to regular rail, and regular rail
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { fMaxOffset - SwitchExtension->fOffset1, ( fMaxOffset - SwitchExtension->fOffset1 ) / 2 } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { ( fMaxOffset - SwitchExtension->fOffset1 ) / 2, 0.f } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, true, texturelength, 1.0, 0, bladelength / 2, { fMaxOffset - SwitchExtension->fOffset1, ( fMaxOffset - SwitchExtension->fOffset1 ) / 2 } );
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength / 2, bladelength, { ( fMaxOffset - SwitchExtension->fOffset1 ) / 2, 0.f } );
GfxRenderer.Replace( vertices, Geometry2[ 0 ], GL_TRIANGLE_STRIP );
vertices.clear();
}
@@ -1863,22 +1857,23 @@ TTrack * TTrack::RaAnimate()
SwitchExtension->pModel ?
SwitchExtension->pModel->GetContainer() : // pobranie głównego submodelu
nullptr );
if (ac)
if ((ac->AngleGet() != SwitchExtension->fOffset) ||
!(ac->TransGet() ==
SwitchExtension->vTrans)) // czy przemieściło się od ostatniego sprawdzania
{
double hlen = 0.5 * SwitchExtension->Segments[0]->GetLength(); // połowa
// długości
SwitchExtension->fOffset = ac->AngleGet(); // pobranie kąta z submodelu
double sina = -hlen * std::sin(glm::radians(SwitchExtension->fOffset)),
cosa = -hlen * std::cos(glm::radians(SwitchExtension->fOffset));
if( ac ) {
if( ( ac->AngleGet() != SwitchExtension->fOffset )
|| !( ac->TransGet() == SwitchExtension->vTrans ) ) { // czy przemieściło się od ostatniego sprawdzania
double hlen = 0.5 * SwitchExtension->Segments[ 0 ]->GetLength(); // połowa długości
SwitchExtension->fOffset =
SwitchExtension->pModel->Angles().y // take into account orientation of the model
+ ac->AngleGet(); // pobranie kąta z submodelu
double
sina = -hlen * std::sin( glm::radians( SwitchExtension->fOffset ) ),
cosa = -hlen * std::cos( glm::radians( SwitchExtension->fOffset ) );
SwitchExtension->vTrans = ac->TransGet();
auto middle =
location() +
SwitchExtension->vTrans; // SwitchExtension->Segments[0]->FastGetPoint(0.5);
Segment->Init(middle + Math3D::vector3(sina, 0.0, cosa),
middle - Math3D::vector3(sina, 0.0, cosa), 10.0); // nowy odcinek
auto middle = location() + SwitchExtension->vTrans; // SwitchExtension->Segments[0]->FastGetPoint(0.5);
Segment->Init(
middle + Math3D::vector3( sina, 0.0, cosa ),
middle - Math3D::vector3( sina, 0.0, cosa ),
10.0 ); // nowy odcinek
for( auto dynamic : Dynamics ) {
// minimalny ruch, aby przeliczyć pozycję
dynamic->Move( 0.000001 );
@@ -1886,6 +1881,7 @@ TTrack * TTrack::RaAnimate()
// NOTE: passing empty handle is a bit of a hack here. could be refactored into something more elegant
create_geometry( {} );
} // animacja trwa nadal
}
}
else
m = false; // koniec animacji albo w ogóle nie połączone z modelem
@@ -3080,10 +3076,10 @@ TTrack::create_switch_trackbed( gfx::vertex_array &Output ) {
gfx::vertex_array trackbedvertices1, trackbedvertices2;
// main trackbed
create_track_bed_profile( trackbedprofile, SwitchExtension->pPrevs[ 0 ], SwitchExtension->pNexts[ 0 ] );
SwitchExtension->Segments[ 0 ]->RenderLoft( trackbedvertices1, m_origin, trackbedprofile, -5, texturelength );
SwitchExtension->Segments[ 0 ]->RenderLoft( trackbedvertices1, m_origin, trackbedprofile, true, texturelength );
// side trackbed
create_track_bed_profile( trackbedprofile, SwitchExtension->pPrevs[ 1 ], SwitchExtension->pNexts[ 1 ] );
SwitchExtension->Segments[ 1 ]->RenderLoft( trackbedvertices2, m_origin, trackbedprofile, -5, texturelength );
SwitchExtension->Segments[ 1 ]->RenderLoft( trackbedvertices2, m_origin, trackbedprofile, true, texturelength );
// ...then combine them into a single geometry sequence
auto const segmentsize { 10 };
auto const segmentcount { trackbedvertices1.size() / segmentsize };
@@ -3163,8 +3159,9 @@ TTrack::copy_adjacent_trackbed_material( TTrack const *Exclude ) {
break;
}
case tt_Switch: {
// only check the neighbour on the joint side
// only check the neighbours of the main track
adjacents.emplace_back( SwitchExtension->pPrevs[ 0 ] );
adjacents.emplace_back( SwitchExtension->pNexts[ 0 ] );
break;
}
default: {

530
Train.cpp

File diff suppressed because it is too large Load Diff

20
Train.h
View File

@@ -34,16 +34,21 @@ public:
// methods
void Load(cParser &Parser);
void Update();
TGauge &Gauge( int n = -1 ); // pobranie adresu obiektu
TButton &Button( int n = -1 ); // pobranie adresu obiektu
// members
Math3D::vector3 CabPos1 { 0, 1, 1 };
Math3D::vector3 CabPos2 { 0, 1, -1 };
bool bEnabled { false };
bool bOccupied { true };
/*
glm::vec3 dimm; // McZapkie-120503: tlumienie swiatla
glm::vec3 intlit; // McZapkie-120503: oswietlenie kabiny
glm::vec3 intlitlow; // McZapkie-120503: przyciemnione oswietlenie kabiny
TGauge &Gauge( int n = -1 ); // pobranie adresu obiektu
TButton &Button( int n = -1 ); // pobranie adresu obiektu
*/
bool bLight { false }; // hunter-091012: czy swiatlo jest zapalone?
bool bLightDim { false }; // hunter-091012: czy przyciemnienie kabiny jest zapalone?
float LightLevel{ 0.f }; // last calculated interior light level
private:
// members
@@ -123,7 +128,7 @@ class TTrain
void clear_cab_controls();
// sets cabin controls based on current state of the vehicle
// NOTE: we can get rid of this function once we have per-cab persistent state
void set_cab_controls();
void set_cab_controls( int const Cab );
// initializes a gauge matching provided label. returns: true if the label was found, false otherwise
bool initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex);
// initializes a button matching provided label. returns: true if the label was found, false otherwise
@@ -591,14 +596,14 @@ public: // reszta może by?publiczna
sound_source m_radiosound { sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // cached template for radio messages
std::vector<std::pair<int, std::shared_ptr<sound_source>>> m_radiomessages; // list of currently played radio messages
sound_source m_radiostop { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
/*
int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne)
bool bCabLight; // hunter-091012: czy swiatlo jest zapalone?
bool bCabLightDim; // hunter-091012: czy przyciemnienie kabiny jest zapalone?
*/
// McZapkie: opis kabiny - obszar poruszania sie mechanika oraz zajetosc
TCab Cabine[ maxcab + 1 ]; // przedzial maszynowy, kabina 1 (A), kabina 2 (B)
int iCabn;
std::array<TCab, maxcab + 1> Cabine; // przedzial maszynowy, kabina 1 (A), kabina 2 (B)
int iCabn { 0 };
// McZapkie: do poruszania sie po kabinie
Math3D::vector3 pMechSittingPosition; // ABu 180404
Math3D::vector3 MirrorPosition( bool lewe );
@@ -640,6 +645,7 @@ private:
bool bHeat[8]; // grzanie
// McZapkie: do syczenia
float fPPress, fNPress;
bool m_mastercontrollerinuse { false };
int iRadioChannel { 1 }; // numer aktualnego kana?u radiowego
std::vector<std::tuple<std::string, texture_handle, std::optional<texture_window>>> m_screens;

View File

@@ -74,7 +74,13 @@ openal_source::update( double const Deltatime, glm::vec3 const &Listenervelocity
if( sound_range < 0.0 ) {
sound_velocity = Listenervelocity; // cached for doppler shift calculation
}
/*
// HACK: if the application gets stuck for long time loading assets the audio can gone awry.
// terminate all sources when it happens to stay on the safe side
if( Deltatime > 1.0 ) {
stop();
}
*/
if( id != audio::null_resource ) {
sound_change = false;
@@ -441,6 +447,14 @@ openal_renderer::fetch_source() {
}
}
if( newsource.id == audio::null_resource ) {
// for sources with functional emitter reset emitter parameters from potential last use
::alSourcef( newsource.id, AL_PITCH, 1.f );
::alSourcef( newsource.id, AL_GAIN, 1.f );
::alSourcefv( newsource.id, AL_POSITION, glm::value_ptr( glm::vec3{ 0.f } ) );
::alSourcefv( newsource.id, AL_VELOCITY, glm::value_ptr( glm::vec3{ 0.f } ) );
}
return newsource;
}

View File

@@ -89,11 +89,11 @@ struct openal_source {
private:
// members
double update_deltatime; // time delta of most current update
double update_deltatime { 0.0 }; // time delta of most current update
float pitch_variation { 1.f }; // emitter-specific variation of the base pitch
float sound_range { 50.f }; // cached audible range of the emitted samples
glm::vec3 sound_distance; // cached distance between sound and the listener
glm::vec3 sound_velocity; // sound movement vector
glm::vec3 sound_distance { 0.f }; // cached distance between sound and the listener
glm::vec3 sound_velocity { 0.f }; // sound movement vector
bool is_in_range { false }; // helper, indicates the source was recently within audible range
bool is_multipart { false }; // multi-part sounds are kept alive at longer ranges
};

View File

@@ -27,13 +27,13 @@ http://mozilla.org/MPL/2.0/.
#include "renderer.h"
#include "utilities.h"
#include "Logs.h"
/*
namespace input {
user_command command; // currently issued control command, if any
}
*/
void
driver_mode::drivermode_input::poll() {
if (telemetry)
@@ -48,11 +48,13 @@ driver_mode::drivermode_input::poll() {
if( uart != nullptr ) {
uart->poll();
}
/*
// TBD, TODO: wrap current command in object, include other input sources?
input::command = (
mouse.command() != user_command::none ?
mouse.command() :
keyboard.command() );
*/
}
bool
@@ -467,6 +469,15 @@ driver_mode::update_camera( double const Deltatime ) {
simulation::Train->pMechViewAngle = { Camera.Angle.x, Camera.Angle.y };
simulation::Train->pMechOffset = Camera.m_owneroffset;
}
if( ( true == FreeFlyModeFlag )
&& ( Camera.m_owner != nullptr ) ) {
// cache external view config
auto &externalviewconfig { m_externalviewconfigs[ m_externalviewmode ] };
externalviewconfig.owner = Camera.m_owner;
externalviewconfig.offset = Camera.m_owneroffset;
externalviewconfig.angle = Camera.Angle;
}
}
else {
// debug camera
@@ -566,13 +577,13 @@ driver_mode::update_camera( double const Deltatime ) {
// gdy w korytarzu
Camera.LookAt =
Camera.m_owner->GetWorldPosition( Camera.m_owneroffset )
+ simulation::Train->GetDirection() * 5.0;
+ Camera.m_owner->VectorFront() * 5.0;
}
else {
// patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny
Camera.LookAt =
Camera.m_owner->GetWorldPosition( Camera.m_owneroffset )
+ simulation::Train->GetDirection() * 5.0
+ Camera.m_owner->VectorFront() * 5.0
* simulation::Train->Occupied()->ActiveCab; //-1 albo 1
}
Camera.vUp = simulation::Train->GetUp();
@@ -906,18 +917,26 @@ driver_mode::ExternalView() {
Camera.m_owner = owner;
auto const offsetflip {
( vehicle->MoverParameters->ActiveCab == 0 ? 1 : vehicle->MoverParameters->ActiveCab )
* ( vehicle->MoverParameters->ActiveDir == 0 ? 1 : vehicle->MoverParameters->ActiveDir ) };
auto const &viewconfig { m_externalviewconfigs[ m_externalviewmode ] };
if( owner == viewconfig.owner ) {
// restore view config for previous owner
Camera.m_owneroffset = viewconfig.offset;
Camera.Angle = viewconfig.angle;
}
else {
// default view setup
auto const offsetflip{
( vehicle->MoverParameters->ActiveCab == 0 ? 1 : vehicle->MoverParameters->ActiveCab )
* ( vehicle->MoverParameters->ActiveDir == 0 ? 1 : vehicle->MoverParameters->ActiveDir ) };
Camera.m_owneroffset = {
1.5 * owner->MoverParameters->Dim.W * offsetflip,
std::max( 5.0, 1.25 * owner->MoverParameters->Dim.H ),
- 0.4 * owner->MoverParameters->Dim.L * offsetflip };
Camera.m_owneroffset = {
1.5 * owner->MoverParameters->Dim.W * offsetflip,
std::max( 5.0, 1.25 * owner->MoverParameters->Dim.H ),
-0.4 * owner->MoverParameters->Dim.L * offsetflip };
Camera.Angle.y = glm::radians( ( vehicle->MoverParameters->ActiveDir < 0 ? 180.0 : 0.0 ) );
auto const shakeangles { owner->shake_angles() };
Camera.Angle.y = glm::radians( ( vehicle->MoverParameters->ActiveDir < 0 ? 180.0 : 0.0 ) );
}
auto const shakeangles{ owner->shake_angles() };
Camera.Angle.x -= 0.5 * shakeangles.second; // hustanie kamery przod tyl
Camera.Angle.z = shakeangles.first; // hustanie kamery na boki
@@ -929,18 +948,26 @@ driver_mode::ExternalView() {
Camera.m_owner = owner;
auto const offsetflip {
( vehicle->MoverParameters->ActiveCab == 0 ? 1 : vehicle->MoverParameters->ActiveCab )
* ( vehicle->MoverParameters->ActiveDir == 0 ? 1 : vehicle->MoverParameters->ActiveDir )
* -1 };
auto const &viewconfig{ m_externalviewconfigs[ m_externalviewmode ] };
if( owner == viewconfig.owner ) {
// restore view config for previous owner
Camera.m_owneroffset = viewconfig.offset;
Camera.Angle = viewconfig.angle;
}
else {
// default view setup
auto const offsetflip{
( vehicle->MoverParameters->ActiveCab == 0 ? 1 : vehicle->MoverParameters->ActiveCab )
* ( vehicle->MoverParameters->ActiveDir == 0 ? 1 : vehicle->MoverParameters->ActiveDir )
* -1 };
Camera.m_owneroffset = {
1.5 * owner->MoverParameters->Dim.W * offsetflip,
std::max( 5.0, 1.25 * owner->MoverParameters->Dim.H ),
0.2 * owner->MoverParameters->Dim.L * offsetflip };
Camera.Angle.y = glm::radians( ( vehicle->MoverParameters->ActiveDir < 0 ? 0.0 : 180.0 ) );
Camera.m_owneroffset = {
1.5 * owner->MoverParameters->Dim.W * offsetflip,
std::max( 5.0, 1.25 * owner->MoverParameters->Dim.H ),
0.2 * owner->MoverParameters->Dim.L * offsetflip };
Camera.Angle.y = glm::radians( ( vehicle->MoverParameters->ActiveDir < 0 ? 0.0 : 180.0 ) );
}
auto const shakeangles { owner->shake_angles() };
Camera.Angle.x -= 0.5 * shakeangles.second; // hustanie kamery przod tyl
Camera.Angle.z = shakeangles.first; // hustanie kamery na boki
@@ -951,17 +978,25 @@ driver_mode::ExternalView() {
Camera.m_owner = owner;
auto const offsetflip {
( vehicle->MoverParameters->ActiveCab == 0 ? 1 : vehicle->MoverParameters->ActiveCab )
* ( vehicle->MoverParameters->ActiveDir == 0 ? 1 : vehicle->MoverParameters->ActiveDir ) };
auto const &viewconfig{ m_externalviewconfigs[ m_externalviewmode ] };
if( owner == viewconfig.owner ) {
// restore view config for previous owner
Camera.m_owneroffset = viewconfig.offset;
Camera.Angle = viewconfig.angle;
}
else {
// default view setup
auto const offsetflip{
( vehicle->MoverParameters->ActiveCab == 0 ? 1 : vehicle->MoverParameters->ActiveCab )
* ( vehicle->MoverParameters->ActiveDir == 0 ? 1 : vehicle->MoverParameters->ActiveDir ) };
Camera.m_owneroffset = {
- 0.65 * owner->MoverParameters->Dim.W * offsetflip,
0.90,
0.15 * owner->MoverParameters->Dim.L * offsetflip };
Camera.Angle.y = glm::radians( ( vehicle->MoverParameters->ActiveDir < 0 ? 180.0 : 0.0 ) );
Camera.m_owneroffset = {
-0.65 * owner->MoverParameters->Dim.W * offsetflip,
0.90,
0.15 * owner->MoverParameters->Dim.L * offsetflip };
Camera.Angle.y = glm::radians( ( vehicle->MoverParameters->ActiveDir < 0 ? 180.0 : 0.0 ) );
}
auto const shakeangles { owner->shake_angles() };
Camera.Angle.x -= 0.5 * shakeangles.second; // hustanie kamery przod tyl
Camera.Angle.z = shakeangles.first; // hustanie kamery na boki

View File

@@ -60,6 +60,12 @@ private:
count_
};
struct view_config {
TDynamicObject const *owner { nullptr };
Math3D::vector3 offset {};
Math3D::vector3 angle {};
};
struct drivermode_input {
gamepad_input gamepad;
@@ -94,6 +100,7 @@ private:
TCamera DebugCamera;
int m_externalviewmode { view::consistfront }; // selected external view mode
bool m_externalview { false };
std::array<view_config, view::count_> m_externalviewconfigs;
TDynamicObject *pDynamicNearest { nullptr }; // vehicle nearest to the active camera. TODO: move to camera
double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys
double const m_primaryupdaterate { 1.0 / 100.0 };

View File

@@ -322,6 +322,7 @@ drivermouse_input::button( int const Button, int const Action ) {
m_pickwaiting = false;
if( Button == GLFW_MOUSE_BUTTON_LEFT ) {
if( m_slider.command() != user_command::none ) {
m_relay.post( m_slider.command(), 0, 0, Action, 0 );
m_slider.release();
}
}

View File

@@ -208,23 +208,27 @@ driver_ui::set_cursor( bool const Visible ) {
// render() subclass details
void
driver_ui::render_() {
if( m_paused ) {
// pause/quit modal
auto const popupheader { locale::strings[ locale::string::driver_pause_header ].c_str() };
ImGui::OpenPopup( popupheader );
if( ImGui::BeginPopupModal( popupheader, nullptr, ImGuiWindowFlags_AlwaysAutoResize ) ) {
auto const popupwidth{ locale::strings[ locale::string::driver_pause_header ].size() * 7 };
if( ImGui::Button( locale::strings[ locale::string::driver_pause_resume ].c_str(), ImVec2( popupwidth, 0 ) ) ) {
ImGui::CloseCurrentPopup();
auto const pausemask { 1 | 2 };
Global.iPause &= ~pausemask;
}
if( ImGui::Button( locale::strings[ locale::string::driver_pause_quit ].c_str(), ImVec2( popupwidth, 0 ) ) ) {
ImGui::CloseCurrentPopup();
glfwSetWindowShouldClose( m_window, 1 );
}
ImGui::EndPopup();
// pause/quit modal
auto const popupheader { locale::strings[ locale::string::driver_pause_header ].c_str() };
if (m_paused && !m_pause_modal_opened)
{
m_pause_modal_opened = true;
ImGui::OpenPopup(popupheader);
}
if( ImGui::BeginPopupModal( popupheader, &m_pause_modal_opened, ImGuiWindowFlags_AlwaysAutoResize ) ) {
auto const popupwidth{ locale::strings[ locale::string::driver_pause_header ].size() * 7 };
if( ImGui::Button( locale::strings[ locale::string::driver_pause_resume ].c_str(), ImVec2( popupwidth, 0 ) ) ) {
auto const pausemask { 1 | 2 };
Global.iPause &= ~pausemask;
}
if( ImGui::Button( locale::strings[ locale::string::driver_pause_quit ].c_str(), ImVec2( popupwidth, 0 ) ) ) {
glfwSetWindowShouldClose( m_window, 1 );
}
if (!m_paused)
{
m_pause_modal_opened = false;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}

View File

@@ -49,5 +49,5 @@ private:
debug_panel m_debugpanel { "Debug Data", false };
transcripts_panel m_transcriptspanel { "Transcripts", true }; // voice transcripts
bool m_paused { false };
bool m_pause_modal_opened { false };
};

View File

@@ -117,7 +117,7 @@ drivingaid_panel::update() {
{ // alerter, hints
std::string expandedtext;
if( is_expanded ) {
auto const stoptime { static_cast<int>( -1.0 * controlled->Mechanik->fStopTime ) };
auto const stoptime { static_cast<int>( std::ceil( -1.0 * controlled->Mechanik->fStopTime ) ) };
if( stoptime > 0 ) {
std::snprintf(
m_buffer.data(), m_buffer.size(),
@@ -172,10 +172,10 @@ timetable_panel::update() {
text_lines.emplace_back( m_buffer.data(), Global.UITextColor );
}
auto *vehicle {
( FreeFlyModeFlag ?
std::get<TDynamicObject *>( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) :
controlled ) }; // w trybie latania lokalizujemy wg mapy
auto *vehicle { (
false == FreeFlyModeFlag ? controlled :
camera.m_owner != nullptr ? camera.m_owner :
std::get<TDynamicObject *>( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) ) }; // w trybie latania lokalizujemy wg mapy
if( vehicle == nullptr ) { return; }
// if the nearest located vehicle doesn't have a direct driver, try to query its owner
@@ -285,10 +285,10 @@ debug_panel::update() {
m_input.train = simulation::Train;
m_input.controlled = ( m_input.train ? m_input.train->Dynamic() : nullptr );
m_input.camera = &( Global.pCamera );
m_input.vehicle =
( FreeFlyModeFlag ?
std::get<TDynamicObject *>( simulation::Region->find_vehicle( m_input.camera->Pos, 20, false, false ) ) :
m_input.controlled ); // w trybie latania lokalizujemy wg mapy
m_input.vehicle = (
false == FreeFlyModeFlag ? m_input.controlled :
m_input.camera->m_owner != nullptr ? m_input.camera->m_owner :
std::get<TDynamicObject *>( simulation::Region->find_vehicle( m_input.camera->Pos, 20, false, false ) ) ); // w trybie latania lokalizujemy wg mapy
m_input.mover =
( m_input.vehicle != nullptr ?
m_input.vehicle->MoverParameters :

View File

@@ -75,12 +75,12 @@ private:
bool
mode_snap() const;
// members
state_backup m_statebackup; // helper, cached variables to be restored on mode exit
editormode_input m_input;
TCamera Camera;
double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys
scene::basic_editor m_editor;
scene::basic_node *m_node; // currently selected scene node
bool m_takesnapshot { true }; // helper, hints whether snapshot of selected node(s) should be taken before modification
state_backup m_statebackup; // helper, cached variables to be restored on mode exit
bool m_dragging = false;
};

View File

@@ -9,6 +9,7 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "editoruipanels.h"
#include "scenenodegroups.h"
#include "Globals.h"
#include "Camera.h"
@@ -24,6 +25,8 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
if( false == is_open ) { return; }
text_lines.clear();
m_grouplines.clear();
std::string textline;
// scenario inspector
@@ -38,7 +41,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
}
textline =
"node name: " + node->name()
"name: " + ( node->name().empty() ? "(none)" : node->name() )
+ "\nlocation: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]"
+ " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ camera.Pos.x, 0.0, camera.Pos.z } ), 1 ) + " m)";
text_lines.emplace_back( textline, Global.UITextColor );
@@ -62,7 +65,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
textline += ']';
}
else {
textline += "none";
textline += "(none)";
}
text_lines.emplace_back( textline, Global.UITextColor );
@@ -70,7 +73,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
auto modelfile { (
( subnode->pModel != nullptr ) ?
subnode->pModel->NameGet() :
"none" ) };
"(none)" ) };
if( modelfile.find( szModelPath ) == 0 ) {
// don't include 'models/' in the path
modelfile.erase( 0, std::string{ szModelPath }.size() );
@@ -79,7 +82,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
auto texturefile { (
( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ?
GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name :
"none" ) };
"(none)" ) };
if( texturefile.find( szTexturePath ) == 0 ) {
// don't include 'textures/' in the path
texturefile.erase( 0, std::string{ szTexturePath }.size() );
@@ -92,7 +95,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
auto const *subnode = static_cast<TTrack const *>( node );
// basic attributes
textline =
"isolated: " + ( ( subnode->pIsolated != nullptr ) ? subnode->pIsolated->asName : "none" )
"isolated: " + ( ( subnode->pIsolated != nullptr ) ? subnode->pIsolated->asName : "(none)" )
+ "\nvelocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity )
+ "\nwidth: " + to_string( subnode->fTrackWidth ) + " m"
+ "\nfriction: " + to_string( subnode->fFriction, 2 )
@@ -102,14 +105,14 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
auto texturefile { (
( subnode->m_material1 != null_handle ) ?
GfxRenderer.Material( subnode->m_material1 ).name :
"none" ) };
"(none)" ) };
if( texturefile.find( szTexturePath ) == 0 ) {
texturefile.erase( 0, std::string{ szTexturePath }.size() );
}
auto texturefile2{ (
( subnode->m_material2 != null_handle ) ?
GfxRenderer.Material( subnode->m_material2 ).name :
"none" ) };
"(none)" ) };
if( texturefile2.find( szTexturePath ) == 0 ) {
texturefile2.erase( 0, std::string{ szTexturePath }.size() );
}
@@ -164,11 +167,72 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
+ " [" + to_string( subnode->Value1(), 2 ) + "]"
+ " [" + to_string( subnode->Value2(), 2 ) + "]";
text_lines.emplace_back( textline, Global.UITextColor );
textline = "track: " + ( subnode->asTrackName.empty() ? "none" : subnode->asTrackName );
textline = "track: " + ( subnode->asTrackName.empty() ? "(none)" : subnode->asTrackName );
text_lines.emplace_back( textline, Global.UITextColor );
}
update_group();
}
void
itemproperties_panel::update_group() {
auto const grouphandle { m_node->group() };
if( grouphandle == null_handle ) {
m_grouphandle = null_handle;
m_groupprefix.clear();
return;
}
auto const &nodegroup { scene::Groups.group( grouphandle ) };
if( m_grouphandle != grouphandle ) {
// calculate group name from shared prefix of item names
std::vector<std::reference_wrapper<std::string const>> names;
// build list of custom item and event names
for( auto const *node : nodegroup.nodes ) {
auto const &name { node->name() };
if( name.empty() || name == "none" ) { continue; }
names.emplace_back( name );
}
for( auto const *event : nodegroup.events ) {
auto const &name { event->m_name };
if( name.empty() || name == "none" ) { continue; }
names.emplace_back( name );
}
// find the common prefix
if( names.size() > 1 ) {
m_groupprefix = names.front();
for( auto const &name : names ) {
// NOTE: first calculation runs over two instances of the same name, but, eh
auto const prefixlength{ len_common_prefix( m_groupprefix, name ) };
if( prefixlength > 0 ) {
m_groupprefix = m_groupprefix.substr( 0, prefixlength );
}
else {
m_groupprefix.clear();
break;
}
}
}
else {
// less than two names to compare means no prefix
m_groupprefix.clear();
}
m_grouphandle = grouphandle;
}
m_grouplines.emplace_back(
"nodes: " + to_string( static_cast<int>( nodegroup.nodes.size() ) )
+ "\nevents: " + to_string( static_cast<int>( nodegroup.events.size() ) ),
Global.UITextColor );
m_grouplines.emplace_back(
"names prefix: " + ( m_groupprefix.empty() ? "(none)" : m_groupprefix ),
Global.UITextColor );
}
void
itemproperties_panel::render() {
@@ -196,6 +260,23 @@ itemproperties_panel::render() {
for( auto const &line : text_lines ) {
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
}
// group section
render_group();
}
ImGui::End();
}
bool
itemproperties_panel::render_group() {
if( m_node == nullptr ) { return false; }
if( m_grouplines.empty() ) { return false; }
if( false == ImGui::CollapsingHeader( "Parent Group" ) ) { return false; }
for( auto const &line : m_grouplines ) {
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
}
return true;
}

View File

@@ -21,4 +21,15 @@ public:
void update( scene::basic_node const *Node );
void render() override;
private:
// methods
void update_group();
bool render_group();
// members
scene::basic_node const *m_node { nullptr }; // scene node bound to the panel
scene::group_handle m_grouphandle { null_handle }; // scene group bound to the panel
std::string m_groupprefix;
std::vector<text_line> m_grouplines;
};

View File

@@ -560,7 +560,7 @@ void opengl_renderer::Render_pass(rendermode const Mode)
setup_shadow_map(m_cabshadows_tex.get(), m_cabshadowpass);
auto const *vehicle = simulation::Train->Dynamic();
Render_cab(vehicle, false);
Render_cab(vehicle, vehicle->InteriorLightLevel, false);
}
glDebug("render opaque region");
@@ -593,10 +593,10 @@ void opengl_renderer::Render_pass(rendermode const Mode)
{
// with active precipitation draw the opaque cab parts here to mask rain/snow placed 'inside' the cab
setup_drawing(false);
Render_cab(vehicle, false);
Render_cab(vehicle, vehicle->InteriorLightLevel, false);
setup_drawing(true);
}
Render_cab(vehicle, true);
Render_cab(vehicle, vehicle->InteriorLightLevel, true);
}
setup_shadow_map(nullptr, m_renderpass);
@@ -700,8 +700,8 @@ void opengl_renderer::Render_pass(rendermode const Mode)
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
scene_ubo->update(scene_ubs);
Render_cab(simulation::Train->Dynamic(), false);
Render_cab(simulation::Train->Dynamic(), true);
Render_cab(simulation::Train->Dynamic(), 0.0f, false);
Render_cab(simulation::Train->Dynamic(), 0.0f, true);
m_cabshadowpass = m_renderpass;
glDisable(GL_POLYGON_OFFSET_FILL);
@@ -771,7 +771,10 @@ void opengl_renderer::Render_pass(rendermode const Mode)
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
scene_ubo->update(scene_ubs);
Render_cab(simulation::Train->Dynamic());
if (simulation::Train != nullptr) {
Render_cab(simulation::Train->Dynamic(), 0.0f);
Render(simulation::Train->Dynamic());
}
m_pick_fb->unbind();
@@ -919,7 +922,7 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
}
case rendermode::cabshadows:
{
Config.draw_range = (simulation::Train->Occupied()->ActiveCab != 0 ? 10.f : 20.f);
Config.draw_range = simulation::Train->Occupied()->Dim.L;
break;
}
case rendermode::reflections:
@@ -2088,13 +2091,7 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
// render
if (Dynamic->mdLowPolyInt)
{
// low poly interior
if (FreeFlyModeFlag ? true : !Dynamic->mdKabina || !Dynamic->bDisplayCab)
{
Render(Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance);
}
}
Render(Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance);
if (Dynamic->mdModel)
Render(Dynamic->mdModel, Dynamic->Material(), squaredistance);
@@ -2117,10 +2114,7 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
if (Dynamic->mdLowPolyInt)
{
// low poly interior
if (FreeFlyModeFlag ? true : !Dynamic->mdKabina || !Dynamic->bDisplayCab)
{
Render(Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance);
}
Render(Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance);
}
if (Dynamic->mdModel)
Render(Dynamic->mdModel, Dynamic->Material(), squaredistance);
@@ -2130,6 +2124,13 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
break;
}
case rendermode::pickcontrols:
{
if (Dynamic->mdLowPolyInt) {
// low poly interior
Render(Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance);
}
break;
}
case rendermode::pickscenery:
default:
{
@@ -2149,7 +2150,7 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
}
// rendering kabiny gdy jest oddzielnym modelem i ma byc wyswietlana
bool opengl_renderer::Render_cab(TDynamicObject const *Dynamic, bool const Alpha)
bool opengl_renderer::Render_cab(TDynamicObject const *Dynamic, float const Lightlevel, bool const Alpha)
{
if (Dynamic == nullptr)
@@ -2189,7 +2190,7 @@ bool opengl_renderer::Render_cab(TDynamicObject const *Dynamic, bool const Alpha
// crude way to light the cabin, until we have something more complete in place
glm::vec3 old_ambient = light_ubs.ambient;
light_ubs.ambient += Dynamic->InteriorLight * Dynamic->InteriorLightLevel;
light_ubs.ambient += Dynamic->InteriorLight * Lightlevel;
light_ubo->update(light_ubs);
// render
@@ -2344,10 +2345,9 @@ void opengl_renderer::Render(TSubModel *Submodel)
}
// ...luminance
if (Global.fLuminance < Submodel->fLight)
{
auto const isemissive { ( Submodel->f4Emision.a > 0.f ) && ( Global.fLuminance < Submodel->fLight ) };
if (isemissive)
model_ubs.emission = Submodel->f4Emision.a;
}
// main draw call
draw(Submodel->m_geometry);
@@ -3114,10 +3114,7 @@ bool opengl_renderer::Render_Alpha(TDynamicObject *Dynamic)
if (Dynamic->mdLowPolyInt)
{
// low poly interior
if (FreeFlyModeFlag ? true : !Dynamic->mdKabina || !Dynamic->bDisplayCab)
{
Render_Alpha(Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance);
}
Render_Alpha(Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance);
}
if (Dynamic->mdModel)
@@ -3236,10 +3233,9 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel)
}
// ...luminance
if (Global.fLuminance < Submodel->fLight)
{
auto const isemissive { ( Submodel->f4Emision.a > 0.f ) && ( Global.fLuminance < Submodel->fLight ) };
if (isemissive)
model_ubs.emission = Submodel->f4Emision.a;
}
// main draw call
draw(Submodel->m_geometry);

View File

@@ -258,7 +258,7 @@ class opengl_renderer
void Render(TSubModel *Submodel);
void Render(TTrack *Track);
void Render(scene::basic_cell::path_sequence::const_iterator First, scene::basic_cell::path_sequence::const_iterator Last);
bool Render_cab(TDynamicObject const *Dynamic, bool const Alpha = false);
bool Render_cab(TDynamicObject const *Dynamic, float const Lightlevel, bool const Alpha = false);
void Render(TMemCell *Memcell);
void Render_precipitation();
void Render_Alpha(scene::basic_region *Region);

View File

@@ -64,7 +64,7 @@ struct bounding_area {
deserialize( std::istream &Input );
};
using group_handle = std::size_t;
//using group_handle = std::size_t;
struct node_data {

View File

@@ -334,6 +334,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
>> nodedata.range_min
>> nodedata.name
>> nodedata.type;
if( nodedata.name == "none" ) { nodedata.name.clear(); }
// type-based deserialization. not elegant but it'll do
if( nodedata.type == "dynamic" ) {

View File

@@ -80,6 +80,9 @@ scenario_time::init() {
SYSTEMTIME DaylightDate;
} timezoneinfo = { -60, 0, -60, { 0, 10, 0, 5, 3, 0, 0, 0 }, { 0, 3, 0, 5, 2, 0, 0, 0 } };
convert_transition_time( timezoneinfo.StandardDate );
convert_transition_time( timezoneinfo.DaylightDate );
auto zonebias { timezoneinfo.Bias };
if( m_yearday < year_day( timezoneinfo.DaylightDate.wDay, timezoneinfo.DaylightDate.wMonth, m_time.wYear ) ) {
zonebias += timezoneinfo.StandardBias;
@@ -123,7 +126,7 @@ scenario_time::update( double const Deltatime ) {
}
m_time.wHour -= 24;
}
int leap = ( m_time.wYear % 4 == 0 ) && ( m_time.wYear % 100 != 0 ) || ( m_time.wYear % 400 == 0 );
int leap { ( m_time.wYear % 4 == 0 ) && ( m_time.wYear % 100 != 0 ) || ( m_time.wYear % 400 == 0 ) };
while( m_time.wDay > m_monthdaycounts[ leap ][ m_time.wMonth ] ) {
m_time.wDay -= m_monthdaycounts[ leap ][ m_time.wMonth ];
@@ -146,7 +149,7 @@ scenario_time::year_day( int Day, const int Month, const int Year ) const {
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
int leap { ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ) };
int const leap { ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ) };
for( int i = 1; i < Month; ++i )
Day += daytab[ leap ][ i ];
@@ -161,7 +164,7 @@ scenario_time::daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yea
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
int leap = ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 );
int const leap { ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ) };
WORD idx = 1;
while( ( idx < 13 ) && ( Yearday >= daytab[ leap ][ idx ] ) ) {
@@ -194,10 +197,58 @@ scenario_time::julian_day() const {
return JD;
}
scenario_time::operator std::string(){
// calculates day of week for provided date
int
scenario_time::day_of_week( int const Day, int const Month, int const Year ) const {
return to_string( m_time.wHour ) + ":"
+ ( m_time.wMinute < 10 ? "0" : "" ) + to_string( m_time.wMinute ) + ":"
+ ( m_time.wSecond < 10 ? "0" : "" ) + to_string( m_time.wSecond );
};
//---------------------------------------------------------------------------
// using Zeller's congruence, http://en.wikipedia.org/wiki/Zeller%27s_congruence
int const q = Day;
int const m = Month > 2 ? Month : Month + 12;
int const y = Month > 2 ? Year : Year - 1;
int const h = ( q + ( 26 * ( m + 1 ) / 10 ) + y + ( y / 4 ) + 6 * ( y / 100 ) + ( y / 400 ) ) % 7;
/* return ( (h + 5) % 7 ) + 1; // iso week standard, with monday = 1
*/ return ( (h + 6) % 7 ) + 1; // sunday = 1 numbering method, used in north america, japan
}
// calculates day of month for specified weekday of specified month of the year
int
scenario_time::day_of_month( int const Week, int const Weekday, int const Month, int const Year ) const {
int day = 0;
int dayoffset = weekdays( day_of_week( 1, Month, Year ), Weekday );
day = ( Week - 1 ) * 7 + 1 + dayoffset;
if( Week == 5 ) {
// 5th week potentially indicates last week in the month, not necessarily actual 5th
char const daytab[ 2 ][ 13 ] = {
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
int const leap { ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ) };
while( day > daytab[ leap ][ Month ] ) {
day -= 7;
}
}
return day;
}
// returns number of days between specified days of week
int
scenario_time::weekdays( int const First, int const Second ) const {
if( Second >= First ) { return Second - First; }
else { return 7 - First + Second; }
}
// helper, converts provided time transition date to regular date
void
scenario_time::convert_transition_time( SYSTEMTIME &Time ) const {
// NOTE: windows uses 0-6 range for days of week numbering, our methods use 1-7
Time.wDay = day_of_month( Time.wDay, Time.wDayOfWeek + 1, Time.wMonth, m_time.wYear );
}

View File

@@ -39,9 +39,6 @@ public:
int
year_day() const {
return m_yearday; }
// helper, calculates day of year from given date
int
year_day( int Day, int const Month, int const Year ) const;
int
julian_day() const;
inline
@@ -52,9 +49,24 @@ public:
/** Returns std::string in format: `"mm:ss"`. */
operator std::string();
private:
// converts provided time transition date to regular date
void
convert_transition_time( SYSTEMTIME &Time ) const;
// calculates day and month from given day of year
void
daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday );
// calculates day of year from given date
int
year_day( int Day, int const Month, int const Year ) const;
// calculates day of week for provided date
int
day_of_week( int const Day, int const Month, int const Year ) const;
// calculates day of month for specified weekday of specified month of the year
int
day_of_month( int const Week, int const Weekday, int const Month, int const Year ) const;
// returns number of days between specified days of week
int
weekdays( int const First, int const Second ) const;
SYSTEMTIME m_time;
double m_milliseconds{ 0.0 };

View File

@@ -466,7 +466,7 @@ sound_source::stop( bool const Skipend ) {
if( ( false == Skipend )
&& ( sound( sound_id::end ).buffer != null_handle )
/* && ( sound( sound_id::end ).buffer != sound( sound_id::main ).buffer ) */ // end == main can happen in malformed legacy cases
/* && ( sound( sound_id::end ).playing == 0 ) */ ) {
&& ( sound( sound_id::end ).playing < 2 ) ) { // allows potential single extra instance to account for longer overlapping sounds
// spawn potentially defined sound end sample, if the emitter is currently active
insert( sound_id::end );
}

View File

@@ -37,12 +37,6 @@ basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Sch
// go through all vehicles and update their load
// NOTE: for the time being we limit ourselves to passenger-carrying cars only
auto exchangetime { 0.f };
// platform (1:left, 2:right, 3:both)
// with exchange performed on both sides waiting times are halved
auto const exchangetimemodifier { (
Platform == 3 ?
0.5f :
1.0f ) };
auto *vehicle { First };
while( vehicle != nullptr ) {
@@ -69,18 +63,14 @@ basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Sch
0 :
Random( parameters.MaxLoad * 0.15f * stationsizemodifier ) );
if( true == firststop ) {
// slightly larger group at the initial station
// larger group at the initial station
loadcount *= 2;
}
if( ( unloadcount > 0 ) || ( loadcount > 0 ) ) {
vehicle->LoadExchange( unloadcount, loadcount, Platform );
/*
vehicle->LoadUpdate();
vehicle->update_load_visibility();
*/
exchangetime = std::max( exchangetime, exchangetimemodifier * ( unloadcount / parameters.UnLoadSpeed + loadcount / parameters.LoadSpeed ) );
exchangetime = std::max( exchangetime, vehicle->LoadExchangeTime() );
}
}
vehicle = vehicle->Next();

View File

@@ -411,6 +411,18 @@ substr_path( std::string const &Filename ) {
"" );
}
// returns length of common prefix between two provided strings
std::ptrdiff_t
len_common_prefix( std::string const &Left, std::string const &Right ) {
auto const *left { Left.data() };
auto const *right { Right.data() };
// compare up to the length of the shorter string
return ( Right.size() <= Left.size() ?
std::distance( right, std::mismatch( right, right + Right.size(), left ).first ) :
std::distance( left, std::mismatch( left, left + Left.size(), right ).first ) );
}
// helper, restores content of a 3d vector from provided input stream
// TODO: review and clean up the helper routines, there's likely some redundant ones

View File

@@ -201,6 +201,9 @@ replace_slashes( std::string &Filename );
// returns potential path part from provided file name
std::string substr_path( std::string const &Filename );
// returns common prefix of two provided strings
std::ptrdiff_t len_common_prefix( std::string const &Left, std::string const &Right );
template <typename Type_>
void SafeDelete( Type_ &Pointer ) {
delete Pointer;

View File

@@ -1 +1 @@
#define VERSION_INFO "M7 (GL3) 10.11.2018, based on milek-a1926c8b, tmj-c59b530"
#define VERSION_INFO "M7 (GL3) 03.12.2018, based on milek-0b152db, tmj-3fbf5bf8"