mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-23 17:59:19 +02:00
Merge branch 'milek-dev' into gfx-work
This commit is contained in:
25
Button.cpp
25
Button.cpp
@@ -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
|
||||
|
||||
4
Button.h
4
Button.h
@@ -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;
|
||||
|
||||
@@ -44,6 +44,7 @@ struct light_array;
|
||||
namespace scene {
|
||||
struct node_data;
|
||||
class basic_node;
|
||||
using group_handle = std::size_t;
|
||||
}
|
||||
|
||||
namespace Mtable
|
||||
|
||||
29
Driver.cpp
29
Driver.cpp
@@ -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...
|
||||
|
||||
139
DynObj.cpp
139
DynObj.cpp
@@ -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 §ion : 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 §ion : 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 != "" );
|
||||
|
||||
|
||||
10
DynObj.h
10
DynObj.h
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
21
Gauge.cpp
21
Gauge.cpp
@@ -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
|
||||
|
||||
2
Gauge.h
2
Gauge.h
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 ) );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
191
Track.cpp
191
Track.cpp
@@ -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,33 +1328,19 @@ 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
|
||||
// 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();
|
||||
}
|
||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||
Segment->RenderLoft( vertices, m_origin, rpts2, -3, texturelength ); // tylko jeśli jest z lewej
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tt_Cross: // skrzyżowanie dróg rysujemy inaczej
|
||||
@@ -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,25 +1530,13 @@ 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);
|
||||
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, -3, fTexLength);
|
||||
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid > 0, 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -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 );
|
||||
@@ -1887,6 +1882,7 @@ TTrack * TTrack::RaAnimate()
|
||||
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: {
|
||||
|
||||
20
Train.h
20
Train.h
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
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 };
|
||||
-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() };
|
||||
}
|
||||
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,7 +948,15 @@ driver_mode::ExternalView() {
|
||||
|
||||
Camera.m_owner = owner;
|
||||
|
||||
auto const offsetflip {
|
||||
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 };
|
||||
@@ -940,7 +967,7 @@ driver_mode::ExternalView() {
|
||||
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 {
|
||||
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.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
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ) ) {
|
||||
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 ) ) ) {
|
||||
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 );
|
||||
}
|
||||
if (!m_paused)
|
||||
{
|
||||
m_pause_modal_opened = false;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
};
|
||||
|
||||
@@ -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 :
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
50
renderer.cpp
50
renderer.cpp
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
if (Dynamic->mdModel)
|
||||
Render(Dynamic->mdModel, Dynamic->Material(), squaredistance);
|
||||
@@ -2117,11 +2114,8 @@ 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);
|
||||
}
|
||||
}
|
||||
if (Dynamic->mdModel)
|
||||
Render(Dynamic->mdModel, Dynamic->Material(), squaredistance);
|
||||
if (Dynamic->mdLoad) // renderowanie nieprzezroczystego ładunku
|
||||
@@ -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,11 +3114,8 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (Dynamic->mdModel)
|
||||
Render_Alpha(Dynamic->mdModel, Dynamic->Material(), squaredistance);
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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" ) {
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
14
station.cpp
14
station.cpp
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user