mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-23 23:49:17 +02:00
Merge branch 'tmj-dev' into milek-dev
This commit is contained in:
112
AnimModel.cpp
112
AnimModel.cpp
@@ -424,13 +424,6 @@ TAnimModel::~TAnimModel()
|
||||
SafeDelete(pRoot);
|
||||
}
|
||||
|
||||
bool TAnimModel::Init(TModel3d *pNewModel)
|
||||
{
|
||||
fBlinkTimer = double(Random(1000 * fOffTime)) / (1000 * fOffTime);
|
||||
pModel = pNewModel;
|
||||
return (pModel != nullptr);
|
||||
}
|
||||
|
||||
bool TAnimModel::Init(std::string const &asName, std::string const &asReplacableTexture)
|
||||
{
|
||||
if( asReplacableTexture.substr( 0, 1 ) == "*" ) {
|
||||
@@ -446,17 +439,21 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable
|
||||
m_materialdata.textures_alpha = 0x31310031;
|
||||
}
|
||||
else{
|
||||
// tekstura nieprzezroczysta - nie renderować w cyklu
|
||||
// tekstura nieprzezroczysta - nie renderować w cyklu przezroczystych
|
||||
m_materialdata.textures_alpha = 0x30300030;
|
||||
}
|
||||
// przezroczystych
|
||||
return (Init(TModelsManager::GetModel(asName)));
|
||||
|
||||
fBlinkTimer = double( Random( 1000 * fOffTime ) ) / ( 1000 * fOffTime );
|
||||
|
||||
pModel = TModelsManager::GetModel( asName );
|
||||
return ( pModel != nullptr );
|
||||
}
|
||||
|
||||
bool TAnimModel::Load(cParser *parser, bool ter)
|
||||
{ // rozpoznanie wpisu modelu i ustawienie świateł
|
||||
std::string name = parser->getToken<std::string>();
|
||||
std::string texture = parser->getToken<std::string>(false); // tekstura (zmienia na małe)
|
||||
std::string texture = parser->getToken<std::string>(); // tekstura (zmienia na małe)
|
||||
replace_slashes( name );
|
||||
if (!Init( name, texture ))
|
||||
{
|
||||
if (name != "notload")
|
||||
@@ -505,7 +502,7 @@ bool TAnimModel::Load(cParser *parser, bool ter)
|
||||
while( ( token != "" )
|
||||
&& ( token != "endmodel" ) ) {
|
||||
|
||||
LightSet( i, std::stod( token ) ); // stan światła jest liczbą z ułamkiem
|
||||
LightSet( i, std::stof( token ) ); // stan światła jest liczbą z ułamkiem
|
||||
++i;
|
||||
|
||||
token = "";
|
||||
@@ -564,15 +561,6 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
|
||||
m_framestamp = Framestamp;
|
||||
};
|
||||
|
||||
// calculates piece's bounding radius
|
||||
void
|
||||
TAnimModel::radius_() {
|
||||
|
||||
if( pModel != nullptr ) {
|
||||
m_area.radius = pModel->bounding_radius();
|
||||
}
|
||||
}
|
||||
|
||||
void TAnimModel::RaPrepare()
|
||||
{ // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza
|
||||
bool state; // stan światła
|
||||
@@ -585,7 +573,11 @@ void TAnimModel::RaPrepare()
|
||||
state = ( fBlinkTimer < fOnTime );
|
||||
break;
|
||||
case ls_Dark: // zapalone, gdy ciemno
|
||||
state = ( Global.fLuminance <= ( lsLights[i] - 3.0 ) );
|
||||
state = (
|
||||
Global.fLuminance <= (
|
||||
lsLights[i] == 3.f ?
|
||||
DefaultDarkThresholdLevel :
|
||||
( lsLights[i] - 3.f ) ) );
|
||||
break;
|
||||
default: // zapalony albo zgaszony
|
||||
state = (lightmode == ls_On);
|
||||
@@ -781,15 +773,17 @@ void TAnimModel::LightSet(int const n, float const v)
|
||||
}
|
||||
case ls_Dark: {
|
||||
// zapalenie świateł zależne od oświetlenia scenerii
|
||||
if( v == 3.0 ) {
|
||||
/*
|
||||
if( v == 3.f ) {
|
||||
// standardowy próg zaplania
|
||||
lsLights[ n ] = 3.0 + DefaultDarkThresholdLevel;
|
||||
lsLights[ n ] = 3.f + DefaultDarkThresholdLevel;
|
||||
}
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void TAnimModel::AnimUpdate(double dt)
|
||||
{ // wykonanie zakolejkowanych animacji, nawet gdy modele nie są aktualnie wyświetlane
|
||||
TAnimContainer *p = TAnimModel::acAnimList;
|
||||
@@ -799,4 +793,72 @@ void TAnimModel::AnimUpdate(double dt)
|
||||
p = p->acAnimNext; // na razie bez usuwania z listy, bo głównie obrotnica na nią wchodzi
|
||||
}
|
||||
};
|
||||
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float
|
||||
TAnimModel::radius_() {
|
||||
|
||||
return (
|
||||
pModel ?
|
||||
pModel->bounding_radius() :
|
||||
0.f );
|
||||
}
|
||||
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void
|
||||
TAnimModel::serialize_( std::ostream &Output ) const {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void
|
||||
TAnimModel::deserialize_( std::istream &Input ) {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
TAnimModel::export_as_text_( std::ostream &Output ) const {
|
||||
// header
|
||||
Output << "model ";
|
||||
// location and rotation
|
||||
Output
|
||||
<< location().x << ' '
|
||||
<< location().y << ' '
|
||||
<< location().z << ' '
|
||||
<< vAngle.y << ' ';
|
||||
// 3d shape
|
||||
auto modelfile { (
|
||||
pModel ?
|
||||
pModel->NameGet() + ".t3d" : // rainsted requires model file names to include an extension
|
||||
"none" ) };
|
||||
if( modelfile.find( szModelPath ) == 0 ) {
|
||||
// don't include 'models/' in the path
|
||||
modelfile.erase( 0, std::string{ szModelPath }.size() );
|
||||
}
|
||||
Output << modelfile << ' ';
|
||||
// texture
|
||||
auto texturefile { (
|
||||
m_materialdata.replacable_skins[ 1 ] != null_handle ?
|
||||
GfxRenderer.Material( m_materialdata.replacable_skins[ 1 ] ).name :
|
||||
"none" ) };
|
||||
if( texturefile.find( szTexturePath ) == 0 ) {
|
||||
// don't include 'textures/' in the path
|
||||
texturefile.erase( 0, std::string{ szTexturePath }.size() );
|
||||
}
|
||||
Output << texturefile << ' ';
|
||||
// light submodels activation configuration
|
||||
if( iNumLights > 0 ) {
|
||||
Output << "lights ";
|
||||
for( int lightidx = 0; lightidx < iNumLights; ++lightidx ) {
|
||||
Output << lsLights[ lightidx ] << ' ';
|
||||
}
|
||||
}
|
||||
// footer
|
||||
Output
|
||||
<< "endmodel"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
21
AnimModel.h
21
AnimModel.h
@@ -122,7 +122,7 @@ class TAnimAdvanced
|
||||
};
|
||||
|
||||
// opakowanie modelu, określające stan egzemplarza
|
||||
class TAnimModel : public editor::basic_node {
|
||||
class TAnimModel : public scene::basic_node {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
@@ -133,15 +133,12 @@ public:
|
||||
~TAnimModel();
|
||||
// methods
|
||||
static void AnimUpdate( double dt );
|
||||
bool Init(TModel3d *pNewModel);
|
||||
bool Init(std::string const &asName, std::string const &asReplacableTexture);
|
||||
bool Load(cParser *parser, bool ter = false);
|
||||
TAnimContainer * AddContainer(std::string const &Name);
|
||||
TAnimContainer * GetContainer(std::string const &Name = "");
|
||||
void RaAnglesSet( glm::vec3 Angles ) {
|
||||
vAngle.x = Angles.x;
|
||||
vAngle.y = Angles.y;
|
||||
vAngle.z = Angles.z; };
|
||||
vAngle = { Angles }; };
|
||||
void LightSet( int const n, float const v );
|
||||
void AnimationVND( void *pData, double a, double b, double c, double d );
|
||||
bool TerrainLoaded();
|
||||
@@ -159,16 +156,20 @@ public:
|
||||
// members
|
||||
static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania
|
||||
|
||||
protected:
|
||||
// calculates piece's bounding radius
|
||||
void
|
||||
radius_();
|
||||
|
||||
private:
|
||||
// methods
|
||||
void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu
|
||||
void RaAnimate( unsigned int const Framestamp ); // przeliczenie animacji egzemplarza
|
||||
void Advanced();
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float radius_();
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void serialize_( std::ostream &Output ) const;
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void deserialize_( std::istream &Input );
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void export_as_text_( std::ostream &Output ) const;
|
||||
|
||||
// members
|
||||
TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli
|
||||
TModel3d *pModel { nullptr };
|
||||
|
||||
@@ -75,9 +75,14 @@ void TButton::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *pMod
|
||||
}
|
||||
|
||||
// pass submodel location to defined sounds
|
||||
auto const nulloffset { glm::vec3{} };
|
||||
auto const offset { model_offset() };
|
||||
if( m_soundfxincrease.offset() == nulloffset ) {
|
||||
m_soundfxincrease.offset( offset );
|
||||
}
|
||||
if( m_soundfxdecrease.offset() == nulloffset ) {
|
||||
m_soundfxdecrease.offset( offset );
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
47
Camera.cpp
47
Camera.cpp
@@ -18,8 +18,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void TCamera::Init( Math3D::vector3 NPos, Math3D::vector3 NAngle)
|
||||
{
|
||||
void TCamera::Init( Math3D::vector3 NPos, Math3D::vector3 NAngle) {
|
||||
|
||||
vUp = Math3D::vector3(0, 1, 0);
|
||||
Velocity = Math3D::vector3(0, 0, 0);
|
||||
@@ -31,8 +30,15 @@ void TCamera::Init( Math3D::vector3 NPos, Math3D::vector3 NAngle)
|
||||
Type = (Global.bFreeFly ? tp_Free : tp_Follow);
|
||||
};
|
||||
|
||||
void TCamera::OnCursorMove(double x, double y) {
|
||||
void TCamera::Reset() {
|
||||
|
||||
Pitch = Yaw = Roll = 0;
|
||||
m_rotationoffsets = {};
|
||||
};
|
||||
|
||||
|
||||
void TCamera::OnCursorMove(double x, double y) {
|
||||
/*
|
||||
Yaw -= x;
|
||||
while( Yaw > M_PI ) {
|
||||
Yaw -= 2 * M_PI;
|
||||
@@ -45,6 +51,8 @@ void TCamera::OnCursorMove(double x, double y) {
|
||||
// jeżeli jazda z pojazdem ograniczenie kąta spoglądania w dół i w górę
|
||||
Pitch = clamp( Pitch, -M_PI_4, M_PI_4 );
|
||||
}
|
||||
*/
|
||||
m_rotationoffsets += glm::dvec3 { y, x, 0.0 };
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -151,8 +159,9 @@ void TCamera::Update()
|
||||
OnCommand( command );
|
||||
}
|
||||
|
||||
auto const deltatime = Timer::GetDeltaRenderTime(); // czas bez pauzy
|
||||
auto const deltatime { Timer::GetDeltaRenderTime() }; // czas bez pauzy
|
||||
|
||||
// update position
|
||||
if( ( Type == tp_Free )
|
||||
|| ( false == Global.ctrlState )
|
||||
|| ( true == DebugCameraFlag ) ) {
|
||||
@@ -170,6 +179,24 @@ void TCamera::Update()
|
||||
Vec.RotateY( Yaw );
|
||||
Pos += Vec * 5.0 * deltatime;
|
||||
}
|
||||
// update rotation
|
||||
auto const rotationfactor { std::min( 1.0, 20 * deltatime ) };
|
||||
|
||||
Yaw -= rotationfactor * m_rotationoffsets.y;
|
||||
m_rotationoffsets.y *= ( 1.0 - rotationfactor );
|
||||
while( Yaw > M_PI ) {
|
||||
Yaw -= 2 * M_PI;
|
||||
}
|
||||
while( Yaw < -M_PI ) {
|
||||
Yaw += 2 * M_PI;
|
||||
}
|
||||
|
||||
Pitch -= rotationfactor * m_rotationoffsets.x;
|
||||
m_rotationoffsets.x *= ( 1.0 - rotationfactor );
|
||||
if( Type == tp_Follow ) {
|
||||
// jeżeli jazda z pojazdem ograniczenie kąta spoglądania w dół i w górę
|
||||
Pitch = clamp( Pitch, -M_PI_4, M_PI_4 );
|
||||
}
|
||||
}
|
||||
|
||||
Math3D::vector3 TCamera::GetDirection() {
|
||||
@@ -201,11 +228,15 @@ bool TCamera::SetMatrix( glm::dmat4 &Matrix ) {
|
||||
void TCamera::RaLook()
|
||||
{ // zmiana kierunku patrzenia - przelicza Yaw
|
||||
Math3D::vector3 where = LookAt - Pos + Math3D::vector3(0, 3, 0); // trochę w górę od szyn
|
||||
if ((where.x != 0.0) || (where.z != 0.0))
|
||||
Yaw = atan2(-where.x, -where.z); // kąt horyzontalny
|
||||
if( ( where.x != 0.0 ) || ( where.z != 0.0 ) ) {
|
||||
Yaw = atan2( -where.x, -where.z ); // kąt horyzontalny
|
||||
m_rotationoffsets.y = 0.0;
|
||||
}
|
||||
double l = Math3D::Length3(where);
|
||||
if (l > 0.0)
|
||||
Pitch = asin(where.y / l); // kąt w pionie
|
||||
if( l > 0.0 ) {
|
||||
Pitch = asin( where.y / l ); // kąt w pionie
|
||||
m_rotationoffsets.x = 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
void TCamera::Stop()
|
||||
|
||||
12
Camera.h
12
Camera.h
@@ -22,14 +22,9 @@ enum TCameraType
|
||||
|
||||
class TCamera {
|
||||
|
||||
private:
|
||||
glm::dvec3 m_moverate;
|
||||
|
||||
public: // McZapkie: potrzebuje do kiwania na boki
|
||||
void Init( Math3D::vector3 NPos, Math3D::vector3 NAngle);
|
||||
inline
|
||||
void Reset() {
|
||||
Pitch = Yaw = Roll = 0; };
|
||||
void Reset();
|
||||
void OnCursorMove(double const x, double const y);
|
||||
bool OnCommand( command_data const &Command );
|
||||
void Update();
|
||||
@@ -46,4 +41,9 @@ class TCamera {
|
||||
Math3D::vector3 LookAt; // współrzędne punktu, na który ma patrzeć
|
||||
Math3D::vector3 vUp;
|
||||
Math3D::vector3 Velocity;
|
||||
|
||||
private:
|
||||
glm::dvec3 m_moverate;
|
||||
glm::dvec3 m_rotationoffsets; // requested changes to pitch, yaw and roll
|
||||
|
||||
};
|
||||
|
||||
200
Driver.cpp
200
Driver.cpp
@@ -417,15 +417,17 @@ void TController::TableClear()
|
||||
eSignSkip = nullptr; // nic nie pomijamy
|
||||
};
|
||||
|
||||
TEvent * TController::CheckTrackEvent( TTrack *Track, double const fDirection ) const
|
||||
std::vector<TEvent *> TController::CheckTrackEvent( TTrack *Track, double const fDirection ) const
|
||||
{ // sprawdzanie eventów na podanym torze do podstawowego skanowania
|
||||
TEvent *e = (fDirection > 0) ? Track->evEvent2 : Track->evEvent1;
|
||||
if (!e)
|
||||
return NULL;
|
||||
if (e->bEnabled)
|
||||
return NULL;
|
||||
// jednak wszystkie W4 do tabelki, bo jej czyszczenie na przystanku wprowadza zamieszanie
|
||||
return e;
|
||||
std::vector<TEvent *> events;
|
||||
auto const &eventsequence { ( fDirection > 0 ? Track->m_events2 : Track->m_events1 ) };
|
||||
for( auto const &event : eventsequence ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( false == event.second->bEnabled ) ) {
|
||||
events.emplace_back( event.second );
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
bool TController::TableAddNew()
|
||||
@@ -461,7 +463,6 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
|
||||
TTrack *pTrack{ nullptr }; // zaczynamy od ostatniego analizowanego toru
|
||||
double fTrackLength{ 0.0 }; // długość aktualnego toru (krótsza dla pierwszego)
|
||||
double fCurrentDistance{ 0.0 }; // aktualna przeskanowana długość
|
||||
TEvent *pEvent{ nullptr };
|
||||
double fLastDir{ 0.0 };
|
||||
|
||||
if (iTableDirection != iDirection ) {
|
||||
@@ -537,7 +538,9 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
|
||||
WriteLog( "Speed table for " + OwnerName() + " tracing through track " + pTrack->name() );
|
||||
}
|
||||
|
||||
if( ( pEvent = CheckTrackEvent( pTrack, fLastDir ) ) != nullptr ) // jeśli jest semafor na tym torze
|
||||
auto const events { CheckTrackEvent( pTrack, fLastDir ) };
|
||||
for( auto *pEvent : events ) {
|
||||
if( pEvent != nullptr ) // jeśli jest semafor na tym torze
|
||||
{ // trzeba sprawdzić tabelkę, bo dodawanie drugi raz tego samego przystanku nie jest korzystne
|
||||
if (TableNotFound(pEvent)) // jeśli nie ma
|
||||
{
|
||||
@@ -570,8 +573,8 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((true == newspeedpoint.IsProperSemaphor(OrderCurrentGet()))
|
||||
&& (SemNextIndex == -1)) {
|
||||
if( ( true == newspeedpoint.IsProperSemaphor( OrderCurrentGet() ) )
|
||||
&& ( SemNextIndex == -1 ) ) {
|
||||
SemNextIndex = iLast; // sprawdzamy czy pierwszy na drodze
|
||||
}
|
||||
if (Global.iWriteLogEnabled & 8) {
|
||||
@@ -581,6 +584,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // event dodajemy najpierw, żeby móc sprawdzić, czy tor został dodany po odczytaniu prędkości następnego
|
||||
|
||||
if( ( pTrack->VelocityGet() == 0.0 ) // zatrzymanie
|
||||
@@ -1005,7 +1009,10 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
sSpeedTable[i].iFlags = 0; // W4 nie liczy się już (nie wyśle SetVelocity)
|
||||
sSpeedTable[i].fVelNext = -1; // można jechać za W4
|
||||
fLastStopExpDist = -1.0f; // nie ma rozkładu, nie ma usuwania stacji
|
||||
/*
|
||||
// NOTE: disabled as it's no longer needed, required time is calculated as part of loading/unloading procedure
|
||||
WaitingSet(60); // tak ze 2 minuty, aż wszyscy wysiądą
|
||||
*/
|
||||
// wykonanie kolejnego rozkazu (Change_direction albo Shunt)
|
||||
JumpToNextOrder();
|
||||
// ma się nie ruszać aż do momentu podania sygnału
|
||||
@@ -1326,7 +1333,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
fNext = v; // istotna jest prędkość na końcu tego odcinka
|
||||
fDist = d; // dlugość odcinka
|
||||
}
|
||||
else if ((fAcc > 0) && (v > 0) && (v <= fNext)) {
|
||||
else if ((fAcc > 0) && (v >= 0) && (v <= fNext)) {
|
||||
// jeśli nie ma wskazań do hamowania, można podać drogę i prędkość na jej końcu
|
||||
fNext = v; // istotna jest prędkość na końcu tego odcinka
|
||||
fDist = d; // dlugość odcinka (kolejne pozycje mogą wydłużać drogę, jeśli prędkość jest stała)
|
||||
@@ -2273,7 +2280,7 @@ bool TController::PrepareEngine()
|
||||
{ // najpierw ustalamy kierunek, jeśli nie został ustalony
|
||||
if( !iDirection ) {
|
||||
// jeśli nie ma ustalonego kierunku
|
||||
if( mvOccupied->V == 0 ) { // ustalenie kierunku, gdy stoi
|
||||
if( mvOccupied->Vel < 0.01 ) { // ustalenie kierunku, gdy stoi
|
||||
iDirection = mvOccupied->CabNo; // wg wybranej kabiny
|
||||
if( !iDirection ) {
|
||||
// jeśli nie ma ustalonego kierunku
|
||||
@@ -3221,17 +3228,24 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
iStationStart = TrainParams->StationIndex;
|
||||
asNextStop = TrainParams->NextStop();
|
||||
iDrivigFlags |= movePrimary; // skoro dostał rozkład, to jest teraz głównym
|
||||
NewCommand = Global.asCurrentSceneryPath + NewCommand + ".wav"; // na razie jeden
|
||||
if (FileExists(NewCommand)) {
|
||||
NewCommand = Global.asCurrentSceneryPath + NewCommand;
|
||||
auto lookup =
|
||||
FileExists(
|
||||
{ NewCommand },
|
||||
{ ".ogg", ".flac", ".wav" } );
|
||||
if( false == lookup.first.empty() ) {
|
||||
// wczytanie dźwięku odjazdu podawanego bezpośrenido
|
||||
tsGuardSignal = sound_source( sound_placement::external, 75.f ).deserialize( NewCommand, sound_type::single );
|
||||
tsGuardSignal = sound_source( sound_placement::external, 75.f ).deserialize( lookup.first + lookup.second, sound_type::single );
|
||||
iGuardRadio = 0; // nie przez radio
|
||||
}
|
||||
else {
|
||||
NewCommand = NewCommand.insert(NewCommand.rfind('.'),"radio"); // wstawienie przed kropkč
|
||||
if (FileExists(NewCommand)) {
|
||||
auto lookup =
|
||||
FileExists(
|
||||
{ NewCommand + "radio" },
|
||||
{ ".ogg", ".flac", ".wav" } );
|
||||
if( false == lookup.first.empty() ) {
|
||||
// wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie)
|
||||
tsGuardSignal = sound_source( sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE ).deserialize( NewCommand, sound_type::single );
|
||||
tsGuardSignal = sound_source( sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE ).deserialize( lookup.first + lookup.second, sound_type::single );
|
||||
iGuardRadio = iRadioChannel;
|
||||
}
|
||||
}
|
||||
@@ -4008,9 +4022,9 @@ TController::UpdateSituation(double dt) {
|
||||
// podłączanie do składu
|
||||
if (iDrivigFlags & moveConnect) {
|
||||
// jeśli stanął już blisko, unikając zderzenia i można próbować podłączyć
|
||||
fMinProximityDist = -0.5;
|
||||
fMinProximityDist = -1.0;
|
||||
fMaxProximityDist = 0.0; //[m] dojechać maksymalnie
|
||||
fVelPlus = 0.5; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||||
fVelPlus = 1.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||||
fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu
|
||||
if (AIControllFlag)
|
||||
{ // to robi tylko AI, wersję dla człowieka trzeba dopiero zrobić
|
||||
@@ -4018,21 +4032,17 @@ TController::UpdateSituation(double dt) {
|
||||
bool ok; // true gdy się podłączy (uzyskany sprzęg będzie zgodny z żądanym)
|
||||
if (pVehicles[0]->DirectionGet() > 0) // jeśli sprzęg 0
|
||||
{ // sprzęg 0 - próba podczepienia
|
||||
if (pVehicles[0]->MoverParameters->Couplers[0].Connected) // jeśli jest coś
|
||||
// wykryte (a
|
||||
// chyba jest,
|
||||
// nie?)
|
||||
if (pVehicles[0]->MoverParameters->Attach(
|
||||
0, 2, pVehicles[0]->MoverParameters->Couplers[0].Connected,
|
||||
iCoupler))
|
||||
{
|
||||
if( pVehicles[ 0 ]->MoverParameters->Couplers[ 0 ].Connected ) {
|
||||
// jeśli jest coś wykryte (a chyba jest, nie?)
|
||||
if( pVehicles[ 0 ]->MoverParameters->Attach(
|
||||
0, 2, pVehicles[ 0 ]->MoverParameters->Couplers[ 0 ].Connected,
|
||||
iCoupler ) ) {
|
||||
// pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX);
|
||||
// pVehicles[0]->dsbCouplerAttach->Play(0,0,0);
|
||||
}
|
||||
// WriteLog("CoupleDist[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CoupleDist)+",
|
||||
// Connected[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag));
|
||||
ok = (pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag ==
|
||||
iCoupler); // udało się? (mogło częściowo)
|
||||
}
|
||||
// udało się? (mogło częściowo)
|
||||
ok = (pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag == iCoupler);
|
||||
}
|
||||
else // if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1
|
||||
{ // sprzęg 1 - próba podczepienia
|
||||
@@ -4045,10 +4055,8 @@ TController::UpdateSituation(double dt) {
|
||||
// pVehicles[0]->dsbCouplerAttach->Play(0,0,0);
|
||||
}
|
||||
}
|
||||
// WriteLog("CoupleDist[1]="+AnsiString(Controlling->Couplers[1].CoupleDist)+",
|
||||
// Connected[0]="+AnsiString(Controlling->Couplers[1].CouplingFlag));
|
||||
ok = (pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag ==
|
||||
iCoupler); // udało się? (mogło częściowo)
|
||||
// udało się? (mogło częściowo)
|
||||
ok = (pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag == iCoupler);
|
||||
}
|
||||
if (ok)
|
||||
{ // jeżeli został podłączony
|
||||
@@ -4602,20 +4610,7 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
|
||||
// sprawdzamy możliwe ograniczenia prędkości
|
||||
if( OrderCurrentGet() & ( Shunt | Obey_train ) ) {
|
||||
// w Connect nie, bo moveStopHere odnosi się do stanu po połączeniu
|
||||
if( ( iDrivigFlags & moveStopHere )
|
||||
&& ( vel == 0.0 )
|
||||
&& ( VelNext == 0.0 ) ) {
|
||||
// jeśli ma czekać na wolną drogę, stoi a wyjazdu nie ma, to ma stać
|
||||
VelDesired = 0.0;
|
||||
}
|
||||
}
|
||||
if( fStopTime < 0 ) {
|
||||
// czas postoju przed dalszą jazdą (np. na przystanku)
|
||||
VelDesired = 0.0; // jak ma czekać, to nie ma jazdy
|
||||
}
|
||||
else if( VelSignal >= 0 ) {
|
||||
if( VelSignal >= 0 ) {
|
||||
// jeśli skład był zatrzymany na początku i teraz już może jechać
|
||||
VelDesired =
|
||||
min_speed(
|
||||
@@ -4632,10 +4627,19 @@ TController::UpdateSituation(double dt) {
|
||||
if( VelforDriver >= 0 ) {
|
||||
// tu jest zero przy zmianie kierunku jazdy
|
||||
// Ra: tu może być 40, jeśli mechanik nie ma znajomości szlaaku, albo kierowca jeździ 70
|
||||
VelDesired = min_speed( VelDesired, VelforDriver );
|
||||
VelDesired =
|
||||
min_speed(
|
||||
VelDesired,
|
||||
VelforDriver );
|
||||
}
|
||||
if( ( TrainParams != nullptr )
|
||||
&& ( TrainParams->CheckTrainLatency() < 5.0 )
|
||||
if( fStopTime < 0 ) {
|
||||
// czas postoju przed dalszą jazdą (np. na przystanku)
|
||||
VelDesired = 0.0; // jak ma czekać, to nie ma jazdy
|
||||
}
|
||||
|
||||
if( ( OrderCurrentGet() & Obey_train ) != 0 ) {
|
||||
|
||||
if( ( TrainParams->CheckTrainLatency() < 5.0 )
|
||||
&& ( TrainParams->TTVmax > 0.0 ) ) {
|
||||
// jesli nie spozniony to nie przekraczać rozkladowej
|
||||
VelDesired =
|
||||
@@ -4643,20 +4647,36 @@ TController::UpdateSituation(double dt) {
|
||||
VelDesired,
|
||||
TrainParams->TTVmax );
|
||||
}
|
||||
if (VelDesired > 0.0)
|
||||
if( ( ( iDrivigFlags & moveStopHere ) == 0 )
|
||||
|| ( ( SemNextIndex != -1 )
|
||||
|
||||
if( ( ( iDrivigFlags & moveStopHere ) != 0 )
|
||||
&& ( vel < 0.01 )
|
||||
&& ( SemNextIndex != -1 )
|
||||
&& ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s)
|
||||
&& ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) ) {
|
||||
// jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w
|
||||
// składzie, jeśli nie mamy czekać na sygnał też trzeba odpalić
|
||||
if (iDrivigFlags & moveGuardSignal)
|
||||
{ // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas stania
|
||||
&& ( sSpeedTable[ SemNextIndex ].fVelNext == 0.0 ) ) {
|
||||
// don't depart if told to wait at passenger stop until allowed to by the signal
|
||||
VelDesired = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
if( ( OrderCurrentGet() & ( Shunt | Obey_train ) ) != 0 ) {
|
||||
// w Connect nie, bo moveStopHere odnosi się do stanu po połączeniu
|
||||
if( ( ( iDrivigFlags & moveStopHere ) != 0 )
|
||||
&& ( vel < 0.01 )
|
||||
&& ( VelSignal == 0.0 ) ) {
|
||||
// jeśli ma czekać na wolną drogę, stoi a wyjazdu nie ma, to ma stać
|
||||
VelDesired = 0.0;
|
||||
}
|
||||
}
|
||||
// end of speed caps checks
|
||||
|
||||
if( ( ( OrderCurrentGet() & Obey_train ) != 0 )
|
||||
&& ( ( iDrivigFlags & moveGuardSignal ) != 0 )
|
||||
&& ( VelDesired > 0.0 ) ) {
|
||||
// komunikat od kierownika tu, bo musi być wolna droga i odczekany czas stania
|
||||
iDrivigFlags &= ~moveGuardSignal; // tylko raz nadać
|
||||
if( false == tsGuardSignal.empty() ) {
|
||||
tsGuardSignal.stop();
|
||||
// w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy
|
||||
// bezpośrednim
|
||||
// w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy bezpośrednim
|
||||
// albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w
|
||||
// pobliżu, a drugi radiowy, słyszalny w innych lokomotywach
|
||||
// na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić
|
||||
@@ -4671,8 +4691,7 @@ TController::UpdateSituation(double dt) {
|
||||
else {
|
||||
// if (iGuardRadio==iRadioChannel) //zgodność kanału
|
||||
// if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu
|
||||
// (albo może mieć radio przenośne) - kierownik mógłby powtarzać
|
||||
// przy braku reakcji
|
||||
// (albo może mieć radio przenośne) - kierownik mógłby powtarzać przy braku reakcji
|
||||
// TODO: proper system for sending/receiving radio messages
|
||||
// place the sound in appropriate cab of the manned vehicle
|
||||
tsGuardSignal.owner( pVehicle );
|
||||
@@ -4681,8 +4700,8 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( mvOccupied->V == 0.0 ) {
|
||||
|
||||
if( mvOccupied->Vel < 0.01 ) {
|
||||
// Ra 2014-03: jesli skład stoi, to działa na niego składowa styczna grawitacji
|
||||
AbsAccS = fAccGravity;
|
||||
}
|
||||
@@ -4761,6 +4780,8 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
else {
|
||||
// przy dużej różnicy wysoki stopień (1,00 potrzebnego opoznienia)
|
||||
if( ( std::max( 100.0, fMaxProximityDist ) + fBrakeDist * braking_distance_multiplier( VelNext ) ) >= ( ActualProximityDist - fMaxProximityDist ) ) {
|
||||
// don't slow down prematurely; as long as we have room to come to a full stop at a safe distance, we're good
|
||||
// ensure some minimal coasting speed, otherwise a vehicle entering this zone at very low speed will be crawling forever
|
||||
auto const brakingpointoffset = VelNext * braking_distance_multiplier( VelNext );
|
||||
AccDesired = std::min(
|
||||
@@ -4774,6 +4795,7 @@ TController::UpdateSituation(double dt) {
|
||||
brakingpointoffset ) )
|
||||
+ 0.1 ) ); // najpierw hamuje mocniej, potem zluzuje
|
||||
}
|
||||
}
|
||||
AccDesired = std::min( AccDesired, AccPreferred );
|
||||
}
|
||||
else {
|
||||
@@ -5220,13 +5242,22 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
if (AIControllFlag)
|
||||
{ // odhamowywanie składu po zatrzymaniu i zabezpieczanie lokomotywy
|
||||
if ((OrderList[OrderPos] & (Disconnect | Connect)) ==
|
||||
0) // przy (p)odłączaniu nie zwalniamy tu hamulca
|
||||
if ((mvOccupied->V == 0.0) && ((VelDesired == 0.0) || (AccDesired == 0.0)))
|
||||
if (mvOccupied->BrakeCtrlPos == mvOccupied->Handle->GetPos(bh_RP))
|
||||
mvOccupied->IncLocalBrakeLevel(1); // dodatkowy na pozycję 1
|
||||
else
|
||||
mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_RP));
|
||||
if( ( ( OrderList[ OrderPos ] & ( Disconnect | Connect ) ) == 0 )
|
||||
&& ( std::abs( fAccGravity ) < 0.01 ) ) {
|
||||
// przy (p)odłączaniu nie zwalniamy tu hamulca
|
||||
// only do this on flats, on slopes keep applied the train brake
|
||||
if( ( mvOccupied->Vel < 0.01 )
|
||||
&& ( ( VelDesired == 0.0 )
|
||||
|| ( AccDesired == 0.0 ) ) ) {
|
||||
if( mvOccupied->BrakeCtrlPos == mvOccupied->Handle->GetPos( bh_RP ) ) {
|
||||
// dodatkowy na pozycję 1
|
||||
mvOccupied->IncLocalBrakeLevel( 1 );
|
||||
}
|
||||
else {
|
||||
mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_RP ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break; // rzeczy robione przy jezdzie
|
||||
} // switch (OrderList[OrderPos])
|
||||
@@ -5529,12 +5560,17 @@ bool TController::BackwardTrackBusy(TTrack *Track)
|
||||
|
||||
TEvent * TController::CheckTrackEventBackward(double fDirection, TTrack *Track)
|
||||
{ // sprawdzanie eventu w torze, czy jest sygnałowym - skanowanie do tyłu
|
||||
TEvent *e = (fDirection > 0) ? Track->evEvent2 : Track->evEvent1;
|
||||
if (e)
|
||||
if (!e->bEnabled) // jeśli sygnałowy (nie dodawany do kolejki)
|
||||
if (e->Type == tp_GetValues) // PutValues nie może się zmienić
|
||||
return e;
|
||||
return NULL;
|
||||
// NOTE: this method returns only one event which meets the conditions, due to limitations in the caller
|
||||
// TBD, TODO: clean up the caller and return all suitable events, as in theory things will go awry if the track has more than one signal
|
||||
auto const &eventsequence { ( fDirection > 0 ? Track->m_events2 : Track->m_events1 ) };
|
||||
for( auto const &event : eventsequence ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( false == event.second->bEnabled )
|
||||
&& ( event.second->Type == tp_GetValues ) ) {
|
||||
return event.second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
TTrack * TController::BackwardTraceRoute(double &fDistance, double &fDirection, TTrack *Track, TEvent *&Event)
|
||||
|
||||
2
Driver.h
2
Driver.h
@@ -349,7 +349,7 @@ private:
|
||||
int OrderDirectionChange(int newdir, TMoverParameters *Vehicle);
|
||||
void Lights(int head, int rear);
|
||||
// Ra: metody obsługujące skanowanie toru
|
||||
TEvent *CheckTrackEvent(TTrack *Track, double const fDirection ) const;
|
||||
std::vector<TEvent *> CheckTrackEvent(TTrack *Track, double const fDirection ) const;
|
||||
bool TableAddNew();
|
||||
bool TableNotFound(TEvent const *Event) const;
|
||||
void TableTraceRoute(double fDistance, TDynamicObject *pVehicle = nullptr);
|
||||
|
||||
118
DynObj.cpp
118
DynObj.cpp
@@ -52,6 +52,18 @@ GetSubmodelFromName( TModel3d * const Model, std::string const Name ) {
|
||||
nullptr );
|
||||
}
|
||||
|
||||
// Ra 2015-01: sprawdzenie dostępności tekstury o podanej nazwie
|
||||
std::string
|
||||
TextureTest( std::string const &Name ) {
|
||||
|
||||
auto const lookup {
|
||||
FileExists(
|
||||
{ Global.asCurrentTexturePath + Name, Name, szTexturePath + Name },
|
||||
{ ".mat", ".dds", ".tga", ".bmp" } ) };
|
||||
|
||||
return ( lookup.first + lookup.second );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void TAnimPant::AKP_4E()
|
||||
{ // ustawienie wymiarów dla pantografu AKP-4E
|
||||
@@ -3033,8 +3045,13 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
masa += p->MoverParameters->TotalMass;
|
||||
osie += p->MoverParameters->NAxles;
|
||||
}
|
||||
double RapidMult = 1.0;
|
||||
if (((MoverParameters->BrakeDelays & (bdelay_P + bdelay_R)) == (bdelay_P + bdelay_R))
|
||||
&& (MoverParameters->BrakeDelayFlag & bdelay_P))
|
||||
RapidMult = MoverParameters->RapidMult;
|
||||
|
||||
auto const amax = RapidMult * std::min(FmaxPN / masamax, MoverParameters->MED_amax);
|
||||
|
||||
auto const amax = std::min(FmaxPN / masamax, MoverParameters->MED_amax);
|
||||
if ((MoverParameters->Vel < 0.5) && (MoverParameters->BrakePress > 0.2) ||
|
||||
(dDoorMoveL > 0.001) || (dDoorMoveR > 0.001))
|
||||
{
|
||||
@@ -3062,7 +3079,20 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
{
|
||||
Fzad = std::max(MoverParameters->StopBrakeDecc * masa, Fzad);
|
||||
}
|
||||
|
||||
if ((Fzad > 1) && (!MEDLogFile.is_open()) && (MoverParameters->Vel > 1))
|
||||
{
|
||||
MEDLogFile.open(std::string("MEDLOGS/" + MoverParameters->Name + "_" + to_string(++MEDLogCount) + ".csv"),
|
||||
std::ios::in | std::ios::out | std::ios::trunc);
|
||||
MEDLogFile << std::string("t\tVel\tMasa\tOsie\tFmaxPN\tFmaxED\tFfulED\tFrED\tFzad\tFzadED\tFzadPN").c_str();
|
||||
for(int k=1;k<=np;k++)
|
||||
{
|
||||
MEDLogFile << "\tBP" << k;
|
||||
}
|
||||
MEDLogFile << "\n";
|
||||
MEDLogFile.flush();
|
||||
MEDLogInactiveTime = 0;
|
||||
MEDLogTime = 0;
|
||||
}
|
||||
auto FzadED { 0.0 };
|
||||
if( ( MoverParameters->EpFuse && (MoverParameters->BrakeHandle != MHZ_EN57))
|
||||
|| ( ( MoverParameters->BrakeHandle == MHZ_EN57 )
|
||||
@@ -3197,6 +3227,38 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
MED[0][6] = FzadPN*0.001;
|
||||
MED[0][7] = nPrzekrF;
|
||||
|
||||
if (MEDLogFile.is_open())
|
||||
{
|
||||
MEDLogFile << MEDLogTime << "\t" << MoverParameters->Vel << "\t" << masa*0.001 << "\t" << osie << "\t" << FmaxPN*0.001 << "\t" << FmaxED*0.001 << "\t"
|
||||
<< FfulED*0.001 << "\t" << FrED*0.001 << "\t" << Fzad*0.001 << "\t" << FzadED*0.001 << "\t" << FzadPN*0.001;
|
||||
for (TDynamicObject *p = GetFirstDynamic(MoverParameters->ActiveCab < 0 ? 1 : 0, 4); p;
|
||||
(true == kier ? p = p->NextC(4) : p = p->PrevC(4)))
|
||||
{
|
||||
MEDLogFile << "\t" << p->MoverParameters->BrakePress;
|
||||
}
|
||||
MEDLogFile << "\n";
|
||||
if (floor(MEDLogTime + dt1) > floor(MEDLogTime))
|
||||
{
|
||||
MEDLogFile.flush();
|
||||
}
|
||||
MEDLogTime += dt1;
|
||||
|
||||
if ((MoverParameters->Vel < 0.1) || (MoverParameters->MainCtrlPos > 0))
|
||||
{
|
||||
MEDLogInactiveTime += dt1;
|
||||
}
|
||||
else
|
||||
{
|
||||
MEDLogInactiveTime = 0;
|
||||
}
|
||||
if (MEDLogInactiveTime > 5)
|
||||
{
|
||||
MEDLogFile.flush();
|
||||
MEDLogFile.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete[] PrzekrF;
|
||||
delete[] FzED;
|
||||
delete[] FzEP;
|
||||
@@ -4482,7 +4544,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
|
||||
mdModel = TModelsManager::GetModel(asModel, true);
|
||||
if (ReplacableSkin != "none")
|
||||
{
|
||||
std::string nowheretexture = TextureTest( Global.asCurrentTexturePath + "nowhere" ); // na razie prymitywnie
|
||||
std::string nowheretexture = TextureTest( "nowhere" ); // na razie prymitywnie
|
||||
if( false == nowheretexture.empty() ) {
|
||||
m_materialdata.replacable_skins[ 4 ] = GfxRenderer.Fetch_Material( nowheretexture );
|
||||
}
|
||||
@@ -4552,7 +4614,8 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
|
||||
}
|
||||
if( !MoverParameters->LoadAccepted.empty() ) {
|
||||
|
||||
if( MoverParameters->EnginePowerSource.SourceType == CurrentCollector ) {
|
||||
if( ( MoverParameters->EnginePowerSource.SourceType == CurrentCollector )
|
||||
&& ( asLoadName == "pantstate" ) ) {
|
||||
// wartość niby "pantstate" - nazwa dla formalności, ważna jest ilość
|
||||
if( MoverParameters->Load == 1 ) {
|
||||
MoverParameters->PantFront( true );
|
||||
@@ -4609,10 +4672,12 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
|
||||
*/
|
||||
if( true == pAnimations.empty() )
|
||||
{ // jeśli nie ma jeszcze tabeli animacji, można odczytać nowe ilości
|
||||
int co = 0, ile = -1;
|
||||
int co = 0;
|
||||
iAnimations = 0;
|
||||
int ile;
|
||||
do
|
||||
{ // kolejne liczby to ilość animacj, -1 to znacznik końca
|
||||
ile = -1;
|
||||
parser.getTokens( 1, false );
|
||||
parser >> ile; // ilość danego typu animacji
|
||||
if (ile >= 0)
|
||||
@@ -6209,17 +6274,6 @@ int TDynamicObject::RouteWish(TTrack *tr)
|
||||
return Mechanik ? Mechanik->CrossRoute(tr) : 0; // wg AI albo prosto
|
||||
};
|
||||
|
||||
std::string TDynamicObject::TextureTest(std::string const &name)
|
||||
{ // Ra 2015-01: sprawdzenie dostępności tekstury o podanej nazwie
|
||||
std::vector<std::string> extensions = { ".mat", ".dds", ".tga", ".bmp" };
|
||||
for( auto const &extension : extensions ) {
|
||||
if( true == FileExists( name + extension ) ) {
|
||||
return name + extension;
|
||||
}
|
||||
}
|
||||
return ""; // nie znaleziona
|
||||
};
|
||||
|
||||
void TDynamicObject::DestinationSet(std::string to, std::string numer)
|
||||
{ // ustawienie stacji docelowej oraz wymiennej tekstury 4, jeśli istnieje plik
|
||||
// w zasadzie, to każdy wagon mógłby mieć inną stację docelową
|
||||
@@ -6233,13 +6287,20 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer)
|
||||
numer = Bezogonkow(numer);
|
||||
asDestination = to;
|
||||
to = Bezogonkow(to); // do szukania pliku obcinamy ogonki
|
||||
|
||||
if( true == to.empty() ) {
|
||||
to = "nowhere";
|
||||
}
|
||||
// destination textures are kept in the vehicle's directory so we point the current texture path there
|
||||
auto const currenttexturepath { Global.asCurrentTexturePath };
|
||||
Global.asCurrentTexturePath = asBaseDir;
|
||||
// now see if we can find any version of the texture
|
||||
std::vector<std::string> destinations = {
|
||||
asBaseDir + numer + "@" + MoverParameters->TypeName,
|
||||
asBaseDir + numer,
|
||||
asBaseDir + to + "@" + MoverParameters->TypeName,
|
||||
asBaseDir + to,
|
||||
asBaseDir + "nowhere" };
|
||||
numer + '@' + MoverParameters->TypeName,
|
||||
numer,
|
||||
to + '@' + MoverParameters->TypeName,
|
||||
to,
|
||||
"nowhere" + '@' + MoverParameters->TypeName,
|
||||
"nowhere" };
|
||||
|
||||
for( auto const &destination : destinations ) {
|
||||
|
||||
@@ -6249,6 +6310,8 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// whether we got anything, restore previous texture path
|
||||
Global.asCurrentTexturePath = currenttexturepath;
|
||||
};
|
||||
|
||||
void TDynamicObject::OverheadTrack(float o)
|
||||
@@ -6370,7 +6433,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
|
||||
// main engine sound
|
||||
if( true == Vehicle.Mains ) {
|
||||
|
||||
if( ( std::fabs( Vehicle.enrot ) > 0.01 )
|
||||
if( ( std::abs( Vehicle.enrot ) > 0.01 )
|
||||
// McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach
|
||||
|| ( Vehicle.EngineType == Dumb ) ) {
|
||||
|
||||
@@ -6501,11 +6564,12 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
|
||||
std::max( goalvolume, currentvolume - changerate ) :
|
||||
std::min( goalvolume, currentvolume + changerate ) );
|
||||
|
||||
if( volume > 0.05 ) {
|
||||
engine_turbo
|
||||
.pitch( 0.4 + engine_turbo_pitch * 0.4 )
|
||||
.gain( volume )
|
||||
.play( sound_flags::exclusive | sound_flags::looping );
|
||||
.gain( volume );
|
||||
|
||||
if( volume > 0.05 ) {
|
||||
engine_turbo.play( sound_flags::exclusive | sound_flags::looping );
|
||||
}
|
||||
else {
|
||||
engine_turbo.stop();
|
||||
@@ -6539,7 +6603,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
|
||||
if( ( true == Vehicle.Mains )
|
||||
&& ( false == motors.empty() ) ) {
|
||||
|
||||
if( std::fabs( Vehicle.enrot ) > 0.01 ) {
|
||||
if( std::abs( Vehicle.enrot ) > 0.01 ) {
|
||||
|
||||
auto const &motor { motors.front() };
|
||||
// frequency calculation
|
||||
|
||||
5
DynObj.h
5
DynObj.h
@@ -602,11 +602,14 @@ private:
|
||||
// zapytanie do AI, po którym segmencie skrzyżowania jechać
|
||||
int RouteWish(TTrack *tr);
|
||||
void DestinationSet(std::string to, std::string numer);
|
||||
std::string TextureTest(std::string const &name);
|
||||
void OverheadTrack(float o);
|
||||
|
||||
double MED[9][8]; // lista zmiennych do debugowania hamulca ED
|
||||
static std::string const MED_labels[ 8 ];
|
||||
std::ofstream MEDLogFile; // zapis parametrów hamowania
|
||||
double MEDLogTime = 0;
|
||||
double MEDLogInactiveTime = 0;
|
||||
int MEDLogCount = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
85
EvLaunch.cpp
85
EvLaunch.cpp
@@ -196,11 +196,90 @@ bool TEventLauncher::IsGlobal() const {
|
||||
&& ( dRadius < 0.0 ) ); // bez ograniczenia zasięgu
|
||||
}
|
||||
|
||||
// calculates node's bounding radius
|
||||
void
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float
|
||||
TEventLauncher::radius_() {
|
||||
|
||||
m_area.radius = std::sqrt( dRadius );
|
||||
return std::sqrt( dRadius );
|
||||
}
|
||||
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void
|
||||
TEventLauncher::serialize_( std::ostream &Output ) const {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void
|
||||
TEventLauncher::deserialize_( std::istream &Input ) {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
TEventLauncher::export_as_text_( std::ostream &Output ) const {
|
||||
// header
|
||||
Output << "eventlauncher ";
|
||||
// location
|
||||
Output
|
||||
<< location().x << ' '
|
||||
<< location().y << ' '
|
||||
<< location().z << ' ';
|
||||
// activation radius
|
||||
Output
|
||||
<< ( dRadius > 0 ? std::sqrt( dRadius ) : dRadius ) << ' ';
|
||||
// activation key
|
||||
if( iKey != 0 ) {
|
||||
auto const key { iKey & 0xff };
|
||||
auto const modifier { ( iKey & 0xff00 ) >> 8 };
|
||||
if( ( key >= GLFW_KEY_A ) && ( key <= GLFW_KEY_Z ) ) {
|
||||
Output << static_cast<char>(( 'A' + key - GLFW_KEY_A + ( ( modifier & 1 ) == 0 ? 32 : 0 ) )) << ' ';
|
||||
}
|
||||
else if( ( key >= GLFW_KEY_0 ) && ( key <= GLFW_KEY_9 ) ) {
|
||||
Output << static_cast<char>(( '0' + key - GLFW_KEY_0 )) << ' ';
|
||||
}
|
||||
}
|
||||
else {
|
||||
Output << "none ";
|
||||
}
|
||||
// activation interval or hour
|
||||
if( DeltaTime != 0 ) {
|
||||
// cyclical launcher
|
||||
Output << -DeltaTime << ' ';
|
||||
}
|
||||
else {
|
||||
// single activation at specified time
|
||||
if( ( iHour < 0 )
|
||||
&& ( iMinute < 0 ) ) {
|
||||
Output << DeltaTime << ' ';
|
||||
}
|
||||
else {
|
||||
// NOTE: activation hour might be affected by user-requested time offset
|
||||
auto const timeoffset{ static_cast<int>( Global.ScenarioTimeOffset * 60 ) };
|
||||
auto const adjustedtime{ clamp_circular( iHour * 60 + iMinute - timeoffset, 24 * 60 ) };
|
||||
Output
|
||||
<< ( adjustedtime / 60 ) % 24
|
||||
<< ( adjustedtime % 60 )
|
||||
<< ' ';
|
||||
}
|
||||
}
|
||||
// associated event(s)
|
||||
Output << ( asEvent1Name.empty() ? "none" : asEvent1Name ) << ' ';
|
||||
Output << ( asEvent2Name.empty() ? "none" : asEvent2Name ) << ' ';
|
||||
if( false == asMemCellName.empty() ) {
|
||||
// conditional event
|
||||
Output
|
||||
<< "condition "
|
||||
<< asMemCellName << ' '
|
||||
<< szText << ' '
|
||||
<< ( ( iCheckMask & conditional_memval1 ) != 0 ? to_string( fVal1 ) : "*" ) << ' '
|
||||
<< ( ( iCheckMask & conditional_memval2 ) != 0 ? to_string( fVal2 ) : "*" ) << ' ';
|
||||
}
|
||||
// footer
|
||||
Output
|
||||
<< "end"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
17
EvLaunch.h
17
EvLaunch.h
@@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Classes.h"
|
||||
#include "scenenode.h"
|
||||
|
||||
class TEventLauncher : public editor::basic_node {
|
||||
class TEventLauncher : public scene::basic_node {
|
||||
|
||||
public:
|
||||
// constructor
|
||||
@@ -37,12 +37,17 @@ public:
|
||||
int iCheckMask { 0 };
|
||||
double dRadius { 0.0 };
|
||||
|
||||
protected:
|
||||
// calculates node's bounding radius
|
||||
void
|
||||
radius_();
|
||||
|
||||
private:
|
||||
// methods
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float radius_();
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void serialize_( std::ostream &Output ) const;
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void deserialize_( std::istream &Input );
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void export_as_text_( std::ostream &Output ) const;
|
||||
|
||||
// members
|
||||
int iKey { 0 };
|
||||
double DeltaTime { -1.0 };
|
||||
|
||||
283
Event.cpp
283
Event.cpp
@@ -301,9 +301,9 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
if (token.find('#') != std::string::npos)
|
||||
token.erase(token.find('#')); // obcięcie unikatowości
|
||||
win1250_to_ascii( token ); // get rid of non-ascii chars
|
||||
bEnabled = false; // nie do kolejki (dla SetVelocity też, ale jak jest do toru
|
||||
// dowiązany)
|
||||
Params[6].asCommand = cm_PassengerStopPoint;
|
||||
// nie do kolejki (dla SetVelocity też, ale jak jest do toru dowiązany)
|
||||
bEnabled = false;
|
||||
}
|
||||
else if (token == "SetVelocity")
|
||||
{
|
||||
@@ -325,11 +325,6 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
bEnabled = false;
|
||||
Params[6].asCommand = cm_ShuntVelocity;
|
||||
}
|
||||
//else if (str == "SetProximityVelocity")
|
||||
//{
|
||||
// bEnabled = false;
|
||||
// Params[6].asCommand = cm_SetProximityVelocity;
|
||||
//}
|
||||
else if (token == "OutsideStation")
|
||||
{
|
||||
bEnabled = false; // ma być skanowny, aby AI nie przekraczało W5
|
||||
@@ -388,6 +383,11 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
}
|
||||
}
|
||||
} while( token.compare( "endevent" ) != 0 );
|
||||
while( paramidx < 8 ) {
|
||||
// HACK: mark unspecified lights with magic value
|
||||
Params[ paramidx ].asdouble = -2.0;
|
||||
++paramidx;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_Visible: // zmiana wyświetlania obiektu
|
||||
@@ -400,7 +400,7 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
case tp_Velocity:
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
Params[0].asdouble = atof(token.c_str()) * 0.28;
|
||||
Params[0].asdouble = atof(token.c_str()) * ( 1000.0 / 3600.0 );
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
break;
|
||||
@@ -417,7 +417,6 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
*parser >> token;
|
||||
break;
|
||||
case tp_Exit:
|
||||
asNodeName = ExchangeCharInString( asNodeName, '_', ' ' );
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
break;
|
||||
@@ -534,8 +533,7 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
*parser >> token;
|
||||
break;
|
||||
case tp_Multiple: {
|
||||
int paramidx { 0 };
|
||||
bool ti { false }; // flaga dla else
|
||||
bool conditionalelse { false }; // flaga dla else
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
|
||||
@@ -546,12 +544,7 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
if( token != "else" ) {
|
||||
if( token.substr( 0, 5 ) != "none_" ) {
|
||||
// eventy rozpoczynające się od "none_" są ignorowane
|
||||
ext_params.push_back(std::make_pair(TParam(), 0));
|
||||
ext_params[ paramidx ].first.asText = new char[ token.size() + 1 ];
|
||||
strcpy( ext_params[ paramidx ].first.asText, token.c_str() );
|
||||
// oflagowanie dla eventów "else"
|
||||
ext_params[paramidx].second = (int)ti;
|
||||
++paramidx;
|
||||
m_children.emplace_back( token, nullptr, ( conditionalelse == false ) );
|
||||
}
|
||||
else {
|
||||
WriteLog( "Multi-event \"" + asName + "\" ignored link to event \"" + token + "\"" );
|
||||
@@ -559,8 +552,8 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
}
|
||||
else {
|
||||
// zmiana flagi dla słowa "else"
|
||||
ti = !ti;
|
||||
iFlags |= conditional_anyelse;
|
||||
conditionalelse = !conditionalelse;
|
||||
m_conditionalelse = true;
|
||||
}
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
@@ -597,6 +590,185 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
}
|
||||
};
|
||||
|
||||
// sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
TEvent::export_as_text( std::ostream &Output ) const {
|
||||
|
||||
if( Type == tp_Unknown ) { return; }
|
||||
|
||||
// header
|
||||
Output << "event ";
|
||||
// name
|
||||
Output << asName << ' ';
|
||||
// type
|
||||
std::vector<std::string> const types {
|
||||
"unknown", "sound", "exit", "disable", "velocity", "animation", "lights",
|
||||
"updatevalues", "getvalues", "putvalues", "switch", "dynvel", "trackvel",
|
||||
"multiple", "addvalues", "copyvalues", "whois", "logvalues", "visible",
|
||||
"voltage", "message", "friction" };
|
||||
Output << types[ Type ] << ' ';
|
||||
// delay
|
||||
Output << fDelay << ' ';
|
||||
// associated node
|
||||
Output << ( asNodeName.empty() ? "none" : asNodeName ) << ' ';
|
||||
// type-specific attributes
|
||||
switch( Type ) {
|
||||
case tp_AddValues:
|
||||
case tp_UpdateValues: {
|
||||
Output
|
||||
<< ( ( iFlags & update_memstring ) == 0 ? "*" : Params[ 0 ].asText ) << ' '
|
||||
<< ( ( iFlags & update_memval1 ) == 0 ? "*" : to_string( Params[ 1 ].asdouble ) ) << ' '
|
||||
<< ( ( iFlags & update_memval2 ) == 0 ? "*" : to_string( Params[ 2 ].asdouble ) ) << ' ';
|
||||
break;
|
||||
}
|
||||
case tp_CopyValues: {
|
||||
// NOTE: there's no way to get the original parameter value if it doesn't point to existing memcell
|
||||
Output
|
||||
<< ( Params[ 9 ].asMemCell == nullptr ? "none" : Params[ 9 ].asMemCell->name() ) << ' '
|
||||
<< ( iFlags & ( update_memstring | update_memval1 | update_memval2 ) ) << ' ';
|
||||
break;
|
||||
}
|
||||
case tp_PutValues: {
|
||||
Output
|
||||
// location
|
||||
<< Params[ 3 ].asdouble << ' '
|
||||
<< Params[ 4 ].asdouble << ' '
|
||||
<< Params[ 5 ].asdouble << ' '
|
||||
// command
|
||||
<< Params[ 0 ].asText << ' '
|
||||
<< Params[ 1 ].asdouble << ' '
|
||||
<< Params[ 2 ].asdouble << ' ';
|
||||
break;
|
||||
}
|
||||
case tp_Multiple: {
|
||||
for( auto const &childevent : m_children ) {
|
||||
if( std::get<TEvent *>( childevent ) == nullptr ) { continue; }
|
||||
if( true == std::get<bool>( childevent ) ) {
|
||||
Output << std::get<std::string>( childevent ) << ' ';
|
||||
}
|
||||
}
|
||||
// optional 'else' block
|
||||
if( true == m_conditionalelse ) {
|
||||
Output << "else ";
|
||||
for( auto const &childevent : m_children ) {
|
||||
if( std::get<TEvent *>( childevent ) == nullptr ) { continue; }
|
||||
if( false == std::get<bool>( childevent ) ) {
|
||||
Output << std::get<std::string>( childevent ) << ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_Visible: {
|
||||
Output << Params[ 0 ].asInt << ' ';
|
||||
break;
|
||||
}
|
||||
case tp_Switch: {
|
||||
Output << Params[ 0 ].asInt << ' ';
|
||||
if( ( Params[ 1 ].asdouble != -1.0 )
|
||||
|| ( Params[ 2 ].asdouble != -1.0 ) ) {
|
||||
Output << Params[ 1 ].asdouble << ' ';
|
||||
}
|
||||
if( Params[ 2 ].asdouble != -1.0 ) {
|
||||
Output << Params[ 2 ].asdouble << ' ';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_Lights: {
|
||||
auto lightidx { 0 };
|
||||
while( ( lightidx < iMaxNumLights )
|
||||
&& ( Params[ lightidx ].asdouble > -2.0 ) ) {
|
||||
Output << Params[ lightidx ].asdouble << ' ';
|
||||
++lightidx;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_Animation: {
|
||||
// animation type
|
||||
Output << (
|
||||
Params[ 0 ].asInt == 1 ? "rotate" :
|
||||
Params[ 0 ].asInt == 2 ? "translate" :
|
||||
// NOTE: .vmd animation doesn't preserve file name, can't be exported. TODO: fix this
|
||||
Params[ 0 ].asInt == 8 ? "digital" :
|
||||
"none" )
|
||||
<< ' ';
|
||||
// submodel
|
||||
Output << (
|
||||
Params[ 9 ].asAnimContainer != nullptr ?
|
||||
Params[ 9 ].asAnimContainer->NameGet() :
|
||||
"none" ) << ' ';
|
||||
// animation parameters
|
||||
Output
|
||||
<< Params[ 1 ].asdouble << ' '
|
||||
<< Params[ 2 ].asdouble << ' '
|
||||
<< Params[ 3 ].asdouble << ' '
|
||||
<< Params[ 4 ].asdouble << ' ';
|
||||
break;
|
||||
}
|
||||
case tp_Sound: {
|
||||
// playback mode
|
||||
Output << Params[ 0 ].asInt << ' ';
|
||||
// optional radio channel
|
||||
if( Params[ 1 ].asdouble > 0.0 ) {
|
||||
Output << Params[ 1 ].asdouble << ' ';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_DynVel:
|
||||
case tp_TrackVel:
|
||||
case tp_Voltage:
|
||||
case tp_Friction: {
|
||||
Output << Params[ 0 ].asdouble << ' ';
|
||||
break;
|
||||
}
|
||||
case tp_Velocity: {
|
||||
Output << Params[ 0 ].asdouble * ( 3600.0 / 1000.0 ) << ' ';
|
||||
break;
|
||||
}
|
||||
case tp_WhoIs: {
|
||||
Output
|
||||
<< ( iFlags & ( update_memstring | update_memval1 | update_memval2 ) ) << ' ';
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// optional conditions
|
||||
// NOTE: for flexibility condition check and export is performed for all event types rather than only for these which support it currently
|
||||
auto const isconditional { ( conditional_trackoccupied | conditional_trackfree | conditional_propability | conditional_memcompare ) };
|
||||
if( ( ( iFlags & isconditional ) != 0 ) ) {
|
||||
Output << "condition ";
|
||||
if( ( iFlags & conditional_trackoccupied ) != 0 ) {
|
||||
Output << "trackoccupied ";
|
||||
}
|
||||
else if( ( iFlags & conditional_trackfree ) != 0 ) {
|
||||
Output << "trackfree ";
|
||||
}
|
||||
else if( ( iFlags & conditional_propability ) != 0 ) {
|
||||
Output
|
||||
<< "propability "
|
||||
<< Params[ 10 ].asdouble << ' ';
|
||||
}
|
||||
else if( ( iFlags & conditional_memcompare ) != 0 ) {
|
||||
Output
|
||||
<< "memcompare "
|
||||
<< ( ( iFlags & conditional_memstring ) == 0 ? "*" : Params[ 10 ].asText ) << ' '
|
||||
<< ( ( iFlags & conditional_memval1 ) == 0 ? "*" : to_string( Params[ 11 ].asdouble ) ) << ' '
|
||||
<< ( ( iFlags & conditional_memval2 ) == 0 ? "*" : to_string( Params[ 12 ].asdouble ) ) << ' ';
|
||||
}
|
||||
}
|
||||
if( fRandomDelay != 0.0 ) {
|
||||
Output
|
||||
<< "randomdelay "
|
||||
<< fRandomDelay << ' ';
|
||||
}
|
||||
// footer
|
||||
Output
|
||||
<< "endevent"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void TEvent::AddToQuery( TEvent *Event, TEvent *&Start ) {
|
||||
|
||||
TEvent *target( Start );
|
||||
@@ -994,6 +1166,10 @@ event_manager::CheckQuery() {
|
||||
case tp_Lights: {
|
||||
if( m_workevent->Params[ 9 ].asModel ) {
|
||||
for( i = 0; i < iMaxNumLights; ++i ) {
|
||||
if( m_workevent->Params[ i ].asdouble == -2.0 ) {
|
||||
// processed all supplied values, bail out
|
||||
break;
|
||||
}
|
||||
if( m_workevent->Params[ i ].asdouble >= 0 ) {
|
||||
// -1 zostawia bez zmiany
|
||||
m_workevent->Params[ 9 ].asModel->LightSet(
|
||||
@@ -1005,8 +1181,8 @@ event_manager::CheckQuery() {
|
||||
break;
|
||||
}
|
||||
case tp_Visible: {
|
||||
if( m_workevent->Params[ 9 ].asEditorNode )
|
||||
m_workevent->Params[ 9 ].asEditorNode->visible( m_workevent->Params[ 0 ].asInt > 0 );
|
||||
if( m_workevent->Params[ 9 ].asSceneNode )
|
||||
m_workevent->Params[ 9 ].asSceneNode->visible( m_workevent->Params[ 0 ].asInt > 0 );
|
||||
break;
|
||||
}
|
||||
case tp_Velocity: {
|
||||
@@ -1014,7 +1190,6 @@ event_manager::CheckQuery() {
|
||||
break;
|
||||
}
|
||||
case tp_Exit: {
|
||||
Global.iTextMode = -1; // wyłączenie takie samo jak sekwencja F10 -> Y
|
||||
return false;
|
||||
}
|
||||
case tp_Sound: {
|
||||
@@ -1115,17 +1290,20 @@ event_manager::CheckQuery() {
|
||||
Error("Event \"DynVel\" is obsolete");
|
||||
break;
|
||||
case tp_Multiple: {
|
||||
auto const bCondition = EventConditon(m_workevent);
|
||||
if( ( bCondition )
|
||||
|| ( m_workevent->iFlags & conditional_anyelse ) ) {
|
||||
auto const condition { EventConditon( m_workevent ) };
|
||||
if( ( true == condition )
|
||||
|| ( true == m_workevent->m_conditionalelse ) ) {
|
||||
// warunek spelniony albo było użyte else
|
||||
WriteLog("Type: Multi-event");
|
||||
for (i = 0; i < m_workevent->ext_params.size(); ++i) {
|
||||
// dodawane do kolejki w kolejności zapisania
|
||||
if( m_workevent->ext_params[ i ].first.asEvent ) {
|
||||
if( bCondition != (bool)m_workevent->ext_params[i].second ) {
|
||||
if( m_workevent->ext_params[ i ].first.asEvent != m_workevent )
|
||||
AddToQuery( m_workevent->ext_params[ i ].first.asEvent, m_workevent->Activator ); // normalnie dodać
|
||||
for( auto &childevent : m_workevent->m_children ) {
|
||||
auto *childeventdata { std::get<TEvent*>( childevent ) };
|
||||
if( childeventdata == nullptr ) { continue; }
|
||||
if( std::get<bool>( childevent ) != condition ) { continue; }
|
||||
|
||||
if( childeventdata != m_workevent ) {
|
||||
// normalnie dodać
|
||||
AddToQuery( childeventdata, m_workevent->Activator );
|
||||
}
|
||||
else {
|
||||
// jeśli ma być rekurencja to musi mieć sensowny okres powtarzania
|
||||
if( m_workevent->fDelay >= 5.0 ) {
|
||||
@@ -1133,11 +1311,9 @@ event_manager::CheckQuery() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( Global.iMultiplayer ) {
|
||||
// dajemy znać do serwera o wykonaniu
|
||||
if( ( m_workevent->iFlags & conditional_anyelse ) == 0 ) {
|
||||
if( false == m_workevent->m_conditionalelse ) {
|
||||
// jednoznaczne tylko, gdy nie było else
|
||||
if( m_workevent->Activator ) {
|
||||
multiplayer::WyslijEvent( m_workevent->asName, m_workevent->Activator->name() );
|
||||
@@ -1397,7 +1573,6 @@ event_manager::InitEvents() {
|
||||
else {
|
||||
ErrorLog( "Bad event: animation event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Lights: {
|
||||
@@ -1407,12 +1582,11 @@ event_manager::InitEvents() {
|
||||
event->Params[ 9 ].asModel = instance;
|
||||
else
|
||||
ErrorLog( "Bad event: lights event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" );
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Visible: {
|
||||
// ukrycie albo przywrócenie obiektu
|
||||
editor::basic_node *node = simulation::Instances.find( event->asNodeName ); // najpierw model
|
||||
scene::basic_node *node = simulation::Instances.find( event->asNodeName ); // najpierw model
|
||||
if( node == nullptr ) {
|
||||
// albo tory?
|
||||
node = simulation::Paths.find( event->asNodeName );
|
||||
@@ -1422,12 +1596,11 @@ event_manager::InitEvents() {
|
||||
node = simulation::Traction.find( event->asNodeName );
|
||||
}
|
||||
if( node != nullptr )
|
||||
event->Params[ 9 ].asEditorNode = node;
|
||||
event->Params[ 9 ].asSceneNode = node;
|
||||
else {
|
||||
event->m_ignored = true;
|
||||
ErrorLog( "Bad event: visibility event \"" + event->asName + "\" cannot find item \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Switch: {
|
||||
@@ -1453,7 +1626,6 @@ event_manager::InitEvents() {
|
||||
else {
|
||||
ErrorLog( "Bad event: switch event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Sound: {
|
||||
@@ -1463,7 +1635,6 @@ event_manager::InitEvents() {
|
||||
event->Params[ 9 ].tsTextSound = sound;
|
||||
else
|
||||
ErrorLog( "Bad event: sound event \"" + event->asName + "\" cannot find static sound \"" + event->asNodeName + "\"" );
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_TrackVel: {
|
||||
@@ -1479,7 +1650,6 @@ event_manager::InitEvents() {
|
||||
ErrorLog( "Bad event: track velocity event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_DynVel: {
|
||||
@@ -1493,7 +1663,6 @@ event_manager::InitEvents() {
|
||||
else
|
||||
ErrorLog( "Bad event: vehicle velocity event \"" + event->asName + "\" cannot find vehicle \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Multiple: {
|
||||
@@ -1519,15 +1688,10 @@ event_manager::InitEvents() {
|
||||
event->iFlags &= ~( conditional_memstring | conditional_memval1 | conditional_memval2 );
|
||||
}
|
||||
}
|
||||
for( int i = 0; i < event->ext_params.size(); ++i ) {
|
||||
if( event->ext_params[ i ].first.asText != nullptr ) {
|
||||
cellastext = event->ext_params[ i ].first.asText;
|
||||
SafeDeleteArray( event->ext_params[ i ].first.asText );
|
||||
event->ext_params[ i ].first.asEvent = FindEvent( cellastext );
|
||||
if( event->ext_params[ i ].first.asEvent == nullptr ) {
|
||||
// Ra: tylko w logu informacja o braku
|
||||
ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find event \"" + cellastext + "\"" );
|
||||
}
|
||||
for( auto &childevent : event->m_children ) {
|
||||
std::get<TEvent *>( childevent ) = FindEvent( std::get<std::string>( childevent ) );
|
||||
if( std::get<TEvent *>( childevent ) == nullptr ) {
|
||||
ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find event \"" + std::get<std::string>( childevent ) + "\"" );
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1541,7 +1705,6 @@ event_manager::InitEvents() {
|
||||
else
|
||||
ErrorLog( "Bad event: voltage event \"" + event->asName + "\" cannot find power source \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Message: {
|
||||
@@ -1590,6 +1753,20 @@ event_manager::InitLaunchers() {
|
||||
}
|
||||
}
|
||||
|
||||
// sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
event_manager::export_as_text( std::ostream &Output ) const {
|
||||
|
||||
Output << "// events\n";
|
||||
for( auto const *event : m_events ) {
|
||||
event->export_as_text( Output );
|
||||
}
|
||||
Output << "// event launchers\n";
|
||||
for( auto const *launcher : m_launchers.sequence() ) {
|
||||
launcher->export_as_text( Output );
|
||||
}
|
||||
}
|
||||
|
||||
// legacy method, verifies condition for specified event
|
||||
bool
|
||||
event_manager::EventConditon( TEvent *Event ) {
|
||||
|
||||
56
Event.h
56
Event.h
@@ -17,7 +17,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
enum TEventType {
|
||||
tp_Unknown,
|
||||
tp_Sound,
|
||||
tp_SoundPos,
|
||||
tp_Exit,
|
||||
tp_Disable,
|
||||
tp_Velocity,
|
||||
@@ -31,7 +30,6 @@ enum TEventType {
|
||||
tp_TrackVel,
|
||||
tp_Multiple,
|
||||
tp_AddValues,
|
||||
// tp_Ignored, // NOTE: refactored to separate flag
|
||||
tp_CopyValues,
|
||||
tp_WhoIs,
|
||||
tp_LogValues,
|
||||
@@ -51,7 +49,6 @@ const int update_only = 0x00000FF; // wartość graniczna
|
||||
const int conditional_memstring = 0x0000100; // porównanie tekstu
|
||||
const int conditional_memval1 = 0x0000200; // porównanie pierwszej wartości liczbowej
|
||||
const int conditional_memval2 = 0x0000400; // porównanie drugiej wartości
|
||||
const int conditional_anyelse = 0x0FF0000; // do sprawdzania, czy są odwrócone warunki
|
||||
const int conditional_trackoccupied = 0x1000000; // jeśli tor zajęty
|
||||
const int conditional_trackfree = 0x2000000; // jeśli tor wolny
|
||||
const int conditional_propability = 0x4000000; // zależnie od generatora lizcb losowych
|
||||
@@ -61,7 +58,7 @@ union TParam
|
||||
{
|
||||
void *asPointer;
|
||||
TMemCell *asMemCell;
|
||||
editor::basic_node *asEditorNode;
|
||||
scene::basic_node *asSceneNode;
|
||||
glm::dvec3 const *asLocation;
|
||||
TTrack *asTrack;
|
||||
TAnimModel *asModel;
|
||||
@@ -69,7 +66,6 @@ union TParam
|
||||
TTrain *asTrain;
|
||||
TDynamicObject *asDynamic;
|
||||
TEvent *asEvent;
|
||||
bool asBool;
|
||||
double asdouble;
|
||||
int asInt;
|
||||
sound_source *tsTextSound;
|
||||
@@ -80,10 +76,27 @@ union TParam
|
||||
|
||||
class TEvent // zmienne: ev*
|
||||
{ // zdarzenie
|
||||
private:
|
||||
void Conditions(cParser *parser, std::string s);
|
||||
|
||||
public:
|
||||
public:
|
||||
// types
|
||||
// wrapper for binding between editor-supplied name, event, and execution conditional flag
|
||||
using conditional_event = std::tuple<std::string, TEvent *, bool>;
|
||||
// constructors
|
||||
TEvent(std::string const &m = "");
|
||||
~TEvent();
|
||||
// metody
|
||||
void Load(cParser *parser, Math3D::vector3 const &org);
|
||||
// sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
export_as_text( std::ostream &Output ) const;
|
||||
static void AddToQuery( TEvent *Event, TEvent *&Start );
|
||||
std::string CommandGet();
|
||||
TCommandType Command();
|
||||
double ValueGet(int n);
|
||||
glm::dvec3 PositionGet() const;
|
||||
bool StopCommand();
|
||||
void StopCommandSent();
|
||||
void Append(TEvent *e);
|
||||
// members
|
||||
std::string asName;
|
||||
bool m_ignored { false }; // replacement for tp_ignored
|
||||
bool bEnabled = false; // false gdy ma nie być dodawany do kolejki (skanowanie sygnałów)
|
||||
@@ -95,27 +108,15 @@ class TEvent // zmienne: ev*
|
||||
TDynamicObject *Activator = nullptr;
|
||||
TParam Params[13]; // McZapkie-070502 //Ra: zamienić to na union/struct
|
||||
|
||||
// this is already mess, so one more hack won't make it much worse...
|
||||
// stores TParam union and magic flag (eg. else flag)
|
||||
std::vector<std::pair<TParam, int>> ext_params;
|
||||
|
||||
unsigned int iFlags = 0; // zamiast Params[8] z flagami warunku
|
||||
std::string asNodeName; // McZapkie-100302 - dodalem zeby zapamietac nazwe toru
|
||||
TEvent *evJoined = nullptr; // kolejny event z tą samą nazwą - od wersji 378
|
||||
double fRandomDelay = 0.0; // zakres dodatkowego opóźnienia // standardowo nie będzie dodatkowego losowego opóźnienia
|
||||
public:
|
||||
// metody
|
||||
TEvent(std::string const &m = "");
|
||||
~TEvent();
|
||||
void Load(cParser *parser, Math3D::vector3 const &org);
|
||||
static void AddToQuery( TEvent *Event, TEvent *&Start );
|
||||
std::string CommandGet();
|
||||
TCommandType Command();
|
||||
double ValueGet(int n);
|
||||
glm::dvec3 PositionGet() const;
|
||||
bool StopCommand();
|
||||
void StopCommandSent();
|
||||
void Append(TEvent *e);
|
||||
std::vector<conditional_event> m_children; // events which are placed in the query when this event is executed
|
||||
bool m_conditionalelse { false }; // TODO: make a part of condition struct
|
||||
|
||||
private:
|
||||
void Conditions( cParser *parser, std::string s );
|
||||
};
|
||||
|
||||
class event_manager {
|
||||
@@ -156,6 +157,9 @@ public:
|
||||
// legacy method, initializes event launchers after deserialization from scenario file
|
||||
void
|
||||
InitLaunchers();
|
||||
// sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
export_as_text( std::ostream &Output ) const;
|
||||
|
||||
private:
|
||||
// types
|
||||
|
||||
@@ -61,12 +61,19 @@ void TGauge::Init(TSubModel *Submodel, TGaugeType Type, float Scale, float Offse
|
||||
else // a banan może być z optymalizacją?
|
||||
Submodel->WillBeAnimated(); // wyłączenie ignowania jedynkowego transformu
|
||||
// pass submodel location to defined sounds
|
||||
auto const nulloffset { glm::vec3{} };
|
||||
auto const offset{ model_offset() };
|
||||
if( m_soundfxincrease.offset() == nulloffset ) {
|
||||
m_soundfxincrease.offset( offset );
|
||||
}
|
||||
if( m_soundfxdecrease.offset() == nulloffset ) {
|
||||
m_soundfxdecrease.offset( offset );
|
||||
}
|
||||
for( auto &soundfxrecord : m_soundfxvalues ) {
|
||||
if( soundfxrecord.second.offset() == nulloffset ) {
|
||||
soundfxrecord.second.offset( offset );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, TModel3d *md2, double mul ) {
|
||||
|
||||
@@ -355,7 +355,7 @@ enum TBrakeSystem { Individual, Pneumatic, ElectroPneumatic };
|
||||
/*podtypy hamulcow zespolonych*/
|
||||
enum TBrakeSubSystem { ss_None, ss_W, ss_K, ss_KK, ss_Hik, ss_ESt, ss_KE, ss_LSt, ss_MT, ss_Dako };
|
||||
enum TBrakeValve { NoValve, W, W_Lu_VI, W_Lu_L, W_Lu_XR, K, Kg, Kp, Kss, Kkg, Kkp, Kks, Hikg1, Hikss, Hikp1, KE, SW, EStED, NESt3, ESt3, LSt, ESt4, ESt3AL2, EP1, EP2, M483, CV1_L_TR, CV1, CV1_R, Other };
|
||||
enum TBrakeHandle { NoHandle, West, FV4a, M394, M254, FVel1, FVel6, D2, Knorr, FD1, BS2, testH, St113, MHZ_P, MHZ_T, MHZ_EN57 };
|
||||
enum TBrakeHandle { NoHandle, West, FV4a, M394, M254, FVel1, FVel6, D2, Knorr, FD1, BS2, testH, St113, MHZ_P, MHZ_T, MHZ_EN57, MHZ_K5P };
|
||||
/*typy hamulcow indywidualnych*/
|
||||
enum TLocalBrake { NoBrake, ManualBrake, PneumaticBrake, HydraulicBrake };
|
||||
/*dla osob/towar: opoznienie hamowania/odhamowania*/
|
||||
@@ -669,6 +669,7 @@ struct heat_data {
|
||||
// bool okienko { true }; // window in the engine compartment
|
||||
// system configuration
|
||||
bool auxiliary_water_circuit { false }; // cooling system has an extra water circuit
|
||||
double fan_speed { 0.075 }; // cooling fan rpm; either fraction of engine rpm, or absolute value if negative
|
||||
// heat exchange factors
|
||||
double kw { 0.35 };
|
||||
double kv { 0.6 };
|
||||
@@ -740,6 +741,7 @@ public:
|
||||
double Mred = 0.0; /*Ra: zredukowane masy wirujące; potrzebne do obliczeń hamowania*/
|
||||
double TotalMass = 0.0; /*wyliczane przez ComputeMass*/
|
||||
double HeatingPower = 0.0;
|
||||
double EngineHeatingRPM { 0.0 }; // guaranteed engine revolutions with heating enabled
|
||||
double LightPower = 0.0; /*moc pobierana na ogrzewanie/oswietlenie*/
|
||||
double BatteryVoltage = 0.0; /*Winger - baterie w elektrykach*/
|
||||
bool Battery = false; /*Czy sa zalavzone baterie*/
|
||||
|
||||
@@ -1614,7 +1614,7 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) {
|
||||
|
||||
OilPump.pressure_target = (
|
||||
enrot > 0.1 ? interpolate( minpressure, OilPump.pressure_maximum, static_cast<float>( clamp( enrot / maxrevolutions, 0.0, 1.0 ) ) ) * OilPump.resource_amount :
|
||||
true == OilPump.is_active ? minpressure :
|
||||
true == OilPump.is_active ? std::min( minpressure + 0.1f, OilPump.pressure_maximum ) : // slight pressure margin to give time to switch off the pump and start the engine
|
||||
0.f );
|
||||
|
||||
if( OilPump.pressure_present < OilPump.pressure_target ) {
|
||||
@@ -3300,7 +3300,7 @@ void TMoverParameters::CompressorCheck(double dt)
|
||||
CompressedVolume +=
|
||||
CompressorSpeed
|
||||
* ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor
|
||||
* ( DElist[ MainCtrlPos ].RPM / DElist[ MainCtrlPosNo ].RPM )
|
||||
* ( ( 60.0 * std::abs( enrot ) ) / DElist[ MainCtrlPosNo ].RPM )
|
||||
* dt;
|
||||
}
|
||||
else {
|
||||
@@ -3465,7 +3465,7 @@ void TMoverParameters::CompressorCheck(double dt)
|
||||
// the compressor is coupled with the diesel engine, engine revolutions affect the output
|
||||
if( false == CompressorGovernorLock ) {
|
||||
auto const enginefactor { (
|
||||
EngineType == DieselElectric ? ( DElist[ MainCtrlPos ].RPM / DElist[ MainCtrlPosNo ].RPM ) :
|
||||
EngineType == DieselElectric ? ( ( 60.0 * std::abs( enrot ) ) / DElist[ MainCtrlPosNo ].RPM ) :
|
||||
EngineType == DieselEngine ? ( std::abs( enrot ) / nmax ) :
|
||||
1.0 ) }; // shouldn't ever get here but, eh
|
||||
CompressedVolume +=
|
||||
@@ -4424,8 +4424,7 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
|
||||
// Q: 20160714
|
||||
// oblicza sile trakcyjna lokomotywy (dla elektrowozu tez calkowity prad)
|
||||
// *************************************************************************************************
|
||||
double TMoverParameters::TractionForce(double dt)
|
||||
{
|
||||
double TMoverParameters::TractionForce( double dt ) {
|
||||
double PosRatio, dmoment, dtrans, tmp;
|
||||
|
||||
Ft = 0;
|
||||
@@ -4441,13 +4440,15 @@ double TMoverParameters::TractionForce(double dt)
|
||||
|
||||
if( ( true == Heating )
|
||||
&& ( HeatingPower > 0 )
|
||||
&& ( MainCtrlPosNo > MainCtrlPos ) ) {
|
||||
|
||||
int i = MainCtrlPosNo;
|
||||
while( DElist[ i - 2 ].RPM / 60.0 > tmp ) {
|
||||
--i;
|
||||
}
|
||||
tmp = DElist[ i ].RPM / 60.0;
|
||||
&& ( EngineHeatingRPM > 0 ) ) {
|
||||
// bump engine revolutions up if needed, when heating is on
|
||||
tmp =
|
||||
std::max(
|
||||
tmp,
|
||||
std::min(
|
||||
DElist[ MainCtrlPosNo ].RPM,
|
||||
EngineHeatingRPM )
|
||||
/ 60.0 );
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -4577,13 +4578,35 @@ double TMoverParameters::TractionForce(double dt)
|
||||
}
|
||||
}
|
||||
|
||||
switch( EngineType ) {
|
||||
case Dumb: {
|
||||
PosRatio = ( MainCtrlPos + ScndCtrlPos ) / ( MainCtrlPosNo + ScndCtrlPosNo + 0.01 );
|
||||
EnginePower = 1000.0 * Power * PosRatio;
|
||||
break;
|
||||
}
|
||||
case DieselEngine: {
|
||||
EnginePower = ( 2 * dizel_Mstand + dmoment ) * enrot * ( 2.0 * M_PI / 1000.0 );
|
||||
if( MainCtrlPos > 1 ) {
|
||||
// dodatkowe opory z powodu sprezarki}
|
||||
dmoment -= dizel_Mstand * ( 0.2 * enrot / dizel_nmax );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DieselElectric: {
|
||||
EnginePower = 0; // the actual calculation is done in two steps later in the method
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ActiveDir != 0)
|
||||
switch (EngineType)
|
||||
{
|
||||
case Dumb:
|
||||
{
|
||||
PosRatio = (MainCtrlPos + ScndCtrlPos) / (MainCtrlPosNo + ScndCtrlPosNo + 0.01);
|
||||
if (Mains && (ActiveDir != 0) && (CabNo != 0))
|
||||
if (Mains && (CabNo != 0))
|
||||
{
|
||||
if (Vel > 0.1)
|
||||
{
|
||||
@@ -4595,7 +4618,6 @@ double TMoverParameters::TractionForce(double dt)
|
||||
}
|
||||
else
|
||||
Ft = 0;
|
||||
EnginePower = 1000.0 * Power * PosRatio;
|
||||
break;
|
||||
} // Dumb
|
||||
|
||||
@@ -4680,11 +4702,6 @@ double TMoverParameters::TractionForce(double dt)
|
||||
|
||||
case DieselEngine:
|
||||
{
|
||||
EnginePower = ( 2 * dizel_Mstand + dmoment ) * enrot * ( 2.0 * M_PI / 1000.0 );
|
||||
if( MainCtrlPos > 1 ) {
|
||||
// dodatkowe opory z powodu sprezarki}
|
||||
dmoment -= dizel_Mstand * ( 0.2 * enrot / dizel_nmax );
|
||||
}
|
||||
Mm = dmoment; //bylo * dizel_engage
|
||||
Mw = Mm * dtrans; // dmoment i dtrans policzone przy okazji enginerotation
|
||||
Fw = Mw * 2.0 / WheelDiameter / NPoweredAxles;
|
||||
@@ -4702,6 +4719,7 @@ double TMoverParameters::TractionForce(double dt)
|
||||
if( ( true == Mains ) && ( MainCtrlPos > 0 ) ) {
|
||||
Voltage = ( SST[ MainCtrlPos ].Umax * AnPos ) + ( SST[ MainCtrlPos ].Umin * ( 1.0 - AnPos ) );
|
||||
// NOTE: very crude way to approximate power generated at current rpm instead of instant top output
|
||||
// NOTE, TODO: doesn't take into account potentially increased revolutions if heating is on, fix it
|
||||
auto const rpmratio { 60.0 * enrot / DElist[ MainCtrlPos ].RPM };
|
||||
tmp = rpmratio * ( SST[ MainCtrlPos ].Pmax * AnPos ) + ( SST[ MainCtrlPos ].Pmin * ( 1.0 - AnPos ) );
|
||||
Ft = tmp * 1000.0 / ( abs( tmpV ) + 1.6 );
|
||||
@@ -4718,6 +4736,7 @@ double TMoverParameters::TractionForce(double dt)
|
||||
if( true == Heating ) { power -= HeatingPower; }
|
||||
if( power < 0.0 ) { power = 0.0; }
|
||||
// NOTE: very crude way to approximate power generated at current rpm instead of instant top output
|
||||
// NOTE, TODO: doesn't take into account potentially increased revolutions if heating is on, fix it
|
||||
auto const currentgenpower { (
|
||||
DElist[ MainCtrlPos ].RPM > 0 ?
|
||||
DElist[ MainCtrlPos ].GenPower * ( 60.0 * enrot / DElist[ MainCtrlPos ].RPM ) :
|
||||
@@ -4833,6 +4852,8 @@ double TMoverParameters::TractionForce(double dt)
|
||||
else {
|
||||
if( AutoRelayFlag ) {
|
||||
|
||||
auto const shuntfieldstate { ScndCtrlPos };
|
||||
|
||||
switch( RelayType ) {
|
||||
|
||||
case 0: {
|
||||
@@ -4978,6 +4999,10 @@ double TMoverParameters::TractionForce(double dt)
|
||||
break;
|
||||
}
|
||||
} // switch RelayType
|
||||
|
||||
if( ScndCtrlPos != shuntfieldstate ) {
|
||||
SetFlag( SoundFlag, ( sound::relay | sound::shuntfield ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -4993,9 +5018,7 @@ double TMoverParameters::TractionForce(double dt)
|
||||
}
|
||||
}
|
||||
if( true == Mains ) {
|
||||
|
||||
//tempomat
|
||||
|
||||
if (ScndCtrlPosNo > 1)
|
||||
{
|
||||
if (ScndCtrlPos != NewSpeed)
|
||||
@@ -5019,7 +5042,6 @@ double TMoverParameters::TractionForce(double dt)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dtrans = Hamulec->GetEDBCP();
|
||||
if (((DoorLeftOpened) || (DoorRightOpened)))
|
||||
DynamicBrakeFlag = true;
|
||||
@@ -5239,6 +5261,20 @@ double TMoverParameters::TractionForce(double dt)
|
||||
break;
|
||||
}
|
||||
} // case EngineType
|
||||
|
||||
switch( EngineType ) {
|
||||
case DieselElectric: {
|
||||
// rough approximation of extra effort to overcome friction etc
|
||||
auto const rpmratio{ 60.0 * enrot / DElist[ MainCtrlPosNo ].RPM };
|
||||
EnginePower += rpmratio * 0.2 * DElist[ MainCtrlPosNo ].GenPower;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Ft;
|
||||
}
|
||||
|
||||
@@ -5986,6 +6022,18 @@ bool TMoverParameters::dizel_AutoGearCheck(void)
|
||||
case 2:
|
||||
dizel_EngageSwitch(1.0);
|
||||
break;
|
||||
case 3:
|
||||
if (Vel>dizel_minVelfullengage)
|
||||
dizel_EngageSwitch(1.0);
|
||||
else
|
||||
dizel_EngageSwitch(0.5);
|
||||
break;
|
||||
case 4:
|
||||
if (Vel>dizel_minVelfullengage)
|
||||
dizel_EngageSwitch(1.0);
|
||||
else
|
||||
dizel_EngageSwitch(0.66);
|
||||
break;
|
||||
default:
|
||||
if (hydro_TC && hydro_TC_Fill>0.01)
|
||||
dizel_EngageSwitch(1.0);
|
||||
@@ -6125,6 +6173,18 @@ double TMoverParameters::dizel_fillcheck(int mcp)
|
||||
else
|
||||
nreg = dizel_nmin;
|
||||
break;
|
||||
case 3:
|
||||
if ((dizel_automaticgearstatus == 0) && (Vel > dizel_minVelfullengage))
|
||||
nreg = dizel_nmax;
|
||||
else
|
||||
nreg = dizel_nmin;
|
||||
break;
|
||||
case 4:
|
||||
if ((dizel_automaticgearstatus == 0) && (Vel > dizel_minVelfullengage))
|
||||
nreg = dizel_nmax;
|
||||
else
|
||||
nreg = dizel_nmin * 0.75 + dizel_nmax * 0.25;
|
||||
break;
|
||||
default:
|
||||
realfill = 0; // sluczaj
|
||||
break;
|
||||
@@ -6401,7 +6461,7 @@ void TMoverParameters::dizel_Heat( double const dt ) {
|
||||
&& ( dizel_heat.water_aux.config.temp_cooling > 0 )
|
||||
&& ( dizel_heat.temperatura2 > dizel_heat.water_aux.config.temp_cooling - ( dizel_heat.water_aux.is_warm ? 8 : 0 ) ) ) );
|
||||
auto const PTC2 { ( dizel_heat.water_aux.is_warm /*or PTC2p*/ ? 1 : 0 ) };
|
||||
dizel_heat.rpmwz2 = PTC2 * 80 * rpm / ( ( 0.5 * rpm ) + 500 );
|
||||
dizel_heat.rpmwz2 = PTC2 * ( dizel_heat.fan_speed >= 0 ? ( rpm * dizel_heat.fan_speed ) : ( dizel_heat.fan_speed * -1 ) );
|
||||
dizel_heat.zaluzje2 = ( dizel_heat.water_aux.config.shutters ? ( PTC2 == 1 ) : true ); // no shutters is an equivalent to having them open
|
||||
auto const zaluzje2 { ( dizel_heat.zaluzje2 ? 1 : 0 ) };
|
||||
// auxiliary water circuit heat transfer values
|
||||
@@ -6429,7 +6489,7 @@ void TMoverParameters::dizel_Heat( double const dt ) {
|
||||
&& ( dizel_heat.water.config.temp_cooling > 0 )
|
||||
&& ( dizel_heat.temperatura1 > dizel_heat.water.config.temp_cooling - ( dizel_heat.water.is_warm ? 8 : 0 ) ) ) );
|
||||
auto const PTC1 { ( dizel_heat.water.is_warm /*or PTC1p*/ ? 1 : 0 ) };
|
||||
dizel_heat.rpmwz = PTC1 * 80 * rpm / ( ( 0.5 * rpm ) + 500 );
|
||||
dizel_heat.rpmwz = PTC1 * ( dizel_heat.fan_speed >= 0 ? ( rpm * dizel_heat.fan_speed ) : ( dizel_heat.fan_speed * -1 ) );
|
||||
dizel_heat.zaluzje1 = ( dizel_heat.water.config.shutters ? ( PTC1 == 1 ) : true ); // no shutters is an equivalent to having them open
|
||||
auto const zaluzje1 { ( dizel_heat.zaluzje1 ? 1 : 0 ) };
|
||||
// primary water circuit heat transfer values
|
||||
@@ -8030,6 +8090,7 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) {
|
||||
{ "test", testH },
|
||||
{ "D2", D2 },
|
||||
{ "MHZ_EN57", MHZ_EN57 },
|
||||
{ "MHZ_K5P", MHZ_K5P },
|
||||
{ "M394", M394 },
|
||||
{ "Knorr", Knorr },
|
||||
{ "Westinghouse", West },
|
||||
@@ -8385,6 +8446,7 @@ void TMoverParameters::LoadFIZ_Engine( std::string const &Input ) {
|
||||
ImaxHi = 2;
|
||||
ImaxLo = 1;
|
||||
}
|
||||
extract_value( EngineHeatingRPM, "HeatingRPM", Input, "" );
|
||||
break;
|
||||
}
|
||||
case ElectricInductionMotor: {
|
||||
@@ -8415,8 +8477,7 @@ void TMoverParameters::LoadFIZ_Engine( std::string const &Input ) {
|
||||
extract_value( eimc[ eimc_p_eped ], "edep", Input, "" );
|
||||
extract_value( EIMCLogForce, "eimclf", Input, "" );
|
||||
|
||||
Flat = ( extract_value( "Flat", Input ) == "1" );
|
||||
|
||||
extract_value( Flat, "Flat", Input, "");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -8450,6 +8511,7 @@ void TMoverParameters::LoadFIZ_Engine( std::string const &Input ) {
|
||||
extract_value( dizel_heat.water_aux.config.shutters, "WaterAuxShutters", Input, "" );
|
||||
extract_value( dizel_heat.oil.config.temp_min, "OilMinTemperature", Input, "" );
|
||||
extract_value( dizel_heat.oil.config.temp_max, "OilMaxTemperature", Input, "" );
|
||||
extract_value( dizel_heat.fan_speed, "WaterCoolingFanSpeed", Input, "" );
|
||||
// water heater
|
||||
extract_value( WaterHeater.config.temp_min, "HeaterMinTemperature", Input, "" );
|
||||
extract_value( WaterHeater.config.temp_max, "HeaterMaxTemperature", Input, "" );
|
||||
@@ -8836,6 +8898,9 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir)
|
||||
case St113:
|
||||
Handle = std::make_shared<TSt113>();
|
||||
break;
|
||||
case MHZ_K5P:
|
||||
Handle = std::make_shared<TMHZ_K5P>();
|
||||
break;
|
||||
default:
|
||||
Handle = std::make_shared<TDriverHandle>();
|
||||
}
|
||||
@@ -9515,6 +9580,7 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
||||
else {
|
||||
OK = false;
|
||||
}
|
||||
SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||
}
|
||||
else if (Command == "Sandbox")
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ Copyright (C) 2007-2014 Maciej Cierniak
|
||||
static double const DPL = 0.25;
|
||||
double const TFV4aM::pos_table[11] = {-2, 6, -1, 0, -2, 1, 4, 6, 0, 0, 0};
|
||||
double const TMHZ_EN57::pos_table[11] = {-1, 10, -1, 0, 0, 2, 9, 10, 0, 0, 0};
|
||||
double const TMHZ_K5P::pos_table[11] = { -1, 3, -1, 0, 1, 1, 2, 3, 0, 0, 0 };
|
||||
double const TM394::pos_table[11] = {-1, 5, -1, 0, 1, 2, 4, 5, 0, 0, 0};
|
||||
double const TH14K1::BPT_K[6][2] = {{10, 0}, {4, 1}, {0, 1}, {4, 0}, {4, -1}, {15, -1}};
|
||||
double const TH14K1::pos_table[11] = {-1, 4, -1, 0, 1, 2, 3, 4, 0, 0, 0};
|
||||
@@ -2516,7 +2517,7 @@ bool TFV4aM::EQ(double pos, double i_pos)
|
||||
return (pos <= i_pos + 0.5) && (pos > i_pos - 0.5);
|
||||
}
|
||||
|
||||
//---FV4a/M--- nowonapisany kran bez poprawki IC
|
||||
//---MHZ_EN57--- manipulator hamulca zespolonego do EN57
|
||||
|
||||
double TMHZ_EN57::GetPF( double i_bcp, double PP, double HP, double dt, double ep ) {
|
||||
static int const LBDelay = 100;
|
||||
@@ -2656,6 +2657,119 @@ bool TMHZ_EN57::EQ(double pos, double i_pos)
|
||||
return (pos <= i_pos + 0.5) && (pos > i_pos - 0.5);
|
||||
}
|
||||
|
||||
//---MHZ_K5P--- manipulator hamulca zespolonego Knorr 5-ciopozycyjny
|
||||
|
||||
double TMHZ_K5P::GetPF(double i_bcp, double PP, double HP, double dt, double ep) {
|
||||
static int const LBDelay = 100;
|
||||
|
||||
double LimPP;
|
||||
double dpPipe;
|
||||
double dpMainValve;
|
||||
double ActFlowSpeed;
|
||||
double DP;
|
||||
double pom;
|
||||
|
||||
for (int idx = 0; idx < 5; ++idx) {
|
||||
Sounds[idx] = 0;
|
||||
}
|
||||
|
||||
DP = 0;
|
||||
|
||||
i_bcp = Max0R(Min0R(i_bcp, 2.999), -0.999); // na wszelki wypadek, zeby nie wyszlo poza zakres
|
||||
|
||||
if ((TP > 0))
|
||||
{
|
||||
DP = 0.004;
|
||||
TP = TP - DP * dt;
|
||||
Sounds[s_fv4a_t] = DP;
|
||||
}
|
||||
else
|
||||
{
|
||||
TP = 0;
|
||||
}
|
||||
|
||||
if (EQ(i_bcp, 1)) //odcięcie - nie rób nic
|
||||
LimPP = CP;
|
||||
else if (i_bcp > 1) //hamowanie
|
||||
LimPP = 3.4;
|
||||
else //luzowanie
|
||||
LimPP = 5.0;
|
||||
pom = CP;
|
||||
LimPP = Min0R(LimPP + TP + RedAdj, HP); // pozycja + czasowy lub zasilanie
|
||||
ActFlowSpeed = 4;
|
||||
|
||||
if ((LimPP > CP)) // podwyzszanie szybkie
|
||||
CP = CP + 9 * Min0R(abs(LimPP - CP), 0.05) * PR(CP, LimPP) * dt; // zbiornik sterujacy;
|
||||
else
|
||||
CP = CP + 9 * Min0R(abs(LimPP - CP), 0.05) * PR(CP, LimPP) * dt; // zbiornik sterujacy
|
||||
|
||||
LimPP = pom; // cp
|
||||
dpPipe = Min0R(HP, LimPP);
|
||||
|
||||
if (dpPipe > PP)
|
||||
dpMainValve = -PFVa(HP, PP, ActFlowSpeed / LBDelay, dpPipe, 0.4);
|
||||
else
|
||||
dpMainValve = PFVd(PP, 0, ActFlowSpeed / LBDelay, dpPipe, 0.4);
|
||||
|
||||
if (EQ(i_bcp, -1))
|
||||
{
|
||||
if ((TP < 1))
|
||||
TP = TP + 0.03 * dt;
|
||||
}
|
||||
|
||||
if (EQ(i_bcp, 3))
|
||||
{
|
||||
DP = PF(0, PP, 2 * ActFlowSpeed / LBDelay);
|
||||
dpMainValve = DP;
|
||||
Sounds[s_fv4a_e] = DP;
|
||||
Sounds[s_fv4a_u] = 0;
|
||||
Sounds[s_fv4a_b] = 0;
|
||||
Sounds[s_fv4a_x] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dpMainValve > 0)
|
||||
Sounds[s_fv4a_b] = dpMainValve;
|
||||
else
|
||||
Sounds[s_fv4a_u] = -dpMainValve;
|
||||
}
|
||||
|
||||
return dpMainValve * dt;
|
||||
}
|
||||
|
||||
void TMHZ_K5P::Init(double Press)
|
||||
{
|
||||
CP = Press;
|
||||
}
|
||||
|
||||
void TMHZ_K5P::SetReductor(double nAdj)
|
||||
{
|
||||
RedAdj = nAdj;
|
||||
}
|
||||
|
||||
double TMHZ_K5P::GetSound(int i)
|
||||
{
|
||||
if (i > 4)
|
||||
return 0;
|
||||
else
|
||||
return Sounds[i];
|
||||
}
|
||||
|
||||
double TMHZ_K5P::GetPos(int i)
|
||||
{
|
||||
return pos_table[i];
|
||||
}
|
||||
|
||||
double TMHZ_K5P::GetCP()
|
||||
{
|
||||
return RP;
|
||||
}
|
||||
|
||||
bool TMHZ_K5P::EQ(double pos, double i_pos)
|
||||
{
|
||||
return (pos <= i_pos + 0.5) && (pos > i_pos - 0.5);
|
||||
}
|
||||
|
||||
//---M394--- Matrosow
|
||||
|
||||
double TM394::GetPF(double i_bcp, double PP, double HP, double dt, double ep)
|
||||
|
||||
@@ -591,6 +591,31 @@ class TMHZ_EN57 : public TDriverHandle {
|
||||
{}
|
||||
};
|
||||
|
||||
class TMHZ_K5P : public TDriverHandle {
|
||||
|
||||
private:
|
||||
double CP = 0.0; //zbiornik sterujący
|
||||
double TP = 0.0; //zbiornik czasowy
|
||||
double RP = 0.0; //zbiornik redukcyjny
|
||||
double RedAdj = 0.0; //dostosowanie reduktora cisnienia (krecenie kapturkiem)
|
||||
bool Fala = false;
|
||||
static double const pos_table[11]; //= { -2, 10, -1, 0, 0, 2, 9, 10, 0, 0, 0 };
|
||||
|
||||
bool EQ(double pos, double i_pos);
|
||||
|
||||
public:
|
||||
double GetPF(double i_bcp, double PP, double HP, double dt, double ep)/*override*/;
|
||||
void Init(double Press)/*override*/;
|
||||
void SetReductor(double nAdj)/*override*/;
|
||||
double GetSound(int i)/*override*/;
|
||||
double GetPos(int i)/*override*/;
|
||||
double GetCP()/*override*/;
|
||||
|
||||
inline TMHZ_K5P(void) :
|
||||
TDriverHandle()
|
||||
{}
|
||||
};
|
||||
|
||||
/* FBS2= class(TTDriverHandle)
|
||||
private
|
||||
CP, TP, RP: real; //zbiornik sterujący, czasowy, redukcyjny
|
||||
|
||||
35
MemCell.cpp
35
MemCell.cpp
@@ -162,6 +162,41 @@ void TMemCell::AssignEvents(TEvent *e)
|
||||
OnSent = e;
|
||||
};
|
||||
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void
|
||||
TMemCell::serialize_( std::ostream &Output ) const {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void
|
||||
TMemCell::deserialize_( std::istream &Input ) {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
TMemCell::export_as_text_( std::ostream &Output ) const {
|
||||
// header
|
||||
Output << "memcell ";
|
||||
// location
|
||||
Output
|
||||
<< location().x << ' '
|
||||
<< location().y << ' '
|
||||
<< location().z << ' '
|
||||
// cell data
|
||||
<< szText << ' '
|
||||
<< fValue1 << ' '
|
||||
<< fValue2 << ' '
|
||||
// associated track
|
||||
<< ( asTrackName.empty() ? "none" : asTrackName ) << ' '
|
||||
// footer
|
||||
<< "endmemcell"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// legacy method, initializes traction after deserialization from scenario file
|
||||
|
||||
12
MemCell.h
12
MemCell.h
@@ -13,10 +13,11 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "scenenode.h"
|
||||
#include "Names.h"
|
||||
|
||||
class TMemCell : public editor::basic_node {
|
||||
class TMemCell : public scene::basic_node {
|
||||
|
||||
public:
|
||||
std::string asTrackName; // McZapkie-100302 - zeby nazwe toru na ktory jest Putcommand wysylane pamietac
|
||||
bool is_exportable { true }; // export helper; autogenerated cells don't need to be exported
|
||||
|
||||
explicit TMemCell( scene::node_data const &Nodedata );
|
||||
|
||||
@@ -49,6 +50,15 @@ public:
|
||||
void AssignEvents(TEvent *e);
|
||||
|
||||
private:
|
||||
// methods
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void serialize_( std::ostream &Output ) const;
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void deserialize_( std::istream &Input );
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void export_as_text_( std::ostream &Output ) const;
|
||||
|
||||
// members
|
||||
// content
|
||||
std::string szText;
|
||||
double fValue1 { 0.0 };
|
||||
|
||||
@@ -1252,8 +1252,6 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic)
|
||||
LoadFromBinFile(asBinary, dynamic);
|
||||
asBinary = ""; // wyłączenie zapisu
|
||||
Init();
|
||||
// cache the file name, in case someone wants it later
|
||||
m_filename = name + ".e3d";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1264,10 +1262,10 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic)
|
||||
// pojazdy dopiero po ustawieniu animacji
|
||||
Init(); // generowanie siatek i zapis E3D
|
||||
}
|
||||
}
|
||||
}
|
||||
// cache the file name, in case someone wants it later
|
||||
m_filename = name + ".t3d";
|
||||
}
|
||||
}
|
||||
m_filename = name;
|
||||
bool const result =
|
||||
Root ? (iSubModelsCount > 0) : false; // brak pliku albo problem z wczytaniem
|
||||
if (false == result)
|
||||
|
||||
3
Names.h
3
Names.h
@@ -63,5 +63,8 @@ public:
|
||||
type_sequence &
|
||||
sequence() {
|
||||
return m_items; }
|
||||
type_sequence const &
|
||||
sequence() const {
|
||||
return m_items; }
|
||||
|
||||
};
|
||||
|
||||
62
Segment.cpp
62
Segment.cpp
@@ -18,8 +18,36 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// 101206 Ra: trapezoidalne drogi
|
||||
// 110806 Ra: odwrócone mapowanie wzdłuż - Point1 == 1.0
|
||||
// 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
|
||||
Math3D::vector3 LoadPoint( cParser &Input ) {
|
||||
// pobranie współrzędnych punktu
|
||||
Input.getTokens( 3 );
|
||||
Math3D::vector3 point;
|
||||
Input
|
||||
>> point.x
|
||||
>> point.y
|
||||
>> point.z;
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
segment_data::deserialize( cParser &Input, Math3D::vector3 const &Offset ) {
|
||||
|
||||
points[ segment_data::point::start ] = LoadPoint( Input ) + Offset;
|
||||
Input.getTokens();
|
||||
Input >> rolls[ 0 ];
|
||||
points[ segment_data::point::control1 ] = LoadPoint( Input );
|
||||
points[ segment_data::point::control2 ] = LoadPoint( Input );
|
||||
points[ segment_data::point::end ] = LoadPoint( Input ) + Offset;
|
||||
Input.getTokens( 2 );
|
||||
Input
|
||||
>> rolls[ 1 ]
|
||||
>> radius;
|
||||
}
|
||||
|
||||
|
||||
TSegment::TSegment(TTrack *owner) :
|
||||
pOwner( owner )
|
||||
@@ -62,6 +90,7 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
|
||||
// poprawienie przechyłki
|
||||
fRoll1 = glm::radians(fNewRoll1); // Ra: przeliczone jest bardziej przydatne do obliczeń
|
||||
fRoll2 = glm::radians(fNewRoll2);
|
||||
bCurve = bIsCurve;
|
||||
if (Global.bRollFix)
|
||||
{ // Ra: poprawianie przechyłki
|
||||
// Przechyłka powinna być na środku wewnętrznej szyny, a standardowo jest w osi
|
||||
@@ -91,7 +120,6 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
|
||||
// kąt w planie, żeby nie liczyć wielokrotnie
|
||||
// Ra: ten kąt jeszcze do przemyślenia jest
|
||||
fDirection = -std::atan2(Point2.x - Point1.x, Point2.z - Point1.z);
|
||||
bCurve = bIsCurve;
|
||||
if (bCurve)
|
||||
{ // przeliczenie współczynników wielomianu, będzie mniej mnożeń i można policzyć pochodne
|
||||
vC = 3.0 * (CPointOut - Point1); // t^1
|
||||
@@ -99,9 +127,9 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
|
||||
vA = Point2 - Point1 - vC - vB; // t^3
|
||||
fLength = ComputeLength();
|
||||
}
|
||||
else
|
||||
fLength = (Point1 - Point2).Length();
|
||||
fStep = fNewStep;
|
||||
else {
|
||||
fLength = ( Point1 - Point2 ).Length();
|
||||
}
|
||||
if (fLength <= 0) {
|
||||
|
||||
ErrorLog( "Bad track: zero length spline \"" + pOwner->name() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
|
||||
@@ -111,17 +139,25 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
|
||||
*/
|
||||
}
|
||||
|
||||
if( ( pOwner->eType == tt_Switch )
|
||||
&& ( fStep * 3.0 > fLength ) ) {
|
||||
// NOTE: a workaround for too short switches (less than 3 segments) messing up animation/generation of blades
|
||||
fStep = fLength / 3.0;
|
||||
}
|
||||
|
||||
fStoop = std::atan2((Point2.y - Point1.y), fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie
|
||||
SafeDeleteArray(fTsBuffer);
|
||||
|
||||
fStep = fNewStep;
|
||||
// NOTE: optionally replace this part with the commented version, after solving geometry issues with double switches
|
||||
if( ( pOwner->eType == tt_Switch )
|
||||
&& ( fStep * ( 3.0 * Global.SplineFidelity ) > fLength ) ) {
|
||||
// NOTE: a workaround for too short switches (less than 3 segments) messing up animation/generation of blades
|
||||
fStep = fLength / ( 3.0 * Global.SplineFidelity );
|
||||
}
|
||||
iSegCount = static_cast<int>( std::ceil( fLength / fStep ) ); // potrzebne do VBO
|
||||
/*
|
||||
iSegCount = (
|
||||
pOwner->eType == tt_Switch ?
|
||||
6 * Global.SplineFidelity :
|
||||
static_cast<int>( std::ceil( fLength / fStep ) ) ); // potrzebne do VBO
|
||||
*/
|
||||
fStep = fLength / iSegCount; // update step to equalize size of individual pieces
|
||||
|
||||
SafeDeleteArray( fTsBuffer );
|
||||
fTsBuffer = new double[ iSegCount + 1 ];
|
||||
fTsBuffer[ 0 ] = 0.0;
|
||||
for( int i = 1; i < iSegCount; ++i ) {
|
||||
|
||||
18
Segment.h
18
Segment.h
@@ -14,6 +14,24 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "openglgeometrybank.h"
|
||||
#include "utilities.h"
|
||||
|
||||
struct segment_data {
|
||||
// types
|
||||
enum point {
|
||||
start = 0,
|
||||
control1,
|
||||
control2,
|
||||
end
|
||||
};
|
||||
// members
|
||||
std::array<glm::dvec3, 4> points {};
|
||||
std::array<float, 2> rolls {};
|
||||
float radius {};
|
||||
// constructors
|
||||
segment_data() = default;
|
||||
// methods
|
||||
void deserialize( cParser &Input, Math3D::vector3 const &Offset );
|
||||
};
|
||||
|
||||
class TSegment
|
||||
{ // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny)
|
||||
private:
|
||||
|
||||
76
Texture.cpp
76
Texture.cpp
@@ -823,55 +823,22 @@ texture_manager::create( std::string Filename, bool const Loadnow ) {
|
||||
Filename.erase( 0, 1 );
|
||||
}
|
||||
|
||||
std::vector<std::string> extensions{ { ".dds" }, { ".tga" }, { ".png" }, { ".bmp" }, { ".ext" } };
|
||||
|
||||
// try to locate requested texture in the databank
|
||||
auto lookup = find_in_databank( Filename + Global.szDefaultExt );
|
||||
auto lookup { find_in_databank( Filename ) };
|
||||
if( lookup != npos ) {
|
||||
// start with the default extension...
|
||||
return lookup;
|
||||
}
|
||||
else {
|
||||
// ...then try recognized file extensions other than default
|
||||
for( auto const &extension : extensions ) {
|
||||
|
||||
if( extension == Global.szDefaultExt ) {
|
||||
// we already tried this one
|
||||
continue;
|
||||
}
|
||||
lookup = find_in_databank( Filename + extension );
|
||||
if( lookup != npos ) {
|
||||
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we don't have the texture in the databank, check if it's on disk
|
||||
std::string filename = find_on_disk( Filename + Global.szDefaultExt );
|
||||
if( true == filename.empty() ) {
|
||||
// if the default lookup fails, try other known extensions
|
||||
for( auto const &extension : extensions ) {
|
||||
auto const disklookup { find_on_disk( Filename ) };
|
||||
|
||||
if( extension == Global.szDefaultExt ) {
|
||||
// we already tried this one
|
||||
continue;
|
||||
}
|
||||
filename = find_on_disk( Filename + extension );
|
||||
if( false == filename.empty() ) {
|
||||
// we found something, don't bother with others
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( true == filename.empty() ) {
|
||||
if( true == disklookup.first.empty() ) {
|
||||
// there's nothing matching in the databank nor on the disk, report failure
|
||||
ErrorLog( "Bad file: failed do locate texture file \"" + Filename + "\"", logtype::file );
|
||||
return npos;
|
||||
}
|
||||
|
||||
auto texture = new opengl_texture();
|
||||
texture->name = filename;
|
||||
texture->name = disklookup.first + disklookup.second;
|
||||
if( Filename.find('#') != std::string::npos ) {
|
||||
// temporary code for legacy assets -- textures with names beginning with # are to be sharpened
|
||||
traits += '#';
|
||||
@@ -879,9 +846,9 @@ texture_manager::create( std::string Filename, bool const Loadnow ) {
|
||||
texture->traits = traits;
|
||||
auto const textureindex = (texture_handle)m_textures.size();
|
||||
m_textures.emplace_back( texture, std::chrono::steady_clock::time_point() );
|
||||
m_texturemappings.emplace( filename, textureindex );
|
||||
m_texturemappings.emplace( disklookup.first, textureindex );
|
||||
|
||||
WriteLog( "Created texture object for \"" + filename + "\"", logtype::texture );
|
||||
WriteLog( "Created texture object for \"" + disklookup.first + disklookup.second + "\"", logtype::texture );
|
||||
|
||||
if( true == Loadnow ) {
|
||||
|
||||
@@ -998,7 +965,7 @@ texture_manager::info() const {
|
||||
texture_handle
|
||||
texture_manager::find_in_databank( std::string const &Texturename ) const {
|
||||
|
||||
std::vector<std::string> filenames {
|
||||
std::vector<std::string> const filenames {
|
||||
Global.asCurrentTexturePath + Texturename,
|
||||
Texturename,
|
||||
szTexturePath + Texturename };
|
||||
@@ -1009,19 +976,34 @@ texture_manager::find_in_databank( std::string const &Texturename ) const {
|
||||
return lookup->second;
|
||||
}
|
||||
}
|
||||
|
||||
// all lookups failed
|
||||
return npos;
|
||||
}
|
||||
|
||||
// checks whether specified file exists.
|
||||
std::string
|
||||
std::pair<std::string, std::string>
|
||||
texture_manager::find_on_disk( std::string const &Texturename ) const {
|
||||
|
||||
return(
|
||||
FileExists( Global.asCurrentTexturePath + Texturename ) ? Global.asCurrentTexturePath + Texturename :
|
||||
FileExists( Texturename ) ? Texturename :
|
||||
FileExists( szTexturePath + Texturename ) ? szTexturePath + Texturename :
|
||||
"" );
|
||||
std::vector<std::string> const filenames {
|
||||
Global.asCurrentTexturePath + Texturename,
|
||||
Texturename,
|
||||
szTexturePath + Texturename };
|
||||
|
||||
auto lookup =
|
||||
FileExists(
|
||||
filenames,
|
||||
{ Global.szDefaultExt } );
|
||||
|
||||
if( false == lookup.first.empty() ) {
|
||||
return lookup;
|
||||
}
|
||||
|
||||
// if the first attempt fails, try entire extension list
|
||||
// NOTE: slightly wasteful as it means preferred extension is tested twice, but, eh
|
||||
return (
|
||||
FileExists(
|
||||
filenames,
|
||||
{ ".dds", ".tga", ".bmp", ".ext" } ) );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -20,6 +20,8 @@ struct opengl_texture {
|
||||
static DDPIXELFORMAT deserialize_ddpf(std::istream&);
|
||||
static DDSCAPS2 deserialize_ddscaps(std::istream&);
|
||||
|
||||
// constructors
|
||||
opengl_texture() = default;
|
||||
// methods
|
||||
void
|
||||
load();
|
||||
@@ -120,7 +122,7 @@ private:
|
||||
texture_handle
|
||||
find_in_databank( std::string const &Texturename ) const;
|
||||
// checks whether specified file exists. returns name of the located file, or empty string.
|
||||
std::string
|
||||
std::pair<std::string, std::string>
|
||||
find_on_disk( std::string const &Texturename ) const;
|
||||
void
|
||||
delete_textures();
|
||||
|
||||
641
Track.cpp
641
Track.cpp
@@ -345,14 +345,6 @@ void TTrack::ConnectNextNext(TTrack *pTrack, int typ)
|
||||
}
|
||||
}
|
||||
|
||||
Math3D::vector3 LoadPoint(cParser *parser)
|
||||
{ // pobranie współrzędnych punktu
|
||||
Math3D::vector3 p;
|
||||
parser->getTokens(3);
|
||||
*parser >> p.x >> p.y >> p.z;
|
||||
return p;
|
||||
}
|
||||
|
||||
void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
{ // pobranie obiektu trajektorii ruchu
|
||||
Math3D::vector3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań
|
||||
@@ -475,20 +467,44 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
WriteLog("unvis");
|
||||
Init(); // ustawia SwitchExtension
|
||||
double segsize = 5.0; // długość odcinka segmentowania
|
||||
switch (eType)
|
||||
{ // Ra: łuki segmentowane co 5m albo 314-kątem foremnym
|
||||
case tt_Table: // obrotnica jest prawie jak zwykły tor
|
||||
|
||||
// path data
|
||||
// all subtypes contain at least one path
|
||||
m_paths.emplace_back();
|
||||
m_paths.back().deserialize( *parser, pOrigin );
|
||||
switch( eType ) {
|
||||
case tt_Switch:
|
||||
case tt_Cross:
|
||||
case tt_Tributary: {
|
||||
// these subtypes contain additional path
|
||||
m_paths.emplace_back();
|
||||
m_paths.back().deserialize( *parser, pOrigin );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (eType) {
|
||||
// Ra: łuki segmentowane co 5m albo 314-kątem foremnym
|
||||
case tt_Table: {
|
||||
// obrotnica jest prawie jak zwykły tor
|
||||
iAction |= 2; // flaga zmiany położenia typu obrotnica
|
||||
case tt_Normal:
|
||||
p1 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P1
|
||||
parser->getTokens();
|
||||
*parser >> r1; // pobranie przechyłki w P1
|
||||
cp1 = LoadPoint(parser); // pobranie współrzędnych punktów kontrolnych
|
||||
cp2 = LoadPoint(parser);
|
||||
p2 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P2
|
||||
parser->getTokens(2);
|
||||
*parser >> r2 >> fRadius; // pobranie przechyłki w P1 i promienia
|
||||
fRadius = fabs(fRadius); // we wpisie może być ujemny
|
||||
}
|
||||
case tt_Normal: {
|
||||
// pobranie współrzędnych P1
|
||||
auto const &path { m_paths[ 0 ] };
|
||||
p1 = path.points[ segment_data::point::start ];
|
||||
// pobranie współrzędnych punktów kontrolnych
|
||||
cp1 = path.points[ segment_data::point::control1 ];
|
||||
cp2 = path.points[ segment_data::point::control2 ];
|
||||
// pobranie współrzędnych P2
|
||||
p2 = path.points[ segment_data::point::end ];
|
||||
r1 = path.rolls[ 0 ];
|
||||
r2 = path.rolls[ 1 ];
|
||||
fRadius = std::abs( path.radius ); // we wpisie może być ujemny
|
||||
|
||||
if (iCategoryFlag & 1)
|
||||
{ // zero na główce szyny
|
||||
p1.y += 0.18;
|
||||
@@ -504,7 +520,11 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
|
||||
if( fRadius != 0 ) {
|
||||
// gdy podany promień
|
||||
segsize = clamp( std::abs( fRadius ) * ( 0.02 / Global.SplineFidelity ), 2.0 / Global.SplineFidelity, 10.0 );
|
||||
segsize =
|
||||
clamp(
|
||||
std::abs( fRadius ) * ( 0.02 / Global.SplineFidelity ),
|
||||
2.0 / Global.SplineFidelity,
|
||||
10.0 / Global.SplineFidelity );
|
||||
}
|
||||
else {
|
||||
// HACK: crude check whether claimed straight is an actual straight piece
|
||||
@@ -514,7 +534,11 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
}
|
||||
else {
|
||||
// HACK: divide roughly in 10 segments.
|
||||
segsize = clamp( ( p1 - p2 ).Length() * ( 0.1 / Global.SplineFidelity ), 2.0 / Global.SplineFidelity, 10.0 );
|
||||
segsize =
|
||||
clamp(
|
||||
( p1 - p2 ).Length() * 0.1,
|
||||
2.0 / Global.SplineFidelity,
|
||||
10.0 / Global.SplineFidelity );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,6 +555,7 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
|
||||
if ((r1 != 0) || (r2 != 0))
|
||||
iTrapezoid = 1; // są przechyłki do uwzględniania w rysowaniu
|
||||
|
||||
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
|
||||
@@ -551,56 +576,92 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
fTexRatio2 = w / h; // proporcja boków
|
||||
}
|
||||
break;
|
||||
|
||||
case tt_Cross: // skrzyżowanie dróg - 4 punkty z wektorami kontrolnymi
|
||||
segsize = 1.0; // specjalne segmentowanie ze względu na małe promienie
|
||||
}
|
||||
case tt_Cross: {
|
||||
// skrzyżowanie dróg - 4 punkty z wektorami kontrolnymi
|
||||
// segsize = 1.0; // specjalne segmentowanie ze względu na małe promienie
|
||||
}
|
||||
case tt_Tributary: // dopływ
|
||||
case tt_Switch: // zwrotnica
|
||||
case tt_Switch: { // zwrotnica
|
||||
iAction |= 1; // flaga zmiany położenia typu zwrotnica lub skrzyżowanie dróg
|
||||
// problemy z animacją iglic powstaje, gdzy odcinek prosty ma zmienną przechyłkę
|
||||
// wtedy dzieli się na dodatkowe odcinki (po 0.2m, bo R=0) i animację diabli biorą
|
||||
// Ra: na razie nie podejmuję się przerabiania iglic
|
||||
|
||||
// SwitchExtension=new TSwitchExtension(this,eType==tt_Cross?6:2); //zwrotnica ma doklejkę
|
||||
auto const &path { m_paths[ 0 ] };
|
||||
p1 = path.points[ segment_data::point::start ];
|
||||
// pobranie współrzędnych punktów kontrolnych
|
||||
cp1 = path.points[ segment_data::point::control1 ];
|
||||
cp2 = path.points[ segment_data::point::control2 ];
|
||||
// pobranie współrzędnych P2
|
||||
p2 = path.points[ segment_data::point::end ];
|
||||
r1 = path.rolls[ 0 ];
|
||||
r2 = path.rolls[ 1 ];
|
||||
fRadiusTable[0] = std::abs( path.radius ); // we wpisie może być ujemny
|
||||
|
||||
p1 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P1
|
||||
parser->getTokens();
|
||||
*parser >> r1;
|
||||
cp1 = LoadPoint(parser);
|
||||
cp2 = LoadPoint(parser);
|
||||
p2 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P2
|
||||
parser->getTokens(2);
|
||||
*parser >> r2 >> fRadiusTable[0];
|
||||
fRadiusTable[0] = fabs(fRadiusTable[0]); // we wpisie może być ujemny
|
||||
if (iCategoryFlag & 1)
|
||||
{ // zero na główce szyny
|
||||
p1.y += 0.18;
|
||||
p2.y += 0.18;
|
||||
// na przechyłce doliczyć jeszcze pół przechyłki?
|
||||
}
|
||||
if (fRadiusTable[0] > 0)
|
||||
segsize = clamp( 0.2 + fRadiusTable[0] * 0.02, 2.0, 5.0 );
|
||||
else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne
|
||||
{ // jak promień zerowy, to przeliczamy punkty kontrolne
|
||||
cp1 = (p1 + p1 + p2) / 3.0 - p1; // jak jest prosty, to się zoptymalizuje
|
||||
cp2 = (p1 + p2 + p2) / 3.0 - p2;
|
||||
segsize = 5.0;
|
||||
} // ułomny prosty
|
||||
|
||||
if (!(cp1 == Math3D::vector3(0, 0, 0)) && !(cp2 == Math3D::vector3(0, 0, 0)))
|
||||
SwitchExtension->Segments[0]->Init(p1, p1 + cp1, p2 + cp2, p2, segsize, r1, r2);
|
||||
else
|
||||
SwitchExtension->Segments[0]->Init(p1, p2, segsize, r1, r2);
|
||||
if( eType != tt_Cross ) {
|
||||
// dla skrzyżowań muszą być podane kontrolne
|
||||
if( ( ( ( p1 + p1 + p2 ) / 3.0 - p1 - cp1 ).Length() < 0.02 )
|
||||
|| ( ( ( p1 + p2 + p2 ) / 3.0 - p2 + cp1 ).Length() < 0.02 ) ) {
|
||||
// "prostowanie" prostych z kontrolnymi, dokładność 2cm
|
||||
cp1 = cp2 = Math3D::vector3( 0, 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if( fRadiusTable[ 0 ] != 0 ) {
|
||||
// gdy podany promień
|
||||
segsize =
|
||||
clamp(
|
||||
std::abs( fRadiusTable[ 0 ] ) * ( 0.02 / Global.SplineFidelity ),
|
||||
2.0 / Global.SplineFidelity,
|
||||
10.0 / Global.SplineFidelity );
|
||||
}
|
||||
else {
|
||||
// HACK: crude check whether claimed straight is an actual straight piece
|
||||
if( ( cp1 == Math3D::vector3() )
|
||||
&& ( cp2 == Math3D::vector3() ) ) {
|
||||
segsize = 10.0; // for straights, 10m per segment works good enough
|
||||
}
|
||||
else {
|
||||
// HACK: divide roughly in 10 segments.
|
||||
segsize =
|
||||
clamp(
|
||||
( p1 - p2 ).Length() * 0.1,
|
||||
2.0 / Global.SplineFidelity,
|
||||
10.0 / Global.SplineFidelity );
|
||||
}
|
||||
}
|
||||
|
||||
if( ( cp1 == Math3D::vector3( 0, 0, 0 ) )
|
||||
&& ( cp2 == Math3D::vector3( 0, 0, 0 ) ) ) {
|
||||
// Ra: hm, czasem dla prostego są podane...
|
||||
// gdy prosty, kontrolne wyliczane przy zmiennej przechyłce
|
||||
SwitchExtension->Segments[ 0 ]->Init( p1, p2, segsize, r1, r2 );
|
||||
}
|
||||
else {
|
||||
// gdy łuk (ustawia bCurve=true)
|
||||
SwitchExtension->Segments[ 0 ]->Init( p1, cp1 + p1, cp2 + p2, p2, segsize, r1, r2 );
|
||||
}
|
||||
|
||||
auto const &path2 { m_paths[ 1 ] };
|
||||
p3 = path2.points[ segment_data::point::start ];
|
||||
// pobranie współrzędnych punktów kontrolnych
|
||||
cp3 = path2.points[ segment_data::point::control1 ];
|
||||
cp4 = path2.points[ segment_data::point::control2 ];
|
||||
// pobranie współrzędnych P2
|
||||
p4 = path2.points[ segment_data::point::end ];
|
||||
r3 = path2.rolls[ 0 ];
|
||||
r4 = path2.rolls[ 1 ];
|
||||
fRadiusTable[1] = std::abs( path2.radius ); // we wpisie może być ujemny
|
||||
|
||||
p3 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P3
|
||||
parser->getTokens();
|
||||
*parser >> r3;
|
||||
cp3 = LoadPoint(parser);
|
||||
cp4 = LoadPoint(parser);
|
||||
p4 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P4
|
||||
parser->getTokens(2);
|
||||
*parser >> r4 >> fRadiusTable[1];
|
||||
fRadiusTable[1] = fabs(fRadiusTable[1]); // we wpisie może być ujemny
|
||||
if (iCategoryFlag & 1)
|
||||
{ // zero na główce szyny
|
||||
p3.y += 0.18;
|
||||
@@ -608,25 +669,54 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
// na przechyłce doliczyć jeszcze pół przechyłki?
|
||||
}
|
||||
|
||||
if (fRadiusTable[1] > 0)
|
||||
segsize = clamp( 0.2 + fRadiusTable[ 1 ] * 0.02, 2.0, 5.0 );
|
||||
|
||||
else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne
|
||||
{ // jak promień zerowy, to przeliczamy punkty kontrolne
|
||||
cp3 = (p3 + p3 + p4) / 3.0 - p3; // jak jest prosty, to się zoptymalizuje
|
||||
cp4 = (p3 + p4 + p4) / 3.0 - p4;
|
||||
segsize = 5.0;
|
||||
} // ułomny prosty
|
||||
|
||||
if (!(cp3 == Math3D::vector3(0, 0, 0)) && !(cp4 == Math3D::vector3(0, 0, 0)))
|
||||
{ // dla skrzyżowania dróg dać odwrotnie końce, żeby brzegi generować lewym
|
||||
if (eType != tt_Cross)
|
||||
SwitchExtension->Segments[1]->Init(p3, p3 + cp3, p4 + cp4, p4, segsize, r3, r4);
|
||||
else
|
||||
SwitchExtension->Segments[1]->Init(p4, p4 + cp4, p3 + cp3, p3, segsize, r4, r3); // odwrócony
|
||||
if( eType != tt_Cross ) {
|
||||
// dla skrzyżowań muszą być podane kontrolne
|
||||
if( ( ( ( p3 + p3 + p4 ) / 3.0 - p3 - cp3 ).Length() < 0.02 )
|
||||
|| ( ( ( p3 + p4 + p4 ) / 3.0 - p4 + cp3 ).Length() < 0.02 ) ) {
|
||||
// "prostowanie" prostych z kontrolnymi, dokładność 2cm
|
||||
cp3 = cp4 = Math3D::vector3( 0, 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if( fRadiusTable[ 1 ] != 0 ) {
|
||||
// gdy podany promień
|
||||
segsize =
|
||||
clamp(
|
||||
std::abs( fRadiusTable[ 1 ] ) * ( 0.02 / Global.SplineFidelity ),
|
||||
2.0 / Global.SplineFidelity,
|
||||
10.0 / Global.SplineFidelity );
|
||||
}
|
||||
else {
|
||||
// HACK: crude check whether claimed straight is an actual straight piece
|
||||
if( ( cp3 == Math3D::vector3() )
|
||||
&& ( cp4 == Math3D::vector3() ) ) {
|
||||
segsize = 10.0; // for straights, 10m per segment works good enough
|
||||
}
|
||||
else {
|
||||
// HACK: divide roughly in 10 segments.
|
||||
segsize =
|
||||
clamp(
|
||||
( p3 - p4 ).Length() * 0.1,
|
||||
2.0 / Global.SplineFidelity,
|
||||
10.0 / Global.SplineFidelity );
|
||||
}
|
||||
}
|
||||
|
||||
if( ( cp3 == Math3D::vector3( 0, 0, 0 ) )
|
||||
&& ( cp4 == Math3D::vector3( 0, 0, 0 ) ) ) {
|
||||
// Ra: hm, czasem dla prostego są podane...
|
||||
// gdy prosty, kontrolne wyliczane przy zmiennej przechyłce
|
||||
SwitchExtension->Segments[ 1 ]->Init( p3, p4, segsize, r3, r4 );
|
||||
}
|
||||
else {
|
||||
if( eType != tt_Cross ) {
|
||||
SwitchExtension->Segments[ 1 ]->Init( p3, p3 + cp3, p4 + cp4, p4, segsize, r3, r4 );
|
||||
}
|
||||
else {
|
||||
// dla skrzyżowania dróg dać odwrotnie końce, żeby brzegi generować lewym
|
||||
SwitchExtension->Segments[ 1 ]->Init( p4, p4 + cp4, p3 + cp3, p3, segsize, r4, r3 ); // odwrócony
|
||||
}
|
||||
}
|
||||
else
|
||||
SwitchExtension->Segments[1]->Init(p3, p4, segsize, r3, r4);
|
||||
|
||||
if (eType == tt_Cross)
|
||||
{ // Ra 2014-07: dla skrzyżowań będą dodatkowe segmenty
|
||||
@@ -648,10 +738,10 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
{
|
||||
Math3D::vector3 v1, v2;
|
||||
double a1, a2;
|
||||
v1 = SwitchExtension->Segments[0]->FastGetPoint_1() -
|
||||
SwitchExtension->Segments[0]->FastGetPoint_0();
|
||||
v2 = SwitchExtension->Segments[1]->FastGetPoint_1() -
|
||||
SwitchExtension->Segments[1]->FastGetPoint_0();
|
||||
v1 = SwitchExtension->Segments[0]->FastGetPoint_1()
|
||||
- SwitchExtension->Segments[0]->FastGetPoint_0();
|
||||
v2 = SwitchExtension->Segments[1]->FastGetPoint_1()
|
||||
- SwitchExtension->Segments[1]->FastGetPoint_0();
|
||||
a1 = atan2(v1.x, v1.z);
|
||||
a2 = atan2(v2.x, v2.z);
|
||||
a2 = a2 - a1;
|
||||
@@ -663,6 +753,9 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// optional attributes
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
str = token;
|
||||
@@ -672,46 +765,46 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
asEvent0Name = token;
|
||||
m_events0.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "event1")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
asEvent1Name = token;
|
||||
m_events1.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "event2")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
asEvent2Name = token;
|
||||
m_events2.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "eventall0")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
asEventall0Name = token;
|
||||
m_events0all.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "eventall1")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
asEventall1Name = token;
|
||||
m_events1all.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "eventall2")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
asEventall2Name = token;
|
||||
m_events2all.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "velocity")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> fVelocity; //*0.28; McZapkie-010602
|
||||
if (SwitchExtension) // jeśli tor ruchomy
|
||||
if (std::fabs(fVelocity) >= 1.0) //żeby zero nie ograniczało dożywotnio
|
||||
SwitchExtension->fVelocity = static_cast<float>(fVelocity); // zapamiętanie głównego ograniczenia; a
|
||||
// np. -40 ogranicza tylko na bok
|
||||
if (std::abs(fVelocity) >= 1.0) //żeby zero nie ograniczało dożywotnio
|
||||
// zapamiętanie głównego ograniczenia; a np. -40 ogranicza tylko na bok
|
||||
SwitchExtension->fVelocity = static_cast<float>(fVelocity);
|
||||
}
|
||||
else if (str == "isolated")
|
||||
{ // obwód izolowany, do którego tor należy
|
||||
@@ -778,127 +871,44 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
/ 3.0 } );
|
||||
}
|
||||
|
||||
// TODO: refactor this mess
|
||||
bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2)
|
||||
{
|
||||
bool bError = false;
|
||||
bool TTrack::AssignEvents() {
|
||||
|
||||
if( NewEvent0 == nullptr ) {
|
||||
if( false == asEvent0Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
bool lookupfail { false };
|
||||
|
||||
std::vector< std::pair< std::string, event_sequence * > > const eventsequences {
|
||||
{ "event0", &m_events0 }, { "eventall0", &m_events0all },
|
||||
{ "event1", &m_events1 }, { "eventall1", &m_events1all },
|
||||
{ "event2", &m_events2 }, { "eventall2", &m_events2all } };
|
||||
|
||||
for( auto &eventsequence : eventsequences ) {
|
||||
for( auto &event : *( eventsequence.second ) ) {
|
||||
event.second = simulation::Events.FindEvent( event.first );
|
||||
if( event.second != nullptr ) {
|
||||
m_events = true;
|
||||
}
|
||||
else {
|
||||
if( evEvent0 == nullptr ) {
|
||||
evEvent0 = NewEvent0;
|
||||
asEvent0Name = "";
|
||||
iEvents |= 1; // sumaryczna informacja o eventach
|
||||
ErrorLog( "Bad event: event \"" + event.first + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
lookupfail = true;
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad track: event \"" + NewEvent0->asName + "\" cannot be assigned to track, track already has one" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( NewEvent1 == nullptr ) {
|
||||
if( false == asEvent1Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
auto const trackname { name() };
|
||||
|
||||
if( ( Global.iHiddenEvents & 1 )
|
||||
&& ( false == trackname.empty() ) ) {
|
||||
// jeśli podana jest nazwa torów, można szukać eventów skojarzonych przez nazwę
|
||||
for( auto &eventsequence : eventsequences ) {
|
||||
auto *event = simulation::Events.FindEvent( trackname + ':' + eventsequence.first );
|
||||
if( event != nullptr ) {
|
||||
// HACK: auto-associated events come with empty lookup string, to avoid including them in the text format export
|
||||
eventsequence.second->emplace_back( "", event );
|
||||
m_events = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEvent1 == nullptr ) {
|
||||
evEvent1 = NewEvent1;
|
||||
asEvent1Name = "";
|
||||
iEvents |= 2; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad track: event \"" + NewEvent1->asName + "\" cannot be assigned to track, track already has one" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( NewEvent2 == nullptr ) {
|
||||
if( false == asEvent2Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEvent2 == nullptr ) {
|
||||
evEvent2 = NewEvent2;
|
||||
asEvent2Name = "";
|
||||
iEvents |= 4; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad track: event \"" + NewEvent2->asName + "\" cannot be assigned to track, track already has one" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ( bError == false );
|
||||
}
|
||||
|
||||
bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2)
|
||||
{
|
||||
bool bError = false;
|
||||
|
||||
if( NewEvent0 == nullptr ) {
|
||||
if( false == asEventall0Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEventall0 == nullptr ) {
|
||||
evEventall0 = NewEvent0;
|
||||
asEventall0Name = "";
|
||||
iEvents |= 8; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad track: event \"" + NewEvent0->asName + "\" cannot be assigned to track, track already has one" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( NewEvent1 == nullptr ) {
|
||||
if( false == asEventall1Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEventall1 == nullptr ) {
|
||||
evEventall1 = NewEvent1;
|
||||
asEventall1Name = "";
|
||||
iEvents |= 16; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad track: event \"" + NewEvent1->asName + "\" cannot be assigned to track, track already has one" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( NewEvent2 == nullptr ) {
|
||||
if( false == asEventall2Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEventall2 == nullptr ) {
|
||||
evEventall2 = NewEvent2;
|
||||
asEventall2Name = "";
|
||||
iEvents |= 32; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad track: event \"" + NewEvent2->asName + "\" cannot be assigned to track, track already has one" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ( bError == false );
|
||||
return ( lookupfail == false );
|
||||
}
|
||||
|
||||
bool TTrack::AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus)
|
||||
@@ -1406,6 +1416,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
{szyna[ i ].texture.x, 0.f} };
|
||||
}
|
||||
// TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers
|
||||
auto const bladelength { 2 * Global.SplineFidelity };
|
||||
if (SwitchExtension->RightSwitch)
|
||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||
gfx::vertex_array vertices;
|
||||
@@ -1414,11 +1425,11 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, 2 );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, bladelength );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
// left blade
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, SwitchExtension->fOffset2 );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -1427,11 +1438,11 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, 2 );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, bladelength );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
// right blade
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -1444,11 +1455,11 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, bladelength ); // prawa szyna za iglicą
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
// right blade
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -1457,11 +1468,11 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, bladelength ); // lewa szyna za iglicą
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
// left blade
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -2222,9 +2233,13 @@ bool TTrack::Switch(int i, float const t, float const d)
|
||||
iNextDirection = SwitchExtension->iNextDirection[i];
|
||||
iPrevDirection = SwitchExtension->iPrevDirection[i];
|
||||
fRadius = fRadiusTable[i]; // McZapkie: wybor promienia toru
|
||||
if (SwitchExtension->fVelocity <=
|
||||
-2) //-1 oznacza maksymalną prędkość, a dalsze ujemne to ograniczenie na bok
|
||||
if( SwitchExtension->fVelocity <= -2 ) {
|
||||
//-1 oznacza maksymalną prędkość, a dalsze ujemne to ograniczenie na bok
|
||||
fVelocity = i ? -SwitchExtension->fVelocity : -1;
|
||||
}
|
||||
else {
|
||||
fVelocity = SwitchExtension->fVelocity;
|
||||
}
|
||||
if (SwitchExtension->pOwner ? SwitchExtension->pOwner->RaTrackAnimAdd(this) :
|
||||
true) // jeśli nie dodane do animacji
|
||||
{ // nie ma się co bawić
|
||||
@@ -2457,17 +2472,18 @@ TTrack * TTrack::RaAnimate()
|
||||
|
||||
gfx::vertex_array vertices;
|
||||
|
||||
auto const bladelength { 2 * Global.SplineFidelity };
|
||||
if (SwitchExtension->RightSwitch)
|
||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||
if( m_material1 ) {
|
||||
// left blade
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, SwitchExtension->fOffset2 );
|
||||
GfxRenderer.Replace( vertices, Geometry1[ 2 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
if( m_material2 ) {
|
||||
// right blade
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 );
|
||||
GfxRenderer.Replace( vertices, Geometry2[ 2 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -2475,13 +2491,13 @@ TTrack * TTrack::RaAnimate()
|
||||
else { // lewa działa lepiej niż prawa
|
||||
if( m_material1 ) {
|
||||
// right blade
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 );
|
||||
GfxRenderer.Replace( vertices, Geometry1[ 2 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
if( m_material2 ) {
|
||||
// left blade
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 );
|
||||
GfxRenderer.Replace( vertices, Geometry2[ 2 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -2661,32 +2677,184 @@ TTrack::endpoints() const {
|
||||
}
|
||||
}
|
||||
|
||||
// calculates path's bounding radius
|
||||
void
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float
|
||||
TTrack::radius_() {
|
||||
|
||||
auto const points = endpoints();
|
||||
auto const points { endpoints() };
|
||||
auto radius { 0.f };
|
||||
for( auto &point : points ) {
|
||||
m_area.radius = std::max(
|
||||
m_area.radius,
|
||||
radius = std::max(
|
||||
radius,
|
||||
static_cast<float>( glm::length( m_area.center - point ) ) ); // extra margin to prevent driven vehicle from flicking
|
||||
}
|
||||
return radius;
|
||||
}
|
||||
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void
|
||||
TTrack::serialize_( std::ostream &Output ) const {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void
|
||||
TTrack::deserialize_( std::istream &Input ) {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
TTrack::export_as_text_( std::ostream &Output ) const {
|
||||
// header
|
||||
Output << "track ";
|
||||
// type
|
||||
Output << (
|
||||
eType == tt_Normal ? (
|
||||
iCategoryFlag == 1 ? "normal" :
|
||||
iCategoryFlag == 2 ? "road" :
|
||||
iCategoryFlag == 4 ? "river" :
|
||||
"none" ) :
|
||||
eType == tt_Switch ? "switch" :
|
||||
eType == tt_Cross ? "cross" :
|
||||
eType == tt_Table ? "turn" :
|
||||
eType == tt_Tributary ? "tributary" :
|
||||
"none" )
|
||||
<< ' ';
|
||||
// basic attributes
|
||||
Output
|
||||
<< Length() << ' '
|
||||
<< fTrackWidth << ' '
|
||||
<< fFriction << ' '
|
||||
<< fSoundDistance << ' '
|
||||
<< iQualityFlag << ' '
|
||||
<< iDamageFlag << ' ';
|
||||
// environment
|
||||
Output << (
|
||||
eEnvironment == e_flat ? "flat" :
|
||||
eEnvironment == e_bridge ? "bridge" :
|
||||
eEnvironment == e_tunnel ? "tunnel" :
|
||||
eEnvironment == e_bank ? "bank" :
|
||||
eEnvironment == e_canyon ? "canyon" :
|
||||
eEnvironment == e_mountains ? "mountains" :
|
||||
"none" )
|
||||
<< ' ';
|
||||
// visibility
|
||||
// NOTE: 'invis' would be less wrong than 'unvis', but potentially incompatible with old 3rd party tools
|
||||
Output << ( m_visible ? "vis" : "unvis" ) << ' ';
|
||||
if( m_visible ) {
|
||||
// texture parameters are supplied only if the path is set as visible
|
||||
auto texturefile { (
|
||||
m_material1 != null_handle ?
|
||||
GfxRenderer.Material( m_material1 ).name :
|
||||
"none" ) };
|
||||
if( texturefile.find( szTexturePath ) == 0 ) {
|
||||
// don't include 'textures/' in the path
|
||||
texturefile.erase( 0, std::string{ szTexturePath }.size() );
|
||||
}
|
||||
Output
|
||||
<< texturefile << ' '
|
||||
<< fTexLength << ' ';
|
||||
|
||||
texturefile = (
|
||||
m_material2 != null_handle ?
|
||||
GfxRenderer.Material( m_material2 ).name :
|
||||
"none" );
|
||||
if( texturefile.find( szTexturePath ) == 0 ) {
|
||||
// don't include 'textures/' in the path
|
||||
texturefile.erase( 0, std::string{ szTexturePath }.size() );
|
||||
}
|
||||
Output << texturefile << ' ';
|
||||
|
||||
Output
|
||||
<< (fTexHeight1 - fTexHeightOffset ) * ( ( iCategoryFlag & 4 ) ? -1 : 1 ) << ' '
|
||||
<< fTexWidth << ' '
|
||||
<< fTexSlope << ' ';
|
||||
}
|
||||
// path data
|
||||
for( auto const &path : m_paths ) {
|
||||
Output
|
||||
<< path.points[ segment_data::point::start ].x << ' '
|
||||
<< path.points[ segment_data::point::start ].y << ' '
|
||||
<< path.points[ segment_data::point::start ].z << ' '
|
||||
<< path.rolls[ 0 ] << ' '
|
||||
|
||||
<< path.points[ segment_data::point::control1 ].x << ' '
|
||||
<< path.points[ segment_data::point::control1 ].y << ' '
|
||||
<< path.points[ segment_data::point::control1 ].z << ' '
|
||||
|
||||
<< path.points[ segment_data::point::control2 ].x << ' '
|
||||
<< path.points[ segment_data::point::control2 ].y << ' '
|
||||
<< path.points[ segment_data::point::control2 ].z << ' '
|
||||
|
||||
<< path.points[ segment_data::point::end ].x << ' '
|
||||
<< path.points[ segment_data::point::end ].y << ' '
|
||||
<< path.points[ segment_data::point::end ].z << ' '
|
||||
<< path.rolls[ 1 ] << ' '
|
||||
|
||||
<< path.radius << ' ';
|
||||
}
|
||||
// optional attributes
|
||||
std::vector< std::pair< std::string, event_sequence const * > > const eventsequences {
|
||||
{ "event0", &m_events0 }, { "eventall0", &m_events0all },
|
||||
{ "event1", &m_events1 }, { "eventall1", &m_events1all },
|
||||
{ "event2", &m_events2 }, { "eventall2", &m_events2all } };
|
||||
|
||||
for( auto &eventsequence : eventsequences ) {
|
||||
for( auto &event : *( eventsequence.second ) ) {
|
||||
if( false == event.first.empty() ) {
|
||||
Output
|
||||
<< eventsequence.first << ' '
|
||||
<< event.first << ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
if( ( SwitchExtension )
|
||||
&& ( SwitchExtension->fVelocity != -1.0 ) ) {
|
||||
Output << "velocity " << SwitchExtension->fVelocity << ' ';
|
||||
}
|
||||
else {
|
||||
if( fVelocity != -1.0 ) {
|
||||
Output << "velocity " << fVelocity << ' ';
|
||||
}
|
||||
}
|
||||
if( pIsolated ) {
|
||||
Output << "isolated " << pIsolated->asName << ' ';
|
||||
}
|
||||
if( fOverhead != -1.0 ) {
|
||||
Output << "overhead " << fOverhead << ' ';
|
||||
}
|
||||
// footer
|
||||
Output
|
||||
<< "endtrack"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void TTrack::MovedUp1(float const dh)
|
||||
{ // poprawienie przechyłki wymaga wydłużenia podsypki
|
||||
fTexHeight1 += dh;
|
||||
fTexHeightOffset += dh;
|
||||
};
|
||||
|
||||
void TTrack::VelocitySet(float v)
|
||||
{ // ustawienie prędkości z ograniczeniem do pierwotnej wartości (zapisanej w scenerii)
|
||||
if (SwitchExtension ? SwitchExtension->fVelocity >= 0.0 : false)
|
||||
{ // zwrotnica może mieć odgórne ograniczenie, nieprzeskakiwalne eventem
|
||||
if (v > SwitchExtension->fVelocity ? true : v < 0.0)
|
||||
return void(fVelocity =
|
||||
SwitchExtension->fVelocity); // maksymalnie tyle, ile było we wpisie
|
||||
// ustawienie prędkości z ograniczeniem do pierwotnej wartości (zapisanej w scenerii)
|
||||
void TTrack::VelocitySet(float v) {
|
||||
// TBD, TODO: add a variable to preserve potential speed limit set by the track configuration on basic track pieces
|
||||
if( ( SwitchExtension )
|
||||
&& ( SwitchExtension->fVelocity != -1 ) ) {
|
||||
// zwrotnica może mieć odgórne ograniczenie, nieprzeskakiwalne eventem
|
||||
fVelocity =
|
||||
min_speed<float>(
|
||||
v,
|
||||
( SwitchExtension->fVelocity > 0 ?
|
||||
SwitchExtension->fVelocity : // positive limit applies to both switch tracks
|
||||
( SwitchExtension->CurrentIndex == 0 ?
|
||||
-1 : // negative limit applies only to the diverging track
|
||||
-SwitchExtension->fVelocity ) ) );
|
||||
}
|
||||
else {
|
||||
fVelocity = v; // nie ma ograniczenia
|
||||
}
|
||||
};
|
||||
|
||||
double TTrack::VelocityGet()
|
||||
@@ -2784,31 +2952,10 @@ path_table::InitTracks() {
|
||||
for( auto first = std::rbegin(m_items); first != std::rend(m_items); ++first ) {
|
||||
auto *track = *first;
|
||||
#endif
|
||||
|
||||
track->AssignEvents(
|
||||
simulation::Events.FindEvent( track->asEvent0Name ),
|
||||
simulation::Events.FindEvent( track->asEvent1Name ),
|
||||
simulation::Events.FindEvent( track->asEvent2Name ) );
|
||||
track->AssignallEvents(
|
||||
simulation::Events.FindEvent( track->asEventall0Name ),
|
||||
simulation::Events.FindEvent( track->asEventall1Name ),
|
||||
simulation::Events.FindEvent( track->asEventall2Name ) );
|
||||
track->AssignEvents();
|
||||
|
||||
auto const trackname { track->name() };
|
||||
|
||||
if( ( Global.iHiddenEvents & 1 )
|
||||
&& ( false == trackname.empty() ) ) {
|
||||
// jeśli podana jest nazwa torów, można szukać eventów skojarzonych przez nazwę
|
||||
track->AssignEvents(
|
||||
simulation::Events.FindEvent( trackname + ":event0" ),
|
||||
simulation::Events.FindEvent( trackname + ":event1" ),
|
||||
simulation::Events.FindEvent( trackname + ":event2" ) );
|
||||
track->AssignallEvents(
|
||||
simulation::Events.FindEvent( trackname + ":eventall0" ),
|
||||
simulation::Events.FindEvent( trackname + ":eventall1" ),
|
||||
simulation::Events.FindEvent( trackname + ":eventall2" ) );
|
||||
}
|
||||
|
||||
switch (track->eType) {
|
||||
// TODO: re-enable
|
||||
case tt_Table: {
|
||||
@@ -2950,6 +3097,8 @@ path_table::InitTracks() {
|
||||
scene::node_data nodedata;
|
||||
nodedata.name = isolated->asName;
|
||||
auto *memorycell = new TMemCell( nodedata ); // to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy
|
||||
// NOTE: autogenerated cells aren't exported; they'll be autogenerated anew when exported file is loaded
|
||||
memorycell->is_exportable = false;
|
||||
simulation::Memory.insert( memorycell );
|
||||
isolated->pMemCell = memorycell; // wskaźnik komóki przekazany do odcinka izolowanego
|
||||
}
|
||||
|
||||
39
Track.h
39
Track.h
@@ -124,7 +124,7 @@ private:
|
||||
};
|
||||
|
||||
// trajektoria ruchu - opakowanie
|
||||
class TTrack : public editor::basic_node {
|
||||
class TTrack : public scene::basic_node {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
@@ -142,20 +142,33 @@ private:
|
||||
float fTexRatio1 = 1.0f; // proporcja boków tekstury nawierzchni (żeby zaoszczędzić na rozmiarach tekstur...)
|
||||
float fTexRatio2 = 1.0f; // proporcja boków tekstury chodnika (żeby zaoszczędzić na rozmiarach tekstur...)
|
||||
float fTexHeight1 = 0.6f; // wysokość brzegu względem trajektorii
|
||||
float fTexHeightOffset = 0.f; // potential adjustment to account for the path roll
|
||||
float fTexWidth = 0.9f; // szerokość boku
|
||||
float fTexSlope = 0.9f;
|
||||
|
||||
glm::dvec3 m_origin;
|
||||
material_handle m_material1 = 0; // tekstura szyn albo nawierzchni
|
||||
material_handle m_material2 = 0; // tekstura automatycznej podsypki albo pobocza
|
||||
typedef std::vector<gfx::geometry_handle> geometryhandle_sequence;
|
||||
using geometryhandle_sequence = std::vector<gfx::geometry_handle>;
|
||||
geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1
|
||||
geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2
|
||||
|
||||
std::vector<segment_data> m_paths; // source data for owned paths
|
||||
|
||||
public:
|
||||
typedef std::deque<TDynamicObject *> dynamics_sequence;
|
||||
using dynamics_sequence = std::deque<TDynamicObject *>;
|
||||
using event_sequence = std::vector<std::pair<std::string, TEvent *> >;
|
||||
|
||||
dynamics_sequence Dynamics;
|
||||
int iEvents = 0; // Ra: flaga informująca o obecności eventów
|
||||
event_sequence
|
||||
m_events0all,
|
||||
m_events1all,
|
||||
m_events2all,
|
||||
m_events0,
|
||||
m_events1,
|
||||
m_events2;
|
||||
bool m_events { false }; // Ra: flaga informująca o obecności eventów
|
||||
/*
|
||||
TEvent *evEventall0 = nullptr; // McZapkie-140302: wyzwalany gdy pojazd stoi
|
||||
TEvent *evEventall1 = nullptr;
|
||||
TEvent *evEventall2 = nullptr;
|
||||
@@ -168,6 +181,7 @@ public:
|
||||
std::string asEvent0Name;
|
||||
std::string asEvent1Name;
|
||||
std::string asEvent2Name;
|
||||
*/
|
||||
int iNextDirection = 0; // 0:Point1, 1:Point2, 3:do odchylonego na zwrotnicy
|
||||
int iPrevDirection = 0; // domyślnie wirtualne odcinki dołączamy stroną od Point1
|
||||
TTrackType eType = tt_Normal; // domyślnie zwykły
|
||||
@@ -231,8 +245,7 @@ public:
|
||||
SwitchExtension->iRoads - 1 :
|
||||
1 ); }
|
||||
void Load(cParser *parser, Math3D::vector3 pOrigin);
|
||||
bool AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2);
|
||||
bool AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2);
|
||||
bool AssignEvents();
|
||||
bool AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus);
|
||||
bool CheckDynamicObject(TDynamicObject *Dynamic);
|
||||
bool AddDynamicObject(TDynamicObject *Dynamic);
|
||||
@@ -270,10 +283,16 @@ public:
|
||||
double VelocityGet();
|
||||
void ConnectionsLog();
|
||||
|
||||
protected:
|
||||
// calculates path's bounding radius
|
||||
void
|
||||
radius_();
|
||||
private:
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float radius_();
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void serialize_( std::ostream &Output ) const;
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void deserialize_( std::istream &Input );
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void export_as_text_( std::ostream &Output ) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
84
Traction.cpp
84
Traction.cpp
@@ -529,18 +529,6 @@ double TTraction::VoltageGet(double u, double i)
|
||||
return 0.0; // gdy nie podłączony wcale?
|
||||
};
|
||||
|
||||
// calculates path's bounding radius
|
||||
void
|
||||
TTraction::radius_() {
|
||||
|
||||
auto const points = endpoints();
|
||||
for( auto &point : points ) {
|
||||
m_area.radius = std::max(
|
||||
m_area.radius,
|
||||
static_cast<float>( glm::length( m_area.center - point ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3
|
||||
TTraction::wire_color() const {
|
||||
|
||||
@@ -581,6 +569,7 @@ TTraction::wire_color() const {
|
||||
color.r *= Global.DayLight.ambient[ 0 ];
|
||||
color.g *= Global.DayLight.ambient[ 1 ];
|
||||
color.b *= Global.DayLight.ambient[ 2 ];
|
||||
color *= 0.5f;
|
||||
}
|
||||
else {
|
||||
// tymczasowo pokazanie zasilanych odcinków
|
||||
@@ -676,6 +665,77 @@ TTraction::wire_color() const {
|
||||
return color;
|
||||
}
|
||||
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float
|
||||
TTraction::radius_() {
|
||||
|
||||
auto const points { endpoints() };
|
||||
auto radius { 0.f };
|
||||
for( auto &point : points ) {
|
||||
radius = std::max(
|
||||
radius,
|
||||
static_cast<float>( glm::length( m_area.center - point ) ) );
|
||||
}
|
||||
return radius;
|
||||
}
|
||||
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void
|
||||
TTraction::serialize_( std::ostream &Output ) const {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void
|
||||
TTraction::deserialize_( std::istream &Input ) {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
TTraction::export_as_text_( std::ostream &Output ) const {
|
||||
// header
|
||||
Output << "traction ";
|
||||
// basic attributes
|
||||
Output
|
||||
<< asPowerSupplyName << ' '
|
||||
<< NominalVoltage << ' '
|
||||
<< MaxCurrent << ' '
|
||||
<< ( fResistivity * 1000 ) << ' '
|
||||
<< (
|
||||
Material == 2 ? "al" :
|
||||
Material == 0 ? "none" :
|
||||
"cu" ) << ' '
|
||||
<< WireThickness << ' '
|
||||
<< DamageFlag << ' ';
|
||||
// path data
|
||||
Output
|
||||
<< pPoint1.x << ' ' << pPoint1.y << ' ' << pPoint1.z << ' '
|
||||
<< pPoint2.x << ' ' << pPoint2.y << ' ' << pPoint2.z << ' '
|
||||
<< pPoint3.x << ' ' << pPoint3.y << ' ' << pPoint3.z << ' '
|
||||
<< pPoint4.x << ' ' << pPoint4.y << ' ' << pPoint4.z << ' ';
|
||||
// minimum height
|
||||
Output << ( ( pPoint3.y - pPoint1.y + pPoint4.y - pPoint2.y ) * 0.5 - fHeightDifference ) << ' ';
|
||||
// segment length
|
||||
Output << static_cast<int>( iNumSections ? glm::length( pPoint1 - pPoint2 ) / iNumSections : 0.0 ) << ' ';
|
||||
// wire data
|
||||
Output
|
||||
<< Wires << ' '
|
||||
<< WireOffset << ' ';
|
||||
// visibility
|
||||
// NOTE: 'invis' would be less wrong than 'unvis', but potentially incompatible with old 3rd party tools
|
||||
Output << ( m_visible ? "vis" : "unvis" ) << ' ';
|
||||
// optional attributes
|
||||
if( false == asParallel.empty() ) {
|
||||
Output << "parallel " << asParallel << ' ';
|
||||
}
|
||||
// footer
|
||||
Output
|
||||
<< "endtraction"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// legacy method, initializes traction after deserialization from scenario file
|
||||
|
||||
17
Traction.h
17
Traction.h
@@ -19,7 +19,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
class TTractionPowerSource;
|
||||
|
||||
class TTraction : public editor::basic_node {
|
||||
class TTraction : public scene::basic_node {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
@@ -74,13 +74,18 @@ class TTraction : public editor::basic_node {
|
||||
void PowerSet(TTractionPowerSource *ps);
|
||||
double VoltageGet(double u, double i);
|
||||
|
||||
protected:
|
||||
// calculates piece's bounding radius
|
||||
void
|
||||
radius_();
|
||||
|
||||
private:
|
||||
// methods
|
||||
glm::vec3 wire_color() const;
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float radius_();
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void serialize_( std::ostream &Output ) const;
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void deserialize_( std::istream &Input );
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void export_as_text_( std::ostream &Output ) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -141,6 +141,52 @@ void TTractionPowerSource::PowerSet(TTractionPowerSource *ps)
|
||||
// else ErrorLog("nie może być więcej punktów zasilania niż dwa");
|
||||
};
|
||||
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void
|
||||
TTractionPowerSource::serialize_( std::ostream &Output ) const {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void
|
||||
TTractionPowerSource::deserialize_( std::istream &Input ) {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
TTractionPowerSource::export_as_text_( std::ostream &Output ) const {
|
||||
// header
|
||||
Output << "tractionpowersource ";
|
||||
// placement
|
||||
Output
|
||||
<< location().x << ' '
|
||||
<< location().y << ' '
|
||||
<< location().z << ' ';
|
||||
// basic attributes
|
||||
Output
|
||||
<< NominalVoltage << ' '
|
||||
<< VoltageFrequency << ' '
|
||||
<< InternalRes << ' '
|
||||
<< MaxOutputCurrent << ' '
|
||||
<< FastFuseTimeOut << ' '
|
||||
<< FastFuseRepetition << ' '
|
||||
<< SlowFuseTimeOut << ' ';
|
||||
// optional attributes
|
||||
if( true == Recuperation ) {
|
||||
Output << "recuperation ";
|
||||
}
|
||||
if( true == bSection ) {
|
||||
Output << "section ";
|
||||
}
|
||||
// footer
|
||||
Output
|
||||
<< "end"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// legacy method, calculates changes in simulation state over specified time
|
||||
|
||||
@@ -13,9 +13,33 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "scenenode.h"
|
||||
#include "Names.h"
|
||||
|
||||
class TTractionPowerSource : public editor::basic_node {
|
||||
class TTractionPowerSource : public scene::basic_node {
|
||||
|
||||
private:
|
||||
public:
|
||||
// constructor
|
||||
TTractionPowerSource( scene::node_data const &Nodedata );
|
||||
// methods
|
||||
void Init(double const u, double const i);
|
||||
bool Load(cParser *parser);
|
||||
bool Update(double dt);
|
||||
double CurrentGet(double res);
|
||||
void VoltageSet(double const v) {
|
||||
NominalVoltage = v; };
|
||||
void PowerSet(TTractionPowerSource *ps);
|
||||
// members
|
||||
TTractionPowerSource *psNode[ 2 ] = { nullptr, nullptr }; // zasilanie na końcach dla sekcji
|
||||
bool bSection = false; // czy jest sekcją
|
||||
|
||||
private:
|
||||
// methods
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
void serialize_( std::ostream &Output ) const;
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
void deserialize_( std::istream &Input );
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void export_as_text_( std::ostream &Output ) const;
|
||||
|
||||
// members
|
||||
double NominalVoltage = 0.0;
|
||||
double VoltageFrequency = 0.0;
|
||||
double InternalRes = 0.2;
|
||||
@@ -34,20 +58,6 @@ class TTractionPowerSource : public editor::basic_node {
|
||||
double FuseTimer = 0.0;
|
||||
int FuseCounter = 0;
|
||||
|
||||
public:
|
||||
// zmienne publiczne
|
||||
TTractionPowerSource *psNode[ 2 ] = { nullptr, nullptr }; // zasilanie na końcach dla sekcji
|
||||
bool bSection = false; // czy jest sekcją
|
||||
|
||||
TTractionPowerSource( scene::node_data const &Nodedata );
|
||||
|
||||
void Init(double const u, double const i);
|
||||
bool Load(cParser *parser);
|
||||
bool Update(double dt);
|
||||
double CurrentGet(double res);
|
||||
void VoltageSet(double const v) {
|
||||
NominalVoltage = v; };
|
||||
void PowerSet(TTractionPowerSource *ps);
|
||||
};
|
||||
|
||||
|
||||
|
||||
112
Train.cpp
112
Train.cpp
@@ -207,6 +207,7 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = {
|
||||
{ user_command::mubrakingindicatortoggle, &TTrain::OnCommand_mubrakingindicatortoggle },
|
||||
{ user_command::reverserincrease, &TTrain::OnCommand_reverserincrease },
|
||||
{ user_command::reverserdecrease, &TTrain::OnCommand_reverserdecrease },
|
||||
{ user_command::reverserforwardhigh, &TTrain::OnCommand_reverserforwardhigh },
|
||||
{ user_command::reverserforward, &TTrain::OnCommand_reverserforward },
|
||||
{ user_command::reverserneutral, &TTrain::OnCommand_reverserneutral },
|
||||
{ user_command::reverserbackward, &TTrain::OnCommand_reverserbackward },
|
||||
@@ -744,12 +745,22 @@ void TTrain::OnCommand_mastercontrollerdecreasefast( TTrain *Train, command_data
|
||||
|
||||
void TTrain::OnCommand_mastercontrollerset( TTrain *Train, command_data const &Command ) {
|
||||
|
||||
auto const targetposition { std::min<int>( Command.param1, Train->mvControlled->MainCtrlPosNo ) };
|
||||
while( targetposition < Train->mvControlled->MainCtrlPos ) {
|
||||
Train->mvControlled->DecMainCtrl( 1 );
|
||||
auto positionchange {
|
||||
std::min<int>(
|
||||
Command.param1,
|
||||
( Train->mvControlled->CoupledCtrl ?
|
||||
Train->mvControlled->MainCtrlPosNo + Train->mvControlled->ScndCtrlPosNo :
|
||||
Train->mvControlled->MainCtrlPosNo ) )
|
||||
- ( Train->mvControlled->CoupledCtrl ?
|
||||
Train->mvControlled->MainCtrlPos + Train->mvControlled->ScndCtrlPos :
|
||||
Train->mvControlled->MainCtrlPos ) };
|
||||
while( ( positionchange < 0 )
|
||||
&& ( true == Train->mvControlled->DecMainCtrl( 1 ) ) ) {
|
||||
++positionchange;
|
||||
}
|
||||
while( targetposition > Train->mvControlled->MainCtrlPos ) {
|
||||
Train->mvControlled->IncMainCtrl( 1 );
|
||||
while( ( positionchange > 0 )
|
||||
&& ( true == Train->mvControlled->IncMainCtrl( 1 ) ) ) {
|
||||
--positionchange;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -854,11 +865,15 @@ void TTrain::OnCommand_secondcontrollerdecreasefast( TTrain *Train, command_data
|
||||
void TTrain::OnCommand_secondcontrollerset( TTrain *Train, command_data const &Command ) {
|
||||
|
||||
auto const targetposition { std::min<int>( Command.param1, Train->mvControlled->ScndCtrlPosNo ) };
|
||||
while( targetposition < Train->mvControlled->ScndCtrlPos ) {
|
||||
Train->mvControlled->DecScndCtrl( 1 );
|
||||
while( ( targetposition < Train->mvControlled->ScndCtrlPos )
|
||||
&& ( true == Train->mvControlled->DecScndCtrl( 1 ) ) ) {
|
||||
// all work is done in the header
|
||||
;
|
||||
}
|
||||
while( targetposition > Train->mvControlled->ScndCtrlPos ) {
|
||||
Train->mvControlled->IncScndCtrl( 1 );
|
||||
while( ( targetposition > Train->mvControlled->ScndCtrlPos )
|
||||
&& ( true == Train->mvControlled->IncScndCtrl( 1 ) ) ) {
|
||||
// all work is done in the header
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1458,9 +1473,20 @@ void TTrain::OnCommand_reverserdecrease( TTrain *Train, command_data const &Comm
|
||||
}
|
||||
}
|
||||
|
||||
void TTrain::OnCommand_reverserforwardhigh( TTrain *Train, command_data const &Command ) {
|
||||
|
||||
if( Command.action == GLFW_PRESS ) {
|
||||
|
||||
OnCommand_reverserforward( Train, Command );
|
||||
OnCommand_reverserincrease( Train, Command );
|
||||
}
|
||||
}
|
||||
|
||||
void TTrain::OnCommand_reverserforward( TTrain *Train, command_data const &Command ) {
|
||||
|
||||
if( Command.action == GLFW_PRESS ) {
|
||||
// HACK: try to move the reverser one position back, in case it's set to "high forward"
|
||||
OnCommand_reverserdecrease( Train, Command );
|
||||
|
||||
if( Train->mvOccupied->ActiveDir < 1 ) {
|
||||
|
||||
@@ -4322,7 +4348,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
|
||||
tor = DynamicObject->GetTrack(); // McZapkie-180203
|
||||
// McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol
|
||||
float maxtacho = 3;
|
||||
auto const maxtacho { 3.0 };
|
||||
fTachoVelocity = static_cast<float>( std::min( std::abs(11.31 * mvControlled->WheelDiameter * mvControlled->nrot), mvControlled->Vmax * 1.05) );
|
||||
{ // skacze osobna zmienna
|
||||
float ff = simulation::Time.data().wSecond; // skacze co sekunde - pol sekundy
|
||||
@@ -4338,12 +4364,12 @@ bool TTrain::Update( double const Deltatime )
|
||||
}
|
||||
if (fTachoVelocity > 1) // McZapkie-270503: podkrecanie tachometru
|
||||
{
|
||||
if (fTachoCount < maxtacho)
|
||||
fTachoCount += Deltatime * 3; // szybciej zacznij stukac
|
||||
// szybciej zacznij stukac
|
||||
fTachoCount = std::min( maxtacho, fTachoCount + Deltatime * 3 );
|
||||
}
|
||||
else if( fTachoCount > 0 ) {
|
||||
// schodz powoli - niektore haslery to ze 4 sekundy potrafia stukac
|
||||
fTachoCount -= Deltatime * 0.66;
|
||||
fTachoCount = std::max( 0.0, fTachoCount - Deltatime * 0.66 );
|
||||
}
|
||||
|
||||
// Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są ewentualnie na PoKeys
|
||||
@@ -5171,10 +5197,8 @@ bool TTrain::Update( double const Deltatime )
|
||||
//---------
|
||||
// hunter-080812: poprawka na ogrzewanie w elektrykach - usuniete uzaleznienie od przetwornicy
|
||||
if( ( mvControlled->Heating == true )
|
||||
&& ( ( mvControlled->ConverterFlag )
|
||||
|| ( ( mvControlled->EngineType == ElectricSeriesMotor )
|
||||
&& ( mvControlled->Mains == true )
|
||||
&& ( mvControlled->ConvOvldFlag == false ) ) ) )
|
||||
&& ( mvControlled->ConvOvldFlag == false ) )
|
||||
btLampkaOgrzewanieSkladu.Turn( true );
|
||||
else
|
||||
btLampkaOgrzewanieSkladu.Turn( false );
|
||||
@@ -5887,6 +5911,10 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
sound->offset( nullvector );
|
||||
sound->owner( DynamicObject );
|
||||
}
|
||||
// reset view angles
|
||||
pMechViewAngle = { 0.0, 0.0 };
|
||||
Global.pCamera->Pitch = pMechViewAngle.x;
|
||||
Global.pCamera->Yaw = pMechViewAngle.y;
|
||||
|
||||
pyScreens.reset(this);
|
||||
pyScreens.setLookupPath(DynamicObject->asBaseDir);
|
||||
@@ -5939,41 +5967,59 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
{
|
||||
// jeśli znaleziony wpis kabiny
|
||||
Cabine[cabindex].Load(*parser);
|
||||
// NOTE: the next part is likely to break if sitpos doesn't follow pos
|
||||
// NOTE: the position and angle definitions depend on strict entry order
|
||||
// TODO: refactor into more flexible arrangement
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
if( token == std::string( "driver" + std::to_string( cabindex ) + "angle:" ) ) {
|
||||
// camera view angle
|
||||
parser->getTokens( 2, false );
|
||||
// angle is specified in degrees but internally stored in radians
|
||||
glm::vec2 viewangle;
|
||||
*parser
|
||||
>> viewangle.y // yaw first, then pitch
|
||||
>> viewangle.x;
|
||||
pMechViewAngle = glm::radians( viewangle );
|
||||
Global.pCamera->Pitch = pMechViewAngle.x;
|
||||
Global.pCamera->Yaw = pMechViewAngle.y;
|
||||
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
}
|
||||
if (token == std::string("driver" + std::to_string(cabindex) + "pos:"))
|
||||
{
|
||||
// pozycja poczatkowa maszynisty
|
||||
parser->getTokens(3, false);
|
||||
*parser >> pMechOffset.x >> pMechOffset.y >> pMechOffset.z;
|
||||
pMechSittingPosition.x = pMechOffset.x;
|
||||
pMechSittingPosition.y = pMechOffset.y;
|
||||
pMechSittingPosition.z = pMechOffset.z;
|
||||
}
|
||||
// ABu: pozycja siedzaca mechanika
|
||||
*parser
|
||||
>> pMechOffset.x
|
||||
>> pMechOffset.y
|
||||
>> pMechOffset.z;
|
||||
pMechSittingPosition = pMechOffset;
|
||||
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
}
|
||||
// ABu: pozycja siedzaca mechanika
|
||||
if (token == std::string("driver" + std::to_string(cabindex) + "sitpos:"))
|
||||
{
|
||||
// ABu 180404 pozycja siedzaca maszynisty
|
||||
parser->getTokens(3, false);
|
||||
*parser >> pMechSittingPosition.x >> pMechSittingPosition.y >> pMechSittingPosition.z;
|
||||
parse = true;
|
||||
*parser
|
||||
>> pMechSittingPosition.x
|
||||
>> pMechSittingPosition.y
|
||||
>> pMechSittingPosition.z;
|
||||
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
}
|
||||
// else parse=false;
|
||||
do
|
||||
{
|
||||
// ABu: wstawione warunki, wczesniej tylko to:
|
||||
// str=Parser->GetNextSymbol().LowerCase();
|
||||
if (parse == true) {
|
||||
|
||||
do {
|
||||
if( parse == true ) {
|
||||
token = "";
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
parse = true;
|
||||
}
|
||||
// inicjacja kabiny
|
||||
|
||||
2
Train.h
2
Train.h
@@ -198,6 +198,7 @@ class TTrain
|
||||
static void OnCommand_mubrakingindicatortoggle( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_reverserincrease( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_reverserdecrease( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_reverserforwardhigh( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_reverserforward( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_reverserneutral( TTrain *Train, command_data const &Command );
|
||||
static void OnCommand_reverserbackward( TTrain *Train, command_data const &Command );
|
||||
@@ -594,6 +595,7 @@ public: // reszta może by?publiczna
|
||||
|
||||
Math3D::vector3 pMechSittingPosition; // ABu 180404
|
||||
Math3D::vector3 MirrorPosition(bool lewe);
|
||||
glm::vec2 pMechViewAngle { 0.0, 0.0 }; // camera pitch and yaw values, preserved while in external view
|
||||
|
||||
private:
|
||||
double fBlinkTimer;
|
||||
|
||||
102
TrkFoll.cpp
102
TrkFoll.cpp
@@ -101,7 +101,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
{ // pętla przesuwająca wózek przez kolejne tory, aż do trafienia w jakiś
|
||||
if( pCurrentTrack == nullptr ) { return false; } // nie ma toru, to nie ma przesuwania
|
||||
// TODO: refactor following block as track method
|
||||
if( pCurrentTrack->iEvents ) { // sumaryczna informacja o eventach
|
||||
if( pCurrentTrack->m_events ) { // sumaryczna informacja o eventach
|
||||
// omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma)
|
||||
if( ( std::abs( fDistance ) < 0.01 )
|
||||
&& ( Owner->GetVelocity() < 0.01 ) ) {
|
||||
@@ -109,14 +109,18 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
if( ( Owner->Mechanik != nullptr )
|
||||
&& ( Owner->Mechanik->Primary() ) ) {
|
||||
// tylko dla jednego członu
|
||||
if( ( pCurrentTrack->evEvent0 )
|
||||
&& ( pCurrentTrack->evEvent0->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEvent0, Owner );
|
||||
for( auto &event : pCurrentTrack->m_events0 ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( event.second->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( event.second, Owner );
|
||||
}
|
||||
}
|
||||
if( ( pCurrentTrack->evEventall0 )
|
||||
&& ( pCurrentTrack->evEventall0->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEventall0, Owner );
|
||||
}
|
||||
for( auto &event : pCurrentTrack->m_events0all ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( event.second->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( event.second, Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fDistance < 0) {
|
||||
@@ -127,20 +131,27 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
&& ( Owner->Mechanik->Primary() ) ) {
|
||||
// tylko dla jednego członu
|
||||
// McZapkie-280503: wyzwalanie event tylko dla pojazdow z obsada
|
||||
if( ( true == bPrimary )
|
||||
&& ( pCurrentTrack->evEvent1 != nullptr )
|
||||
&& ( pCurrentTrack->evEvent1->iQueued == 0 ) ) {
|
||||
if( true == bPrimary ) {
|
||||
for( auto &event : pCurrentTrack->m_events1 ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( event.second->iQueued == 0 ) ) {
|
||||
// dodanie do kolejki
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEvent1, Owner );
|
||||
simulation::Events.AddToQuery( event.second, Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( SetFlag( iEventallFlag, -1 ) ) {
|
||||
// McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow
|
||||
if( ( true == bPrimary )
|
||||
&& ( pCurrentTrack->evEventall1 != nullptr )
|
||||
&& ( pCurrentTrack->evEventall1->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEventall1, Owner ); // dodanie do kolejki
|
||||
if( true == bPrimary ) {
|
||||
for( auto &event : pCurrentTrack->m_events1all ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( event.second->iQueued == 0 ) ) {
|
||||
// dodanie do kolejki
|
||||
simulation::Events.AddToQuery( event.second, Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,19 +162,27 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
if( ( Owner->Mechanik != nullptr )
|
||||
&& ( Owner->Mechanik->Primary() ) ) {
|
||||
// tylko dla jednego członu
|
||||
if( ( true == bPrimary )
|
||||
&& ( pCurrentTrack->evEvent2 != nullptr )
|
||||
&& ( pCurrentTrack->evEvent2->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEvent2, Owner );
|
||||
if( true == bPrimary ) {
|
||||
for( auto &event : pCurrentTrack->m_events2 ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( event.second->iQueued == 0 ) ) {
|
||||
// dodanie do kolejki
|
||||
simulation::Events.AddToQuery( event.second, Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( SetFlag( iEventallFlag, -2 ) ) {
|
||||
// sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0
|
||||
if( ( true == bPrimary )
|
||||
&& ( pCurrentTrack->evEventall2 != nullptr )
|
||||
&& ( pCurrentTrack->evEventall2->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEventall2, Owner );
|
||||
if( true == bPrimary ) {
|
||||
for( auto &event : pCurrentTrack->m_events2all ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( event.second->iQueued == 0 ) ) {
|
||||
// dodanie do kolejki
|
||||
simulation::Events.AddToQuery( event.second, Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,18 +277,33 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
{ // gdy zostaje na tym samym torze (przesuwanie już nie zmienia toru)
|
||||
if (bPrimary)
|
||||
{ // tylko gdy początkowe ustawienie, dodajemy eventy stania do kolejki
|
||||
if (Owner->MoverParameters->ActiveCab != 0)
|
||||
// if (Owner->MoverParameters->CabNo!=0)
|
||||
{
|
||||
if (pCurrentTrack->evEvent1 && pCurrentTrack->evEvent1->fDelay <= -1.0f)
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEvent1, Owner);
|
||||
if (pCurrentTrack->evEvent2 && pCurrentTrack->evEvent2->fDelay <= -1.0f)
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEvent2, Owner);
|
||||
if (Owner->MoverParameters->ActiveCab != 0) {
|
||||
|
||||
for( auto &event : pCurrentTrack->m_events1 ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( event.second->fDelay <= -1.0 ) ) {
|
||||
simulation::Events.AddToQuery( event.second, Owner );
|
||||
}
|
||||
}
|
||||
for( auto &event : pCurrentTrack->m_events2 ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( event.second->fDelay <= -1.0 ) ) {
|
||||
simulation::Events.AddToQuery( event.second, Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
for( auto &event : pCurrentTrack->m_events1all ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( event.second->fDelay <= -1.0 ) ) {
|
||||
simulation::Events.AddToQuery( event.second, Owner );
|
||||
}
|
||||
}
|
||||
for( auto &event : pCurrentTrack->m_events2all ) {
|
||||
if( ( event.second != nullptr )
|
||||
&& ( event.second->fDelay <= -1.0 ) ) {
|
||||
simulation::Events.AddToQuery( event.second, Owner );
|
||||
}
|
||||
}
|
||||
if (pCurrentTrack->evEventall1 && pCurrentTrack->evEventall1->fDelay <= -1.0f)
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEventall1, Owner);
|
||||
if (pCurrentTrack->evEventall2 && pCurrentTrack->evEventall2->fDelay <= -1.0f)
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEventall2, Owner);
|
||||
}
|
||||
fCurrentDistance = s;
|
||||
// fDistance=0;
|
||||
|
||||
46
World.cpp
46
World.cpp
@@ -329,7 +329,6 @@ bool TWorld::Init( GLFWwindow *Window ) {
|
||||
|
||||
void TWorld::OnKeyDown(int cKey) {
|
||||
// dump keypress info in the log
|
||||
if( !Global.iPause ) {
|
||||
// podczas pauzy klawisze nie działają
|
||||
std::string keyinfo;
|
||||
auto keyname = glfwGetKeyName( cKey, 0 );
|
||||
@@ -372,7 +371,6 @@ void TWorld::OnKeyDown(int cKey) {
|
||||
|
||||
WriteLog( "Key pressed: " + keymodifiers + "[" + keyinfo + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
// actual key processing
|
||||
// TODO: redo the input system
|
||||
@@ -522,6 +520,14 @@ void TWorld::OnKeyDown(int cKey) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GLFW_KEY_F11: {
|
||||
// scenery export
|
||||
if( Global.ctrlState
|
||||
&& Global.shiftState ) {
|
||||
simulation::State.export_as_text( Global.SceneryFile );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GLFW_KEY_F12: {
|
||||
// quick debug mode toggle
|
||||
if( Global.ctrlState
|
||||
@@ -626,6 +632,7 @@ void TWorld::InOutKey( bool const Near )
|
||||
if (Train) {
|
||||
// cache current cab position so there's no need to set it all over again after each out-in switch
|
||||
Train->pMechSittingPosition = Train->pMechOffset;
|
||||
|
||||
Train->Dynamic()->bDisplayCab = false;
|
||||
DistantView( Near );
|
||||
}
|
||||
@@ -637,9 +644,8 @@ void TWorld::InOutKey( bool const Near )
|
||||
if (Train)
|
||||
{
|
||||
Train->Dynamic()->bDisplayCab = true;
|
||||
Train->Dynamic()->ABuSetModelShake(
|
||||
Math3D::vector3(0, 0, 0)); // zerowanie przesunięcia przed powrotem?
|
||||
// Camera.Stop(); //zatrzymanie ruchu
|
||||
// zerowanie przesunięcia przed powrotem?
|
||||
Train->Dynamic()->ABuSetModelShake( { 0, 0, 0 } );
|
||||
Train->MechStop();
|
||||
FollowView(); // na pozycję mecha
|
||||
}
|
||||
@@ -713,14 +719,12 @@ void TWorld::FollowView(bool wycisz) {
|
||||
// tu ustawić nową, bo od niej liczą się odległości
|
||||
Global.pCameraPosition = Camera.Pos;
|
||||
}
|
||||
else if (Train)
|
||||
{ // korekcja ustawienia w kabinie - OK
|
||||
if( wycisz ) {
|
||||
// wyciszenie dźwięków z poprzedniej pozycji
|
||||
// trzymanie prawego w kabinie daje marny efekt
|
||||
// TODO: re-implement, old one kinda didn't really work
|
||||
}
|
||||
else if (Train) {
|
||||
Camera.Pos = Train->pMechPosition;
|
||||
// potentially restore cached camera angles
|
||||
Camera.Pitch = Train->pMechViewAngle.x;
|
||||
Camera.Yaw = Train->pMechViewAngle.y;
|
||||
|
||||
Camera.Roll = std::atan(Train->pMechShake.x * Train->fMechRoll); // hustanie kamery na boki
|
||||
Camera.Pitch -= 0.5 * std::atan(Train->vMechVelocity.z * Train->fMechPitch); // hustanie kamery przod tyl
|
||||
|
||||
@@ -969,6 +973,14 @@ TWorld::Update_Camera( double const Deltatime ) {
|
||||
|
||||
if( DebugCameraFlag ) { DebugCamera.Update(); }
|
||||
else { Camera.Update(); } // uwzględnienie ruchu wywołanego klawiszami
|
||||
|
||||
if( ( false == FreeFlyModeFlag )
|
||||
&& ( false == Global.CabWindowOpen )
|
||||
&& ( Train != nullptr ) ) {
|
||||
// cache cab camera view angles in case of view type switch
|
||||
Train->pMechViewAngle = { Camera.Pitch, Camera.Yaw };
|
||||
}
|
||||
|
||||
// reset window state, it'll be set again if applicable in a check below
|
||||
Global.CabWindowOpen = false;
|
||||
|
||||
@@ -977,7 +989,7 @@ TWorld::Update_Camera( double const Deltatime ) {
|
||||
&& ( false == DebugCameraFlag ) ) {
|
||||
// jeśli jazda w kabinie, przeliczyć trzeba parametry kamery
|
||||
auto tempangle = Controlled->VectorFront() * ( Controlled->MoverParameters->ActiveCab == -1 ? -1 : 1 );
|
||||
double modelrotate = atan2( -tempangle.x, tempangle.z );
|
||||
// double modelrotate = atan2( -tempangle.x, tempangle.z );
|
||||
|
||||
if( ( true == Global.ctrlState )
|
||||
&& ( ( glfwGetKey( Global.window, GLFW_KEY_LEFT ) == GLFW_TRUE )
|
||||
@@ -1005,6 +1017,11 @@ TWorld::Update_Camera( double const Deltatime ) {
|
||||
}
|
||||
else {
|
||||
// patrzenie standardowe
|
||||
// potentially restore view angle after returning from external view
|
||||
// TODO: mirror view toggle as separate method
|
||||
Camera.Pitch = Train->pMechViewAngle.x;
|
||||
Camera.Yaw = Train->pMechViewAngle.y;
|
||||
|
||||
Camera.Pos = Train->GetWorldMechPosition(); // Train.GetPosition1();
|
||||
if( !Global.iPause ) {
|
||||
// podczas pauzy nie przeliczać kątów przypadkowymi wartościami
|
||||
@@ -1014,8 +1031,8 @@ TWorld::Update_Camera( double const Deltatime ) {
|
||||
// Ra: tu jest uciekanie kamery w górę!!!
|
||||
Camera.Pitch -= 0.5 * atan( Train->vMechVelocity.z * Train->fMechPitch );
|
||||
}
|
||||
// ABu011104: rzucanie pudlem
|
||||
/*
|
||||
// ABu011104: rzucanie pudlem
|
||||
vector3 temp;
|
||||
if( abs( Train->pMechShake.y ) < 0.25 )
|
||||
temp = vector3( 0, 0, 6 * Train->pMechShake.y );
|
||||
@@ -1027,7 +1044,6 @@ TWorld::Update_Camera( double const Deltatime ) {
|
||||
Controlled->ABuSetModelShake( temp );
|
||||
// ABu: koniec rzucania
|
||||
*/
|
||||
|
||||
if( Train->Dynamic()->MoverParameters->ActiveCab == 0 )
|
||||
Camera.LookAt = Train->GetWorldMechPosition() + Train->GetDirection() * 5.0; // gdy w korytarzu
|
||||
else // patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny
|
||||
|
||||
21
audio.cpp
21
audio.cpp
@@ -159,8 +159,9 @@ buffer_manager::emplace( std::string Filename ) {
|
||||
m_buffers.emplace_back( Filename );
|
||||
|
||||
// NOTE: we store mapping without file type extension, to simplify lookups
|
||||
erase_extension( Filename );
|
||||
m_buffermappings.emplace(
|
||||
Filename.erase( Filename.rfind( '.' ) ),
|
||||
Filename,
|
||||
handle );
|
||||
|
||||
return handle;
|
||||
@@ -169,26 +170,22 @@ buffer_manager::emplace( std::string Filename ) {
|
||||
audio::buffer_handle
|
||||
buffer_manager::find_buffer( std::string const &Buffername ) const {
|
||||
|
||||
auto lookup = m_buffermappings.find( Buffername );
|
||||
if( lookup != m_buffermappings.end() )
|
||||
auto const lookup = m_buffermappings.find( Buffername );
|
||||
if( lookup != std::end( m_buffermappings ) )
|
||||
return lookup->second;
|
||||
else
|
||||
return null_handle;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
buffer_manager::find_file( std::string const &Filename ) const {
|
||||
|
||||
std::vector<std::string> const extensions { ".ogg", ".flac", ".wav" };
|
||||
auto const lookup {
|
||||
FileExists(
|
||||
{ Filename },
|
||||
{ ".ogg", ".flac", ".wav" } ) };
|
||||
|
||||
for( auto const &extension : extensions ) {
|
||||
if( FileExists( Filename + extension ) ) {
|
||||
// valid name on success
|
||||
return Filename + extension;
|
||||
}
|
||||
}
|
||||
return {}; // empty string on failure
|
||||
return lookup.first + lookup.second;
|
||||
}
|
||||
|
||||
} // audio
|
||||
|
||||
@@ -60,6 +60,7 @@ commanddescription_sequence Commands_descriptions = {
|
||||
{ "sandboxactivate", command_target::vehicle },
|
||||
{ "reverserincrease", command_target::vehicle },
|
||||
{ "reverserdecrease", command_target::vehicle },
|
||||
{ "reverserforwardhigh", command_target::vehicle },
|
||||
{ "reverserforward", command_target::vehicle },
|
||||
{ "reverserneutral", command_target::vehicle },
|
||||
{ "reverserbackward", command_target::vehicle },
|
||||
|
||||
@@ -55,6 +55,7 @@ enum class user_command {
|
||||
sandboxactivate,
|
||||
reverserincrease,
|
||||
reverserdecrease,
|
||||
reverserforwardhigh,
|
||||
reverserforward,
|
||||
reverserneutral,
|
||||
reverserbackward,
|
||||
|
||||
@@ -249,6 +249,8 @@ keyboard_input::default_bindings() {
|
||||
{ GLFW_KEY_D },
|
||||
// reverserdecrease
|
||||
{ GLFW_KEY_R },
|
||||
// reverserforwardhigh
|
||||
{ -1 },
|
||||
// reverserforward
|
||||
{ -1 },
|
||||
// reverserneutral
|
||||
|
||||
40
material.cpp
40
material.cpp
@@ -14,15 +14,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Globals.h"
|
||||
#include "utilities.h"
|
||||
|
||||
// helper, returns potential path part from provided file name
|
||||
std::string path( std::string const &Filename )
|
||||
{
|
||||
return (
|
||||
Filename.rfind( '/' ) != std::string::npos ?
|
||||
Filename.substr( 0, Filename.rfind( '/' ) + 1 ) :
|
||||
"" );
|
||||
}
|
||||
|
||||
bool
|
||||
opengl_material::deserialize( cParser &Input, bool const Loadnow ) {
|
||||
|
||||
@@ -120,23 +111,21 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
|
||||
filename.erase( 0, 1 );
|
||||
}
|
||||
|
||||
filename += ".mat";
|
||||
|
||||
// try to locate requested material in the databank
|
||||
auto const databanklookup = find_in_databank( filename );
|
||||
auto const databanklookup { find_in_databank( filename ) };
|
||||
if( databanklookup != null_handle ) {
|
||||
return databanklookup;
|
||||
}
|
||||
// if this fails, try to look for it on disk
|
||||
opengl_material material;
|
||||
auto const disklookup = find_on_disk( filename );
|
||||
if( disklookup != "" ) {
|
||||
cParser materialparser( disklookup, cParser::buffer_FILE );
|
||||
auto const disklookup { find_on_disk( filename ) };
|
||||
if( false == disklookup.first.empty() ) {
|
||||
cParser materialparser( disklookup.first + disklookup.second, cParser::buffer_FILE );
|
||||
if( false == material.deserialize( materialparser, Loadnow ) ) {
|
||||
// deserialization failed but the .mat file does exist, so we give up at this point
|
||||
return null_handle;
|
||||
}
|
||||
material.name = disklookup;
|
||||
material.name = disklookup.first;
|
||||
}
|
||||
else {
|
||||
// if there's no .mat file, this could be legacy method of referring just to diffuse texture directly, make a material out of it in such case
|
||||
@@ -148,7 +137,7 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
|
||||
// use texture path and name to tell the newly created materials apart
|
||||
filename = GfxRenderer.Texture( material.texture1 ).name;
|
||||
erase_extension( filename );
|
||||
material.name = filename + ".mat";
|
||||
material.name = filename;
|
||||
material.has_alpha = GfxRenderer.Texture( material.texture1 ).has_alpha;
|
||||
}
|
||||
|
||||
@@ -162,7 +151,7 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
|
||||
material_handle
|
||||
material_manager::find_in_databank( std::string const &Materialname ) const {
|
||||
|
||||
std::vector<std::string> filenames {
|
||||
std::vector<std::string> const filenames {
|
||||
Global.asCurrentTexturePath + Materialname,
|
||||
Materialname,
|
||||
szTexturePath + Materialname };
|
||||
@@ -173,20 +162,19 @@ material_manager::find_in_databank( std::string const &Materialname ) const {
|
||||
return lookup->second;
|
||||
}
|
||||
}
|
||||
|
||||
// all lookups failed
|
||||
return null_handle;
|
||||
}
|
||||
|
||||
// checks whether specified file exists.
|
||||
// NOTE: this is direct copy of the method used by texture manager. TBD, TODO: refactor into common routine?
|
||||
std::string
|
||||
// NOTE: technically could be static, but we might want to switch from global texture path to instance-specific at some point
|
||||
std::pair<std::string, std::string>
|
||||
material_manager::find_on_disk( std::string const &Materialname ) const {
|
||||
|
||||
return(
|
||||
FileExists( Global.asCurrentTexturePath + Materialname ) ? Global.asCurrentTexturePath + Materialname :
|
||||
FileExists( Materialname ) ? Materialname :
|
||||
FileExists( szTexturePath + Materialname ) ? szTexturePath + Materialname :
|
||||
"" );
|
||||
return (
|
||||
FileExists(
|
||||
{ Global.asCurrentTexturePath + Materialname, Materialname, szTexturePath + Materialname },
|
||||
{ ".mat" } ) );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -25,6 +25,9 @@ struct opengl_material {
|
||||
bool has_alpha { false }; // alpha state, calculated from presence of alpha in texture1
|
||||
std::string name;
|
||||
|
||||
// constructors
|
||||
opengl_material() = default;
|
||||
|
||||
// methods
|
||||
bool
|
||||
deserialize( cParser &Input, bool const Loadnow );
|
||||
@@ -59,7 +62,7 @@ private:
|
||||
material_handle
|
||||
find_in_databank( std::string const &Materialname ) const;
|
||||
// checks whether specified file exists. returns name of the located file, or empty string.
|
||||
std::string
|
||||
std::pair<std::string, std::string>
|
||||
find_on_disk( std::string const &Materialname ) const;
|
||||
// members:
|
||||
material_sequence m_materials;
|
||||
|
||||
49
scene.cpp
49
scene.cpp
@@ -228,6 +228,17 @@ basic_cell::deserialize( std::istream &Input ) {
|
||||
|| ( false == m_lines.empty() ) );
|
||||
}
|
||||
|
||||
// sends content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
basic_cell::export_as_text( std::ostream &Output ) const {
|
||||
|
||||
// text format export dumps only relevant basic objects
|
||||
// sounds
|
||||
for( auto const *sound : m_sounds ) {
|
||||
sound->export_as_text( Output );
|
||||
}
|
||||
}
|
||||
|
||||
// adds provided shape to the cell
|
||||
void
|
||||
basic_cell::insert( shape_node Shape ) {
|
||||
@@ -421,7 +432,7 @@ basic_cell::find( glm::dvec3 const &Point, float const Radius, bool const Onlyco
|
||||
std::tie( vehiclenearest, leastdistance ) = std::tie( vehicle, distance );
|
||||
}
|
||||
}
|
||||
return std::tie( vehiclenearest, leastdistance );
|
||||
return { vehiclenearest, leastdistance };
|
||||
}
|
||||
|
||||
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
|
||||
@@ -438,7 +449,7 @@ basic_cell::find( glm::dvec3 const &Point, TTrack const *Exclude ) const {
|
||||
endpointid = path->TestPoint( &point );
|
||||
if( endpointid >= 0 ) {
|
||||
|
||||
return std::tie( path, endpointid );
|
||||
return { path, endpointid };
|
||||
}
|
||||
}
|
||||
return { nullptr, -1 };
|
||||
@@ -457,7 +468,7 @@ basic_cell::find( glm::dvec3 const &Point, TTraction const *Exclude ) const {
|
||||
endpointid = traction->TestPoint( Point );
|
||||
if( endpointid >= 0 ) {
|
||||
|
||||
return std::tie( traction, endpointid );
|
||||
return { traction, endpointid };
|
||||
}
|
||||
}
|
||||
return { nullptr, -1 };
|
||||
@@ -530,7 +541,7 @@ basic_cell::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
|
||||
// adjusts cell bounding area to enclose specified node
|
||||
void
|
||||
basic_cell::enclose_area( editor::basic_node *Node ) {
|
||||
basic_cell::enclose_area( scene::basic_node *Node ) {
|
||||
|
||||
m_area.radius = std::max(
|
||||
m_area.radius,
|
||||
@@ -645,6 +656,16 @@ basic_section::deserialize( std::istream &Input ) {
|
||||
}
|
||||
}
|
||||
|
||||
// sends content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
basic_section::export_as_text( std::ostream &Output ) const {
|
||||
|
||||
// text format export dumps only relevant basic objects from non-empty cells
|
||||
for( auto const &cell : m_cells ) {
|
||||
cell.export_as_text( Output );
|
||||
}
|
||||
}
|
||||
|
||||
// adds provided shape to the section
|
||||
void
|
||||
basic_section::insert( shape_node Shape ) {
|
||||
@@ -708,7 +729,7 @@ basic_section::find( glm::dvec3 const &Point, float const Radius, bool const Onl
|
||||
std::tie( vehiclenearest, distancenearest ) = std::tie( vehiclefound, distancefound );
|
||||
}
|
||||
}
|
||||
return std::tie( vehiclenearest, distancenearest );
|
||||
return { vehiclenearest, distancenearest };
|
||||
}
|
||||
|
||||
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
|
||||
@@ -949,6 +970,18 @@ basic_region::deserialize( std::string const &Scenariofile ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// sends content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
basic_region::export_as_text( std::ostream &Output ) const {
|
||||
|
||||
for( auto *section : m_sections ) {
|
||||
// text format export dumps only relevant basic objects from non-empty sections
|
||||
if( section != nullptr ) {
|
||||
section->export_as_text( Output );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// legacy method, links specified path piece with potential neighbours
|
||||
void
|
||||
basic_region::TrackJoin( TTrack *Track ) {
|
||||
@@ -1212,7 +1245,7 @@ basic_region::find_vehicle( glm::dvec3 const &Point, float const Radius, bool co
|
||||
std::tie( nearestvehicle, nearestdistance ) = std::tie( foundvehicle, founddistance );
|
||||
}
|
||||
}
|
||||
return std::tie( nearestvehicle, nearestdistance );
|
||||
return { nearestvehicle, nearestdistance };
|
||||
}
|
||||
|
||||
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
|
||||
@@ -1225,7 +1258,7 @@ basic_region::find_path( glm::dvec3 const &Point, TTrack const *Exclude ) {
|
||||
return section( Point ).find( Point, Exclude );
|
||||
}
|
||||
|
||||
return std::make_tuple<TTrack *, int>( nullptr, -1 );
|
||||
return { nullptr, -1 };
|
||||
}
|
||||
|
||||
// finds a traction piece with one of its ends located in specified point. returns: located traction piece and id of the matching endpoint
|
||||
@@ -1238,7 +1271,7 @@ basic_region::find_traction( glm::dvec3 const &Point, TTraction const *Exclude )
|
||||
return section( Point ).find( Point, Exclude );
|
||||
}
|
||||
|
||||
return std::make_tuple<TTraction *, int>( nullptr, -1 );
|
||||
return { nullptr, -1 };
|
||||
}
|
||||
|
||||
// finds a traction piece located nearest to specified point, sharing section with specified other piece and powered in specified direction. returns: located traction piece
|
||||
|
||||
11
scene.h
11
scene.h
@@ -89,6 +89,9 @@ public:
|
||||
// restores content of the class from provided stream
|
||||
void
|
||||
deserialize( std::istream &Input );
|
||||
// sends content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
export_as_text( std::ostream &Output ) const;
|
||||
// adds provided shape to the cell
|
||||
void
|
||||
insert( shape_node Shape );
|
||||
@@ -149,7 +152,7 @@ private:
|
||||
using eventlauncher_sequence = std::vector<TEventLauncher *>;
|
||||
// methods
|
||||
void
|
||||
enclose_area( editor::basic_node *Node );
|
||||
enclose_area( scene::basic_node *Node );
|
||||
// members
|
||||
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE ) };
|
||||
bool m_active { false }; // whether the cell holds any actual data
|
||||
@@ -199,6 +202,9 @@ public:
|
||||
// restores content of the class from provided stream
|
||||
void
|
||||
deserialize( std::istream &Input );
|
||||
// sends content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
export_as_text( std::ostream &Output ) const;
|
||||
// adds provided shape to the section
|
||||
void
|
||||
insert( shape_node Shape );
|
||||
@@ -289,6 +295,9 @@ public:
|
||||
// restores content of the class from file with specified name. returns: true on success, false otherwise
|
||||
bool
|
||||
deserialize( std::string const &Scenariofile );
|
||||
// sends content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
export_as_text( std::ostream &Output ) const;
|
||||
// legacy method, links specified path piece with potential neighbours
|
||||
void
|
||||
TrackJoin( TTrack *Track );
|
||||
|
||||
@@ -139,7 +139,7 @@ shape_node::deserialize( std::istream &Input ) {
|
||||
|
||||
// restores content of the node from provided input stream
|
||||
shape_node &
|
||||
shape_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) {
|
||||
shape_node::import( cParser &Input, scene::node_data const &Nodedata ) {
|
||||
|
||||
// import common data
|
||||
m_name = Nodedata.name;
|
||||
@@ -520,7 +520,7 @@ lines_node::deserialize( std::istream &Input ) {
|
||||
|
||||
// restores content of the node from provded input stream
|
||||
lines_node &
|
||||
lines_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) {
|
||||
lines_node::import( cParser &Input, scene::node_data const &Nodedata ) {
|
||||
|
||||
// import common data
|
||||
m_name = Nodedata.name;
|
||||
@@ -681,12 +681,9 @@ memory_node::deserialize( cParser &Input, node_data const &Nodedata ) {
|
||||
memorycell.Load( &Input );
|
||||
}
|
||||
*/
|
||||
} // scene
|
||||
|
||||
|
||||
|
||||
namespace editor {
|
||||
|
||||
basic_node::basic_node( scene::node_data const &Nodedata ) :
|
||||
m_name( Nodedata.name )
|
||||
{
|
||||
@@ -697,23 +694,69 @@ basic_node::basic_node( scene::node_data const &Nodedata ) :
|
||||
std::numeric_limits<double>::max() );
|
||||
}
|
||||
|
||||
// sends content of the class to provided stream
|
||||
void
|
||||
basic_node::serialize( std::ostream &Output ) const {
|
||||
// bounding area
|
||||
m_area.serialize( Output );
|
||||
// visibility
|
||||
sn_utils::ls_float64( Output, m_rangesquaredmin );
|
||||
sn_utils::ls_float64( Output, m_rangesquaredmax );
|
||||
sn_utils::s_bool( Output, m_visible );
|
||||
// name
|
||||
sn_utils::s_str( Output, m_name );
|
||||
// template method implementation
|
||||
serialize_( Output );
|
||||
}
|
||||
|
||||
// restores content of the class from provided stream
|
||||
void
|
||||
basic_node::deserialize( std::istream &Input ) {
|
||||
// bounding area
|
||||
m_area.deserialize( Input );
|
||||
// visibility
|
||||
m_rangesquaredmin = sn_utils::ld_float64( Input );
|
||||
m_rangesquaredmax = sn_utils::ld_float64( Input );
|
||||
m_visible = sn_utils::d_bool( Input );
|
||||
// name
|
||||
m_name = sn_utils::d_str( Input );
|
||||
// template method implementation
|
||||
deserialize_( Input );
|
||||
}
|
||||
|
||||
// sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
basic_node::export_as_text( std::ostream &Output ) const {
|
||||
|
||||
Output
|
||||
// header
|
||||
<< "node"
|
||||
// visibility
|
||||
<< ' ' << ( m_rangesquaredmax < std::numeric_limits<double>::max() ? std::sqrt( m_rangesquaredmax ) : -1 )
|
||||
<< ' ' << std::sqrt( m_rangesquaredmin )
|
||||
// name
|
||||
<< ' ' << m_name << ' ';
|
||||
// template method implementation
|
||||
export_as_text_( Output );
|
||||
}
|
||||
|
||||
float const &
|
||||
basic_node::radius() {
|
||||
|
||||
if( m_area.radius == -1.0 ) {
|
||||
// calculate if needed
|
||||
radius_();
|
||||
m_area.radius = radius_();
|
||||
}
|
||||
return m_area.radius;
|
||||
}
|
||||
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
// by default nodes are 'virtual don't extend from their center point
|
||||
void
|
||||
float
|
||||
basic_node::radius_() {
|
||||
|
||||
m_area.radius = 0.f;
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
} // editor
|
||||
} // scene
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
34
scenenode.h
34
scenenode.h
@@ -112,7 +112,7 @@ public:
|
||||
deserialize( std::istream &Input );
|
||||
// restores content of the node from provided input stream
|
||||
shape_node &
|
||||
deserialize( cParser &Input, scene::node_data const &Nodedata );
|
||||
import( cParser &Input, scene::node_data const &Nodedata );
|
||||
// imports data from provided submodel
|
||||
shape_node &
|
||||
convert( TSubModel const *Submodel );
|
||||
@@ -201,7 +201,7 @@ public:
|
||||
deserialize( std::istream &Input );
|
||||
// restores content of the node from provided input stream
|
||||
lines_node &
|
||||
deserialize( cParser &Input, scene::node_data const &Nodedata );
|
||||
import( cParser &Input, scene::node_data const &Nodedata );
|
||||
// adds content of provided node to already enclosed geometry. returns: true if merge could be performed
|
||||
bool
|
||||
merge( lines_node &Lines );
|
||||
@@ -295,12 +295,9 @@ private:
|
||||
TTrack * m_path;
|
||||
};
|
||||
*/
|
||||
} // scene
|
||||
|
||||
|
||||
|
||||
namespace editor {
|
||||
|
||||
// base interface for nodes which can be actvated in scenario editor
|
||||
struct basic_node {
|
||||
|
||||
@@ -310,6 +307,15 @@ public:
|
||||
// destructor
|
||||
virtual ~basic_node() = default;
|
||||
// methods
|
||||
// sends content of the class to provided stream
|
||||
void
|
||||
serialize( std::ostream &Output ) const;
|
||||
// restores content of the class from provided stream
|
||||
void
|
||||
deserialize( std::istream &Input );
|
||||
// sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
export_as_text( std::ostream &Output ) const;
|
||||
std::string const &
|
||||
name() const;
|
||||
void
|
||||
@@ -324,15 +330,23 @@ public:
|
||||
visible() const;
|
||||
|
||||
protected:
|
||||
// methods
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
virtual void radius_();
|
||||
// members
|
||||
scene::bounding_area m_area;
|
||||
bool m_visible { true };
|
||||
double m_rangesquaredmin { 0.0 }; // visibility range, min
|
||||
double m_rangesquaredmax { 0.0 }; // visibility range, max
|
||||
bool m_visible { true }; // visibility flag
|
||||
std::string m_name;
|
||||
|
||||
private:
|
||||
// methods
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
virtual float radius_();
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
virtual void serialize_( std::ostream &Output ) const = 0;
|
||||
// deserialize() subclass details, restores content of the subclass from provided stream
|
||||
virtual void deserialize_( std::istream &Input ) = 0;
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
virtual void export_as_text_( std::ostream &Output ) const = 0;
|
||||
};
|
||||
|
||||
inline
|
||||
@@ -365,6 +379,6 @@ basic_node::visible() const {
|
||||
return m_visible;
|
||||
}
|
||||
|
||||
} // editor
|
||||
} // scene
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "renderer.h"
|
||||
#include "World.h"
|
||||
|
||||
|
||||
namespace simulation {
|
||||
|
||||
state_manager State;
|
||||
@@ -58,8 +59,6 @@ state_manager::deserialize( std::string const &Scenariofile ) {
|
||||
// as long as the scenario file wasn't rainsted-created base file override
|
||||
Region->serialize( Scenariofile );
|
||||
}
|
||||
|
||||
Global.iPause &= ~0x10; // koniec pauzy wczytywania
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -419,7 +418,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
|
||||
simulation::Region->insert_shape(
|
||||
scene::shape_node().deserialize(
|
||||
scene::shape_node().import(
|
||||
Input, nodedata ),
|
||||
Scratchpad,
|
||||
true );
|
||||
@@ -436,7 +435,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
|
||||
simulation::Region->insert_lines(
|
||||
scene::lines_node().deserialize(
|
||||
scene::lines_node().import(
|
||||
Input, nodedata ),
|
||||
Scratchpad );
|
||||
}
|
||||
@@ -449,7 +448,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
|
||||
auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Memory.insert( memorycell ) ) {
|
||||
ErrorLog( "Bad scenario: memory cell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
/*
|
||||
// TODO: implement this
|
||||
@@ -805,7 +804,7 @@ state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratch
|
||||
}
|
||||
|
||||
if( ( true == Scratchpad.trainset.vehicles.empty() ) // jeśli pierwszy pojazd,
|
||||
&& ( false == path->asEvent0Name.empty() ) // tor ma Event0
|
||||
&& ( false == path->m_events0.empty() ) // tor ma Event0
|
||||
&& ( std::abs( velocity ) <= 1.f ) // a skład stoi
|
||||
&& ( Scratchpad.trainset.offset >= 0.0 ) // ale może nie sięgać na owy tor
|
||||
&& ( Scratchpad.trainset.offset < 8.0 ) ) { // i raczej nie sięga
|
||||
@@ -912,6 +911,65 @@ state_manager::transform( glm::dvec3 Location, scene::scratch_data const &Scratc
|
||||
return Location;
|
||||
}
|
||||
|
||||
|
||||
// stores class data in specified file, in legacy (text) format
|
||||
void
|
||||
state_manager::export_as_text( std::string const &Scenariofile ) const {
|
||||
|
||||
if( Scenariofile == "$.scn" ) {
|
||||
ErrorLog( "Bad file: scenery export not supported for file \"$.scn\"" );
|
||||
}
|
||||
else {
|
||||
WriteLog( "Scenery data export in progress..." );
|
||||
}
|
||||
|
||||
auto filename { Scenariofile };
|
||||
while( filename[ 0 ] == '$' ) {
|
||||
// trim leading $ char rainsted utility may add to the base name for modified .scn files
|
||||
filename.erase( 0, 1 );
|
||||
}
|
||||
erase_extension( filename );
|
||||
filename = Global.asCurrentSceneryPath + filename + "_export";
|
||||
|
||||
std::ofstream scmfile { filename + ".scm" };
|
||||
// tracks
|
||||
scmfile << "// paths\n";
|
||||
for( auto const *path : Paths.sequence() ) {
|
||||
path->export_as_text( scmfile );
|
||||
}
|
||||
// traction
|
||||
scmfile << "// traction\n";
|
||||
for( auto const *traction : Traction.sequence() ) {
|
||||
traction->export_as_text( scmfile );
|
||||
}
|
||||
// power grid
|
||||
scmfile << "// traction power sources\n";
|
||||
for( auto const *powersource : Powergrid.sequence() ) {
|
||||
powersource->export_as_text( scmfile );
|
||||
}
|
||||
// models
|
||||
scmfile << "// instanced models\n";
|
||||
for( auto const *instance : Instances.sequence() ) {
|
||||
instance->export_as_text( scmfile );
|
||||
}
|
||||
// sounds
|
||||
scmfile << "// sounds\n";
|
||||
Region->export_as_text( scmfile );
|
||||
|
||||
std::ofstream ctrfile { filename + ".ctr" };
|
||||
// mem cells
|
||||
ctrfile << "// memory cells\n";
|
||||
for( auto const *memorycell : Memory.sequence() ) {
|
||||
if( true == memorycell->is_exportable ) {
|
||||
memorycell->export_as_text( ctrfile );
|
||||
}
|
||||
}
|
||||
// events
|
||||
Events.export_as_text( ctrfile );
|
||||
|
||||
WriteLog( "Scenery data export done." );
|
||||
}
|
||||
|
||||
} // simulation
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -37,6 +37,9 @@ public:
|
||||
update( double Deltatime, int Iterationcount );
|
||||
bool
|
||||
deserialize( std::string const &Scenariofile );
|
||||
// stores class data in specified file, in legacy (text) format
|
||||
void
|
||||
export_as_text( std::string const &Scenariofile ) const;
|
||||
|
||||
private:
|
||||
// methods
|
||||
@@ -71,6 +74,7 @@ private:
|
||||
void skip_until( cParser &Input, std::string const &Token );
|
||||
// transforms provided location by specifed rotation and offset
|
||||
glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad );
|
||||
|
||||
};
|
||||
|
||||
extern state_manager State;
|
||||
|
||||
37
sound.cpp
37
sound.cpp
@@ -295,6 +295,43 @@ sound_source::deserialize_soundset( cParser &Input ) {
|
||||
}
|
||||
}
|
||||
|
||||
// sends content of the class in legacy (text) format to provided stream
|
||||
// NOTE: currently exports only the main sound
|
||||
void
|
||||
sound_source::export_as_text( std::ostream &Output ) const {
|
||||
|
||||
if( sound( sound_id::main ).buffer == null_handle ) { return; }
|
||||
|
||||
// generic node header
|
||||
Output
|
||||
<< "node "
|
||||
// visibility
|
||||
<< m_range << ' '
|
||||
<< 0 << ' '
|
||||
// name
|
||||
<< m_name << ' ';
|
||||
// sound node header
|
||||
Output
|
||||
<< "sound ";
|
||||
// location
|
||||
Output
|
||||
<< m_offset.x << ' '
|
||||
<< m_offset.y << ' '
|
||||
<< m_offset.z << ' ';
|
||||
// sound data
|
||||
auto soundfile { audio::renderer.buffer( sound( sound_id::main ).buffer ).name };
|
||||
if( soundfile.find( szSoundPath ) == 0 ) {
|
||||
// don't include 'sounds/' in the path
|
||||
soundfile.erase( 0, std::string{ szSoundPath }.size() );
|
||||
}
|
||||
Output
|
||||
<< soundfile << ' ';
|
||||
// footer
|
||||
Output
|
||||
<< "endsound"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
// copies list of sounds from provided source
|
||||
sound_source &
|
||||
sound_source::copy_sounds( sound_source const &Source ) {
|
||||
|
||||
3
sound.h
3
sound.h
@@ -60,6 +60,9 @@ public:
|
||||
deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = 0, int const Chunkrange = 100 );
|
||||
sound_source &
|
||||
deserialize( std::string const &Input, sound_type const Legacytype, int const Legacyparameters = 0 );
|
||||
// sends content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
export_as_text( std::ostream &Output ) const;
|
||||
// copies list of sounds from provided source
|
||||
sound_source &
|
||||
copy_sounds( sound_source const &Source );
|
||||
|
||||
13
uilayer.cpp
13
uilayer.cpp
@@ -116,6 +116,7 @@ ui_layer::on_key( int const Key, int const Action ) {
|
||||
case GLFW_KEY_F8:
|
||||
case GLFW_KEY_F9:
|
||||
case GLFW_KEY_F10:
|
||||
case GLFW_KEY_F11:
|
||||
case GLFW_KEY_F12: { // ui mode selectors
|
||||
|
||||
if( ( true == Global.ctrlState )
|
||||
@@ -303,11 +304,17 @@ ui_layer::update() {
|
||||
|
||||
if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) {
|
||||
// detail mode on second key press
|
||||
auto const speedlimit { static_cast<int>( std::floor( driver->VelDesired ) ) };
|
||||
uitextline2 +=
|
||||
" Speed: " + std::to_string( static_cast<int>( std::floor( mover->Vel ) ) ) + " km/h"
|
||||
+ " (limit: " + std::to_string( static_cast<int>( std::floor( driver->VelDesired ) ) ) + " km/h"
|
||||
+ ", next limit: " + std::to_string( static_cast<int>( std::floor( controlled->Mechanik->VelNext ) ) ) + " km/h"
|
||||
+ " in " + to_string( controlled->Mechanik->ActualProximityDist * 0.001, 1 ) + " km)";
|
||||
+ " (limit: " + std::to_string( speedlimit ) + " km/h";
|
||||
auto const nextspeedlimit { static_cast<int>( std::floor( controlled->Mechanik->VelNext ) ) };
|
||||
if( nextspeedlimit != speedlimit ) {
|
||||
uitextline2 +=
|
||||
", new limit: " + std::to_string( nextspeedlimit ) + " km/h"
|
||||
+ " in " + to_string( controlled->Mechanik->ActualProximityDist * 0.001, 1 ) + " km";
|
||||
}
|
||||
uitextline2 += ")";
|
||||
uitextline3 +=
|
||||
" Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa"
|
||||
+ " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)";
|
||||
|
||||
@@ -328,6 +328,20 @@ bool FileExists( std::string const &Filename ) {
|
||||
return( true == file.is_open() );
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string>
|
||||
FileExists( std::vector<std::string> const &Names, std::vector<std::string> const &Extensions ) {
|
||||
|
||||
for( auto const &name : Names ) {
|
||||
for( auto const &extension : Extensions ) {
|
||||
if( FileExists( name + extension ) ) {
|
||||
return { name, extension };
|
||||
}
|
||||
}
|
||||
}
|
||||
// nothing found
|
||||
return { {}, {} };
|
||||
}
|
||||
|
||||
// returns time of last modification for specified file
|
||||
std::time_t
|
||||
last_modified( std::string const &Filename ) {
|
||||
@@ -363,3 +377,13 @@ replace_slashes( std::string &Filename ) {
|
||||
std::begin( Filename ), std::end( Filename ),
|
||||
'\\', '/' );
|
||||
}
|
||||
|
||||
// returns potential path part from provided file name
|
||||
std::string
|
||||
substr_path( std::string const &Filename ) {
|
||||
|
||||
return (
|
||||
Filename.rfind( '/' ) != std::string::npos ?
|
||||
Filename.substr( 0, Filename.rfind( '/' ) + 1 ) :
|
||||
"" );
|
||||
}
|
||||
|
||||
@@ -179,6 +179,8 @@ extract_value( bool &Variable, std::string const &Key, std::string const &Input,
|
||||
|
||||
bool FileExists( std::string const &Filename );
|
||||
|
||||
std::pair<std::string, std::string> FileExists( std::vector<std::string> const &Names, std::vector<std::string> const &Extensions );
|
||||
|
||||
// returns time of last modification for specified file
|
||||
std::time_t last_modified( std::string const &Filename );
|
||||
|
||||
@@ -190,6 +192,9 @@ erase_extension( std::string &Filename );
|
||||
void
|
||||
replace_slashes( std::string &Filename );
|
||||
|
||||
// returns potential path part from provided file name
|
||||
std::string substr_path( std::string const &Filename );
|
||||
|
||||
template <typename Type_>
|
||||
void SafeDelete( Type_ &Pointer ) {
|
||||
delete Pointer;
|
||||
@@ -227,6 +232,8 @@ template <typename Type_>
|
||||
Type_
|
||||
min_speed( Type_ const Left, Type_ const Right ) {
|
||||
|
||||
if( Left == Right ) { return Left; }
|
||||
|
||||
return std::min(
|
||||
( Left != -1 ?
|
||||
Left :
|
||||
|
||||
Reference in New Issue
Block a user