16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 20:59:19 +02:00

continued refacoring: vehicles, events, memcells, tracks, traction, traction power sources; minor readability enhancements and bug fixes

This commit is contained in:
tmj-fstate
2017-10-11 20:21:05 +02:00
parent 020c71533f
commit de4e10ab39
39 changed files with 1849 additions and 907 deletions

View File

@@ -19,12 +19,7 @@ TAdvancedSound::~TAdvancedSound()
// SoundShut.Stop(); // SoundShut.Stop();
} }
void TAdvancedSound::Free() void TAdvancedSound::Init( std::string const &NameOn, std::string const &Name, std::string const &NameOff, double DistanceAttenuation, Math3D::vector3 const &pPosition)
{
}
void TAdvancedSound::Init( std::string const &NameOn, std::string const &Name, std::string const &NameOff, double DistanceAttenuation,
vector3 const &pPosition)
{ {
SoundStart.Init(NameOn, DistanceAttenuation, pPosition.x, pPosition.y, pPosition.z, true); SoundStart.Init(NameOn, DistanceAttenuation, pPosition.x, pPosition.y, pPosition.z, true);
SoundCommencing.Init(Name, DistanceAttenuation, pPosition.x, pPosition.y, pPosition.z, true); SoundCommencing.Init(Name, DistanceAttenuation, pPosition.x, pPosition.y, pPosition.z, true);
@@ -47,7 +42,7 @@ void TAdvancedSound::Init( std::string const &NameOn, std::string const &Name, s
SoundShut.FA = 0.0; SoundShut.FA = 0.0;
} }
void TAdvancedSound::Load(cParser &Parser, vector3 const &pPosition) void TAdvancedSound::Load(cParser &Parser, Math3D::vector3 const &pPosition)
{ {
std::string nameon, name, nameoff; std::string nameon, name, nameoff;
double attenuation; double attenuation;
@@ -62,7 +57,7 @@ void TAdvancedSound::Load(cParser &Parser, vector3 const &pPosition)
Init( nameon, name, nameoff, attenuation, pPosition ); Init( nameon, name, nameoff, attenuation, pPosition );
} }
void TAdvancedSound::TurnOn(bool ListenerInside, vector3 NewPosition) void TAdvancedSound::TurnOn(bool ListenerInside, Math3D::vector3 NewPosition)
{ {
// hunter-311211: nie trzeba czekac na ponowne odtworzenie dzwieku, az sie wylaczy // hunter-311211: nie trzeba czekac na ponowne odtworzenie dzwieku, az sie wylaczy
if ((State == ss_Off || State == ss_ShuttingDown) && (SoundStart.AM > 0)) if ((State == ss_Off || State == ss_ShuttingDown) && (SoundStart.AM > 0))
@@ -76,7 +71,7 @@ void TAdvancedSound::TurnOn(bool ListenerInside, vector3 NewPosition)
} }
} }
void TAdvancedSound::TurnOff(bool ListenerInside, vector3 NewPosition) void TAdvancedSound::TurnOff(bool ListenerInside, Math3D::vector3 NewPosition)
{ {
if ((State == ss_Commencing || State == ss_Starting) && (SoundShut.AM > 0)) if ((State == ss_Commencing || State == ss_Starting) && (SoundShut.AM > 0))
{ {
@@ -90,7 +85,7 @@ void TAdvancedSound::TurnOff(bool ListenerInside, vector3 NewPosition)
} }
} }
void TAdvancedSound::Update(bool ListenerInside, vector3 NewPosition) void TAdvancedSound::Update(bool ListenerInside, Math3D::vector3 NewPosition)
{ {
if ((State == ss_Commencing) && (SoundCommencing.AM > 0)) if ((State == ss_Commencing) && (SoundCommencing.AM > 0))
{ {
@@ -126,7 +121,7 @@ void TAdvancedSound::Update(bool ListenerInside, vector3 NewPosition)
} }
} }
void TAdvancedSound::UpdateAF(double A, double F, bool ListenerInside, vector3 NewPosition) void TAdvancedSound::UpdateAF(double A, double F, bool ListenerInside, Math3D::vector3 NewPosition)
{ // update, ale z amplituda i czestotliwoscia { // update, ale z amplituda i czestotliwoscia
if( State == ss_Off ) { if( State == ss_Off ) {
return; return;

View File

@@ -13,13 +13,13 @@ http://mozilla.org/MPL/2.0/.
#include "RealSound.h" #include "RealSound.h"
#include "parser.h" #include "parser.h"
typedef enum enum TSoundState {
{
ss_Off, ss_Off,
ss_Starting, ss_Starting,
ss_Commencing, ss_Commencing,
ss_ShuttingDown ss_ShuttingDown
} TSoundState; };
class TAdvancedSound class TAdvancedSound
{ // klasa dźwięków mających początek, dowolnie długi środek oraz zakończenie (np. Rp1) { // klasa dźwięków mających początek, dowolnie długi środek oraz zakończenie (np. Rp1)
@@ -36,13 +36,12 @@ class TAdvancedSound
public: public:
TAdvancedSound() = default; TAdvancedSound() = default;
~TAdvancedSound(); ~TAdvancedSound();
void Init( std::string const &NameOn, std::string const &Name, std::string const &NameOff, double DistanceAttenuation, vector3 const &pPosition); void Init( std::string const &NameOn, std::string const &Name, std::string const &NameOff, double DistanceAttenuation, Math3D::vector3 const &pPosition);
void Load(cParser &Parser, vector3 const &pPosition); void Load(cParser &Parser, Math3D::vector3 const &pPosition);
void TurnOn(bool ListenerInside, vector3 NewPosition); void TurnOn(bool ListenerInside, Math3D::vector3 NewPosition);
void TurnOff(bool ListenerInside, vector3 NewPosition); void TurnOff(bool ListenerInside, Math3D::vector3 NewPosition);
void Free(); void Update(bool ListenerInside, Math3D::vector3 NewPosition);
void Update(bool ListenerInside, vector3 NewPosition); void UpdateAF(double A, double F, bool ListenerInside, Math3D::vector3 NewPosition);
void UpdateAF(double A, double F, bool ListenerInside, vector3 NewPosition);
void CopyIfEmpty(TAdvancedSound &s); void CopyIfEmpty(TAdvancedSound &s);
}; };

View File

@@ -759,21 +759,27 @@ void TAnimModel::LightSet(int n, float v)
{ // ustawienie światła (n) na wartość (v) { // ustawienie światła (n) na wartość (v)
if (n >= iMaxNumLights) if (n >= iMaxNumLights)
return; // przekroczony zakres return; // przekroczony zakres
lsLights[n] = TLightState(int(v)); lsLights[ n ] = TLightState( static_cast<int>( v ) );
switch (lsLights[n]) switch( lsLights[ n ] ) {
{ // interpretacja ułamka zależnie od typu // interpretacja ułamka zależnie od typu
case 0: // ustalenie czasu migotania, t<1s (f>1Hz), np. 0.1 => t=0.1 (f=10Hz) case ls_Off: {
break; // ustalenie czasu migotania, t<1s (f>1Hz), np. 0.1 => t=0.1 (f=10Hz)
case 1: // ustalenie wypełnienia ułamkiem, np. 1.25 => zapalony przez 1/4 okresu break;
break; }
case 2: // ustalenie częstotliwości migotania, f<1Hz (t>1s), np. 2.2 => f=0.2Hz (t=5s) case ls_On: {
break; // ustalenie wypełnienia ułamkiem, np. 1.25 => zapalony przez 1/4 okresu
case 3: // zapalenie świateł zależne od oświetlenia scenerii break;
if (v > 3.0) }
fDark = v - 3.0; // ustawienie indywidualnego progu zapalania case ls_Blink: {
else // ustalenie częstotliwości migotania, f<1Hz (t>1s), np. 2.2 => f=0.2Hz (t=5s)
fDark = 0.25; // standardowy próg zaplania break;
break; }
case ls_Dark: {
// zapalenie świateł zależne od oświetlenia scenerii
if( v > 3.0 ) { fDark = v - 3.0; } // ustawienie indywidualnego progu zapalania
else { fDark = 0.25; } // standardowy próg zaplania
break;
}
} }
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -176,7 +176,9 @@ private:
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
}; };
class instance_manager : public basic_table<TAnimModel> {
class instance_table : public basic_table<TAnimModel> {
}; };

View File

@@ -37,7 +37,7 @@ class TMtableTime; // czas dla danego posterunku
class TController; // obiekt sterujący pociągiem (AI) class TController; // obiekt sterujący pociągiem (AI)
typedef enum enum TCommandType
{ // binarne odpowiedniki komend w komórce pamięci { // binarne odpowiedniki komend w komórce pamięci
cm_Unknown, // ciąg nierozpoznany (nie jest komendą) cm_Unknown, // ciąg nierozpoznany (nie jest komendą)
cm_Ready, // W4 zezwala na odjazd, ale semafor może zatrzymać cm_Ready, // W4 zezwala na odjazd, ale semafor może zatrzymać
@@ -51,6 +51,6 @@ typedef enum
cm_OutsideStation, cm_OutsideStation,
cm_Shunt, cm_Shunt,
cm_Command // komenda pobierana z komórki cm_Command // komenda pobierana z komórki
} TCommandType; };
#endif #endif

View File

@@ -4150,7 +4150,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
// Ra 15-01: gałka nastawy hamulca // Ra 15-01: gałka nastawy hamulca
parser.getTokens(); parser.getTokens();
parser >> asAnimName; parser >> asAnimName;
smBrakeMode = mdModel->GetFromName(asAnimName.c_str()); smBrakeMode = mdModel->GetFromName(asAnimName);
// jeszcze wczytać kąty obrotu dla poszczególnych ustawień // jeszcze wczytać kąty obrotu dla poszczególnych ustawień
} }
@@ -4158,7 +4158,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
// Ra 15-01: gałka nastawy hamulca // Ra 15-01: gałka nastawy hamulca
parser.getTokens(); parser.getTokens();
parser >> asAnimName; parser >> asAnimName;
smLoadMode = mdModel->GetFromName(asAnimName.c_str()); smLoadMode = mdModel->GetFromName(asAnimName);
// jeszcze wczytać kąty obrotu dla poszczególnych ustawień // jeszcze wczytać kąty obrotu dla poszczególnych ustawień
} }
@@ -4170,7 +4170,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
for (i = 0; i < iAnimType[ANIM_WHEELS]; ++i) // liczba osi for (i = 0; i < iAnimType[ANIM_WHEELS]; ++i) // liczba osi
{ // McZapkie-050402: wyszukiwanie kol o nazwie str* { // McZapkie-050402: wyszukiwanie kol o nazwie str*
asAnimName = token + std::to_string(i + 1); asAnimName = token + std::to_string(i + 1);
pAnimations[i].smAnimated = mdModel->GetFromName(asAnimName.c_str()); // ustalenie submodelu pAnimations[i].smAnimated = mdModel->GetFromName(asAnimName); // ustalenie submodelu
if (pAnimations[i].smAnimated) if (pAnimations[i].smAnimated)
{ //++iAnimatedAxles; { //++iAnimatedAxles;
pAnimations[i].smAnimated->WillBeAnimated(); // wyłączenie optymalizacji transformu pAnimations[i].smAnimated->WillBeAnimated(); // wyłączenie optymalizacji transformu
@@ -4311,8 +4311,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
} }
} }
else else
ErrorLog("Bad model: " + asFileName + " - missed submodel " + ErrorLog("Bad model: " + asFileName + " - missed submodel " + asAnimName); // brak ramienia
asAnimName); // brak ramienia
} }
} }
@@ -4346,10 +4345,9 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
} }
} }
else else
ErrorLog( "Bad model: " + asFileName + " - missed submodel " + ErrorLog( "Bad model: " + asFileName + " - missed submodel " + asAnimName ); // brak ramienia
asAnimName ); // brak ramienia
} }
} }
} }
else if( token == "animpantrg1prefix:" ) { else if( token == "animpantrg1prefix:" ) {
@@ -5393,3 +5391,59 @@ TDynamicObject::ConnectedEnginePowerSource( TDynamicObject const *Caller ) const
// ...if we're still here, report lack of power source // ...if we're still here, report lack of power source
return MoverParameters->EnginePowerSource.SourceType; return MoverParameters->EnginePowerSource.SourceType;
} }
// legacy method, calculates changes in simulation state over specified time
void
vehicle_table::update( double Deltatime, int Iterationcount ) {
// Ra: w zasadzie to trzeba by utworzyć oddzielną listę taboru do liczenia fizyki
// na którą by się zapisywały wszystkie pojazdy będące w ruchu
// pojazdy stojące nie potrzebują aktualizacji, chyba że np. ktoś im zmieni nastawę hamulca
// oddzielną listę można by zrobić na pojazdy z napędem, najlepiej posortowaną wg typu napędu
for( auto *vehicle : m_items ) {
// Ra: zmienić warunek na sprawdzanie pantografów w jednej zmiennej: czy pantografy i czy podniesione
if( vehicle->MoverParameters->EnginePowerSource.SourceType == CurrentCollector ) {
/*
// TODO: re-implement
GetTraction( vehicle );
*/
}
vehicle->MoverParameters->ComputeConstans();
vehicle->CoupleDist();
}
if( Iterationcount > 1 ) {
// ABu: ponizsze wykonujemy tylko jesli wiecej niz jedna iteracja
for( int iteration = 0; iteration < ( Iterationcount - 1 ); ++iteration ) {
for( auto *vehicle : m_items ) {
vehicle->UpdateForce( Deltatime, Deltatime, false );
}
for( auto *vehicle : m_items ) {
vehicle->FastUpdate( Deltatime );
}
}
}
auto const totaltime { Deltatime * Iterationcount }; // całkowity czas
for( auto *vehicle : m_items ) {
vehicle->UpdateForce( Deltatime, totaltime, true );
}
for( auto *vehicle : m_items ) {
// Ra 2015-01: tylko tu przelicza sieć trakcyjną
vehicle->Update( Deltatime, totaltime );
}
/*
// TODO: re-implement
if (bDynamicRemove)
{ // jeśli jest coś do usunięcia z listy, to trzeba na końcu
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
if ( false == Current->DynamicObject->bEnabled)
{
DynamicRemove(Current->DynamicObject); // usunięcie tego i podłączonych
Current = nRootDynamic; // sprawdzanie listy od początku
}
bDynamicRemove = false; // na razie koniec
}
*/
}

187
DynObj.h
View File

@@ -160,19 +160,17 @@ private: // położenie pojazdu w świecie oraz parametry ruchu
TTrackParam tp; // parametry toru przekazywane do fizyki TTrackParam tp; // parametry toru przekazywane do fizyki
TTrackFollower Axle0; // oś z przodu (od sprzęgu 0) TTrackFollower Axle0; // oś z przodu (od sprzęgu 0)
TTrackFollower Axle1; // oś z tyłu (od sprzęgu 1) TTrackFollower Axle1; // oś z tyłu (od sprzęgu 1)
int iAxleFirst; // numer pierwszej osi w kierunku ruchu (oś wiążąca pojazd z torem i wyzwalająca int iAxleFirst; // numer pierwszej osi w kierunku ruchu (oś wiążąca pojazd z torem i wyzwalająca eventy)
// eventy)
float fAxleDist; // rozstaw wózków albo osi do liczenia proporcji zacienienia float fAxleDist; // rozstaw wózków albo osi do liczenia proporcji zacienienia
Math3D::vector3 modelRot; // obrot pudła względem świata - do przeanalizowania, czy potrzebne!!! Math3D::vector3 modelRot; // obrot pudła względem świata - do przeanalizowania, czy potrzebne!!!
// bool bCameraNear; //blisko kamer są potrzebne dodatkowe obliczenia szczegółów
TDynamicObject * ABuFindNearestObject( TTrack *Track, TDynamicObject *MyPointer, int &CouplNr ); TDynamicObject * ABuFindNearestObject( TTrack *Track, TDynamicObject *MyPointer, int &CouplNr );
public: // parametry położenia pojazdu dostępne publicznie public:
// parametry położenia pojazdu dostępne publicznie
std::string asTrack; // nazwa toru początkowego; wywalić? std::string asTrack; // nazwa toru początkowego; wywalić?
std::string asDestination; // dokąd pojazd ma być kierowany "(stacja):(tor)" std::string asDestination; // dokąd pojazd ma być kierowany "(stacja):(tor)"
Math3D::matrix4x4 mMatrix; // macierz przekształcenia do renderowania modeli Math3D::matrix4x4 mMatrix; // macierz przekształcenia do renderowania modeli
TMoverParameters *MoverParameters; // parametry fizyki ruchu oraz przeliczanie TMoverParameters *MoverParameters; // parametry fizyki ruchu oraz przeliczanie
// TMoverParameters *pControlled; //wskaźnik do sterowanego członu silnikowego
TDynamicObject *NextConnected; // pojazd podłączony od strony sprzęgu 1 (kabina -1) TDynamicObject *NextConnected; // pojazd podłączony od strony sprzęgu 1 (kabina -1)
TDynamicObject *PrevConnected; // pojazd podłączony od strony sprzęgu 0 (kabina 1) TDynamicObject *PrevConnected; // pojazd podłączony od strony sprzęgu 0 (kabina 1)
int NextConnectedNo; // numer sprzęgu podłączonego z tyłu int NextConnectedNo; // numer sprzęgu podłączonego z tyłu
@@ -182,7 +180,7 @@ public: // parametry położenia pojazdu dostępne publicznie
TPowerSource ConnectedEnginePowerSource( TDynamicObject const *Caller ) const; TPowerSource ConnectedEnginePowerSource( TDynamicObject const *Caller ) const;
public: // modele składowe pojazdu // modele składowe pojazdu
TModel3d *mdModel; // model pudła TModel3d *mdModel; // model pudła
TModel3d *mdLoad; // model zmiennego ładunku TModel3d *mdLoad; // model zmiennego ładunku
TModel3d *mdKabina; // model kabiny dla użytkownika; McZapkie-030303: to z train.h TModel3d *mdKabina; // model kabiny dla użytkownika; McZapkie-030303: to z train.h
@@ -201,28 +199,26 @@ public: // modele składowe pojazdu
bool SectionLightsActive { false }; // flag indicating whether section lights were set. bool SectionLightsActive { false }; // flag indicating whether section lights were set.
float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?) float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?)
private: // zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe private:
// zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe
material_data m_materialdata; material_data m_materialdata;
public: public:
inline inline
material_data const material_data const
*Material() const { *Material() const {
return &m_materialdata; } return &m_materialdata; }
// tymczasowo udostępnione do wyszukiwania drutu // tymczasowo udostępnione do wyszukiwania drutu
int iAnimType[ ANIM_TYPES ]; // 0-osie,1-drzwi,2-obracane,3-zderzaki,4-wózki,5-pantografy,6-tłoki int iAnimType[ ANIM_TYPES ]; // 0-osie,1-drzwi,2-obracane,3-zderzaki,4-wózki,5-pantografy,6-tłoki
private: private:
int iAnimations; // liczba obiektów animujących int iAnimations; // liczba obiektów animujących
/* /*
TAnim *pAnimations; // obiekty animujące (zawierają wskaźnik do funkcji wykonującej animację) TAnim *pAnimations; // obiekty animujące (zawierają wskaźnik do funkcji wykonującej animację)
*/ */
std::vector<TAnim> pAnimations; std::vector<TAnim> pAnimations;
TSubModel ** TSubModel ** pAnimated; // lista animowanych submodeli (może być ich więcej niż obiektów animujących)
pAnimated; // lista animowanych submodeli (może być ich więcej niż obiektów animujących) double dWheelAngle[3]; // kąty obrotu kół: 0=przednie toczne, 1=napędzające i wiązary, 2=tylne toczne
double dWheelAngle[3]; // kąty obrotu kół: 0=przednie toczne, 1=napędzające i wiązary, 2=tylne void UpdateNone(TAnim *pAnim){}; // animacja pusta (funkcje ustawiania submodeli, gdy blisko kamery)
// toczne
void
UpdateNone(TAnim *pAnim){}; // animacja pusta (funkcje ustawiania submodeli, gdy blisko kamery)
void UpdateAxle(TAnim *pAnim); // animacja osi void UpdateAxle(TAnim *pAnim); // animacja osi
void UpdateBoogie(TAnim *pAnim); // animacja wózka void UpdateBoogie(TAnim *pAnim); // animacja wózka
void UpdateDoorTranslate(TAnim *pAnim); // animacja drzwi - przesuw void UpdateDoorTranslate(TAnim *pAnim); // animacja drzwi - przesuw
@@ -268,8 +264,7 @@ public: // modele składowe pojazdu
TButton btCoupler1; // sprzegi TButton btCoupler1; // sprzegi
TButton btCoupler2; TButton btCoupler2;
TAirCoupler TAirCoupler btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
TAirCoupler btCPneumatic2; TAirCoupler btCPneumatic2;
TAirCoupler btCPneumatic1r; // ABu: to zeby nie bylo problemow przy laczeniu wagonow, TAirCoupler btCPneumatic1r; // ABu: to zeby nie bylo problemow przy laczeniu wagonow,
TAirCoupler btCPneumatic2r; // jesli beda polaczone sprzegami 1<->1 lub 0<->0 TAirCoupler btCPneumatic2r; // jesli beda polaczone sprzegami 1<->1 lub 0<->0
@@ -300,8 +295,6 @@ public: // modele składowe pojazdu
TButton btHeadSignals23; TButton btHeadSignals23;
TButton btMechanik1; TButton btMechanik1;
TButton btMechanik2; TButton btMechanik2;
//TSubModel *smMechanik0; // Ra: mechanik wbudowany w model jako submodel?
//TSubModel *smMechanik1; // mechanik od strony sprzęgu 1
double enginevolume; // MC: pomocnicze zeby gladziej silnik buczal double enginevolume; // MC: pomocnicze zeby gladziej silnik buczal
int iAxles; // McZapkie: to potem mozna skasowac i zastapic iNumAxles int iAxles; // McZapkie: to potem mozna skasowac i zastapic iNumAxles
@@ -325,7 +318,6 @@ public: // modele składowe pojazdu
TAdvancedSound sReleaser; TAdvancedSound sReleaser;
// Winger 010304 // Winger 010304
// TRealSound rsPanTup; //PSound sPantUp;
TRealSound sPantUp; TRealSound sPantUp;
TRealSound sPantDown; TRealSound sPantDown;
TRealSound rsDoorOpen; // Ra: przeniesione z kabiny TRealSound rsDoorOpen; // Ra: przeniesione z kabiny
@@ -352,8 +344,6 @@ public: // modele składowe pojazdu
int iHornWarning; // numer syreny do użycia po otrzymaniu sygnału do jazdy int iHornWarning; // numer syreny do użycia po otrzymaniu sygnału do jazdy
bool bEnabled; // Ra: wyjechał na portal i ma być usunięty bool bEnabled; // Ra: wyjechał na portal i ma być usunięty
protected: protected:
// TTrackFollower Axle2; //dwie osie z czterech (te są protected)
// TTrackFollower Axle3; //Ra: wyłączyłem, bo kąty są liczone w Segment.cpp
int iNumAxles; // ilość osi int iNumAxles; // ilość osi
std::string asModel; std::string asModel;
@@ -373,26 +363,18 @@ public: // modele składowe pojazdu
TDynamicObject * PrevC(int C); TDynamicObject * PrevC(int C);
TDynamicObject * NextC(int C); TDynamicObject * NextC(int C);
double NextDistance(double d = -1.0); double NextDistance(double d = -1.0);
void SetdMoveLen(double dMoveLen) void SetdMoveLen(double dMoveLen) {
{ MoverParameters->dMoveLen = dMoveLen; }
MoverParameters->dMoveLen = dMoveLen; void ResetdMoveLen() {
} MoverParameters->dMoveLen = 0; }
void ResetdMoveLen() double GetdMoveLen() {
{ return MoverParameters->dMoveLen; }
MoverParameters->dMoveLen = 0;
}
double GetdMoveLen()
{
return MoverParameters->dMoveLen;
}
int GetPneumatic(bool front, bool red); int GetPneumatic(bool front, bool red);
void SetPneumatic(bool front, bool red); void SetPneumatic(bool front, bool red);
std::string asName; std::string asName;
std::string GetName() std::string name() const {
{ return this ? asName : std::string(); };
return this ? asName : std::string("");
};
TRealSound rsDiesielInc; // youBy TRealSound rsDiesielInc; // youBy
TRealSound rscurve; // youBy TRealSound rscurve; // youBy
@@ -405,7 +387,6 @@ public: // modele składowe pojazdu
TDynamicObject * ABuScanNearestObject(TTrack *Track, double ScanDir, double ScanDist, TDynamicObject * ABuScanNearestObject(TTrack *Track, double ScanDir, double ScanDist,
int &CouplNr); int &CouplNr);
TDynamicObject * GetFirstDynamic(int cpl_type, int cf = 1); TDynamicObject * GetFirstDynamic(int cpl_type, int cf = 1);
// TDynamicObject* GetFirstCabDynamic(int cpl_type);
void ABuSetModelShake( Math3D::vector3 mShake); void ABuSetModelShake( Math3D::vector3 mShake);
// McZapkie-010302 // McZapkie-010302
@@ -437,99 +418,65 @@ public: // modele składowe pojazdu
void Move(double fDistance); void Move(double fDistance);
void FastMove(double fDistance); void FastMove(double fDistance);
void RenderSounds(); void RenderSounds();
inline Math3D::vector3 GetPosition() const inline Math3D::vector3 GetPosition() const {
{ return vPosition; };
return vPosition; // pobranie współrzędnych czoła
}; inline Math3D::vector3 HeadPosition() {
inline Math3D::vector3 HeadPosition() return vCoulpler[iDirection ^ 1]; };
{ // pobranie współrzędnych tyłu
return vCoulpler[iDirection ^ 1]; inline Math3D::vector3 RearPosition() {
}; // pobranie współrzędnych czoła return vCoulpler[iDirection]; };
inline Math3D::vector3 RearPosition() inline Math3D::vector3 AxlePositionGet() {
{ return iAxleFirst ? Axle1.pPosition : Axle0.pPosition; };
return vCoulpler[iDirection]; inline Math3D::vector3 VectorFront() const {
}; // pobranie współrzędnych tyłu return vFront; };
inline Math3D::vector3 AxlePositionGet() inline Math3D::vector3 VectorUp() {
{ return vUp; };
return iAxleFirst ? Axle1.pPosition : Axle0.pPosition; inline Math3D::vector3 VectorLeft() const {
}; return vLeft; };
inline Math3D::vector3 VectorFront() const inline double * Matrix() {
{ return mMatrix.getArray(); };
return vFront; inline double GetVelocity() {
}; return MoverParameters->Vel; };
inline Math3D::vector3 VectorUp() inline double GetLength() const {
{ return MoverParameters->Dim.L; };
return vUp; inline double GetWidth() const {
}; return MoverParameters->Dim.W; };
inline Math3D::vector3 VectorLeft() const inline TTrack * GetTrack() {
{ return (iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack()); };
return vLeft;
};
inline double * Matrix()
{
return mMatrix.getArray();
};
inline double GetVelocity()
{
return MoverParameters->Vel;
};
inline double GetLength() const
{
return MoverParameters->Dim.L;
};
inline double GetWidth() const
{
return MoverParameters->Dim.W;
};
inline TTrack * GetTrack()
{
return (iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack());
};
// void UpdatePos();
// McZapkie-260202 // McZapkie-260202
void LoadMMediaFile(std::string BaseDir, std::string TypeName, std::string ReplacableSkin); void LoadMMediaFile(std::string BaseDir, std::string TypeName, std::string ReplacableSkin);
inline double ABuGetDirection() const // ABu. inline double ABuGetDirection() const { // ABu.
{ return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection()); };
return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection()); // zwraca kierunek pojazdu na torze z aktywną osą
}; inline double RaDirectionGet() {
// inline double ABuGetTranslation() //ABu. return iAxleFirst ? Axle1.GetDirection() : Axle0.GetDirection(); };
// {//zwraca przesunięcie wózka względem Point1 toru // zwraca przesunięcie wózka względem Point1 toru z aktywną osią
// return (Axle1.GetTrack()==MyTrack?Axle1.GetTranslation():Axle0.GetTranslation()); inline double RaTranslationGet() {
// }; return iAxleFirst ? Axle1.GetTranslation() : Axle0.GetTranslation(); };
inline double RaDirectionGet() // zwraca tor z aktywną osią
{ // zwraca kierunek pojazdu na torze z aktywną osą inline TTrack * RaTrackGet() {
return iAxleFirst ? Axle1.GetDirection() : Axle0.GetDirection(); return iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack(); };
};
inline double RaTranslationGet()
{ // zwraca przesunięcie wózka względem Point1 toru z aktywną osią
return iAxleFirst ? Axle1.GetTranslation() : Axle0.GetTranslation();
};
inline TTrack * RaTrackGet()
{ // zwraca tor z aktywną osią
return iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack();
};
void CouplersDettach(double MinDist, int MyScanDir); void CouplersDettach(double MinDist, int MyScanDir);
void RadioStop(); void RadioStop();
void Damage(char flag); void Damage(char flag);
void RaLightsSet(int head, int rear); void RaLightsSet(int head, int rear);
// void RaAxleEvent(TEvent *e);
TDynamicObject * FirstFind(int &coupler_nr, int cf = 1); TDynamicObject * FirstFind(int &coupler_nr, int cf = 1);
float GetEPP(); // wyliczanie sredniego cisnienia w PG float GetEPP(); // wyliczanie sredniego cisnienia w PG
int DirectionSet(int d); // ustawienie kierunku w składzie int DirectionSet(int d); // ustawienie kierunku w składzie
int DirectionGet() // odczyt kierunku w składzie
{ int DirectionGet() {
return iDirection + iDirection - 1; return iDirection + iDirection - 1; };
}; // odczyt kierunku w składzie
int DettachStatus(int dir); int DettachStatus(int dir);
int Dettach(int dir); int Dettach(int dir);
TDynamicObject * Neightbour(int &dir); TDynamicObject * Neightbour(int &dir);
void CoupleDist(); void CoupleDist();
TDynamicObject * ControlledFind(); TDynamicObject * ControlledFind();
void ParamSet(int what, int into); void ParamSet(int what, int into);
int RouteWish(TTrack *tr); // zapytanie do AI, po którym segmencie skrzyżowania // zapytanie do AI, po którym segmencie skrzyżowania jechać
// jechać int RouteWish(TTrack *tr);
void DestinationSet(std::string to, std::string numer); void DestinationSet(std::string to, std::string numer);
std::string TextureTest(std::string const &name); std::string TextureTest(std::string const &name);
void OverheadTrack(float o); void OverheadTrack(float o);
@@ -537,4 +484,14 @@ public: // modele składowe pojazdu
static std::string const MED_labels[ 8 ]; static std::string const MED_labels[ 8 ];
}; };
class vehicle_table : public basic_table<TDynamicObject> {
public:
// legacy method, calculates changes in simulation state over specified time
void
update( double dt, int iter );
};
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

248
Event.cpp
View File

@@ -74,10 +74,6 @@ TEvent::~TEvent() {
}; };
void TEvent::Init(){
};
void TEvent::Conditions(cParser *parser, std::string s) void TEvent::Conditions(cParser *parser, std::string s)
{ // przetwarzanie warunków, wspólne dla Multiple i UpdateValues { // przetwarzanie warunków, wspólne dla Multiple i UpdateValues
if (s == "condition") if (s == "condition")
@@ -949,7 +945,7 @@ event_manager::CheckQuery() {
// TODO: re-enable when messaging module is in place // TODO: re-enable when messaging module is in place
if( Global::iMultiplayer ) { if( Global::iMultiplayer ) {
// potwierdzenie wykonania dla serwera (odczyt semafora już tak nie działa) // potwierdzenie wykonania dla serwera (odczyt semafora już tak nie działa)
WyslijEvent( tmpEvent->asName, tmpEvent->Activator->GetName() ); WyslijEvent( tmpEvent->asName, tmpEvent->Activator->name() );
} }
*/ */
m_workevent->Params[ 9 ].asMemCell->PutCommand( m_workevent->Params[ 9 ].asMemCell->PutCommand(
@@ -984,61 +980,105 @@ event_manager::CheckQuery() {
} }
break; break;
} }
case tp_Lights: case tp_Lights: {
if (m_workevent->Params[9].asModel) if( m_workevent->Params[ 9 ].asModel ) {
for (i = 0; i < iMaxNumLights; i++) for( i = 0; i < iMaxNumLights; ++i ) {
if (m_workevent->Params[i].asdouble >= 0) //-1 zostawia bez zmiany if( m_workevent->Params[ i ].asdouble >= 0 ) {
m_workevent->Params[9].asModel->LightSet( // -1 zostawia bez zmiany
i, m_workevent->Params[i].asdouble); // teraz też ułamek m_workevent->Params[ 9 ].asModel->LightSet(
break; i,
case tp_Visible: m_workevent->Params[ i ].asdouble );
if (m_workevent->Params[9].nGroundNode) }
m_workevent->Params[9].nGroundNode->bVisible = (m_workevent->Params[i].asInt > 0); }
break;
case tp_Velocity:
Error("Not implemented yet :(");
break;
case tp_Exit:
MessageBox(0, m_workevent->asNodeName.c_str(), " THE END ", MB_OK);
Global::iTextMode = -1; // wyłączenie takie samo jak sekwencja F10 -> Y
return false;
case tp_Sound:
switch (m_workevent->Params[0].asInt)
{ // trzy możliwe przypadki:
case 0:
m_workevent->Params[9].tsTextSound->Stop();
break;
case 1:
m_workevent->Params[9].tsTextSound->Play(
1, 0, true, m_workevent->Params[9].tsTextSound->vSoundPosition);
break;
case -1:
m_workevent->Params[9].tsTextSound->Play(
1, DSBPLAY_LOOPING, true, m_workevent->Params[9].tsTextSound->vSoundPosition);
break;
} }
break; break;
}
case tp_Visible: {
#ifdef EU07_USE_OLD_GROUNDCODE
if( m_workevent->Params[ 9 ].nGroundNode )
m_workevent->Params[ 9 ].nGroundNode->bVisible = ( m_workevent->Params[ i ].asInt > 0 );
#else
if( m_workevent->Params[ 9 ].asEditorNode )
m_workevent->Params[ 9 ].asEditorNode->visible( m_workevent->Params[ i ].asInt > 0 );
#endif
break;
}
case tp_Velocity: {
Error( "Not implemented yet :(" );
break;
}
case tp_Exit: {
MessageBox( 0, m_workevent->asNodeName.c_str(), " THE END ", MB_OK );
Global::iTextMode = -1; // wyłączenie takie samo jak sekwencja F10 -> Y
return false;
}
case tp_Sound: {
switch( m_workevent->Params[ 0 ].asInt ) {
// trzy możliwe przypadki:
case 0: {
m_workevent->Params[ 9 ].tsTextSound->Stop();
break;
}
case 1: {
m_workevent->Params[ 9 ].tsTextSound->Play(
1,
0,
true,
m_workevent->Params[ 9 ].tsTextSound->vSoundPosition );
break;
}
case -1: {
m_workevent->Params[ 9 ].tsTextSound->Play(
1,
DSBPLAY_LOOPING,
true,
m_workevent->Params[ 9 ].tsTextSound->vSoundPosition );
break;
}
default: {
break;
}
}
break;
}
case tp_Disable: case tp_Disable:
Error("Not implemented yet :("); Error("Not implemented yet :(");
break; break;
case tp_Animation: // Marcin: dorobic translacje - Ra: dorobiłem ;-) case tp_Animation: {
if (m_workevent->Params[0].asInt == 1) switch( m_workevent->Params[ 0 ].asInt ) {
m_workevent->Params[9].asAnimContainer->SetRotateAnim( case 1: {
Math3D::vector3(m_workevent->Params[1].asdouble, m_workevent->Params[2].asdouble, m_workevent->Params[ 9 ].asAnimContainer->SetRotateAnim(
m_workevent->Params[3].asdouble), Math3D::vector3 {
m_workevent->Params[4].asdouble); m_workevent->Params[ 1 ].asdouble,
else if (m_workevent->Params[0].asInt == 2) m_workevent->Params[ 2 ].asdouble,
m_workevent->Params[9].asAnimContainer->SetTranslateAnim( m_workevent->Params[ 3 ].asdouble },
Math3D::vector3(m_workevent->Params[1].asdouble, m_workevent->Params[2].asdouble, m_workevent->Params[ 4 ].asdouble );
m_workevent->Params[3].asdouble), break;
m_workevent->Params[4].asdouble); }
else if (m_workevent->Params[0].asInt == 4) case 2: {
m_workevent->Params[9].asModel->AnimationVND( m_workevent->Params[ 9 ].asAnimContainer->SetTranslateAnim(
m_workevent->Params[8].asPointer, Math3D::vector3 {
m_workevent->Params[1].asdouble, // tu mogą być dodatkowe parametry, np. od-do m_workevent->Params[ 1 ].asdouble,
m_workevent->Params[2].asdouble, m_workevent->Params[3].asdouble, m_workevent->Params[ 2 ].asdouble,
m_workevent->Params[4].asdouble); m_workevent->Params[ 3 ].asdouble },
m_workevent->Params[ 4 ].asdouble );
break;
}
case 4: {
m_workevent->Params[ 9 ].asModel->AnimationVND(
m_workevent->Params[ 8 ].asPointer,
m_workevent->Params[ 1 ].asdouble, // tu mogą być dodatkowe parametry, np. od-do
m_workevent->Params[ 2 ].asdouble,
m_workevent->Params[ 3 ].asdouble,
m_workevent->Params[ 4 ].asdouble );
break;
}
default: {
break;
}
}
break; break;
}
case tp_Switch: { case tp_Switch: {
if( m_workevent->Params[ 9 ].asTrack ) { if( m_workevent->Params[ 9 ].asTrack ) {
m_workevent->Params[ 9 ].asTrack->Switch( m_workevent->Params[ 9 ].asTrack->Switch(
@@ -1057,13 +1097,15 @@ event_manager::CheckQuery() {
break; break;
} }
case tp_TrackVel: case tp_TrackVel:
if (m_workevent->Params[9].asTrack) if (m_workevent->Params[9].asTrack) {
{ // prędkość na zwrotnicy może być ograniczona z góry we wpisie, większej się nie // prędkość na zwrotnicy może być ograniczona z góry we wpisie, większej się nie ustawi eventem
// ustawi eventem
WriteLog("Type: TrackVel");
m_workevent->Params[9].asTrack->VelocitySet(m_workevent->Params[0].asdouble); m_workevent->Params[9].asTrack->VelocitySet(m_workevent->Params[0].asdouble);
if (DebugModeFlag) // wyświetlana jest ta faktycznie ustawiona // wyświetlana jest ta faktycznie ustawiona
WriteLog(" - velocity: ", m_workevent->Params[9].asTrack->VelocityGet()); WriteLog( "Type: TrackVel - ["
+ to_string( m_workevent->Params[ 0 ].asdouble, 2 ) + "]"
+ ( DebugModeFlag ?
", actual [ " + to_string( m_workevent->Params[ 9 ].asTrack->VelocityGet(), 2 ) + "]" :
"" ) );
} }
break; break;
case tp_DynVel: case tp_DynVel:
@@ -1097,7 +1139,7 @@ event_manager::CheckQuery() {
if( ( m_workevent->iFlags & conditional_anyelse ) == 0 ) { if( ( m_workevent->iFlags & conditional_anyelse ) == 0 ) {
// jednoznaczne tylko, gdy nie było else // jednoznaczne tylko, gdy nie było else
if( m_workevent->Activator ) { if( m_workevent->Activator ) {
WyslijEvent( m_workevent->asName, m_workevent->Activator->GetName() ); WyslijEvent( m_workevent->asName, m_workevent->Activator->name() );
} }
else { else {
WyslijEvent( m_workevent->asName, "" ); WyslijEvent( m_workevent->asName, "" );
@@ -1175,8 +1217,9 @@ event_manager::CheckQuery() {
m_workevent->Params[ 9 ].asMemCell->UpdateValues( m_workevent->Params[ 9 ].asMemCell->UpdateValues(
m_workevent->Activator->Mechanik->TrainName(), m_workevent->Activator->Mechanik->TrainName(),
m_workevent->Activator->Mechanik->StationCount() - m_workevent->Activator->Mechanik->StationIndex(), // ile przystanków do końca m_workevent->Activator->Mechanik->StationCount() - m_workevent->Activator->Mechanik->StationIndex(), // ile przystanków do końca
m_workevent->Activator->Mechanik->IsStop() ? 1 : m_workevent->Activator->Mechanik->IsStop() ?
0, // 1, gdy ma tu zatrzymanie 1 :
0, // 1, gdy ma tu zatrzymanie
m_workevent->iFlags); m_workevent->iFlags);
WriteLog("Train detected: " + m_workevent->Activator->Mechanik->TrainName()); WriteLog("Train detected: " + m_workevent->Activator->Mechanik->TrainName());
} }
@@ -1186,10 +1229,10 @@ event_manager::CheckQuery() {
// zapisanie zawartości komórki pamięci do logu // zapisanie zawartości komórki pamięci do logu
if( m_workevent->Params[ 9 ].asMemCell ) { if( m_workevent->Params[ 9 ].asMemCell ) {
// jeśli była podana nazwa komórki // jeśli była podana nazwa komórki
WriteLog( "Memcell \"" + m_workevent->asNodeName + "\": " WriteLog( "Memcell \"" + m_workevent->asNodeName + "\": ["
+ m_workevent->Params[ 9 ].asMemCell->Text() + " " + m_workevent->Params[ 9 ].asMemCell->Text() + "] ["
+ std::to_string( m_workevent->Params[ 9 ].asMemCell->Value1() ) + " " + to_string( m_workevent->Params[ 9 ].asMemCell->Value1(), 2 ) + "] ["
+ std::to_string( m_workevent->Params[ 9 ].asMemCell->Value2() ) ); + to_string( m_workevent->Params[ 9 ].asMemCell->Value2(), 2 ) + "]" );
} }
else { else {
// TODO: re-enable when cell manager is in place // TODO: re-enable when cell manager is in place
@@ -1237,7 +1280,7 @@ event_manager::InitEvents() {
case tp_AddValues: // sumowanie wartości case tp_AddValues: // sumowanie wartości
case tp_UpdateValues: { // zmiana wartości case tp_UpdateValues: { // zmiana wartości
auto *cell = simulation::Memory.find( Current->asNodeName ); // nazwa komórki powiązanej z eventem auto *cell = simulation::Memory.find( Current->asNodeName ); // nazwa komórki powiązanej z eventem
if( cell ) { // McZapkie-100302 if( cell != nullptr ) { // McZapkie-100302
if( Current->iFlags & ( conditional_trackoccupied | conditional_trackfree ) ) { if( Current->iFlags & ( conditional_trackoccupied | conditional_trackfree ) ) {
// jeśli chodzi o zajetosc toru (tor może być inny, niż wpisany w komórce) // jeśli chodzi o zajetosc toru (tor może być inny, niż wpisany w komórce)
// nazwa toru ta sama, co nazwa komórki // nazwa toru ta sama, co nazwa komórki
@@ -1281,7 +1324,7 @@ event_manager::InitEvents() {
case tp_GetValues: case tp_GetValues:
case tp_WhoIs: { case tp_WhoIs: {
auto *cell = simulation::Memory.find( Current->asNodeName ); auto *cell = simulation::Memory.find( Current->asNodeName );
if( cell ) { if( cell != nullptr ) {
Current->Params[ 8 ].asLocation = &( cell->location() ); Current->Params[ 8 ].asLocation = &( cell->location() );
Current->Params[ 9 ].asMemCell = cell; Current->Params[ 9 ].asMemCell = cell;
if( ( Current->Type == tp_GetValues ) if( ( Current->Type == tp_GetValues )
@@ -1301,7 +1344,7 @@ event_manager::InitEvents() {
case tp_CopyValues: { case tp_CopyValues: {
// skopiowanie komórki do innej // skopiowanie komórki do innej
auto *cell = simulation::Memory.find( Current->asNodeName ); // komórka docelowa auto *cell = simulation::Memory.find( Current->asNodeName ); // komórka docelowa
if( cell ) { if( cell != nullptr ) {
Current->Params[ 4 ].asLocation = &( cell->location() ); Current->Params[ 4 ].asLocation = &( cell->location() );
Current->Params[ 5 ].asMemCell = cell; // komórka docelowa Current->Params[ 5 ].asMemCell = cell; // komórka docelowa
if( false == cell->asTrackName.empty() ) { if( false == cell->asTrackName.empty() ) {
@@ -1338,7 +1381,7 @@ event_manager::InitEvents() {
SafeDeleteArray( Current->Params[ 9 ].asText ); SafeDeleteArray( Current->Params[ 9 ].asText );
// egzemplarz modelu do animowania // egzemplarz modelu do animowania
auto *instance = simulation::Instances.find( Current->asNodeName ); auto *instance = simulation::Instances.find( Current->asNodeName );
if( instance ) { if( instance != nullptr ) {
if( Current->Params[ 0 ].asInt == 4 ) { if( Current->Params[ 0 ].asInt == 4 ) {
// model dla całomodelowych animacji // model dla całomodelowych animacji
Current->Params[ 9 ].asModel = instance; Current->Params[ 9 ].asModel = instance;
@@ -1365,33 +1408,35 @@ event_manager::InitEvents() {
case tp_Lights: { case tp_Lights: {
// zmiana świeteł modelu // zmiana świeteł modelu
auto *instance = simulation::Instances.find( Current->asNodeName ); auto *instance = simulation::Instances.find( Current->asNodeName );
if( instance ) if( instance != nullptr )
Current->Params[ 9 ].asModel = instance; Current->Params[ 9 ].asModel = instance;
else else
ErrorLog( "Bad event: lights event \"" + Current->asName + "\" cannot find model instance \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: lights event \"" + Current->asName + "\" cannot find model instance \"" + Current->asNodeName + "\"" );
Current->asNodeName = ""; Current->asNodeName = "";
break; break;
} }
/*
case tp_Visible: { case tp_Visible: {
// ukrycie albo przywrócenie obiektu // ukrycie albo przywrócenie obiektu
tmp = FindGroundNode( Current->asNodeName, TP_MODEL ); // najpierw model editor::basic_node *node = simulation::Instances.find( Current->asNodeName ); // najpierw model
if( !tmp ) if( node == nullptr ) {
tmp = FindGroundNode( Current->asNodeName, TP_TRACK ); // albo tory? // albo tory?
if( !tmp ) node = simulation::Paths.find( Current->asNodeName );
tmp = FindGroundNode( Current->asNodeName, TP_TRACTION ); // może druty? }
if( tmp ) if( node == nullptr ) {
Current->Params[ 9 ].nGroundNode = tmp; // może druty?
node = simulation::Traction.find( Current->asNodeName );
}
if( node != nullptr )
Current->Params[ 9 ].asEditorNode = node;
else else
ErrorLog( "Bad event: visibility event \"" + Current->asName + "\" cannot find item \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: visibility event \"" + Current->asName + "\" cannot find item \"" + Current->asNodeName + "\"" );
Current->asNodeName = ""; Current->asNodeName = "";
break; break;
} }
*/
case tp_Switch: { case tp_Switch: {
// przełożenie zwrotnicy albo zmiana stanu obrotnicy // przełożenie zwrotnicy albo zmiana stanu obrotnicy
auto *track = simulation::Paths.find( Current->asNodeName ); auto *track = simulation::Paths.find( Current->asNodeName );
if( track ) { if( track != nullptr ) {
// dowiązanie toru // dowiązanie toru
if( track->iAction == NULL ) { if( track->iAction == NULL ) {
// jeśli nie jest zwrotnicą ani obrotnicą to będzie się zmieniał stan uszkodzenia // jeśli nie jest zwrotnicą ani obrotnicą to będzie się zmieniał stan uszkodzenia
@@ -1414,23 +1459,21 @@ event_manager::InitEvents() {
Current->asNodeName = ""; Current->asNodeName = "";
break; break;
} }
/*
case tp_Sound: { case tp_Sound: {
// odtworzenie dźwięku // odtworzenie dźwięku
tmp = FindGroundNode( Current->asNodeName, TP_SOUND ); auto *sound = simulation::Sounds.find( Current->asNodeName );
if( tmp ) if( sound != nullptr )
Current->Params[ 9 ].tsTextSound = tmp->tsStaticSound; Current->Params[ 9 ].tsTextSound = sound;
else else
ErrorLog( "Bad event: sound event \"" + Current->asName + "\" cannot find static sound \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: sound event \"" + Current->asName + "\" cannot find static sound \"" + Current->asNodeName + "\"" );
Current->asNodeName = ""; Current->asNodeName = "";
break; break;
} }
*/
case tp_TrackVel: { case tp_TrackVel: {
// ustawienie prędkości na torze // ustawienie prędkości na torze
if( false == Current->asNodeName.empty() ) { if( false == Current->asNodeName.empty() ) {
auto *track = simulation::Paths.find( Current->asNodeName ); auto *track = simulation::Paths.find( Current->asNodeName );
if( track ) { if( track != nullptr ) {
// flaga zmiany prędkości toru jest istotna dla skanowania // flaga zmiany prędkości toru jest istotna dla skanowania
track->iAction |= 0x200; track->iAction |= 0x200;
Current->Params[ 9 ].asTrack = track; Current->Params[ 9 ].asTrack = track;
@@ -1442,22 +1485,20 @@ event_manager::InitEvents() {
Current->asNodeName = ""; Current->asNodeName = "";
break; break;
} }
/*
case tp_DynVel: { case tp_DynVel: {
// komunikacja z pojazdem o konkretnej nazwie // komunikacja z pojazdem o konkretnej nazwie
if( Current->asNodeName == "activator" ) if( Current->asNodeName == "activator" )
Current->Params[ 9 ].asDynamic = nullptr; Current->Params[ 9 ].asDynamic = nullptr;
else { else {
tmp = FindGroundNode( Current->asNodeName, TP_DYNAMIC ); auto *vehicle = simulation::Vehicles.find( Current->asNodeName );
if( tmp ) if( vehicle != nullptr )
Current->Params[ 9 ].asDynamic = tmp->DynamicObject; Current->Params[ 9 ].asDynamic = vehicle;
else else
Error( "Bad event: vehicle velocity event \"" + Current->asName + "\" cannot find vehicle \"" + Current->asNodeName + "\"" ); Error( "Bad event: vehicle velocity event \"" + Current->asName + "\" cannot find vehicle \"" + Current->asNodeName + "\"" );
} }
Current->asNodeName = ""; Current->asNodeName = "";
break; break;
} }
*/
case tp_Multiple: { case tp_Multiple: {
std::string cellastext; std::string cellastext;
if( Current->Params[ 9 ].asText != nullptr ) { // przepisanie nazwy do bufora if( Current->Params[ 9 ].asText != nullptr ) { // przepisanie nazwy do bufora
@@ -1494,36 +1535,27 @@ event_manager::InitEvents() {
} }
break; break;
} }
/*
case tp_Voltage: { case tp_Voltage: {
// zmiana napięcia w zasilaczu (TractionPowerSource) // zmiana napięcia w zasilaczu (TractionPowerSource)
if( !Current->asNodeName.empty() ) { if( false == Current->asNodeName.empty() ) {
tmp = FindGroundNode( Current->asNodeName, TP_TRACTIONPOWERSOURCE ); // podłączenie zasilacza auto *powersource = simulation::Powergrid.find( Current->asNodeName ); // podłączenie zasilacza
if( tmp ) if( powersource != nullptr )
Current->Params[ 9 ].psPower = tmp->psTractionPowerSource; Current->Params[ 9 ].psPower = powersource;
else else
ErrorLog( "Bad event: voltage event \"" + Current->asName + "\" cannot find power source \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: voltage event \"" + Current->asName + "\" cannot find power source \"" + Current->asNodeName + "\"" );
} }
Current->asNodeName = ""; Current->asNodeName = "";
break; break;
} }
*/
case tp_Message: { case tp_Message: {
// wyświetlenie komunikatu // wyświetlenie komunikatu
break; break;
} }
} // switch } // switch
if( Current->fDelay < 0 ) {
AddToQuery( Current, nullptr ); if( Current->fDelay < 0 ) { AddToQuery( Current, nullptr ); }
}
} }
/*
for (TGroundNode *Current = nRootOfType[TP_MEMCELL]; Current; Current = Current->nNext)
{ // Ra: eventy komórek pamięci, wykonywane po wysłaniu komendy do zatrzymanego pojazdu
Current->MemCell->AssignEvents( FindEvent( Current->asName + ":sent" ) );
}
*/
} }
// legacy method, verifies condition for specified event // legacy method, verifies condition for specified event

14
Event.h
View File

@@ -12,6 +12,9 @@ http://mozilla.org/MPL/2.0/.
#include <string> #include <string>
#include "dumb3d.h" #include "dumb3d.h"
#include "classes.h" #include "classes.h"
#include "names.h"
#include "scenenode.h"
#include "evlaunch.h"
enum TEventType { enum TEventType {
tp_Unknown, tp_Unknown,
@@ -61,6 +64,7 @@ union TParam
void *asPointer; void *asPointer;
TMemCell *asMemCell; TMemCell *asMemCell;
TGroundNode *nGroundNode; TGroundNode *nGroundNode;
editor::basic_node *asEditorNode;
glm::dvec3 const *asLocation; glm::dvec3 const *asLocation;
TTrack *asTrack; TTrack *asTrack;
TAnimModel *asModel; TAnimModel *asModel;
@@ -104,7 +108,6 @@ public:
// metody // metody
TEvent(std::string const &m = ""); TEvent(std::string const &m = "");
~TEvent(); ~TEvent();
void Init();
void Load(cParser *parser, Math3D::vector3 const &org); void Load(cParser *parser, Math3D::vector3 const &org);
static void AddToQuery( TEvent *Event, TEvent *&Start ); static void AddToQuery( TEvent *Event, TEvent *&Start );
std::string CommandGet(); std::string CommandGet();
@@ -123,9 +126,12 @@ public:
~event_manager(); ~event_manager();
// methods // methods
// adds provided event to the collection. returns: true on success // adds provided event to the collection. returns: true on success
// TODO: return handle instead of pointer // TBD, TODO: return handle to the event
bool bool
insert( TEvent *Event ); insert( TEvent *Event );
bool
insert( TEventLauncher *Launcher ) {
return m_launchers.insert( Launcher ); }
// legacy method, returns pointer to specified event, or null // legacy method, returns pointer to specified event, or null
TEvent * TEvent *
FindEvent( std::string const &Name ); FindEvent( std::string const &Name );
@@ -143,6 +149,7 @@ private:
// types // types
using event_sequence = std::deque<TEvent *>; using event_sequence = std::deque<TEvent *>;
using event_map = std::unordered_map<std::string, std::size_t>; using event_map = std::unordered_map<std::string, std::size_t>;
using eventlauncher_sequence = std::vector<TEventLauncher *>;
// methods // methods
// legacy method, verifies condition for specified event // legacy method, verifies condition for specified event
@@ -158,8 +165,9 @@ private:
// legacy version of the above // legacy version of the above
TEvent *QueryRootEvent { nullptr }; TEvent *QueryRootEvent { nullptr };
TEvent *m_workevent { nullptr }; TEvent *m_workevent { nullptr };
event_map m_eventmap; event_map m_eventmap;
basic_table<TEventLauncher> m_launchers;
eventlauncher_sequence m_launcherqueue;
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -12,15 +12,14 @@ http://mozilla.org/MPL/2.0/.
#include "Classes.h" #include "Classes.h"
#include "sound.h" #include "sound.h"
typedef enum enum TGaugeType {
{ // typ ruchu // typ ruchu
gt_Unknown, // na razie nie znany gt_Unknown, // na razie nie znany
gt_Rotate, // obrót gt_Rotate, // obrót
gt_Move, // przesunięcie równoległe gt_Move, // przesunięcie równoległe
gt_Wiper, // obrót trzech kolejnych submodeli o ten sam kąt (np. wycieraczka, drzwi gt_Wiper, // obrót trzech kolejnych submodeli o ten sam kąt (np. wycieraczka, drzwi harmonijkowe)
// harmonijkowe)
gt_Digital // licznik cyfrowy, np. kilometrów gt_Digital // licznik cyfrowy, np. kilometrów
} TGaugeType; };
// animowany wskaźnik, mogący przyjmować wiele stanów pośrednich // animowany wskaźnik, mogący przyjmować wiele stanów pośrednich
class TGauge { class TGauge {

View File

@@ -996,10 +996,12 @@ void Global::TrainDelete(TDynamicObject *d)
pWorld->TrainDelete(d); pWorld->TrainDelete(d);
}; };
#ifdef EU07_USE_OLD_GROUNDCODE
TDynamicObject *Global::DynamicNearest() TDynamicObject *Global::DynamicNearest()
{ // ustalenie pojazdu najbliższego kamerze { // ustalenie pojazdu najbliższego kamerze
return pGround->DynamicNearest(pCamera->Pos); return pGround->DynamicNearest(pCamera->Pos);
}; };
#endif
TDynamicObject *Global::CouplerNearest() TDynamicObject *Global::CouplerNearest()
{ // ustalenie pojazdu najbliższego kamerze { // ustalenie pojazdu najbliższego kamerze

View File

@@ -297,7 +297,9 @@ class Global
static void TrainDelete(TDynamicObject *d); static void TrainDelete(TDynamicObject *d);
static void ConfigParse(cParser &parser); static void ConfigParse(cParser &parser);
static std::string GetNextSymbol(); static std::string GetNextSymbol();
#ifdef EU07_USE_OLD_GROUNDCODE
static TDynamicObject * DynamicNearest(); static TDynamicObject * DynamicNearest();
#endif
static TDynamicObject * CouplerNearest(); static TDynamicObject * CouplerNearest();
static bool AddToQuery(TEvent *event, TDynamicObject *who); static bool AddToQuery(TEvent *event, TDynamicObject *who);
static bool DoEvents(); static bool DoEvents();

View File

@@ -586,7 +586,7 @@ void TGround::Free()
// RootNode=NULL; // RootNode=NULL;
nRootDynamic = NULL; nRootDynamic = NULL;
} }
#ifdef EU07_USE_OLD_GROUNDCODE
TGroundNode * TGround::DynamicFindAny(std::string const &Name) TGroundNode * TGround::DynamicFindAny(std::string const &Name)
{ // wyszukanie pojazdu o podanej nazwie, szukanie po wszystkich (użyć drzewa!) { // wyszukanie pojazdu o podanej nazwie, szukanie po wszystkich (użyć drzewa!)
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
@@ -603,7 +603,7 @@ TGroundNode * TGround::DynamicFind(std::string const &Name)
return Current; return Current;
return NULL; return NULL;
}; };
#endif
void void
TGround::DynamicList(bool all) TGround::DynamicList(bool all)
{ // odesłanie nazw pojazdów dostępnych na scenerii (nazwy, szczególnie wagonów, mogą się { // odesłanie nazw pojazdów dostępnych na scenerii (nazwy, szczególnie wagonów, mogą się
@@ -694,6 +694,7 @@ int iTrainSetWehicleNumber = 0;
TGroundNode *nTrainSetNode = NULL; // poprzedni pojazd do łączenia TGroundNode *nTrainSetNode = NULL; // poprzedni pojazd do łączenia
TGroundNode *nTrainSetDriver = NULL; // pojazd, któremu zostanie wysłany rozkład TGroundNode *nTrainSetDriver = NULL; // pojazd, któremu zostanie wysłany rozkład
#ifdef EU07_USE_OLD_GROUNDCODE
void TGround::RaTriangleDivider(TGroundNode *node) void TGround::RaTriangleDivider(TGroundNode *node)
{ // tworzy dodatkowe trójkąty i zmiejsza podany { // tworzy dodatkowe trójkąty i zmiejsza podany
// to jest wywoływane przy wczytywaniu trójkątów // to jest wywoływane przy wczytywaniu trójkątów
@@ -814,7 +815,7 @@ void TGround::RaTriangleDivider(TGroundNode *node)
RaTriangleDivider(node); // rekurencja, bo nawet na TD raz nie wystarczy RaTriangleDivider(node); // rekurencja, bo nawet na TD raz nie wystarczy
RaTriangleDivider(ntri); RaTriangleDivider(ntri);
}; };
#endif
TGroundNode * TGround::AddGroundNode(cParser *parser) TGroundNode * TGround::AddGroundNode(cParser *parser)
{ // wczytanie wpisu typu "node" { // wczytanie wpisu typu "node"
std::string str, str1, str2, str3, str4, Skin, DriverType, asNodeName; std::string str, str1, str2, str3, str4, Skin, DriverType, asNodeName;
@@ -889,7 +890,8 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
switch (tmp->iType) switch (tmp->iType)
{ {
case TP_TRACTION: #ifdef EU07_USE_OLD_GROUNDCODE
case TP_TRACTION:
tmp->hvTraction = new TTraction( tmp->asName ); tmp->hvTraction = new TTraction( tmp->asName );
parser->getTokens(); parser->getTokens();
*parser >> token; *parser >> token;
@@ -983,7 +985,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
>> tmp->pCenter.y >> tmp->pCenter.y
>> tmp->pCenter.z; >> tmp->pCenter.z;
tmp->pCenter += pOrigin; tmp->pCenter += pOrigin;
tmp->psTractionPowerSource = new TTractionPowerSource(tmp); tmp->psTractionPowerSource = new TTractionPowerSource( tmp->asName );
tmp->psTractionPowerSource->Load(parser); tmp->psTractionPowerSource->Load(parser);
break; break;
case TP_MEMCELL: case TP_MEMCELL:
@@ -1004,6 +1006,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
} }
} }
break; break;
#endif
case TP_EVLAUNCH: case TP_EVLAUNCH:
parser->getTokens(3); parser->getTokens(3);
*parser *parser
@@ -1015,6 +1018,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
tmp->EvLaunch = new TEventLauncher(); tmp->EvLaunch = new TEventLauncher();
tmp->EvLaunch->Load(parser); tmp->EvLaunch->Load(parser);
break; break;
#ifdef EU07_USE_OLD_GROUNDCODE
case TP_TRACK: case TP_TRACK:
tmp->pTrack = new TTrack( tmp->asName ); tmp->pTrack = new TTrack( tmp->asName );
if (Global::iWriteLogEnabled & 4) if (Global::iWriteLogEnabled & 4)
@@ -1191,57 +1195,8 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
} }
break; break;
#endif
case TP_MODEL: { case TP_MODEL: {
#ifdef EU07_USE_OLD_TERRAINCODE
if( rmin < 0 ) {
tmp->iType = TP_TERRAIN;
tmp->fSquareMinRadius = 0; // to w ogóle potrzebne?
}
parser->getTokens( 3 );
*parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z;
parser->getTokens();
*parser >> tf1;
// OlO_EU&KAKISH-030103: obracanie punktow zaczepien w modelu
tmp->pCenter.RotateY( aRotate.y / 180.0 * M_PI );
// McZapkie-260402: model tez ma wspolrzedne wzgledne
tmp->pCenter += pOrigin;
tmp->Model = new TAnimModel();
tmp->Model->RaAnglesSet( aRotate.x, tf1 + aRotate.y, aRotate.z ); // dostosowanie do pochylania linii
if( tmp->Model->Load( parser, tmp->iType == TP_TERRAIN ) ) {
// wczytanie modelu, tekstury i stanu świateł...
tmp->iFlags = tmp->Model->Flags() | 0x200; // ustalenie, czy przezroczysty; flaga usuwania
}
else if( tmp->iType != TP_TERRAIN ) { // model nie wczytał się - ignorowanie node
delete tmp;
tmp = NULL; // nie może być tu return
break; // nie może być tu return?
}
if( tmp->iType == TP_TERRAIN ) { // jeśli model jest terenem, trzeba utworzyć dodatkowe obiekty
// po wczytaniu model ma już utworzone DL albo VBO
Global::pTerrainCompact = tmp->Model; // istnieje co najmniej jeden obiekt terenu
tmp->pCenter = Math3D::vector3( 0.0, 0.0, 0.0 ); // enforce placement in the world center
tmp->iCount = Global::pTerrainCompact->TerrainCount() + 1; // zliczenie submodeli
tmp->nNode = new TGroundNode[ tmp->iCount ]; // sztuczne node dla kwadratów
tmp->nNode[ 0 ].iType = TP_MODEL; // pierwszy zawiera model (dla delete)
tmp->nNode[ 0 ].Model = Global::pTerrainCompact;
tmp->nNode[ 0 ].iFlags = 0x200; // nie wyświetlany, ale usuwany
for( int i = 1; i < tmp->iCount; ++i ) { // a reszta to submodele
tmp->nNode[ i ].iType = TP_SUBMODEL;
tmp->nNode[ i ].smTerrain = Global::pTerrainCompact->TerrainSquare( i - 1 );
tmp->nNode[ i ].iFlags = 0x10; // nieprzezroczyste; nie usuwany
tmp->nNode[ i ].bVisible = true;
tmp->nNode[ i ].pCenter = tmp->pCenter; // nie przesuwamy w inne miejsce
}
}
else if( !tmp->asName.empty() ) // jest pusta gdy "none"
{ // dodanie do wyszukiwarki
if( false == m_nodemap.Add( TP_MODEL, tmp->asName, tmp ) ) {
// przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność wsteczna)
ErrorLog( "Duplicated model: " + tmp->asName ); // to zgłaszać duplikat
}
}
#else
if( rmin < 0 ) { if( rmin < 0 ) {
// legacy leftover: special case, terrain provided as 3d model // legacy leftover: special case, terrain provided as 3d model
tmp->iType = TP_TERRAIN; tmp->iType = TP_TERRAIN;
@@ -1274,6 +1229,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
} }
} }
else { else {
#ifdef EU07_USE_OLD_GROUNDCODE
// regular 3d model // regular 3d model
parser->getTokens( 3 ); parser->getTokens( 3 );
*parser *parser
@@ -1304,10 +1260,11 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
ErrorLog( "Duplicated model: " + tmp->asName ); // to zgłaszać duplikat ErrorLog( "Duplicated model: " + tmp->asName ); // to zgłaszać duplikat
} }
} }
}
#endif #endif
}
break; break;
} }
#ifdef EU07_USE_OLD_GROUNDCODE
// case TP_GEOMETRY : // case TP_GEOMETRY :
case GL_TRIANGLES: case GL_TRIANGLES:
case GL_TRIANGLE_STRIP: case GL_TRIANGLE_STRIP:
@@ -1510,6 +1467,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
} // koniec wczytywania trójkątów } // koniec wczytywania trójkątów
break; break;
} }
#endif
case GL_LINES: case GL_LINES:
case GL_LINE_STRIP: case GL_LINE_STRIP:
case GL_LINE_LOOP: { case GL_LINE_LOOP: {
@@ -1802,7 +1760,7 @@ bool TGround::Init(std::string File)
else { // jeśli jest pojazdem else { // jeśli jest pojazdem
if( ( LastNode->DynamicObject->Mechanik != nullptr ) if( ( LastNode->DynamicObject->Mechanik != nullptr )
&& ( LastNode->DynamicObject->Mechanik->Primary() ) ) { && ( LastNode->DynamicObject->Mechanik->Primary() ) ) {
// jeśli jest głównym (pasażer nie jest) // jeśli jest głównym (pasażer nie jest)
nTrainSetDriver = LastNode; // pojazd, któremu zostanie wysłany rozkład nTrainSetDriver = LastNode; // pojazd, któremu zostanie wysłany rozkład
} }
LastNode->nNext = nRootDynamic; LastNode->nNext = nRootDynamic;
@@ -1859,8 +1817,7 @@ bool TGround::Init(std::string File)
if (nTrainSetDriver) // pojazd, któremu zostanie wysłany rozkład if (nTrainSetDriver) // pojazd, któremu zostanie wysłany rozkład
{ // wysłanie komendy "Timetable" ustawia odpowiedni tryb jazdy { // wysłanie komendy "Timetable" ustawia odpowiedni tryb jazdy
nTrainSetDriver->DynamicObject->Mechanik->DirectionInitial(); nTrainSetDriver->DynamicObject->Mechanik->DirectionInitial();
nTrainSetDriver->DynamicObject->Mechanik->PutCommand("Timetable:" + asTrainName, nTrainSetDriver->DynamicObject->Mechanik->PutCommand("Timetable:" + asTrainName, fTrainSetVel, 0, NULL);
fTrainSetVel, 0, NULL);
} }
} }
if( LastNode ) { if( LastNode ) {
@@ -1926,7 +1883,7 @@ bool TGround::Init(std::string File)
{ {
ErrorLog("Duplicated event: " + tmp->asName); ErrorLog("Duplicated event: " + tmp->asName);
found->Append(tmp); // doczepka (taki wirtualny multiple bez warunków) found->Append(tmp); // doczepka (taki wirtualny multiple bez warunków)
found->Type = tp_Ignored; // dezaktywacja pierwotnego - taka proteza na found->m_ignored = true; // dezaktywacja pierwotnego - taka proteza na
// wsteczną zgodność // wsteczną zgodność
// SafeDelete(tmp); //bezlitośnie usuwamy wszelkie duplikaty, żeby nie // SafeDelete(tmp); //bezlitośnie usuwamy wszelkie duplikaty, żeby nie
// zaśmiecać drzewka // zaśmiecać drzewka
@@ -1938,7 +1895,7 @@ bool TGround::Init(std::string File)
RootEvent = tmp; RootEvent = tmp;
if (!found) if (!found)
{ // jeśli nazwa wystąpiła, to do kolejki i wyszukiwarki dodawany jest tylko pierwszy { // jeśli nazwa wystąpiła, to do kolejki i wyszukiwarki dodawany jest tylko pierwszy
if( ( RootEvent->Type != tp_Ignored ) if( ( RootEvent->m_ignored == false )
&& ( RootEvent->asName.find( "onstart" ) != std::string::npos ) ) { && ( RootEvent->asName.find( "onstart" ) != std::string::npos ) ) {
// event uruchamiany automatycznie po starcie // event uruchamiany automatycznie po starcie
AddToQuery( RootEvent, NULL ); // dodanie do kolejki AddToQuery( RootEvent, NULL ); // dodanie do kolejki
@@ -2217,7 +2174,7 @@ bool TGround::InitEvents()
} }
else else
{ // nie ma komórki, to nie będzie działał poprawnie { // nie ma komórki, to nie będzie działał poprawnie
Current->Type = tp_Ignored; // deaktywacja Current->m_ignored = true; // deaktywacja
ErrorLog("Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\""); ErrorLog("Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"");
} }
break; break;
@@ -2241,7 +2198,7 @@ bool TGround::InitEvents()
} }
else else
{ // nie ma komórki, to nie będzie działał poprawnie { // nie ma komórki, to nie będzie działał poprawnie
Current->Type = tp_Ignored; // deaktywacja Current->m_ignored = true; // deaktywacja
ErrorLog("Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\""); ErrorLog("Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"");
} }
break; break;
@@ -2637,7 +2594,7 @@ void TGround::InitTraction()
nTemp = new TGroundNode(); nTemp = new TGroundNode();
nTemp->iType = TP_TRACTIONPOWERSOURCE; nTemp->iType = TP_TRACTIONPOWERSOURCE;
nTemp->asName = Traction->asPowerSupplyName; nTemp->asName = Traction->asPowerSupplyName;
nTemp->psTractionPowerSource = new TTractionPowerSource(nTemp); nTemp->psTractionPowerSource = new TTractionPowerSource(nTemp->asName);
nTemp->psTractionPowerSource->Init(Traction->NominalVoltage, Traction->MaxCurrent); nTemp->psTractionPowerSource->Init(Traction->NominalVoltage, Traction->MaxCurrent);
nTemp->nNext = nRootOfType[nTemp->iType]; // ostatni dodany dołączamy na końcu nTemp->nNext = nRootOfType[nTemp->iType]; // ostatni dodany dołączamy na końcu
// nowego // nowego
@@ -2826,8 +2783,11 @@ void TGround::TrackJoin(TGroundNode *Current)
int iConnection; int iConnection;
if (!Track->CurrentPrev()) if (!Track->CurrentPrev())
{ {
tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_0(), iConnection, #ifdef EU07_USE_OLD_GROUNDCODE
Current); // Current do pominięcia tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_0(), iConnection, Current); // Current do pominięcia
#else
std::tie( tmp, iConnection ) = simulation::Region->find_path( Track->CurrentSegment()->FastGetPoint_0(), Track );
#endif
switch (iConnection) switch (iConnection)
{ {
case 0: case 0:
@@ -2840,7 +2800,11 @@ void TGround::TrackJoin(TGroundNode *Current)
} }
if (!Track->CurrentNext()) if (!Track->CurrentNext())
{ {
#ifdef EU07_USE_OLD_GROUNDCODE
tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_1(), iConnection, Current); tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_1(), iConnection, Current);
#else
std::tie( tmp, iConnection ) = simulation::Region->find_path( Track->CurrentSegment()->FastGetPoint_1(), Track );
#endif
switch (iConnection) switch (iConnection)
{ {
case 0: case 0:
@@ -2892,6 +2856,7 @@ bool TGround::InitLaunchers()
return true; return true;
} }
#ifdef EU07_USE_OLD_GROUNDCODE
TTrack * TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude) TTrack * TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude)
{ // wyszukiwanie innego toru kończącego się w (Point) { // wyszukiwanie innego toru kończącego się w (Point)
TTrack *tmp; TTrack *tmp;
@@ -2978,49 +2943,36 @@ TTraction * TGround::TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n)
if ((sr = FastGetSubRect(c + i, r + j)) != NULL) // o ile w ogóle sektor jest if ((sr = FastGetSubRect(c + i, r + j)) != NULL) // o ile w ogóle sektor jest
for (nCurrent = sr->nRenderWires; nCurrent; nCurrent = nCurrent->nNext3) for (nCurrent = sr->nRenderWires; nCurrent; nCurrent = nCurrent->nNext3)
if (nCurrent->iType == TP_TRACTION) if (nCurrent->iType == TP_TRACTION)
if (nCurrent->hvTraction->psSection == if (nCurrent->hvTraction->psSection == n->hvTraction->psSection) // jeśli ta sama sekcja
n->hvTraction->psSection) // jeśli ta sama sekcja
if (nCurrent != n) // ale nie jest tym samym if (nCurrent != n) // ale nie jest tym samym
if (nCurrent->hvTraction != if (nCurrent->hvTraction != n->hvTraction->hvNext[0]) // ale nie jest bezpośrednio podłączonym
n->hvTraction
->hvNext[0]) // ale nie jest bezpośrednio podłączonym
if (nCurrent->hvTraction != n->hvTraction->hvNext[1]) if (nCurrent->hvTraction != n->hvTraction->hvNext[1])
if (nCurrent->hvTraction->psPower if (nCurrent->hvTraction->psPower
[k = (glm::dot( [k = (glm::dot(
n->hvTraction->vParametric, n->hvTraction->vParametric,
nCurrent->hvTraction->vParametric) >= 0 ? nCurrent->hvTraction->vParametric) >= 0 ?
dir ^ 1 : dir ^ 1 :
dir)]) // ma zasilanie z odpowiedniej dir)]) // ma zasilanie z odpowiedniej strony
// strony if (nCurrent->hvTraction->fResistance[k] >= 0.0) { // żeby się nie propagowały jakieś ujemne
if (nCurrent->hvTraction->fResistance[k] >= // znaleziony kandydat do połączenia
0.0) //żeby się nie propagowały jakieś ujemne
{ // znaleziony kandydat do połączenia
d = glm::length2( p - glm::dvec3{ nCurrent->pCenter } ); // kwadrat odległości środków d = glm::length2( p - glm::dvec3{ nCurrent->pCenter } ); // kwadrat odległości środków
if (dist > d) if (dist > d) {
{ // zapamiętanie nowego najbliższego // zapamiętanie nowego najbliższego
dist = d; // nowy rekord odległości dist = d; // nowy rekord odległości
nBest = nCurrent; nBest = nCurrent;
zg = k; // z którego końca brać wskaźnik zg = k; // z którego końca brać wskaźnik zasilacza
// zasilacza
} }
} }
if (nBest) // jak znalezione przęsło z zasilaniem, to podłączenie "równoległe" if (nBest) {
{ // jak znalezione przęsło z zasilaniem, to podłączenie "równoległe"
n->hvTraction->ResistanceCalc(dir, nBest->hvTraction->fResistance[zg], n->hvTraction->ResistanceCalc(dir, nBest->hvTraction->fResistance[zg], nBest->hvTraction->psPower[zg]);
nBest->hvTraction->psPower[zg]);
// testowo skrzywienie przęsła tak, aby pokazać skąd ma zasilanie
// if (dir) //1 gdy ciąg dalszy jest od strony Point2
// n->hvTraction->pPoint3=0.25*(nBest->pCenter+3*(zg?nBest->hvTraction->pPoint4:nBest->hvTraction->pPoint3));
// else
// n->hvTraction->pPoint4=0.25*(nBest->pCenter+3*(zg?nBest->hvTraction->pPoint4:nBest->hvTraction->pPoint3));
} }
return (nBest ? nBest->hvTraction : nullptr); return (nBest ? nBest->hvTraction : nullptr);
}; };
#ifdef EU07_USE_OLD_GROUNDCODE
bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node)
{ {
if( Event->bEnabled ) { if( ( false == Event->m_ignored ) && ( true == Event->bEnabled ) ) {
// jeśli może być dodany do kolejki (nie używany w skanowaniu) // jeśli może być dodany do kolejki (nie używany w skanowaniu)
if( !Event->iQueued ) // jeśli nie dodany jeszcze do kolejki if( !Event->iQueued ) // jeśli nie dodany jeszcze do kolejki
{ // kolejka eventów jest posortowana względem (fStartTime) { // kolejka eventów jest posortowana względem (fStartTime)
@@ -3169,8 +3121,8 @@ bool TGround::CheckQuery()
} }
else // a jak nazwa jest unikalna, to kolejka idzie dalej else // a jak nazwa jest unikalna, to kolejka idzie dalej
QueryRootEvent = QueryRootEvent->evNext; // NULL w skrajnym przypadku QueryRootEvent = QueryRootEvent->evNext; // NULL w skrajnym przypadku
if (tmpEvent->bEnabled) if( ( false == tmpEvent->m_ignored ) && ( true == tmpEvent->bEnabled ) ) {
{ // w zasadzie te wyłączone są skanowane i nie powinny się nigdy w kolejce znaleźć // w zasadzie te wyłączone są skanowane i nie powinny się nigdy w kolejce znaleźć
--tmpEvent->iQueued; // teraz moze być ponownie dodany do kolejki --tmpEvent->iQueued; // teraz moze być ponownie dodany do kolejki
WriteLog( "EVENT LAUNCHED" + ( tmpEvent->Activator ? ( " by " + tmpEvent->Activator->asName ) : "" ) + ": " + tmpEvent->asName ); WriteLog( "EVENT LAUNCHED" + ( tmpEvent->Activator ? ( " by " + tmpEvent->Activator->asName ) : "" ) + ": " + tmpEvent->asName );
switch (tmpEvent->Type) switch (tmpEvent->Type)
@@ -3222,7 +3174,7 @@ bool TGround::CheckQuery()
// loc.Z= tmpEvent->Params[8].nGroundNode->pCenter.y; // loc.Z= tmpEvent->Params[8].nGroundNode->pCenter.y;
if (Global::iMultiplayer) // potwierdzenie wykonania dla serwera (odczyt if (Global::iMultiplayer) // potwierdzenie wykonania dla serwera (odczyt
// semafora już tak nie działa) // semafora już tak nie działa)
WyslijEvent(tmpEvent->asName, tmpEvent->Activator->GetName()); WyslijEvent(tmpEvent->asName, tmpEvent->Activator->name());
// tmpEvent->Params[9].asMemCell->PutCommand(tmpEvent->Activator->Mechanik,loc); // tmpEvent->Params[9].asMemCell->PutCommand(tmpEvent->Activator->Mechanik,loc);
tmpEvent->Params[9].asMemCell->PutCommand( tmpEvent->Params[9].asMemCell->PutCommand(
tmpEvent->Activator->Mechanik, &tmpEvent->Params[8].nGroundNode->pCenter); tmpEvent->Activator->Mechanik, &tmpEvent->Params[8].nGroundNode->pCenter);
@@ -3355,7 +3307,7 @@ bool TGround::CheckQuery()
0) // jednoznaczne tylko, gdy nie było else 0) // jednoznaczne tylko, gdy nie było else
{ {
if (tmpEvent->Activator) if (tmpEvent->Activator)
WyslijEvent(tmpEvent->asName, tmpEvent->Activator->GetName()); WyslijEvent(tmpEvent->asName, tmpEvent->Activator->name());
else else
WyslijEvent(tmpEvent->asName, ""); WyslijEvent(tmpEvent->asName, "");
} }
@@ -3468,7 +3420,6 @@ bool TGround::CheckQuery()
} // while } // while
return true; return true;
} }
#endif
void TGround::UpdatePhys(double dt, int iter) void TGround::UpdatePhys(double dt, int iter)
{ // aktualizacja fizyki stałym krokiem: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń { // aktualizacja fizyki stałym krokiem: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń
@@ -3587,9 +3538,8 @@ TGround::Update_Hidden() {
} }
} }
} }
} }
#endif
// Winger 170204 - szukanie trakcji nad pantografami // Winger 170204 - szukanie trakcji nad pantografami
bool TGround::GetTraction(TDynamicObject *model) bool TGround::GetTraction(TDynamicObject *model)
{ // aktualizacja drutu zasilającego dla każdego pantografu, żeby odczytać napięcie { // aktualizacja drutu zasilającego dla każdego pantografu, żeby odczytać napięcie
@@ -3709,35 +3659,29 @@ bool TGround::GetTraction(TDynamicObject *model)
{ // dany sektor może nie mieć nic w środku { // dany sektor może nie mieć nic w środku
for (node = tmp->nRenderWires; node; for (node = tmp->nRenderWires; node;
node = node->nNext3) // następny z grupy node = node->nNext3) // następny z grupy
if (node->iType == if (node->iType == TP_TRACTION) // w grupie tej są druty oraz inne linie
TP_TRACTION) // w grupie tej są druty oraz inne linie
{ {
vParam = // współczynniki równania parametrycznego
node->hvTraction vParam = node->hvTraction->vParametric;
->vParametric; // współczynniki równania parametrycznego
fRaParam = -glm::dot(pant0, vFront); fRaParam = -glm::dot(pant0, vFront);
auto const paramfrontdot = glm::dot( vParam, vFront ); auto const paramfrontdot = glm::dot( vParam, vFront );
fRaParam = fRaParam =
-( glm::dot( node->hvTraction->pPoint1, vFront ) + fRaParam ) -( glm::dot( node->hvTraction->pPoint1, vFront ) + fRaParam )
/ ( paramfrontdot != 0.0 ? paramfrontdot : 0.001 ); // div0 trap / ( paramfrontdot != 0.0 ? paramfrontdot : 0.001 ); // div0 trap
if ((fRaParam >= -0.001) ? (fRaParam <= 1.001) : false) if ((fRaParam >= -0.001) ? (fRaParam <= 1.001) : false)
{ // jeśli tylko jest w przedziale, wyznaczyć odległość wzdłuż { // jeśli tylko jest w przedziale, wyznaczyć odległość wzdłuż wektorów vUp i vLeft
// wektorów vUp i vLeft // punkt styku płaszczyzny z drutem (dla generatora łuku el.)
vStyk = node->hvTraction->pPoint1 + vStyk = node->hvTraction->pPoint1 + fRaParam * vParam;
fRaParam * vParam; // punkt styku płaszczyzny z // wektor musi się mieścić w przedziale ruchu pantografu
// drutem (dla generatora łuku vGdzie = vStyk - pant0;
// el.) fVertical = glm::dot( vGdzie, vUp);
vGdzie = vStyk - pant0; // wektor
fVertical = glm::dot(
vGdzie,
vUp); // musi się mieścić w przedziale ruchu pantografu
if (fVertical >= 0.0) // jeśli ponad pantografem (bo może if (fVertical >= 0.0) // jeśli ponad pantografem (bo może
// łapać druty spod wiaduktu) // łapać druty spod wiaduktu)
if (Global::bEnableTraction ? if (Global::bEnableTraction ?
fVertical < p->PantWys - 0.15 : fVertical < p->PantWys - 0.15 :
false) // jeśli drut jest niżej niż 15cm pod false) {
// ślizgiem // jeśli drut jest niżej niż 15cm pod ślizgiem
{ // przełączamy w tryb połamania, o ile jedzie; // przełączamy w tryb połamania, o ile jedzie;
// (bEnableTraction) aby dało się jeździć na // (bEnableTraction) aby dało się jeździć na
// koślawych // koślawych
// sceneriach // sceneriach
@@ -3827,18 +3771,7 @@ bool TGround::GetTraction(TDynamicObject *model)
else else
p->hvPowerWire = NULL; // pantograf opuszczony p->hvPowerWire = NULL; // pantograf opuszczony
} }
// if (model->fWahaczeAmp<model->MoverParameters->DistCounter)
//{//nieużywana normalnie zmienna ogranicza powtórzone logowania
// model->fWahaczeAmp=model->MoverParameters->DistCounter;
// ErrorLog(FloatToStrF(1000.0*model->MoverParameters->DistCounter,ffFixed,7,3)+","+FloatToStrF(p->PantTraction,ffFixed,7,3)+","+FloatToStrF(p->fHorizontal,ffFixed,7,3)+","+FloatToStrF(p->PantWys,ffFixed,7,3)+","+AnsiString(p->hvPowerWire?1:0));
// //
// if (p->fHorizontal>1.0)
//{
// //Global::iPause|=1; //zapauzowanie symulacji
// Global::fTimeSpeed=1; //spowolnienie czasu do obejrzenia pantografu
// return true; //łapacz
//}
//}
return true; return true;
}; };

View File

@@ -285,20 +285,24 @@ class TGround
bool InitEvents(); bool InitEvents();
#endif #endif
bool InitLaunchers(); bool InitLaunchers();
#ifdef EU07_USE_OLD_GROUNDCODE
TTrack * FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude); TTrack * FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude);
TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TGroundNode *Exclude); TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TGroundNode *Exclude);
TTraction * TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n); TTraction * TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n);
#endif
TGroundNode * AddGroundNode(cParser *parser); TGroundNode * AddGroundNode(cParser *parser);
#ifdef EU07_USE_OLD_GROUNDCODE
void UpdatePhys(double dt, int iter); // aktualizacja fizyki stałym krokiem void UpdatePhys(double dt, int iter); // aktualizacja fizyki stałym krokiem
bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS
void Update_Hidden(); // updates invisible elements of the scene void Update_Hidden(); // updates invisible elements of the scene
#endif
bool GetTraction(TDynamicObject *model); bool GetTraction(TDynamicObject *model);
#ifdef EU07_USE_OLD_GROUNDCODE #ifdef EU07_USE_OLD_GROUNDCODE
bool AddToQuery( TEvent *Event, TDynamicObject *Node ); bool AddToQuery( TEvent *Event, TDynamicObject *Node );
bool CheckQuery(); bool CheckQuery();
#endif
TGroundNode * DynamicFindAny(std::string const &Name); TGroundNode * DynamicFindAny(std::string const &Name);
TGroundNode * DynamicFind(std::string const &Name); TGroundNode * DynamicFind(std::string const &Name);
#endif
void DynamicList(bool all = false); void DynamicList(bool all = false);
TGroundNode * FindGroundNode(std::string const &asNameToFind, TGroundNodeType const iNodeType); TGroundNode * FindGroundNode(std::string const &asNameToFind, TGroundNodeType const iNodeType);
TGroundRect * GetRect( double x, double z ); TGroundRect * GetRect( double x, double z );
@@ -325,7 +329,9 @@ class TGround
// convert tp_terrain model to a series of triangle nodes // convert tp_terrain model to a series of triangle nodes
void convert_terrain( TGroundNode const *Terrain ); void convert_terrain( TGroundNode const *Terrain );
void convert_terrain( TSubModel const *Submodel ); void convert_terrain( TSubModel const *Submodel );
#ifdef EU07_USE_OLD_GROUNDCODE
void RaTriangleDivider(TGroundNode *node); void RaTriangleDivider(TGroundNode *node);
#endif
void Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam); void Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam);
public: public:

View File

@@ -180,3 +180,15 @@ void TMemCell::AssignEvents(TEvent *e)
{ // powiązanie eventu { // powiązanie eventu
OnSent = e; OnSent = e;
}; };
// legacy method, initializes traction after deserialization from scenario file
void
memory_table::InitCells() {
for( auto *cell : m_items ) {
// Ra: eventy komórek pamięci, wykonywane po wysłaniu komendy do zatrzymanego pojazdu
cell->AssignEvents( simulation::Events.FindEvent( cell->name() + ":sent" ) );
}
}

View File

@@ -61,8 +61,14 @@ class TMemCell : public editor::basic_node {
void AssignEvents(TEvent *e); void AssignEvents(TEvent *e);
}; };
class memory_manager : public basic_table<TMemCell> {
class memory_table : public basic_table<TMemCell> {
public:
// legacy method, initializes traction after deserialization from scenario file
void
InitCells();
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -1641,7 +1641,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector<std::string> *t,
} }
} }
else { else {
ErrorLog( "Bad model: reference to non-existent texture index in sub-model" + ( pName.empty() ? "" : " \"" + pName + "\"" ) ); ErrorLog( "Bad model: reference to nonexistent texture index in sub-model" + ( pName.empty() ? "" : " \"" + pName + "\"" ) );
m_material = null_handle; m_material = null_handle;
} }
} }

View File

@@ -21,8 +21,7 @@ http://mozilla.org/MPL/2.0/.
#include "mczapkie/mctools.h" #include "mczapkie/mctools.h"
#include "usefull.h" #include "usefull.h"
TRealSound::TRealSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, TRealSound::TRealSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod, double rmin)
bool freqmod, double rmin)
{ {
Init(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin); Init(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin);
} }
@@ -32,12 +31,7 @@ TRealSound::~TRealSound()
// if (this) if (pSound) pSound->Stop(); // if (this) if (pSound) pSound->Stop();
} }
void TRealSound::Free() void TRealSound::Init(std::string const &SoundName, double DistanceAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod, double rmin)
{
}
void TRealSound::Init(std::string const &SoundName, double DistanceAttenuation, double X, double Y, double Z,
bool Dynamic, bool freqmod, double rmin)
{ {
// Nazwa=SoundName; //to tak raczej nie zadziała, (SoundName) jest tymczasowe // Nazwa=SoundName; //to tak raczej nie zadziała, (SoundName) jest tymczasowe
pSound = TSoundsManager::GetFromName(SoundName, Dynamic, &fFrequency); pSound = TSoundsManager::GetFromName(SoundName, Dynamic, &fFrequency);
@@ -71,7 +65,7 @@ void TRealSound::Init(std::string const &SoundName, double DistanceAttenuation,
dSoundAtt = -1; dSoundAtt = -1;
}; };
double TRealSound::ListenerDistance(vector3 ListenerPosition) double TRealSound::ListenerDistance( Math3D::vector3 ListenerPosition)
{ {
if (dSoundAtt == -1) if (dSoundAtt == -1)
{ {
@@ -83,7 +77,7 @@ double TRealSound::ListenerDistance(vector3 ListenerPosition)
} }
} }
void TRealSound::Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition) void TRealSound::Play(double Volume, int Looping, bool ListenerInside, Math3D::vector3 NewPosition)
{ {
if (!pSound) if (!pSound)
return; return;
@@ -155,11 +149,6 @@ void TRealSound::Play(double Volume, int Looping, bool ListenerInside, vector3 N
} }
}; };
void TRealSound::Start(){
// włączenie dźwięku
};
void TRealSound::Stop() void TRealSound::Stop()
{ {
DWORD stat; DWORD stat;
@@ -231,17 +220,14 @@ void TRealSound::ResetPosition()
pSound->SetCurrentPosition(0); pSound->SetCurrentPosition(0);
} }
TTextSound::TTextSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, TTextSound::TTextSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod, double rmin) :
bool Dynamic, bool freqmod, double rmin) TRealSound(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin)
: TRealSound(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin)
{ {
Init(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin); Init(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin);
} }
void TTextSound::Init(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, void TTextSound::Init(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod, double rmin)
bool Dynamic, bool freqmod, double rmin)
{ // dodatkowo doczytuje plik tekstowy { // dodatkowo doczytuje plik tekstowy
//TRealSound::Init(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin);
fTime = GetWaveTime(); fTime = GetWaveTime();
std::string txt(SoundName); std::string txt(SoundName);
txt.erase( txt.rfind( '.' ) ); // obcięcie rozszerzenia txt.erase( txt.rfind( '.' ) ); // obcięcie rozszerzenia
@@ -253,15 +239,11 @@ void TTextSound::Init(std::string const &SoundName, double SoundAttenuation, dou
txt = "sounds\\" + txt; //ścieżka może nie być podana txt = "sounds\\" + txt; //ścieżka może nie być podana
if (FileExists(txt)) if (FileExists(txt))
{ // wczytanie { // wczytanie
/* TFileStream *ts = new TFileStream(txt, fmOpenRead); std::ifstream inputfile( txt );
asText = AnsiString::StringOfChar(' ', ts->Size);
ts->Read(asText.c_str(), ts->Size);
delete ts;
*/ std::ifstream inputfile( txt );
asText.assign( std::istreambuf_iterator<char>( inputfile ), std::istreambuf_iterator<char>() ); asText.assign( std::istreambuf_iterator<char>( inputfile ), std::istreambuf_iterator<char>() );
} }
}; };
void TTextSound::Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition) void TTextSound::Play(double Volume, int Looping, bool ListenerInside, Math3D::vector3 NewPosition)
{ {
if (false == asText.empty()) if (false == asText.empty())
{ // jeśli ma powiązany tekst { // jeśli ma powiązany tekst

View File

@@ -7,24 +7,25 @@ obtain one at
http://mozilla.org/MPL/2.0/. http://mozilla.org/MPL/2.0/.
*/ */
#ifndef RealSoundH #pragma once
#define RealSoundH
#include <string> #include <string>
#include "Sound.h"
#include "Geometry.h"
class TRealSound #include "Sound.h"
{ #include "dumb3d.h"
protected: #include "names.h"
class TRealSound {
protected:
PSound pSound = nullptr; PSound pSound = nullptr;
// char *Nazwa; // dla celow odwszawiania NOTE: currently not used anywhere double fDistance = 0.0;
double fDistance = 0.0, double fPreviousDistance = 0.0; // dla liczenia Dopplera
fPreviousDistance = 0.0; // dla liczenia Dopplera
float fFrequency = 22050.0; // częstotliwość samplowania pliku float fFrequency = 22050.0; // częstotliwość samplowania pliku
int iDoppler = 0; // Ra 2014-07: możliwość wyłączenia efektu Dopplera np. dla śpiewu ptaków int iDoppler = 0; // Ra 2014-07: możliwość wyłączenia efektu Dopplera np. dla śpiewu ptaków
public: public:
vector3 vSoundPosition; // polozenie zrodla dzwieku std::string m_name;
Math3D::vector3 vSoundPosition; // polozenie zrodla dzwieku
double dSoundAtt = -1.0; // odleglosc polowicznego zaniku dzwieku double dSoundAtt = -1.0; // odleglosc polowicznego zaniku dzwieku
double AM = 0.0; // mnoznik amplitudy double AM = 0.0; // mnoznik amplitudy
double AA = 0.0; // offset amplitudy double AA = 0.0; // offset amplitudy
@@ -32,37 +33,43 @@ class TRealSound
double FA = 0.0; // offset czestotliwosci double FA = 0.0; // offset czestotliwosci
bool bLoopPlay = false; // czy zapętlony dźwięk jest odtwarzany bool bLoopPlay = false; // czy zapętlony dźwięk jest odtwarzany
TRealSound() = default; TRealSound() = default;
TRealSound( std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, TRealSound( std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod = false, double rmin = 0.0 );
bool freqmod = false, double rmin = 0.0);
~TRealSound(); ~TRealSound();
void Free(); void Init( std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod = false, double rmin = 0.0 );
void Init(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, double ListenerDistance( Math3D::vector3 ListenerPosition);
bool freqmod = false, double rmin = 0.0); void Play(double Volume, int Looping, bool ListenerInside, Math3D::vector3 NewPosition);
double ListenerDistance(vector3 ListenerPosition);
void Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition);
void Start();
void Stop(); void Stop();
void AdjFreq(double Freq, double dt); void AdjFreq(double Freq, double dt);
void SetPan(int Pan); void SetPan(int Pan);
double GetWaveTime(); // McZapkie TODO: dorobic dla roznych bps double GetWaveTime(); // McZapkie TODO: dorobic dla roznych bps
int GetStatus(); int GetStatus();
void ResetPosition(); void ResetPosition();
// void FreqReset(float f=22050.0) {fFrequency=f;};
bool Empty() { return ( pSound == nullptr ); } bool Empty() { return ( pSound == nullptr ); }
void
name( std::string Name ) {
m_name = Name; }
std::string const &
name() const {
return m_name; }
glm::dvec3
location() const {
return vSoundPosition; };
}; };
class TTextSound : public TRealSound
{ // dźwięk ze stenogramem
class TTextSound : public TRealSound {
// dźwięk ze stenogramem
std::string asText; std::string asText;
float fTime; // czas trwania float fTime; // czas trwania
public: public:
TTextSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, TTextSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod = false, double rmin = 0.0);
bool Dynamic, bool freqmod = false, double rmin = 0.0); void Init(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod = false, double rmin = 0.0);
void Init(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, void Play(double Volume, int Looping, bool ListenerInside, Math3D::vector3 NewPosition);
bool Dynamic, bool freqmod = false, double rmin = 0.0);
void Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition);
}; };
class TSynthSound class TSynthSound
{ // klasa generująca sygnał odjazdu (Rp12, Rp13), potem rozbudować o pracę manewrowego... { // klasa generująca sygnał odjazdu (Rp12, Rp13), potem rozbudować o pracę manewrowego...
int iIndex[44]; // indeksy początkowe, gdy mamy kilka wariantów dźwięków składowych int iIndex[44]; // indeksy początkowe, gdy mamy kilka wariantów dźwięków składowych
@@ -74,10 +81,16 @@ class TSynthSound
// 41 - "tysiące" // 41 - "tysiące"
// 42 - indeksy początkowe dla "odjazd" // 42 - indeksy początkowe dla "odjazd"
// 43 - indeksy początkowe dla "gotów" // 43 - indeksy początkowe dla "gotów"
PSound *sSound; // posortowana tablica dźwięków, rozmiar zależny od liczby znalezionych plików PSound sSound; // posortowana tablica dźwięków, rozmiar zależny od liczby znalezionych plików
// a może zamiast wielu plików/dźwięków zrobić jeden połączony plik i posługiwać się czasem // a może zamiast wielu plików/dźwięków zrobić jeden połączony plik i posługiwać się czasem
// od..do? // od..do?
}; };
// collection of generators for power grid present in the scene
class sound_table : public basic_table<TTextSound> {
};
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#endif

View File

@@ -103,7 +103,7 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
fStep = fNewStep; fStep = fNewStep;
if (fLength <= 0) { if (fLength <= 0) {
ErrorLog( "Bad geometry: zero length spline \"" + pOwner->NameGet() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" ); ErrorLog( "Bad geometry: zero length spline \"" + pOwner->name() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
fLength = 0.01; // crude workaround TODO: fix this properly fLength = 0.01; // crude workaround TODO: fix this properly
/* /*
return false; // zerowe nie mogą być return false; // zerowe nie mogą być
@@ -205,7 +205,7 @@ double TSegment::GetTFromS(double const s) const
// Newton's method failed. If this happens, increase iterations or // Newton's method failed. If this happens, increase iterations or
// tolerance or integration accuracy. // tolerance or integration accuracy.
// return -1; //Ra: tu nigdy nie dojdzie // return -1; //Ra: tu nigdy nie dojdzie
ErrorLog( "Bad geometry: shape estimation failed for spline \"" + pOwner->NameGet() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" ); ErrorLog( "Bad geometry: shape estimation failed for spline \"" + pOwner->name() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
// MessageBox(0,"Too many iterations","GetTFromS",MB_OK); // MessageBox(0,"Too many iterations","GetTFromS",MB_OK);
return fTime; return fTime;
}; };
@@ -323,23 +323,28 @@ Math3D::vector3 TSegment::GetPoint(double const fDistance) const
} }
}; };
void TSegment::RaPositionGet(double const fDistance, Math3D::vector3 &p, Math3D::vector3 &a) const // ustalenie pozycji osi na torze, przechyłki, pochylenia i kierunku jazdy
{ // ustalenie pozycji osi na torze, przechyłki, pochylenia i kierunku jazdy void TSegment::RaPositionGet(double const fDistance, Math3D::vector3 &p, Math3D::vector3 &a) const {
if (bCurve)
{ // można by wprowadzić uproszczony wzór dla okręgów płaskich if (bCurve) {
double t = GetTFromS(fDistance); // aproksymacja dystansu na krzywej Beziera na parametr (t) // można by wprowadzić uproszczony wzór dla okręgów płaskich
p = RaInterpolate(t); auto const t = GetTFromS(fDistance); // aproksymacja dystansu na krzywej Beziera na parametr (t)
a.x = (1.0 - t) * fRoll1 + (t)*fRoll2; // przechyłka w danym miejscu (zmienia się liniowo) p = FastGetPoint( t );
// przechyłka w danym miejscu (zmienia się liniowo)
a.x = interpolate<double>( fRoll1, fRoll2, t );
// pochodna jest 3*A*t^2+2*B*t+C // pochodna jest 3*A*t^2+2*B*t+C
a.y = atan(t * (t * 3.0 * vA.y + vB.y + vB.y) + vC.y); // pochylenie krzywej (w pionie) auto const tangent = t * ( t * 3.0 * vA + vB + vB ) + vC;
a.z = -atan2(t * (t * 3.0 * vA.x + vB.x + vB.x) + vC.x, // pochylenie krzywej (w pionie)
t * (t * 3.0 * vA.z + vB.z + vB.z) + vC.z); // kierunek krzywej w planie a.y = std::atan( tangent.y );
// kierunek krzywej w planie
a.z = -std::atan2( tangent.x, tangent.z );
} }
else else {
{ // wyliczenie dla odcinka prostego jest prostsze // wyliczenie dla odcinka prostego jest prostsze
double t = fDistance / fLength; // zerowych torów nie ma auto const t = fDistance / fLength; // zerowych torów nie ma
p = ((1.0 - t) * Point1 + (t)*Point2); p = FastGetPoint( t );
a.x = (1.0 - t) * fRoll1 + (t)*fRoll2; // przechyłka w danym miejscu (zmienia się liniowo) // przechyłka w danym miejscu (zmienia się liniowo)
a.x = interpolate<double>( fRoll1, fRoll2, t );
a.y = fStoop; // pochylenie toru prostego a.y = fStoop; // pochylenie toru prostego
a.z = fDirection; // kierunek toru w planie a.z = fDirection; // kierunek toru w planie
} }

View File

@@ -14,37 +14,6 @@ http://mozilla.org/MPL/2.0/.
#include "Classes.h" #include "Classes.h"
#include "usefull.h" #include "usefull.h"
// 110405 Ra: klasa punktów przekroju z normalnymi
/*
class vector6 : public Math3D::vector3
{ // punkt przekroju wraz z wektorem normalnym
public:
Math3D::vector3 n;
vector6()
{
x = y = z = n.x = n.z = 0.0;
n.y = 1.0;
};
vector6(double a, double b, double c, double d, double e, double f)
{
x = a;
y = b;
z = c;
n.x = 0.0;
n.y = 1.0;
n.z = 0.0;
}; // Ra: bo na razie są z tym problemy
vector6(double a, double b, double c)
{
x = a;
y = b;
z = c;
n.x = 0.0;
n.y = 1.0;
n.z = 0.0;
};
};
*/
class TSegment class TSegment
{ // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny) { // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny)
private: private:
@@ -60,7 +29,6 @@ class TSegment
double fStoop = 0.0; // Ra: kąt wzniesienia; dla łuku od Point1 double fStoop = 0.0; // Ra: kąt wzniesienia; dla łuku od Point1
Math3D::vector3 vA, vB, vC; // współczynniki wielomianów trzeciego stopnia vD==Point1 Math3D::vector3 vA, vB, vC; // współczynniki wielomianów trzeciego stopnia vD==Point1
TTrack *pOwner = nullptr; // wskaźnik na właściciela TTrack *pOwner = nullptr; // wskaźnik na właściciela
double fAngle[ 2 ] = { 0.0, 0.0 }; // kąty zakończenia drogi na przejazdach
Math3D::vector3 Math3D::vector3
GetFirstDerivative(double const fTime) const; GetFirstDerivative(double const fTime) const;
@@ -140,10 +108,6 @@ public:
int int
RaSegCount() const { RaSegCount() const {
return fTsBuffer ? iSegCount : 1; }; return fTsBuffer ? iSegCount : 1; };
inline
void
AngleSet(int const i, double const a) {
fAngle[i] = a; };
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -26,6 +26,7 @@ http://mozilla.org/MPL/2.0/.
#include "AnimModel.h" #include "AnimModel.h"
#include "MemCell.h" #include "MemCell.h"
#include "Event.h" #include "Event.h"
#include "simulation.h"
// 101206 Ra: trapezoidalne drogi i tory // 101206 Ra: trapezoidalne drogi i tory
// 110720 Ra: rozprucie zwrotnicy i odcinki izolowane // 110720 Ra: rozprucie zwrotnicy i odcinki izolowane
@@ -2651,6 +2652,31 @@ int TTrack::TestPoint(vector3 *Point)
return -1; return -1;
}; };
// retrieves list of the track's end points
std::vector<glm::dvec3>
TTrack::endpoints() const {
switch( eType ) {
case tt_Normal:
case tt_Table: {
return {
glm::dvec3{ Segment->FastGetPoint_0() },
glm::dvec3{ Segment->FastGetPoint_1() } };
}
case tt_Switch:
case tt_Cross: {
return {
glm::dvec3{ SwitchExtension->Segments[ 0 ]->FastGetPoint_0() },
glm::dvec3{ SwitchExtension->Segments[ 0 ]->FastGetPoint_1() },
glm::dvec3{ SwitchExtension->Segments[ 1 ]->FastGetPoint_0() },
glm::dvec3{ SwitchExtension->Segments[ 1 ]->FastGetPoint_1() } };
}
default: {
return{};
}
}
}
void TTrack::MovedUp1(float const dh) void TTrack::MovedUp1(float const dh)
{ // poprawienie przechyłki wymaga wydłużenia podsypki { // poprawienie przechyłki wymaga wydłużenia podsypki
fTexHeight1 += dh; fTexHeight1 += dh;
@@ -2745,11 +2771,11 @@ TTrack * TTrack::Connected(int s, double &d) const
// legacy method, initializes tracks after deserialization from scenario file // legacy method, initializes tracks after deserialization from scenario file
void void
path_table::InitTracks() { path_table::InitTracks() {
/*
TGroundNode *Model;
int iConnection;
for( auto *track : m_paths ) { int connection { -1 };
TTrack *matchingtrack { nullptr };
for( auto *track : m_items ) {
track->AssignEvents( track->AssignEvents(
simulation::Events.FindEvent( track->asEvent0Name ), simulation::Events.FindEvent( track->asEvent0Name ),
@@ -2776,30 +2802,32 @@ path_table::InitTracks() {
} }
switch (track->eType) { switch (track->eType) {
/*
// TODO: re-enable
case tt_Table: { case tt_Table: {
// obrotnicę też łączymy na starcie z innymi torami // obrotnicę też łączymy na starcie z innymi torami
// szukamy modelu o tej samej nazwie // szukamy modelu o tej samej nazwie
Model = FindGroundNode(Current->asName, TP_MODEL); auto *instance = simulation::Instances.find( trackname );
// wiązanie toru z modelem obrotnicy // wiązanie toru z modelem obrotnicy
track->RaAssign( track->RaAssign(
Current, Current,
( Model ? instance,
Model->Model :
nullptr ),
simulation::Events.FindEvent( trackname + ":done" ), simulation::Events.FindEvent( trackname + ":done" ),
simulation::Events.FindEvent( trackname + ":joined" ) ); simulation::Events.FindEvent( trackname + ":joined" ) );
if( Model == nullptr ) { if( instance == nullptr ) {
// jak nie ma modelu to pewnie jest wykolejnica, a ta jest domyślnie zamknięta i wykoleja // jak nie ma modelu to pewnie jest wykolejnica, a ta jest domyślnie zamknięta i wykoleja
break; break;
} }
// no break on purpose:
// jak coś pójdzie źle, to robimy z tego normalny tor // jak coś pójdzie źle, to robimy z tego normalny tor
} }
*/
case tt_Normal: { case tt_Normal: {
// tylko proste są podłączane do rozjazdów, stąd dwa rozjazdy się nie połączą ze sobą // tylko proste są podłączane do rozjazdów, stąd dwa rozjazdy się nie połączą ze sobą
if( track->CurrentPrev() == nullptr ) { if( track->CurrentPrev() == nullptr ) {
// tylko jeśli jeszcze nie podłączony // tylko jeśli jeszcze nie podłączony
auto *matchingtrack = simulation::Region.FindTrack( track->CurrentSegment()->FastGetPoint_0(), iConnection, track ); std::tie( matchingtrack, connection ) = simulation::Region->find_path( track->CurrentSegment()->FastGetPoint_0(), track );
switch( iConnection ) { switch( connection ) {
case -1: // Ra: pierwsza koncepcja zawijania samochodów i statków case -1: // Ra: pierwsza koncepcja zawijania samochodów i statków
// if ((Track->iCategoryFlag&1)==0) //jeśli nie jest torem szynowym // if ((Track->iCategoryFlag&1)==0) //jeśli nie jest torem szynowym
// Track->ConnectPrevPrev(Track,0); //łączenie końca odcinka do samego siebie // Track->ConnectPrevPrev(Track,0); //łączenie końca odcinka do samego siebie
@@ -2830,12 +2858,14 @@ path_table::InitTracks() {
matchingtrack->SetConnections( 1 ); // robi też Switch(0) matchingtrack->SetConnections( 1 ); // robi też Switch(0)
matchingtrack->Switch( 0 ); matchingtrack->Switch( 0 );
break; break;
default:
break;
} }
} }
if( track->CurrentNext() == nullptr ) { if( track->CurrentNext() == nullptr ) {
// tylko jeśli jeszcze nie podłączony // tylko jeśli jeszcze nie podłączony
auto *matchingtrack = simulation::Region.FindTrack( track->CurrentSegment()->FastGetPoint_1(), iConnection, track ); std::tie( matchingtrack, connection ) = simulation::Region->find_path( track->CurrentSegment()->FastGetPoint_1(), track );
switch( iConnection ) { switch( connection ) {
case -1: // Ra: pierwsza koncepcja zawijania samochodów i statków case -1: // Ra: pierwsza koncepcja zawijania samochodów i statków
// if ((Track->iCategoryFlag&1)==0) //jeśli nie jest torem szynowym // if ((Track->iCategoryFlag&1)==0) //jeśli nie jest torem szynowym
// Track->ConnectNextNext(Track,1); //łączenie końca odcinka do samego siebie // Track->ConnectNextNext(Track,1); //łączenie końca odcinka do samego siebie
@@ -2866,6 +2896,8 @@ path_table::InitTracks() {
matchingtrack->SetConnections( 1 ); // robi też Switch(0) matchingtrack->SetConnections( 1 ); // robi też Switch(0)
// tmp->Switch(0); // tmp->Switch(0);
break; break;
default:
break;
} }
} }
break; break;
@@ -2910,11 +2942,12 @@ path_table::InitTracks() {
else { else {
// utworzenie automatycznej komórki // utworzenie automatycznej komórki
// TODO: determine suitable location for this one, create and add world reference node // TODO: determine suitable location for this one, create and add world reference node
auto *memorycell = new TMemCell( isolated->asName ); // to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy scene::node_data nodedata;
nodedata.name = isolated->asName;
auto *memorycell = new TMemCell( nodedata ); // to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy
simulation::Memory.insert( memorycell ); simulation::Memory.insert( memorycell );
isolated->pMemCell = memorycell; // wskaźnik komóki przekazany do odcinka izolowanego isolated->pMemCell = memorycell; // wskaźnik komóki przekazany do odcinka izolowanego
} }
isolated = isolated->Next(); isolated = isolated->Next();
} }
*/
} }

View File

@@ -119,7 +119,6 @@ class TTrack : public editor::basic_node {
friend class opengl_renderer; friend class opengl_renderer;
private: private:
// TGroundNode * pMyNode = nullptr; // Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode
TIsolated * pIsolated = nullptr; // obwód izolowany obsługujący zajęcia/zwolnienia grupy torów TIsolated * pIsolated = nullptr; // obwód izolowany obsługujący zajęcia/zwolnienia grupy torów
std::shared_ptr<TSwitchExtension> SwitchExtension; // dodatkowe dane do toru, który jest zwrotnicą std::shared_ptr<TSwitchExtension> SwitchExtension; // dodatkowe dane do toru, który jest zwrotnicą
std::shared_ptr<TSegment> Segment; std::shared_ptr<TSegment> Segment;
@@ -234,6 +233,9 @@ public:
void void
origin( glm::dvec3 Origin ) { origin( glm::dvec3 Origin ) {
m_origin = Origin; } m_origin = Origin; }
// retrieves list of the track's end points
std::vector<glm::dvec3>
endpoints() const;
#ifdef EU07_USE_OLD_GROUNDCODE #ifdef EU07_USE_OLD_GROUNDCODE
void create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ); // wypełnianie VBO void create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ); // wypełnianie VBO

View File

@@ -91,7 +91,6 @@ sekcji z sąsiedniego przęsła).
*/ */
TTraction::TTraction( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {} TTraction::TTraction( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {}
// legacy constructor // legacy constructor
TTraction::TTraction( std::string Name ) { TTraction::TTraction( std::string Name ) {
@@ -173,6 +172,13 @@ TTraction::Load( cParser *parser, glm::dvec3 const &pOrigin ) {
m_location = interpolate( pPoint2, pPoint1, 0.5 ); m_location = interpolate( pPoint2, pPoint1, 0.5 );
} }
// retrieves list of the track's end points
std::vector<glm::dvec3>
TTraction::endpoints() const {
return { pPoint1, pPoint2 };
}
std::size_t std::size_t
#ifdef EU07_USE_OLD_GROUNDCODE #ifdef EU07_USE_OLD_GROUNDCODE
TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ) { TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ) {
@@ -621,205 +627,213 @@ TTraction::wire_color() const {
// legacy method, initializes traction after deserialization from scenario file // legacy method, initializes traction after deserialization from scenario file
void void
traction_table::InitTraction() { traction_table::InitTraction() {
/*
//łączenie drutów ze sobą oraz z torami i eventami //łączenie drutów ze sobą oraz z torami i eventami
// TGroundNode *nCurrent, *nTemp; // TGroundNode *nCurrent, *nTemp;
// TTraction *tmp; // znalezione przęsło // TTraction *tmp; // znalezione przęsło
int iConnection;
std::string name; int connection { -1 };
TTraction *matchingtraction { nullptr };
for( auto *traction : m_items ) { for( auto *traction : m_items ) {
// podłączenie do zasilacza, żeby można było sumować prąd kilku pojazdów // podłączenie do zasilacza, żeby można było sumować prąd kilku pojazdów
// a jednocześnie z jednego miejsca zmieniać napięcie eventem // a jednocześnie z jednego miejsca zmieniać napięcie eventem
// wykonywane najpierw, żeby można było logować podłączenie 2 zasilaczy do jednego drutu // wykonywane najpierw, żeby można było logować podłączenie 2 zasilaczy do jednego drutu
// izolator zawieszony na przęśle jest ma być osobnym odcinkiem drutu o długości ok. 1m, // izolator zawieszony na przęśle jest ma być osobnym odcinkiem drutu o długości ok. 1m,
// podłączonym do zasilacza o nazwie "*" (gwiazka); "none" nie będzie odpowiednie // podłączonym do zasilacza o nazwie "*" (gwiazka); "none" nie będzie odpowiednie
nTemp = FindGroundNode(traction->asPowerSupplyName, TP_TRACTIONPOWERSOURCE); auto *powersource = simulation::Powergrid.find( traction->asPowerSupplyName );
if (nTemp) // jak zasilacz znaleziony if( powersource ) {
traction->PowerSet(nTemp->psTractionPowerSource); // to podłączyć do przęsła // jak zasilacz znaleziony to podłączyć do przęsła
else if (traction->asPowerSupplyName != "*") // gwiazdka dla przęsła z izolatorem traction->PowerSet( powersource );
if (traction->asPowerSupplyName != "none") // dopuszczamy na razie brak podłączenia? }
{ // logowanie błędu i utworzenie zasilacza o domyślnej zawartości else {
ErrorLog("Missed TractionPowerSource: " + traction->asPowerSupplyName); if( ( traction->asPowerSupplyName != "*" ) // gwiazdka dla przęsła z izolatorem
nTemp = new TGroundNode(); && ( traction->asPowerSupplyName != "none" ) ) { // dopuszczamy na razie brak podłączenia?
nTemp->iType = TP_TRACTIONPOWERSOURCE; // logowanie błędu i utworzenie zasilacza o domyślnej zawartości
nTemp->asName = traction->asPowerSupplyName; ErrorLog( "Bad scenario: traction piece connected to nonexistent power source \"" + traction->asPowerSupplyName + "\"" );
nTemp->psTractionPowerSource = new TTractionPowerSource(nTemp); scene::node_data nodedata;
nTemp->psTractionPowerSource->Init(traction->NominalVoltage, traction->MaxCurrent); nodedata.name = traction->asPowerSupplyName;
nTemp->nNext = nRootOfType[nTemp->iType]; // ostatni dodany dołączamy na końcu powersource = new TTractionPowerSource( nodedata );
// nowego powersource->Init( traction->NominalVoltage, traction->MaxCurrent );
nRootOfType[nTemp->iType] = nTemp; // ustawienie nowego na początku listy simulation::Powergrid.insert( powersource );
} }
}
} }
for( auto *traction : m_items ) { for( auto *traction : m_items ) {
if (!traction->hvNext[0]) // tylko jeśli jeszcze nie podłączony if (!traction->hvNext[0]) {
{ // tylko jeśli jeszcze nie podłączony
tmp = FindTraction(traction->pPoint1, iConnection, nCurrent); std::tie( matchingtraction, connection ) = simulation::Region->find_traction( traction->pPoint1, traction );
switch (iConnection) switch (connection) {
{ case 0: {
case 0: traction->Connect( 0, matchingtraction, 0 );
traction->Connect(0, tmp, 0); break;
break; }
case 1: case 1: {
traction->Connect(0, tmp, 1); traction->Connect( 0, matchingtraction, 1 );
break; break;
}
default: {
break;
}
} }
if (traction->hvNext[0]) // jeśli został podłączony if( traction->hvNext[ 0 ] ) {
if (traction->psSection && tmp->psSection) // tylko przęsło z izolatorem może nie // jeśli został podłączony
// mieć zasilania, bo ma 2, trzeba if( ( traction->psSection != nullptr )
// sprawdzać sąsiednie && ( matchingtraction->psSection != nullptr ) ) {
if (traction->psSection != // tylko przęsło z izolatorem może nie mieć zasilania, bo ma 2, trzeba sprawdzać sąsiednie
tmp->psSection) // połączone odcinki mają różne zasilacze if( traction->psSection != matchingtraction->psSection ) {
{ // to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo // połączone odcinki mają różne zasilacze
// błąd // to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo błąd
if (traction->psSection->bSection && !tmp->psSection->bSection) if( ( true == traction->psSection->bSection )
{ //(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji && ( false == matchingtraction->psSection->bSection ) ) {
tmp->PowerSet(traction->psSection); // zastąpienie wskazaniem sekcji //(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji
matchingtraction->PowerSet( traction->psSection ); // zastąpienie wskazaniem sekcji
} }
else if (!traction->psSection->bSection && tmp->psSection->bSection) else if( ( false == traction->psSection->bSection ) &&
{ //(Traction->psSection) jest podstacją, a (tmp->psSection) nazwą sekcji ( true == matchingtraction->psSection->bSection ) ) {
traction->PowerSet(tmp->psSection); // zastąpienie wskazaniem sekcji //(Traction->psSection) jest podstacją, a (tmp->psSection) nazwą sekcji
traction->PowerSet( matchingtraction->psSection ); // zastąpienie wskazaniem sekcji
}
else {
// jeśli obie to sekcje albo obie podstacje, to będzie błąd
ErrorLog( "Bad scenario: faulty traction power connection at location " + to_string( traction->pPoint1 ) );
} }
else // jeśli obie to sekcje albo obie podstacje, to będzie błąd
ErrorLog("Bad power: at " +
to_string(traction->pPoint1.x, 2, 6) + " " +
to_string(traction->pPoint1.y, 2, 6) + " " +
to_string(traction->pPoint1.z, 2, 6));
} }
}
}
} }
if (!traction->hvNext[1]) // tylko jeśli jeszcze nie podłączony if (!traction->hvNext[1]) {
{ // tylko jeśli jeszcze nie podłączony
tmp = FindTraction(traction->pPoint2, iConnection, nCurrent); std::tie( matchingtraction, connection ) = simulation::Region->find_traction( traction->pPoint2, traction );
switch (iConnection) switch (connection) {
{ case 0: {
case 0: traction->Connect( 1, matchingtraction, 0 );
traction->Connect(1, tmp, 0); break;
break; }
case 1: case 1: {
traction->Connect(1, tmp, 1); traction->Connect( 1, matchingtraction, 1 );
break; break;
}
default: {
break;
}
} }
if (traction->hvNext[1]) // jeśli został podłączony if( traction->hvNext[ 1 ] ) {
if (traction->psSection && tmp->psSection) // tylko przęsło z izolatorem może nie // jeśli został podłączony
// mieć zasilania, bo ma 2, trzeba if( ( traction->psSection != nullptr )
// sprawdzać sąsiednie && ( matchingtraction->psSection != nullptr ) ) {
if (traction->psSection != tmp->psSection) // tylko przęsło z izolatorem może nie mieć zasilania, bo ma 2, trzeba sprawdzać sąsiednie
{ // to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo if( traction->psSection != matchingtraction->psSection ) {
// błąd // to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo błąd
if (traction->psSection->bSection && !tmp->psSection->bSection) if( ( true == traction->psSection->bSection )
{ //(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji && ( false == matchingtraction->psSection->bSection ) ) {
tmp->PowerSet(traction->psSection); // zastąpienie wskazaniem sekcji //(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji
matchingtraction->PowerSet( traction->psSection ); // zastąpienie wskazaniem sekcji
} }
else if (!traction->psSection->bSection && tmp->psSection->bSection) else if( ( false == traction->psSection->bSection )
{ //(Traction->psSection) jest podstacją, a (tmp->psSection) nazwą sekcji && ( true == matchingtraction->psSection->bSection ) ) {
traction->PowerSet(tmp->psSection); // zastąpienie wskazaniem sekcji //(Traction->psSection) jest podstacją, a (tmp->psSection) nazwą sekcji
traction->PowerSet( matchingtraction->psSection ); // zastąpienie wskazaniem sekcji
}
else {
// jeśli obie to sekcje albo obie podstacje, to będzie błąd
ErrorLog( "Bad scenario: faulty traction power connection at location " + to_string( traction->pPoint2 ) );
} }
else // jeśli obie to sekcje albo obie podstacje, to będzie błąd
ErrorLog("Bad power: at " +
to_string(traction->pPoint2.x, 2, 6) + " " +
to_string(traction->pPoint2.y, 2, 6) + " " +
to_string(traction->pPoint2.z, 2, 6));
} }
}
}
} }
} }
iConnection = 0; // teraz będzie licznikiem końców auto endcount { 0 };
for( auto *traction : m_items ) { for( auto *traction : m_items ) {
// operacje mające na celu wykrywanie bieżni wspólnych i łączenie przęseł naprążania // operacje mające na celu wykrywanie bieżni wspólnych i łączenie przęseł naprążania
if (traction->WhereIs()) // oznakowanie przedostatnich przęseł if( traction->WhereIs() ) {
{ // poszukiwanie bieżni wspólnej dla przedostatnich przęseł, również w celu połączenia // true for outer pieces of the traction section
// zasilania
// to się nie sprawdza, bo połączyć się mogą dwa niezasilane odcinki jako najbliższe
// sobie
// nCurrent->hvTraction->hvParallel=TractionNearestFind(nCurrent->pCenter,0,nCurrent);
// //szukanie najbliższego przęsła
// trzeba by zliczać końce, a potem wpisać je do tablicy, aby sukcesywnie podłączać do
// zasilaczy
traction->iTries = 5; // oznaczanie końcowych traction->iTries = 5; // oznaczanie końcowych
++iConnection; ++endcount;
} }
if (traction->fResistance[0] == 0.0) if (traction->fResistance[0] == 0.0) {
{ // obliczanie przęseł w segmencie z bezpośrednim zasilaniem
traction->ResistanceCalc(); // obliczanie przęseł w segmencie z bezpośrednim zasilaniem traction->ResistanceCalc();
// ErrorLog("Section "+nCurrent->hvTraction->asPowerSupplyName+" connected"); //jako
// niby błąd będzie bardziej widoczne
traction->iTries = 0; // nie potrzeba mu szukać zasilania traction->iTries = 0; // nie potrzeba mu szukać zasilania
} }
// if (!Traction->hvParallel) //jeszcze utworzyć pętle z bieżni wspólnych
} }
int zg = 0; // zgodność kierunku przęseł, tymczasowo iterator do tabeli końców
// końców jest ok. 10 razy mniej niż wszystkich przęseł (Quark: 216) std::vector<TTraction *> ends; ends.reserve( endcount );
TGroundNode **nEnds = new TGroundNode *[iConnection];
for( auto *traction : m_items ) { for( auto *traction : m_items ) {
//łączenie bieżni wspólnych, w tym oznaczanie niepodanych jawnie //łączenie bieżni wspólnych, w tym oznaczanie niepodanych jawnie
if (!traction->asParallel.empty()) // będzie wskaźnik na inne przęsło if( false == traction->asParallel.empty() ) {
// będzie wskaźnik na inne przęsło
if( ( traction->asParallel == "none" ) if( ( traction->asParallel == "none" )
|| ( traction->asParallel == "*" ) ) { || ( traction->asParallel == "*" ) ) {
// jeśli nieokreślone // jeśli nieokreślone
traction->iLast = 2; // jakby przedostatni - niech po prostu szuka (iLast już przeliczone) traction->iLast = 2; // jakby przedostatni - niech po prostu szuka (iLast już przeliczone)
} }
else if (!traction->hvParallel) // jeśli jeszcze nie został włączony w kółko else if( traction->hvParallel == nullptr ) {
{ // jeśli jeszcze nie został włączony w kółko
auto *nTemp = find( traction->asParallel ); auto *nTemp = find( traction->asParallel );
if (nTemp) if( nTemp != nullptr ) {
{ // o ile zostanie znalezione przęsło o takiej nazwie // o ile zostanie znalezione przęsło o takiej nazwie
if (!nTemp->hvParallel) // jeśli tamten jeszcze nie ma wskaźnika bieżni wspólnej if( nTemp->hvParallel == nullptr ) {
// jeśli tamten jeszcze nie ma wskaźnika bieżni wspólnej
traction->hvParallel = nTemp; // wpisać siebie i dalej dać mu wskaźnik zwrotny traction->hvParallel = nTemp; // wpisać siebie i dalej dać mu wskaźnik zwrotny
else // a jak ma, to albo dołączyć się do kółeczka }
else {
// a jak ma, to albo dołączyć się do kółeczka
traction->hvParallel = nTemp->hvParallel; // przjąć dotychczasowy wskaźnik od niego traction->hvParallel = nTemp->hvParallel; // przjąć dotychczasowy wskaźnik od niego
}
nTemp->hvParallel = traction; // i na koniec ustawienie wskaźnika zwrotnego nTemp->hvParallel = traction; // i na koniec ustawienie wskaźnika zwrotnego
} }
if (!traction->hvParallel) if( traction->hvParallel == nullptr ) {
ErrorLog("Missed overhead: " + traction->asParallel); // logowanie braku ErrorLog( "Missed overhead: " + traction->asParallel ); // logowanie braku
}
if (traction->iTries > 0) // jeśli zaznaczony do podłączenia
// if (!nCurrent->hvTraction->psPower[0]||!nCurrent->hvTraction->psPower[1])
if (zg < iConnection) // zabezpieczenie
nEnds[zg++] = nCurrent; // wypełnianie tabeli końców w celu szukania im połączeń
}
while( zg < iConnection ) {
// zapełnienie do końca tablicy, jeśli by jakieś końce wypadły
nEnds[ zg++ ] = nullptr;
}
zg = 1; // nieefektywny przebieg kończy łączenie
while (zg)
{ // ustalenie zastępczej rezystancji dla każdego przęsła
zg = 0; // flaga podłączonych przęseł końcowych: -1=puste wskaźniki, 0=coś zostało,
// 1=wykonano łączenie
for (int i = 0; i < iConnection; ++i)
if (nEnds[i]) // załatwione będziemy zerować
{ // każdy przebieg to próba podłączenia końca segmentu naprężania do innego zasilanego
// przęsła
if (nEnds[i]->hvTraction->hvNext[0])
{ // jeśli końcowy ma ciąg dalszy od strony 0 (Point1), szukamy odcinka najbliższego
// do Point2
if (TractionNearestFind(nEnds[i]->hvTraction->pPoint2, 0,
nEnds[i])) // poszukiwanie przęsła
{
nEnds[i] = NULL;
zg = 1; // jak coś zostało podłączone, to może zasilanie gdzieś dodatkowo
// dotrze
}
}
else if (nEnds[i]->hvTraction->hvNext[1])
{ // jeśli końcowy ma ciąg dalszy od strony 1 (Point2), szukamy odcinka najbliższego
// do Point1
if (TractionNearestFind(nEnds[i]->hvTraction->pPoint1, 1,
nEnds[i])) // poszukiwanie przęsła
{
nEnds[i] = NULL;
zg = 1; // jak coś zostało podłączone, to może zasilanie gdzieś dodatkowo
// dotrze
}
}
else
{ // gdy koniec jest samotny, to na razie nie zostanie podłączony (nie powinno
// takich być)
nEnds[i] = NULL;
} }
} }
}
if( traction->iTries > 0 ) {
// jeśli zaznaczony do podłączenia
// wypełnianie tabeli końców w celu szukania im połączeń
ends.emplace_back( traction );
}
} }
delete[] nEnds; // nie potrzebne już
*/ bool connected; // nieefektywny przebieg kończy łączenie
do {
// ustalenie zastępczej rezystancji dla każdego przęsła
// flaga podłączonych przęseł końcowych: -1=puste wskaźniki, 0=coś zostało, 1=wykonano łączenie
connected = false;
for( auto &end : ends ) {
// załatwione będziemy zerować
if( end == nullptr ) { continue; }
// każdy przebieg to próba podłączenia końca segmentu naprężania do innego zasilanego przęsła
if( end->hvNext[ 0 ] != nullptr ) {
// jeśli końcowy ma ciąg dalszy od strony 0 (Point1), szukamy odcinka najbliższego do Point2
std::tie( matchingtraction, connection ) = simulation::Region->find_traction( end->pPoint2, end, 0 );
if( matchingtraction != nullptr ) {
// jak znalezione przęsło z zasilaniem, to podłączenie "równoległe"
end->ResistanceCalc( 0, matchingtraction->fResistance[ connection ], matchingtraction->psPower[ connection ] );
// jak coś zostało podłączone, to może zasilanie gdzieś dodatkowo dotrze
connected = true;
end = nullptr;
}
}
else if( end->hvNext[ 1 ] != nullptr ) {
// jeśli końcowy ma ciąg dalszy od strony 1 (Point2), szukamy odcinka najbliższego do Point1
std::tie( matchingtraction, connection ) = simulation::Region->find_traction( end->pPoint1, end, 1 );
if( matchingtraction != nullptr ) {
// jak znalezione przęsło z zasilaniem, to podłączenie "równoległe"
end->ResistanceCalc( 1, matchingtraction->fResistance[ connection ], matchingtraction->psPower[ connection ] );
// jak coś zostało podłączone, to może zasilanie gdzieś dodatkowo dotrze
connected = true;
end = nullptr;
}
}
else {
// gdy koniec jest samotny, to na razie nie zostanie podłączony (nie powinno takich być)
end = nullptr;
}
}
} while( true == connected );
} }

View File

@@ -55,13 +55,16 @@ class TTraction : public editor::basic_node {
TTraction( scene::node_data const &Nodedata ); TTraction( scene::node_data const &Nodedata );
// legacy constructor // legacy constructor
TTraction( std::string Name ); TTraction( std::string Name );
virtual ~TTraction() = default;
void Load( cParser *parser, glm::dvec3 const &pOrigin ); void Load( cParser *parser, glm::dvec3 const &pOrigin );
// set origin point // set origin point
void void
origin( glm::dvec3 Origin ) { origin( glm::dvec3 Origin ) {
m_origin = Origin; } m_origin = Origin; }
// retrieves list of the track's end points
std::vector<glm::dvec3>
endpoints() const;
// creates geometry data in specified geometry bank. returns: number of created elements, or NULL // creates geometry data in specified geometry bank. returns: number of created elements, or NULL
// NOTE: deleting nodes doesn't currently release geometry data owned by the node. TODO: implement erasing individual geometry chunks and banks // NOTE: deleting nodes doesn't currently release geometry data owned by the node. TODO: implement erasing individual geometry chunks and banks
#ifdef EU07_USE_OLD_GROUNDCODE #ifdef EU07_USE_OLD_GROUNDCODE

View File

@@ -20,14 +20,12 @@ http://mozilla.org/MPL/2.0/.
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
TTractionPowerSource::TTractionPowerSource(TGroundNode const *node) : TTractionPowerSource::TTractionPowerSource( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {}
gMyNode( node ) // legacy constructor
{ TTractionPowerSource::TTractionPowerSource( std::string Name ) {
psNode[0] = nullptr; // sekcje zostaną podłączone do zasilaczy
psNode[1] = nullptr;
};
TTractionPowerSource::~TTractionPowerSource(){}; m_name = Name;
}
void TTractionPowerSource::Init(double const u, double const i) void TTractionPowerSource::Init(double const u, double const i)
{ // ustawianie zasilacza przy braku w scenerii { // ustawianie zasilacza przy braku w scenerii
@@ -36,61 +34,67 @@ void TTractionPowerSource::Init(double const u, double const i)
MaxOutputCurrent = i; MaxOutputCurrent = i;
}; };
bool TTractionPowerSource::Load(cParser *parser) bool TTractionPowerSource::Load(cParser *parser) {
{
std::string token;
// AnsiString str;
// str= Parser->GetNextSymbol()LowerCase();
// asName= str;
parser->getTokens(5);
*parser >> NominalVoltage >> VoltageFrequency >> InternalRes >> MaxOutputCurrent >>
FastFuseTimeOut;
parser->getTokens();
*parser >> FastFuseRepetition;
parser->getTokens();
*parser >> SlowFuseTimeOut;
parser->getTokens();
*parser >> token;
if (token.compare("recuperation") == 0)
Recuperation = true;
else if (token.compare("section") == 0) // odłącznik sekcyjny
bSection = true; // nie jest źródłem zasilania, a jedynie informuje o prądzie odłączenia
// sekcji z obwodu
parser->getTokens();
*parser >> token;
if (token.compare("end") != 0)
Error("tractionpowersource end statement missing");
// if (!bSection) //odłącznik sekcji zasadniczo nie ma impedancji (0.01 jest OK)
if (InternalRes < 0.1) // coś mała ta rezystancja była...
InternalRes = 0.2; // tak około 0.2, wg
// http://www.ikolej.pl/fileadmin/user_upload/Seminaria_IK/13_05_07_Prezentacja_Kruczek.pdf
return true;
};
bool TTractionPowerSource::Render() #ifdef EU07_USE_OLD_GROUNDCODE
{ parser->getTokens( 7, false );
*parser
#else
parser->getTokens( 10, false );
*parser
>> m_location.x
>> m_location.y
>> m_location.z
#endif
>> NominalVoltage
>> VoltageFrequency
>> InternalRes
>> MaxOutputCurrent
>> FastFuseTimeOut
>> FastFuseRepetition
>> SlowFuseTimeOut;
std::string token { parser->getToken<std::string>() };
if( token == "recuperation" ) {
Recuperation = true;
}
else if( token == "section" ) {
// odłącznik sekcyjny
// nie jest źródłem zasilania, a jedynie informuje o prądzie odłączenia sekcji z obwodu
bSection = true;
}
// skip rest of the section
while( ( false == token.empty() )
&& ( token != "end" ) ) {
token = parser->getToken<std::string>();
}
if( InternalRes < 0.1 ) {
// coś mała ta rezystancja była...
// tak około 0.2, wg
// http://www.ikolej.pl/fileadmin/user_upload/Seminaria_IK/13_05_07_Prezentacja_Kruczek.pdf
InternalRes = 0.2;
}
return true; return true;
}; };
bool TTractionPowerSource::Update(double dt) bool TTractionPowerSource::Update(double dt)
{ // powinno być wykonane raz na krok fizyki { // powinno być wykonane raz na krok fizyki
// if (NominalVoltage * TotalPreviousAdmitance > // iloczyn napięcia i admitancji daje prąd
// MaxOutputCurrent * 0.00000005) // iloczyn napięcia i admitancji daje prąd if (NominalVoltage * TotalPreviousAdmitance > MaxOutputCurrent) {
// ErrorLog("Power overload: \"" + gMyNode->asName + "\" with current " + AnsiString(NominalVoltage * TotalPreviousAdmitance) + "A");
if (NominalVoltage * TotalPreviousAdmitance >
MaxOutputCurrent) // iloczyn napięcia i admitancji daje prąd
{
FastFuse = true; FastFuse = true;
FuseCounter += 1; FuseCounter += 1;
if (FuseCounter > FastFuseRepetition) if (FuseCounter > FastFuseRepetition) {
{
SlowFuse = true; SlowFuse = true;
ErrorLog("Power overload: \"" + gMyNode->asName + "\" disabled for " + ErrorLog( "Power overload: \"" + m_name + "\" disabled for " + std::to_string( SlowFuseTimeOut ) + "s" );
std::to_string(SlowFuseTimeOut) + "s");
} }
else else {
ErrorLog("Power overload: \"" + gMyNode->asName + "\" disabled for " + ErrorLog( "Power overload: \"" + m_name + "\" disabled for " + std::to_string( FastFuseTimeOut ) + "s" );
std::to_string(FastFuseTimeOut) + "s"); }
FuseTimer = 0; FuseTimer = 0;
} }
if (FastFuse || SlowFuse) if (FastFuse || SlowFuse)
@@ -145,4 +149,15 @@ void TTractionPowerSource::PowerSet(TTractionPowerSource *ps)
// else ErrorLog("nie może być więcej punktów zasilania niż dwa"); // else ErrorLog("nie może być więcej punktów zasilania niż dwa");
}; };
// legacy method, calculates changes in simulation state over specified time
void
powergridsource_table::update( double const Deltatime ) {
for( auto *powersource : m_items ) {
powersource->Update( Deltatime );
}
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -7,14 +7,14 @@ obtain one at
http://mozilla.org/MPL/2.0/. http://mozilla.org/MPL/2.0/.
*/ */
#ifndef TractionPowerH #pragma once
#define TractionPowerH
#include "scenenode.h"
#include "parser.h" //Tolaris-010603 #include "parser.h" //Tolaris-010603
#include "names.h"
class TGroundNode; class TTractionPowerSource : public editor::basic_node {
class TTractionPowerSource
{
private: private:
double NominalVoltage = 0.0; double NominalVoltage = 0.0;
double VoltageFrequency = 0.0; double VoltageFrequency = 0.0;
@@ -33,27 +33,34 @@ class TTractionPowerSource
bool SlowFuse = false; bool SlowFuse = false;
double FuseTimer = 0.0; double FuseTimer = 0.0;
int FuseCounter = 0; int FuseCounter = 0;
TGroundNode const *gMyNode = nullptr; // wskaźnik na węzeł rodzica
protected: public:
public: // zmienne publiczne // zmienne publiczne
TTractionPowerSource *psNode[2]; // zasilanie na końcach dla sekcji TTractionPowerSource *psNode[ 2 ] = { nullptr, nullptr }; // zasilanie na końcach dla sekcji
bool bSection = false; // czy jest sekcją bool bSection = false; // czy jest sekcją
public:
// AnsiString asName; TTractionPowerSource( scene::node_data const &Nodedata );
TTractionPowerSource(TGroundNode const *node); // legacy constructor
~TTractionPowerSource(); TTractionPowerSource( std::string Name );
void Init(double const u, double const i); void Init(double const u, double const i);
bool Load(cParser *parser); bool Load(cParser *parser);
bool Render();
bool Update(double dt); bool Update(double dt);
double CurrentGet(double res); double CurrentGet(double res);
void VoltageSet(double const v) void VoltageSet(double const v) {
{ NominalVoltage = v; };
NominalVoltage = v;
};
void PowerSet(TTractionPowerSource *ps); void PowerSet(TTractionPowerSource *ps);
}; };
// collection of generators for power grid present in the scene
class powergridsource_table : public basic_table<TTractionPowerSource> {
public:
// legacy method, calculates changes in simulation state over specified time
void
update( double const Deltatime );
};
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#endif

View File

@@ -357,14 +357,6 @@ TTrain::TTrain() {
fPress[ i ][ j ] = 0.0; fPress[ i ][ j ] = 0.0;
} }
TTrain::~TTrain()
{
if (DynamicObject)
if (DynamicObject->Mechanik)
DynamicObject->Mechanik->TakeControl(
true); // likwidacja kabiny wymaga przejęcia przez AI
}
bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d) bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d)
{ // powiązanie ręcznego sterowania kabiną z pojazdem { // powiązanie ręcznego sterowania kabiną z pojazdem
// Global::pUserDynamic=NewDynamicObject; //pojazd renderowany bez trzęsienia // Global::pUserDynamic=NewDynamicObject; //pojazd renderowany bez trzęsienia
@@ -3587,7 +3579,7 @@ bool TTrain::Update( double const Deltatime )
iDoorNo[i] = p->iAnimType[ANIM_DOORS]; iDoorNo[i] = p->iAnimType[ANIM_DOORS];
iUnits[i] = iUnitNo; iUnits[i] = iUnitNo;
cCode[i] = p->MoverParameters->TypeName[p->MoverParameters->TypeName.length()]; cCode[i] = p->MoverParameters->TypeName[p->MoverParameters->TypeName.length()];
asCarName[i] = p->GetName(); asCarName[i] = p->name();
bPants[iUnitNo - 1][0] = (bPants[iUnitNo - 1][0] || p->MoverParameters->PantFrontUp); bPants[iUnitNo - 1][0] = (bPants[iUnitNo - 1][0] || p->MoverParameters->PantFrontUp);
bPants[iUnitNo - 1][1] = (bPants[iUnitNo - 1][1] || p->MoverParameters->PantRearUp); bPants[iUnitNo - 1][1] = (bPants[iUnitNo - 1][1] || p->MoverParameters->PantRearUp);
bComp[iUnitNo - 1][0] = (bComp[iUnitNo - 1][0] || p->MoverParameters->CompressorAllow); bComp[iUnitNo - 1][0] = (bComp[iUnitNo - 1][0] || p->MoverParameters->CompressorAllow);
@@ -6259,7 +6251,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
} }
else if (token == "pyscreen:") else if (token == "pyscreen:")
{ {
pyScreens.init(*parser, DynamicObject->mdKabina, DynamicObject->GetName(), pyScreens.init(*parser, DynamicObject->mdKabina, DynamicObject->name(),
NewCabNo); NewCabNo);
} }
// btLampkaUnknown.Init("unknown",mdKabina,false); // btLampkaUnknown.Init("unknown",mdKabina,false);

View File

@@ -80,7 +80,6 @@ class TTrain
bool ShowNextCurrent; // pokaz przd w podlaczonej lokomotywie (ET41) bool ShowNextCurrent; // pokaz przd w podlaczonej lokomotywie (ET41)
bool InitializeCab(int NewCabNo, std::string const &asFileName); bool InitializeCab(int NewCabNo, std::string const &asFileName);
TTrain(); TTrain();
~TTrain();
// McZapkie-010302 // McZapkie-010302
bool Init(TDynamicObject *NewDynamicObject, bool e3d = false); bool Init(TDynamicObject *NewDynamicObject, bool e3d = false);
void OnKeyDown(int cKey); void OnKeyDown(int cKey);

201
World.cpp
View File

@@ -207,6 +207,13 @@ void TWorld::TrainDelete(TDynamicObject *d)
if (Train) if (Train)
if (Train->Dynamic() != d) if (Train->Dynamic() != d)
return; // nie tego usuwać return; // nie tego usuwać
#ifdef EU07_SCENERY_EDITOR
if( ( Train->DynamicObject )
&& ( Train->DynamicObject->Mechanik ) ) {
// likwidacja kabiny wymaga przejęcia przez AI
Train->DynamicObject->Mechanik->TakeControl( true );
}
#endif
delete Train; // i nie ma czym sterować delete Train; // i nie ma czym sterować
Train = NULL; Train = NULL;
Controlled = NULL; // tego też już nie ma Controlled = NULL; // tego też już nie ma
@@ -263,13 +270,25 @@ bool TWorld::Init( GLFWwindow *Window ) {
UILayer.set_progress( "Preparing train / Przygotowanie kabiny" ); UILayer.set_progress( "Preparing train / Przygotowanie kabiny" );
WriteLog( "Player train init: " + Global::asHumanCtrlVehicle ); WriteLog( "Player train init: " + Global::asHumanCtrlVehicle );
#ifdef EU07_USE_OLD_GROUNDCODE
TGroundNode *nPlayerTrain = NULL; TGroundNode *nPlayerTrain = NULL;
if (Global::asHumanCtrlVehicle != "ghostview") #else
nPlayerTrain = Ground.DynamicFind(Global::asHumanCtrlVehicle); // szukanie w tych z obsadą TDynamicObject *nPlayerTrain;
#endif
if( Global::asHumanCtrlVehicle != "ghostview" )
#ifdef EU07_USE_OLD_GROUNDCODE
nPlayerTrain = Ground.DynamicFind( Global::asHumanCtrlVehicle ); // szukanie w tych z obsadą
#else
nPlayerTrain = simulation::Vehicles.find( Global::asHumanCtrlVehicle );
#endif
if (nPlayerTrain) if (nPlayerTrain)
{ {
Train = new TTrain(); Train = new TTrain();
#ifdef EU07_USE_OLD_GROUNDCODE
if (Train->Init(nPlayerTrain->DynamicObject)) if (Train->Init(nPlayerTrain->DynamicObject))
#else
if( Train->Init( nPlayerTrain ) )
#endif
{ {
Controlled = Train->Dynamic(); Controlled = Train->Dynamic();
mvControlled = Controlled->ControlledFind()->MoverParameters; mvControlled = Controlled->ControlledFind()->MoverParameters;
@@ -522,7 +541,11 @@ void TWorld::OnKeyDown(int cKey)
break; break;
} }
#ifdef EU07_USE_OLD_GROUNDCODE
TDynamicObject *tmp = Ground.DynamicNearest( Camera.Pos, 50, true ); //łapiemy z obsadą TDynamicObject *tmp = Ground.DynamicNearest( Camera.Pos, 50, true ); //łapiemy z obsadą
#else
TDynamicObject *tmp = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global::pCameraPosition, 50, true ) );
#endif
if( ( tmp != nullptr ) if( ( tmp != nullptr )
&& ( tmp != Controlled ) ) { && ( tmp != Controlled ) ) {
@@ -700,7 +723,11 @@ void TWorld::OnKeyDown(int cKey)
*/ */
if (cKey == Global::Keys[k_Heating]) // Ra: klawisz nie jest najszczęśliwszy if (cKey == Global::Keys[k_Heating]) // Ra: klawisz nie jest najszczęśliwszy
{ // zmiana próżny/ładowny; Ra: zabrane z kabiny { // zmiana próżny/ładowny; Ra: zabrane z kabiny
TDynamicObject *temp = Global::DynamicNearest(); #ifdef EU07_USE_OLD_GROUNDCODE
TDynamicObject *temp = Global::DynamicNearest();
#else
TDynamicObject *temp = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global::pCameraPosition, 20, false ) );
#endif
if (temp) if (temp)
{ {
if (Global::shiftState ? temp->MoverParameters->IncBrakeMult() : if (Global::shiftState ? temp->MoverParameters->IncBrakeMult() :
@@ -743,7 +770,11 @@ void TWorld::OnKeyDown(int cKey)
} }
else if (cKey == Global::Keys[k_IncLocalBrakeLevel]) else if (cKey == Global::Keys[k_IncLocalBrakeLevel])
{ // zahamowanie dowolnego pojazdu { // zahamowanie dowolnego pojazdu
#ifdef EU07_USE_OLD_GROUNDCODE
TDynamicObject *temp = Global::DynamicNearest(); TDynamicObject *temp = Global::DynamicNearest();
#else
TDynamicObject *temp = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global::pCameraPosition, 20, false ) );
#endif
if (temp) if (temp)
{ {
if (Global::ctrlState) if (Global::ctrlState)
@@ -762,7 +793,11 @@ void TWorld::OnKeyDown(int cKey)
} }
else if (cKey == Global::Keys[k_DecLocalBrakeLevel]) else if (cKey == Global::Keys[k_DecLocalBrakeLevel])
{ // odhamowanie dowolnego pojazdu { // odhamowanie dowolnego pojazdu
#ifdef EU07_USE_OLD_GROUNDCODE
TDynamicObject *temp = Global::DynamicNearest(); TDynamicObject *temp = Global::DynamicNearest();
#else
TDynamicObject *temp = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global::pCameraPosition, 20, false ) );
#endif
if (temp) if (temp)
{ {
if (Global::ctrlState) if (Global::ctrlState)
@@ -915,20 +950,7 @@ void TWorld::FollowView(bool wycisz) {
DistantView(); DistantView();
}; };
bool TWorld::Update() bool TWorld::Update() {
{
#ifdef USE_SCENERY_MOVING
vector3 tmpvector = Global::GetCameraPosition();
tmpvector = vector3(-int(tmpvector.x) + int(tmpvector.x) % 10000,
-int(tmpvector.y) + int(tmpvector.y) % 10000,
-int(tmpvector.z) + int(tmpvector.z) % 10000);
if (tmpvector.x || tmpvector.y || tmpvector.z)
{
WriteLog("Moving scenery");
Ground.MoveGroundNode(tmpvector);
WriteLog("Scenery moved");
};
#endif
Timer::UpdateTimers(Global::iPause != 0); Timer::UpdateTimers(Global::iPause != 0);
@@ -955,7 +977,7 @@ bool TWorld::Update()
/* /*
fTimeBuffer += dt; //[s] dodanie czasu od poprzedniej ramki fTimeBuffer += dt; //[s] dodanie czasu od poprzedniej ramki
*/ */
m_primaryupdateaccumulator += dt; // m_primaryupdateaccumulator += dt; // unused for the time being
m_secondaryupdateaccumulator += dt; m_secondaryupdateaccumulator += dt;
/* /*
if (fTimeBuffer >= fMaxDt) // jest co najmniej jeden krok; normalnie 0.01s if (fTimeBuffer >= fMaxDt) // jest co najmniej jeden krok; normalnie 0.01s
@@ -999,21 +1021,26 @@ bool TWorld::Update()
dt = dt / iterations; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem dt = dt / iterations; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem
*/ */
} }
auto const stepdeltatime { dt / updatecount };
// NOTE: updates are limited to 20, but dt is distributed over potentially many more iterations // NOTE: updates are limited to 20, but dt is distributed over potentially many more iterations
// this means at count > 20 simulation and render are going to desync. is that right? // this means at count > 20 simulation and render are going to desync. is that right?
// NOTE: experimentally changing this to prevent the desync. // NOTE: experimentally changing this to prevent the desync.
// TODO: test what happens if we hit more than 20 * 0.01 sec slices, i.e. less than 5 fps // TODO: test what happens if we hit more than 20 * 0.01 sec slices, i.e. less than 5 fps
#ifdef EU07_USE_OLD_GROUNDCODE
if( true == Global::FullPhysics ) { if( true == Global::FullPhysics ) {
// default calculation mode, each step calculated separately // mixed calculation mode, steps calculated in ~0.05s chunks
for( int updateidx = 0; updateidx < updatecount; ++updateidx ) { while( updatecount >= 5 ) {
Ground.Update( dt / updatecount, 1 ); Ground.Update( stepdeltatime, 5 );
updatecount -= 5;
}
if( updatecount ) {
Ground.Update( stepdeltatime, updatecount );
} }
} }
else { else {
// slightly simplified calculation mode; can lead to errors // simplified calculation mode; faster but can lead to errors
Ground.Update( dt / updatecount, updatecount ); Ground.Update( stepdeltatime, updatecount );
} }
// yB dodał przyspieszacz fizyki // yB dodał przyspieszacz fizyki
if( (true == DebugModeFlag) if( (true == DebugModeFlag)
&& (true == Global::bActive) // nie przyspieszać, gdy jedzie w tle :) && (true == Global::bActive) // nie przyspieszać, gdy jedzie w tle :)
@@ -1024,8 +1051,24 @@ bool TWorld::Update()
Ground.Update( dt, 1 ); Ground.Update( dt, 1 );
Ground.Update( dt, 1 ); // 5 razy Ground.Update( dt, 1 ); // 5 razy
} }
// secondary fixed step simulation time routines #else
if( true == Global::FullPhysics ) {
// mixed calculation mode, steps calculated in ~0.05s chunks
while( updatecount >= 5 ) {
simulation::State.update( stepdeltatime, 5 );
updatecount -= 5;
}
if( updatecount ) {
simulation::State.update( stepdeltatime, updatecount );
}
}
else {
// simplified calculation mode; faster but can lead to errors
simulation::State.update( stepdeltatime, updatecount );
}
#endif
// secondary fixed step simulation time routines
while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) { while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) {
Global::tranTexts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie Global::tranTexts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie
@@ -1065,11 +1108,12 @@ bool TWorld::Update()
#ifdef EU07_USE_OLD_GROUNDCODE #ifdef EU07_USE_OLD_GROUNDCODE
Ground.CheckQuery(); Ground.CheckQuery();
Ground.Update_Hidden();
#else #else
simulation::Events.CheckQuery(); simulation::Events.CheckQuery();
simulation::Region->update();
#endif #endif
Ground.Update_Hidden();
simulation::Lights.update(); simulation::Lights.update();
// render time routines follow: // render time routines follow:
@@ -1119,10 +1163,15 @@ TWorld::Update_Camera( double const Deltatime ) {
Camera.LookAt = Controlled->GetPosition(); Camera.LookAt = Controlled->GetPosition();
} }
else { else {
TDynamicObject *d = #ifdef EU07_USE_OLD_GROUNDCODE
Ground.DynamicNearest( Camera.Pos, 300 ); // szukaj w promieniu 300m TDynamicObject *d = Ground.DynamicNearest( Camera.Pos, 300 ); // szukaj w promieniu 300m
if( !d ) if( !d )
d = Ground.DynamicNearest( Camera.Pos, 1000 ); // dalej szukanie, jesli bliżej nie ma d = Ground.DynamicNearest( Camera.Pos, 1000 ); // dalej szukanie, jesli bliżej nie ma
#else
TDynamicObject *d = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global::pCameraPosition, 300, false ) );
if( !d )
d = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global::pCameraPosition, 1000, false ) ); // dalej szukanie, jesli bliżej nie ma
#endif
if( d && pDynamicNearest ) { if( d && pDynamicNearest ) {
// jeśli jakiś jest znaleziony wcześniej // jeśli jakiś jest znaleziony wcześniej
if( 100.0 * LengthSquared3( d->GetPosition() - Camera.Pos ) > LengthSquared3( pDynamicNearest->GetPosition() - Camera.Pos ) ) { if( 100.0 * LengthSquared3( d->GetPosition() - Camera.Pos ) > LengthSquared3( pDynamicNearest->GetPosition() - Camera.Pos ) ) {
@@ -1305,7 +1354,11 @@ TWorld::Update_UI() {
// timetable // timetable
TDynamicObject *tmp = TDynamicObject *tmp =
( FreeFlyModeFlag ? ( FreeFlyModeFlag ?
#ifdef EU07_USE_OLD_GROUNDCODE
Ground.DynamicNearest( Camera.Pos ) : Ground.DynamicNearest( Camera.Pos ) :
#else
std::get<TDynamicObject *>( simulation::Region->find_vehicle( Camera.Pos, 20, false ) ) :
#endif
Controlled ); // w trybie latania lokalizujemy wg mapy Controlled ); // w trybie latania lokalizujemy wg mapy
if( tmp == nullptr ) { break; } if( tmp == nullptr ) { break; }
@@ -1386,8 +1439,12 @@ TWorld::Update_UI() {
TDynamicObject *tmp = TDynamicObject *tmp =
( FreeFlyModeFlag ? ( FreeFlyModeFlag ?
Ground.DynamicNearest( Camera.Pos ) : #ifdef EU07_USE_OLD_GROUNDCODE
Controlled ); // w trybie latania lokalizujemy wg mapy Ground.DynamicNearest( Camera.Pos ) :
#else
std::get<TDynamicObject *>( simulation::Region->find_vehicle( Camera.Pos, 20, false ) ) :
#endif
Controlled ); // w trybie latania lokalizujemy wg mapy
if( tmp != nullptr ) { if( tmp != nullptr ) {
// //
@@ -1403,7 +1460,7 @@ TWorld::Update_UI() {
uitextline1 += uitextline1 +=
"; C0:" + "; C0:" +
( tmp->PrevConnected ? ( tmp->PrevConnected ?
tmp->PrevConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 0 ].CouplingFlag ) + ( tmp->PrevConnected->name() + ":" + to_string( tmp->MoverParameters->Couplers[ 0 ].CouplingFlag ) + (
tmp->MoverParameters->Couplers[ 0 ].CouplingFlag == 0 ? tmp->MoverParameters->Couplers[ 0 ].CouplingFlag == 0 ?
" (" + to_string( tmp->MoverParameters->Couplers[ 0 ].CoupleDist, 1 ) + " m)" : " (" + to_string( tmp->MoverParameters->Couplers[ 0 ].CoupleDist, 1 ) + " m)" :
"" ) : "" ) :
@@ -1411,7 +1468,7 @@ TWorld::Update_UI() {
uitextline1 += uitextline1 +=
" C1:" + " C1:" +
( tmp->NextConnected ? ( tmp->NextConnected ?
tmp->NextConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 1 ].CouplingFlag ) + ( tmp->NextConnected->name() + ":" + to_string( tmp->MoverParameters->Couplers[ 1 ].CouplingFlag ) + (
tmp->MoverParameters->Couplers[ 1 ].CouplingFlag == 0 ? tmp->MoverParameters->Couplers[ 1 ].CouplingFlag == 0 ?
" (" + to_string( tmp->MoverParameters->Couplers[ 1 ].CoupleDist, 1 ) + " m)" : " (" + to_string( tmp->MoverParameters->Couplers[ 1 ].CoupleDist, 1 ) + " m)" :
"" ) : "" ) :
@@ -1653,7 +1710,11 @@ TWorld::Update_UI() {
TDynamicObject *tmp = TDynamicObject *tmp =
( FreeFlyModeFlag ? ( FreeFlyModeFlag ?
#ifdef EU07_USE_OLD_GROUNDCODE
Ground.DynamicNearest( Camera.Pos ) : Ground.DynamicNearest( Camera.Pos ) :
#else
std::get<TDynamicObject *>( simulation::Region->find_vehicle( Camera.Pos, 20, false ) ) :
#endif
Controlled ); // w trybie latania lokalizujemy wg mapy Controlled ); // w trybie latania lokalizujemy wg mapy
if( tmp == nullptr ) { if( tmp == nullptr ) {
break; break;
@@ -1867,6 +1928,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
Now() + " " + to_string(pRozkaz->iComm) + " " + Now() + " " + to_string(pRozkaz->iComm) + " " +
std::string(pRozkaz->cString + 11 + i, (unsigned)(pRozkaz->cString[10 + i])) + std::string(pRozkaz->cString + 11 + i, (unsigned)(pRozkaz->cString[10 + i])) +
" rcvd"); " rcvd");
#ifdef EU07_USE_OLD_GROUNDCODE
TGroundNode *t = Ground.DynamicFind( TGroundNode *t = Ground.DynamicFind(
std::string(pRozkaz->cString + 11 + i, std::string(pRozkaz->cString + 11 + i,
(unsigned)pRozkaz->cString[10 + i])); // nazwa pojazdu jest druga (unsigned)pRozkaz->cString[10 + i])); // nazwa pojazdu jest druga
@@ -1878,6 +1940,19 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
NULL, stopExt); // floaty są z przodu NULL, stopExt); // floaty są z przodu
WriteLog("AI command: " + std::string(pRozkaz->cString + 9, i)); WriteLog("AI command: " + std::string(pRozkaz->cString + 9, i));
} }
#else
// nazwa pojazdu jest druga
auto *vehicle = simulation::Vehicles.find( { pRozkaz->cString + 11 + i, (unsigned)pRozkaz->cString[ 10 + i ] } );
if( ( vehicle != nullptr )
&& ( vehicle->Mechanik != nullptr ) ) {
vehicle->Mechanik->PutCommand(
{ pRozkaz->cString + 9, static_cast<std::size_t>(i) },
pRozkaz->fPar[0], pRozkaz->fPar[1],
nullptr,
stopExt ); // floaty są z przodu
WriteLog("AI command: " + std::string(pRozkaz->cString + 9, i));
}
#endif
} }
break; break;
case 4: // badanie zajętości toru case 4: // badanie zajętości toru
@@ -1920,6 +1995,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
" rcvd"); " rcvd");
if (pRozkaz->cString[0]) // jeśli długość nazwy jest niezerowa if (pRozkaz->cString[0]) // jeśli długość nazwy jest niezerowa
{ // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7 { // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7
#ifdef EU07_USE_OLD_GROUNDCODE
TGroundNode *t; TGroundNode *t;
if (pRozkaz->cString[1] == '*') if (pRozkaz->cString[1] == '*')
t = Ground.DynamicFind( t = Ground.DynamicFind(
@@ -1929,6 +2005,9 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
pRozkaz->cString + 1, (unsigned)pRozkaz->cString[0])); // nazwa pojazdu pRozkaz->cString + 1, (unsigned)pRozkaz->cString[0])); // nazwa pojazdu
if (t) if (t)
Ground.WyslijNamiary(t); // wysłanie informacji o pojeździe Ground.WyslijNamiary(t); // wysłanie informacji o pojeździe
#else
// TODO: implement
#endif
} }
else else
{ // dla pustego wysyłamy ramki 6 z nazwami pojazdów AI (jeśli potrzebne wszystkie, { // dla pustego wysyłamy ramki 6 z nazwami pojazdów AI (jeśli potrzebne wszystkie,
@@ -1964,34 +2043,34 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " +
std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) +
" rcvd"); " rcvd");
if (pRozkaz->cString[1]) // jeśli długość nazwy jest niezerowa #ifdef EU07_USE_OLD_GROUNDCODE
{ // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #13 if( pRozkaz->cString[ 1 ] ) // jeśli długość nazwy jest niezerowa
TGroundNode *t; { // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #13
if (pRozkaz->cString[2] == '*') TGroundNode *t;
t = Ground.DynamicFind( if( pRozkaz->cString[ 2 ] == '*' )
Global::asHumanCtrlVehicle); // nazwa pojazdu użytkownika t = Ground.DynamicFind(
else Global::asHumanCtrlVehicle ); // nazwa pojazdu użytkownika
t = Ground.DynamicFindAny( else
std::string(pRozkaz->cString + 2, t = Ground.DynamicFindAny(
(unsigned)pRozkaz->cString[1])); // nazwa pojazdu std::string( pRozkaz->cString + 2,
if (t) (unsigned)pRozkaz->cString[ 1 ] ) ); // nazwa pojazdu
{ if( t ) {
TDynamicObject *d = t->DynamicObject; TDynamicObject *d = t->DynamicObject;
while (d) while( d ) {
{ d->Damage( pRozkaz->cString[ 0 ] );
d->Damage(pRozkaz->cString[0]); d = d->Next(); // pozostałe też
d = d->Next(); // pozostałe też }
} d = t->DynamicObject->Prev();
d = t->DynamicObject->Prev(); while( d ) {
while (d) d->Damage( pRozkaz->cString[ 0 ] );
{ d = d->Prev(); // w drugą stronę też
d->Damage(pRozkaz->cString[0]); }
d = d->Prev(); // w drugą stronę też Ground.WyslijUszkodzenia( t->asName, t->DynamicObject->MoverParameters->EngDmgFlag ); // zwrot informacji o pojeździe
} }
Ground.WyslijUszkodzenia(t->asName, t->DynamicObject->MoverParameters->EngDmgFlag); // zwrot informacji o pojeździe }
} #else
} // TODO: implement
// Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); #endif
break; break;
} }
}; };
@@ -2143,7 +2222,7 @@ void TWorld::ChangeDynamic() {
Train->DynamicSet( temp ); Train->DynamicSet( temp );
Controlled = temp; Controlled = temp;
mvControlled = Controlled->ControlledFind()->MoverParameters; mvControlled = Controlled->ControlledFind()->MoverParameters;
Global::asHumanCtrlVehicle = Train->Dynamic()->GetName(); Global::asHumanCtrlVehicle = Train->Dynamic()->name();
if( Train->Dynamic()->Mechanik ) // AI może sobie samo pójść if( Train->Dynamic()->Mechanik ) // AI może sobie samo pójść
if( !Train->Dynamic()->Mechanik->AIControllFlag ) // tylko jeśli ręcznie prowadzony if( !Train->Dynamic()->Mechanik->AIControllFlag ) // tylko jeśli ręcznie prowadzony
{ {

View File

@@ -25,8 +25,8 @@ struct basic_vertex {
glm::vec2 texture; // uv space glm::vec2 texture; // uv space
basic_vertex() = default; basic_vertex() = default;
basic_vertex( glm::vec3 const &Position, glm::vec3 const &Normal, glm::vec2 const &Texture ) : basic_vertex( glm::vec3 Position, glm::vec3 Normal, glm::vec2 Texture ) :
position( Position ), normal( Normal ), texture( Texture ) position( Position ), normal( Normal ), texture( Texture )
{} {}
void serialize( std::ostream& ) const; void serialize( std::ostream& ) const;
void deserialize( std::istream& ); void deserialize( std::istream& );
@@ -58,8 +58,8 @@ struct geometry_handle {
geometry_handle() : geometry_handle() :
bank( 0 ), chunk( 0 ) bank( 0 ), chunk( 0 )
{} {}
geometry_handle( std::uint32_t const Bank, std::uint32_t const Chunk ) : geometry_handle( std::uint32_t Bank, std::uint32_t Chunk ) :
bank( Bank ), chunk( Chunk ) bank( Bank ), chunk( Chunk )
{} {}
// methods // methods
inline inline
@@ -121,8 +121,8 @@ protected:
unsigned int type; // kind of geometry used by the chunk unsigned int type; // kind of geometry used by the chunk
vertex_array vertices; // geometry data vertex_array vertices; // geometry data
// NOTE: constructor doesn't copy provided vertex data, but moves it // NOTE: constructor doesn't copy provided vertex data, but moves it
geometry_chunk( vertex_array &Vertices, unsigned int const Type ) : geometry_chunk( vertex_array &Vertices, unsigned int Type ) :
type( Type ) type( Type )
{ {
vertices.swap( Vertices ); vertices.swap( Vertices );
} }

View File

@@ -205,23 +205,21 @@ std::string cParser::readToken(bool ToLower, const char *Break)
if (token.compare("include") == 0) if (token.compare("include") == 0)
{ // obsługa include { // obsługa include
std::string includefile = readToken(ToLower); // nazwa pliku std::string includefile = readToken(ToLower); // nazwa pliku
if (LoadTraction ? true : ((includefile.find("tr/") == std::string::npos) && if( ( true == LoadTraction )
(includefile.find("tra/") == std::string::npos))) || ( ( includefile.find( "tr/" ) == std::string::npos )
{ && ( includefile.find( "tra/" ) == std::string::npos ) ) ) {
// std::string trtest2="niemaproblema"; //nazwa odporna na znalezienie "tr/"
// if (trtest=="x") //jeśli nie wczytywać drutów
// trtest2=includefile; //kopiowanie ścieżki do pliku
std::string parameter = readToken(false); // w parametrach nie zmniejszamy std::string parameter = readToken(false); // w parametrach nie zmniejszamy
while( (parameter.empty() == false) while( (parameter.empty() == false)
&& (parameter.compare("end") != 0) ) && (parameter.compare("end") != 0) )
{ {
parameters.push_back(parameter); parameters.emplace_back(parameter);
parameter = readToken(false); parameter = readToken(false);
} }
// if (trtest2.find("tr/")!=0) // if (trtest2.find("tr/")!=0)
mIncludeParser = std::make_shared<cParser>(includefile, buffer_FILE, mPath, LoadTraction); mIncludeParser = std::make_shared<cParser>(includefile, buffer_FILE, mPath, LoadTraction);
if (mIncludeParser->mSize <= 0) if (mIncludeParser->mSize <= 0)
ErrorLog("Missed include: " + includefile); ErrorLog("Bad include: can't open file \"" + includefile + "\"" );
} }
else { else {
while( token.compare( "end" ) != 0 ) { while( token.compare( "end" ) != 0 ) {

View File

@@ -1602,7 +1602,17 @@ opengl_renderer::Render( scene::basic_region *Region ) {
m_sectionqueue.clear(); m_sectionqueue.clear();
m_cellqueue.clear(); m_cellqueue.clear();
/*
for( auto *section : Region->sections( m_renderpass.camera.position(), m_renderpass.draw_range * Global::fDistanceFactor ) ) {
#ifdef EU07_USE_DEBUG_CULLING
if( m_worldcamera.camera.visible( section->m_area ) ) {
#else
if( m_renderpass.camera.visible( section->m_area ) ) {
#endif
m_sectionqueue.emplace_back( section );
}
}
*/
// build a list of region sections to render // build a list of region sections to render
glm::vec3 const cameraposition { m_renderpass.camera.position() }; glm::vec3 const cameraposition { m_renderpass.camera.position() };
auto const camerax = static_cast<int>( std::floor( cameraposition.x / scene::EU07_SECTIONSIZE + scene::EU07_REGIONSIDESECTIONCOUNT / 2 ) ); auto const camerax = static_cast<int>( std::floor( cameraposition.x / scene::EU07_SECTIONSIZE + scene::EU07_REGIONSIDESECTIONCOUNT / 2 ) );
@@ -1903,11 +1913,22 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
switch( m_renderpass.draw_mode ) { switch( m_renderpass.draw_mode ) {
case rendermode::color: case rendermode::color:
case rendermode::shadows: case rendermode::shadows: {
case rendermode::pickscenery: {
// render
// opaque parts of instanced models // opaque parts of instanced models
for( auto *instance : cell->m_instancesopaque ) { Render( instance ); } for( auto *instance : cell->m_instancesopaque ) { Render( instance ); }
// opaque parts of vehicles
for( auto *path : cell->m_paths ) {
for( auto *dynamic : path->Dynamics ) {
Render( dynamic );
}
}
}
case rendermode::pickscenery: {
// opaque parts of instanced models
for( auto *instance : cell->m_instancesopaque ) {
::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) );
Render( instance );
}
// TODO: add remaining content types // TODO: add remaining content types
break; break;
} }
@@ -2863,7 +2884,12 @@ opengl_renderer::Render_Alpha( cell_sequence::reverse_iterator First, cell_seque
// translucent parts of instanced models // translucent parts of instanced models
for( auto *instance : cell->m_instancetranslucent ) { Render_Alpha( instance ); } for( auto *instance : cell->m_instancetranslucent ) { Render_Alpha( instance ); }
// TODO: add remaining content types // translucent parts of vehicles
for( auto *path : cell->m_paths ) {
for( auto *dynamic : path->Dynamics ) {
Render_Alpha( dynamic );
}
}
++first; ++first;
} }

425
scene.cpp
View File

@@ -10,11 +10,28 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h" #include "stdafx.h"
#include "scene.h" #include "scene.h"
#include "globals.h"
#include "renderer.h" #include "renderer.h"
#include "logs.h" #include "logs.h"
namespace scene { namespace scene {
// legacy method, updates sounds and polls event launchers within radius around specified point
void
basic_cell::update() {
/*
// renderowanie obiektów aktywnych a niewidocznych
for( auto node = subcell->nRenderHidden; node; node = node->nNext3 ) {
node->RenderHidden();
}
*/
// TBD, TODO: move to sound renderer
for( auto *path : m_paths ) {
// dźwięki pojazdów, również niewidocznych
path->RenderDynSounds();
}
}
// adds provided shape to the cell // adds provided shape to the cell
void void
basic_cell::insert( shape_node Shape ) { basic_cell::insert( shape_node Shape ) {
@@ -90,6 +107,131 @@ basic_cell::insert( TAnimModel *Instance ) {
} }
} }
// registers provided path in the lookup directory of the cell
void
basic_cell::register_end( TTrack *Path ) {
m_directories.paths.emplace( Path );
}
// registers provided traction piece in the lookup directory of the cell
void
basic_cell::register_end( TTraction *Traction ) {
m_directories.traction.emplace( Traction );
}
// find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance
std::tuple<TDynamicObject *, float>
basic_cell::find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled ) {
TDynamicObject *vehiclenearest { nullptr };
float leastdistance { std::numeric_limits<float>::max() };
float distance;
float const distancecutoff { Radius * Radius }; // we'll ignore vehicles farther than this
for( auto *path : m_paths ) {
for( auto *vehicle : path->Dynamics ) {
if( ( true == Onlycontrolled )
&& ( vehicle->Mechanik == nullptr ) ) {
continue;
}
distance = glm::length2( glm::dvec3{ vehicle->GetPosition() } - Point );
if( ( distance > distancecutoff )
|| ( distance > leastdistance ) ){
continue;
}
std::tie( vehiclenearest, leastdistance ) = std::tie( vehicle, distance );
}
}
return std::tie( vehiclenearest, leastdistance );
}
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
std::tuple<TTrack *, int>
basic_cell::find( glm::dvec3 const &Point, TTrack const *Exclude ) {
Math3D::vector3 point { Point.x, Point.y, Point.z }; // sad workaround until math classes unification
int endpointid;
for( auto *path : m_directories.paths ) {
if( path == Exclude ) { continue; }
endpointid = path->TestPoint( &point );
if( endpointid >= 0 ) {
return std::tie( path, endpointid );
}
}
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
std::tuple<TTraction *, int>
basic_cell::find( glm::dvec3 const &Point, TTraction const *Exclude ) {
int endpointid;
for( auto *traction : m_directories.traction ) {
if( traction == Exclude ) { continue; }
endpointid = traction->TestPoint( Point );
if( endpointid >= 0 ) {
return std::tie( traction, endpointid );
}
}
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
std::tuple<TTraction *, int, float>
basic_cell::find( glm::dvec3 const &Point, TTraction const *Other, int const Currentdirection ) {
TTraction
*tractionnearest { nullptr };
float
distance,
distancenearest { std::numeric_limits<float>::max() };
int endpoint,
endpointnearest { -1 };
for( auto *traction : m_directories.traction ) {
if( ( traction == Other )
|| ( traction->psSection != Other->psSection )
|| ( traction == Other->hvNext[ 0 ] )
|| ( traction == Other->hvNext[ 1 ] ) ) {
// ignore pieces from different sections, and ones connected to the other piece
continue;
}
endpoint = (
glm::dot( traction->vParametric, Other->vParametric ) >= 0.0 ?
Currentdirection ^ 1 :
Currentdirection );
if( ( traction->psPower[ endpoint ] == nullptr )
|| ( traction->fResistance[ endpoint ] < 0.0 ) ) {
continue;
}
distance = glm::length2( traction->location() - Point );
if( distance < distancenearest ) {
std::tie( tractionnearest, endpointnearest, distancenearest ) = std::tie( traction, endpoint, distance );
}
}
return { tractionnearest, endpointnearest, distancenearest };
}
// sets center point of the section
void
basic_cell::center( glm::dvec3 Center ) {
m_area.center = Center;
// NOTE: we should also update origin point for the contained nodes, but in practice we can skip this
// as all nodes will be added only after the proper center point was set, and won't change
}
// generates renderable version of held non-instanced geometry // generates renderable version of held non-instanced geometry
void void
basic_cell::create_geometry( geometrybank_handle const &Bank ) { basic_cell::create_geometry( geometrybank_handle const &Bank ) {
@@ -104,17 +246,23 @@ basic_cell::create_geometry( geometrybank_handle const &Bank ) {
#endif #endif
} }
// sets center point of the section
// legacy method, updates sounds and polls event launchers within radius around specified point
void void
basic_cell::center( glm::dvec3 Center ) { basic_section::update( glm::dvec3 const &Location, float const Radius ) {
m_area.center = Center; auto const squaredradii { std::pow( ( 0.5 * M_SQRT2 * EU07_CELLSIZE + 0.25 * EU07_CELLSIZE ) + Radius, 2 ) };
// NOTE: we should also update origin point for the contained nodes, but in practice we can skip this
// as all nodes will be added only after the proper center point was set, and won't change for( auto &cell : m_cells ) {
if( glm::length2( cell.area().center - Location ) < squaredradii ) {
// we reject cells which aren't within our area of interest
cell.update();
}
}
} }
// adds provided shape to the section // adds provided shape to the section
void void
basic_section::insert( shape_node Shape ) { basic_section::insert( shape_node Shape ) {
@@ -168,6 +316,96 @@ basic_section::insert( TAnimModel *Instance ) {
cell( Instance->location() ).insert( Instance ); cell( Instance->location() ).insert( Instance );
} }
// registers specified end point of the provided path in the lookup directory of the region
void
basic_section::register_end( TTrack *Path, glm::dvec3 const &Point ) {
cell( Point ).register_end( Path );
}
// registers specified end point of the provided traction piece in the lookup directory of the region
void
basic_section::register_end( TTraction *Traction, glm::dvec3 const &Point ) {
cell( Point ).register_end( Traction );
}
// find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance
std::tuple<TDynamicObject *, float>
basic_section::find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled ) {
// go through sections within radius of interest, and pick the nearest candidate
TDynamicObject
*vehiclefound,
*vehiclenearest { nullptr };
float
distancefound,
distancenearest { std::numeric_limits<float>::max() };
auto const squaredradii { std::pow( ( 0.5 * M_SQRT2 * EU07_CELLSIZE + 0.25 * EU07_CELLSIZE ) + Radius, 2 ) };
for( auto &cell : m_cells ) {
// we reject early cells which aren't within our area of interest
if( glm::length2( cell.area().center - Point ) > squaredradii ) {
continue;
}
std::tie( vehiclefound, distancefound ) = cell.find( Point, Radius, Onlycontrolled );
if( ( vehiclefound != nullptr )
&& ( distancefound < distancenearest ) ) {
std::tie( vehiclenearest, distancenearest ) = std::tie( vehiclefound, distancefound );
}
}
return std::tie( vehiclenearest, distancenearest );
}
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
std::tuple<TTrack *, int>
basic_section::find( glm::dvec3 const &Point, TTrack const *Exclude ) {
return cell( Point ).find( Point, Exclude );
}
// finds a traction piece with one of its ends located in specified point. returns: located traction piece and id of the matching endpoint
std::tuple<TTraction *, int>
basic_section::find( glm::dvec3 const &Point, TTraction const *Exclude ) {
return cell( Point ).find( Point, Exclude );
}
// finds a traction piece located nearest to specified point, sharing section with specified other piece and powered in specified direction. returns: located traction piece
std::tuple<TTraction *, int, float>
basic_section::find( glm::dvec3 const &Point, TTraction const *Other, int const Currentdirection ) {
// go through sections within radius of interest, and pick the nearest candidate
TTraction
*tractionfound,
*tractionnearest { nullptr };
float
distancefound,
distancenearest { std::numeric_limits<float>::max() };
int
endpointfound,
endpointnearest { -1 };
auto const radius { 0.0 }; // { EU07_CELLSIZE * 0.5 }; // experimentally limited, check if it has any negative effect
auto const squaredradii { std::pow( ( 0.5 * M_SQRT2 * EU07_CELLSIZE + 0.25 * EU07_CELLSIZE ) + radius, 2 ) };
for( auto &cell : m_cells ) {
// we reject early cells which aren't within our area of interest
if( glm::length2( cell.area().center - Point ) > squaredradii ) {
continue;
}
std::tie( tractionfound, endpointfound, distancefound ) = cell.find( Point, Other, Currentdirection );
if( ( tractionfound != nullptr )
&& ( distancefound < distancenearest ) ) {
std::tie( tractionnearest, endpointnearest, distancenearest ) = std::tie( tractionfound, endpointfound, distancefound );
}
}
return { tractionnearest, endpointnearest, distancenearest };
}
// sets center point of the section // sets center point of the section
void void
basic_section::center( glm::dvec3 Center ) { basic_section::center( glm::dvec3 Center ) {
@@ -251,6 +489,17 @@ basic_region::~basic_region() {
for( auto section : m_sections ) { if( section != nullptr ) { delete section; } } for( auto section : m_sections ) { if( section != nullptr ) { delete section; } }
} }
// legacy method, updates sounds and polls event launchers around camera
void
basic_region::update() {
// render events and sounds from sectors near enough to the viewer
auto const range = 2750.f; // audible range of 100 db sound
auto const &sectionlist = sections( Global::pCameraPosition, range );
for( auto *section : sectionlist ) {
section->update( Global::pCameraPosition, range );
}
}
void void
basic_region::insert_shape( shape_node Shape, scratch_data &Scratchpad ) { basic_region::insert_shape( shape_node Shape, scratch_data &Scratchpad ) {
@@ -327,6 +576,11 @@ basic_region::insert_path( TTrack *Path, scratch_data &Scratchpad ) {
// tracks are guaranteed to hava a name so we can skip the check // tracks are guaranteed to hava a name so we can skip the check
ErrorLog( "Bad scenario: track node \"" + Path->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" ); ErrorLog( "Bad scenario: track node \"" + Path->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
} }
// also register path ends in appropriate sections, for path merging lookups
// TODO: clean this up during track refactoring
for( auto &point : Path->endpoints() ) {
register_path( Path, point );
}
} }
// inserts provided track in the region // inserts provided track in the region
@@ -344,6 +598,11 @@ basic_region::insert_traction( TTraction *Traction, scratch_data &Scratchpad ) {
// tracks are guaranteed to hava a name so we can skip the check // tracks are guaranteed to hava a name so we can skip the check
ErrorLog( "Bad scenario: traction node \"" + Traction->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" ); ErrorLog( "Bad scenario: traction node \"" + Traction->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
} }
// also register traction ends in appropriate sections, for path merging lookups
// TODO: clean this up during track refactoring
for( auto &point : Traction->endpoints() ) {
register_traction( Traction, point );
}
} }
// inserts provided instance of 3d model in the region // inserts provided instance of 3d model in the region
@@ -363,6 +622,154 @@ basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad )
} }
} }
// inserts provided sound in the region
void
basic_region::insert_sound( TTextSound *Sound, scratch_data &Scratchpad ) {
/*
// TODO: implement
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto center = Sound->location();
if( point_inside( center ) ) {
// NOTE: nodes placed outside of region boundaries are discarded
section( center ).insert( Instance );
}
else {
// tracks are guaranteed to hava a name so we can skip the check
ErrorLog( "Bad scenario: model node \"" + Instance->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
}
*/
}
// find a vehicle located neares to specified location, within specified radius, optionally discarding vehicles without drivers
std::tuple<TDynamicObject *, float>
basic_region::find_vehicle( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled ) {
auto const &sectionlist = sections( Point, Radius );
// go through sections within radius of interest, and pick the nearest candidate
TDynamicObject
*foundvehicle,
*nearestvehicle { nullptr };
float
founddistance,
nearestdistance { std::numeric_limits<float>::max() };
for( auto *section : sectionlist ) {
std::tie( foundvehicle, founddistance ) = section->find( Point, Radius, Onlycontrolled );
if( ( foundvehicle != nullptr )
&& ( founddistance < nearestdistance ) ) {
std::tie( nearestvehicle, nearestdistance ) = std::tie( foundvehicle, founddistance );
}
}
return std::tie( nearestvehicle, nearestdistance );
}
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
std::tuple<TTrack *, int>
basic_region::find_path( glm::dvec3 const &Point, TTrack const *Exclude ) {
// TBD: throw out of bounds exception instead of checks all over the place..?
if( point_inside( Point ) ) {
return section( Point ).find( Point, Exclude );
}
return std::make_tuple<TTrack *, int>( 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
std::tuple<TTraction *, int>
basic_region::find_traction( glm::dvec3 const &Point, TTraction const *Exclude ) {
// TBD: throw out of bounds exception instead of checks all over the place..?
if( point_inside( Point ) ) {
return section( Point ).find( Point, Exclude );
}
return std::make_tuple<TTraction *, int>( 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
std::tuple<TTraction *, int>
basic_region::find_traction( glm::dvec3 const &Point, TTraction const *Other, int const Currentdirection ) {
auto const &sectionlist = sections( Point, 0.f );
// go through sections within radius of interest, and pick the nearest candidate
TTraction
*tractionfound,
*tractionnearest { nullptr };
float
distancefound,
distancenearest { std::numeric_limits<float>::max() };
int
endpointfound,
endpointnearest { -1 };
for( auto *section : sectionlist ) {
std::tie( tractionfound, endpointfound, distancefound ) = section->find( Point, Other, Currentdirection );
if( ( tractionfound != nullptr )
&& ( distancefound < distancenearest ) ) {
std::tie( tractionnearest, endpointnearest, distancenearest ) = std::tie( tractionfound, endpointfound, distancefound );
}
}
return { tractionnearest, endpointnearest };
}
// finds sections inside specified sphere. returns: list of sections
std::vector<basic_section *> const &
basic_region::sections( glm::dvec3 const &Point, float const Radius ) {
m_scratchpad.sections.clear();
auto const centerx { static_cast<int>( std::floor( Point.x / EU07_SECTIONSIZE + EU07_REGIONSIDESECTIONCOUNT / 2 ) ) };
auto const centerz { static_cast<int>( std::floor( Point.z / EU07_SECTIONSIZE + EU07_REGIONSIDESECTIONCOUNT / 2 ) ) };
auto const sectioncount { 2 * static_cast<int>( std::ceil( Radius / EU07_SECTIONSIZE ) ) };
int const originx = centerx - sectioncount / 2;
int const originz = centerz - sectioncount / 2;
auto const squaredradii { std::pow( ( 0.5 * M_SQRT2 * EU07_SECTIONSIZE + 0.25 * EU07_SECTIONSIZE ) + Radius, 2 ) };
for( int row = originz; row <= originz + sectioncount; ++row ) {
if( row < 0 ) { continue; }
if( row >= EU07_REGIONSIDESECTIONCOUNT ) { break; }
for( int column = originx; column <= originx + sectioncount; ++column ) {
if( column < 0 ) { continue; }
if( column >= EU07_REGIONSIDESECTIONCOUNT ) { break; }
auto *section { m_sections[ row * EU07_REGIONSIDESECTIONCOUNT + column ] };
if( ( section != nullptr )
&& ( glm::length2( section->area().center - Point ) < squaredradii ) ) {
m_scratchpad.sections.emplace_back( section );
}
}
}
return m_scratchpad.sections;
}
// registers specified path in the lookup directory of a cell enclosing specified point
void
basic_region::register_path( TTrack *Path, glm::dvec3 const &Point ) {
if( point_inside( Point ) ) {
section( Point ).register_end( Path, Point );
}
}
// registers specified end point of the provided traction piece in the lookup directory of the region
void
basic_region::register_traction( TTraction *Traction, glm::dvec3 const &Point ) {
if( point_inside( Point ) ) {
section( Point ).register_end( Traction, Point );
}
}
// checks whether specified point is within boundaries of the region // checks whether specified point is within boundaries of the region
bool bool
basic_region::point_inside( glm::dvec3 const &Location ) { basic_region::point_inside( glm::dvec3 const &Location ) {
@@ -566,8 +973,8 @@ basic_region::RaTriangleDivider( shape_node &Shape, std::deque<shape_node> &Shap
basic_section & basic_section &
basic_region::section( glm::dvec3 const &Location ) { basic_region::section( glm::dvec3 const &Location ) {
auto const column = static_cast<int>( std::floor( Location.x / EU07_SECTIONSIZE + EU07_REGIONSIDESECTIONCOUNT / 2 ) ); auto const column { static_cast<int>( std::floor( Location.x / EU07_SECTIONSIZE + EU07_REGIONSIDESECTIONCOUNT / 2 ) ) };
auto const row = static_cast<int>( std::floor( Location.z / EU07_SECTIONSIZE + EU07_REGIONSIDESECTIONCOUNT / 2 ) ); auto const row { static_cast<int>( std::floor( Location.z / EU07_SECTIONSIZE + EU07_REGIONSIDESECTIONCOUNT / 2 ) ) };
auto &section = auto &section =
m_sections[ m_sections[

115
scene.h
View File

@@ -30,6 +30,18 @@ struct scratch_data {
std::stack<glm::dvec3> location_offset; std::stack<glm::dvec3> location_offset;
glm::vec3 location_rotation; glm::vec3 location_rotation;
struct trainset_data {
std::string name;
std::string track;
float offset { 0.f };
float velocity { 0.f };
std::vector<TDynamicObject *> vehicles;
std::vector<std::int8_t> couplings;
TDynamicObject * driver { nullptr };
bool is_open { false };
} trainset;
}; };
// basic element of rudimentary partitioning scheme for the section. fixed size, no further subdivision // basic element of rudimentary partitioning scheme for the section. fixed size, no further subdivision
@@ -40,6 +52,9 @@ class basic_cell {
public: public:
// methods // methods
// legacy method, updates sounds and polls event launchers within radius around specified point
void
update();
// adds provided shape to the cell // adds provided shape to the cell
void void
insert( shape_node Shape ); insert( shape_node Shape );
@@ -52,18 +67,42 @@ public:
// adds provided model instance to the cell // adds provided model instance to the cell
void void
insert( TAnimModel *Instance ); insert( TAnimModel *Instance );
// registers provided path in the lookup directory of the cell
void
register_end( TTrack *Path );
// registers provided traction piece in the lookup directory of the cell
void
register_end( TTraction *Traction );
// find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance
std::tuple<TDynamicObject *, float>
find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled );
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
std::tuple<TTrack *, int>
find( glm::dvec3 const &Point, TTrack const *Exclude );
// finds a traction piece with one of its ends located in specified point. returns: located traction piece and id of the matching endpoint
std::tuple<TTraction *, int>
find( glm::dvec3 const &Point, TTraction const *Exclude );
// finds a traction piece located nearest to specified point, sharing section with specified other piece and powered in specified direction. returns: located traction piece
std::tuple<TTraction *, int, float>
find( glm::dvec3 const &Point, TTraction const *Other, int const Currentdirection );
// sets center point of the cell
void
center( glm::dvec3 Center );
// generates renderable version of held non-instanced geometry in specified geometry bank // generates renderable version of held non-instanced geometry in specified geometry bank
void void
create_geometry( geometrybank_handle const &Bank ); create_geometry( geometrybank_handle const &Bank );
// sets center point of the cell // provides access to bounding area data
void bounding_area const &
center( glm::dvec3 Center ); area() const {
return m_area; }
private: private:
// types // types
using shapenode_sequence = std::vector<shape_node>; using shapenode_sequence = std::vector<shape_node>;
using path_sequence = std::vector<TTrack *>; using path_sequence = std::vector<TTrack *>;
using path_set = std::set<TTrack *>;
using traction_sequence = std::vector<TTraction *>; using traction_sequence = std::vector<TTraction *>;
using traction_set = std::set<TTraction *>;
using instance_sequence = std::vector<TAnimModel *>; using instance_sequence = std::vector<TAnimModel *>;
// members // members
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE + 0.25 * EU07_CELLSIZE ) }; scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE + 0.25 * EU07_CELLSIZE ) };
@@ -75,6 +114,11 @@ private:
instance_sequence m_instancesopaque; instance_sequence m_instancesopaque;
instance_sequence m_instancetranslucent; instance_sequence m_instancetranslucent;
traction_sequence m_traction; traction_sequence m_traction;
// search helpers
struct lookup_data {
path_set paths;
traction_set traction;
} m_directories;
}; };
// basic scene partitioning structure, holds terrain geometry and collection of cells // basic scene partitioning structure, holds terrain geometry and collection of cells
@@ -84,6 +128,9 @@ class basic_section {
public: public:
// methods // methods
// legacy method, updates sounds and polls event launchers within radius around specified point
void
update( glm::dvec3 const &Location, float const Radius );
// adds provided shape to the section // adds provided shape to the section
void void
insert( shape_node Shape ); insert( shape_node Shape );
@@ -96,12 +143,34 @@ public:
// adds provided model instance to the section // adds provided model instance to the section
void void
insert( TAnimModel *Instance ); insert( TAnimModel *Instance );
// generates renderable version of held non-instanced geometry // registers specified end point of the provided path in the lookup directory of the region
void void
create_geometry(); register_end( TTrack *Path, glm::dvec3 const &Point );
// registers specified end point of the provided traction piece in the lookup directory of the region
void
register_end( TTraction *Traction, glm::dvec3 const &Point );
// find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance
std::tuple<TDynamicObject *, float>
find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled );
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
std::tuple<TTrack *, int>
find( glm::dvec3 const &Point, TTrack const *Exclude );
// finds a traction piece with one of its ends located in specified point. returns: located traction piece and id of the matching endpoint
std::tuple<TTraction *, int>
find( glm::dvec3 const &Point, TTraction const *Exclude );
// finds a traction piece located nearest to specified point, sharing section with specified other piece and powered in specified direction. returns: located traction piece
std::tuple<TTraction *, int, float>
find( glm::dvec3 const &Point, TTraction const *Other, int const Currentdirection );
// sets center point of the section // sets center point of the section
void void
center( glm::dvec3 Center ); center( glm::dvec3 Center );
// generates renderable version of held non-instanced geometry
void
create_geometry();
// provides access to bounding area data
bounding_area const &
area() const {
return m_area; }
private: private:
// types // types
@@ -134,6 +203,9 @@ public:
// destructor // destructor
~basic_region(); ~basic_region();
// methods // methods
// legacy method, updates sounds and polls event launchers around camera
void
update();
// inserts provided shape in the region // inserts provided shape in the region
void void
insert_shape( shape_node Shape, scratch_data &Scratchpad ); insert_shape( shape_node Shape, scratch_data &Scratchpad );
@@ -146,17 +218,45 @@ public:
// inserts provided instance of 3d model in the region // inserts provided instance of 3d model in the region
void void
insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ); insert_instance( TAnimModel *Instance, scratch_data &Scratchpad );
// inserts provided sound in the region
void
insert_sound( TTextSound *Sound, scratch_data &Scratchpad );
// find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance
std::tuple<TDynamicObject *, float>
find_vehicle( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled );
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
std::tuple<TTrack *, int>
find_path( glm::dvec3 const &Point, TTrack const *Exclude );
// finds a traction piece with one of its ends located in specified point. returns: located traction piece and id of the matching endpoint
std::tuple<TTraction *, int>
find_traction( glm::dvec3 const &Point, TTraction const *Exclude );
// finds a traction piece located nearest to specified point, sharing section with specified other piece and powered in specified direction. returns: located traction piece
std::tuple<TTraction *, int>
find_traction( glm::dvec3 const &Point, TTraction const *Other, int const Currentdirection );
// finds sections inside specified sphere. returns: list of sections
std::vector<basic_section *> const &
sections( glm::dvec3 const &Point, float const Radius );
private: private:
// types // types
using section_array = std::array<basic_section *, EU07_REGIONSIDESECTIONCOUNT * EU07_REGIONSIDESECTIONCOUNT>; using section_array = std::array<basic_section *, EU07_REGIONSIDESECTIONCOUNT * EU07_REGIONSIDESECTIONCOUNT>;
struct region_scratchpad {
std::vector<basic_section *> sections;
};
// methods // methods
// registers specified end point of the provided path in the lookup directory of the region
void
register_path( TTrack *Path, glm::dvec3 const &Point );
// registers specified end point of the provided traction piece in the lookup directory of the region
void
register_traction( TTraction *Traction, glm::dvec3 const &Point );
// checks whether specified point is within boundaries of the region // checks whether specified point is within boundaries of the region
bool bool
point_inside( glm::dvec3 const &Location ); point_inside( glm::dvec3 const &Location );
// trims provided shape to fit into a section, adds trimmed part at the end of provided list // legacy method, trims provided shape to fit into a section. adds trimmed part at the end of provided list, returns true if changes were made
bool bool
RaTriangleDivider( shape_node &Shape, std::deque<shape_node> &Shapes ); RaTriangleDivider( shape_node &Shape, std::deque<shape_node> &Shapes );
// provides access to section enclosing specified point // provides access to section enclosing specified point
@@ -165,6 +265,7 @@ private:
// members // members
section_array m_sections; section_array m_sections;
region_scratchpad m_scratchpad;
}; };

View File

@@ -17,7 +17,7 @@ namespace scene {
// restores content of the node from provded input stream // restores content of the node from provded input stream
shape_node & shape_node &
shape_node::deserialize( cParser &Input, node_data const &Nodedata ) { shape_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) {
// import common data // import common data
m_name = Nodedata.name; m_name = Nodedata.name;
@@ -291,6 +291,5 @@ basic_node::basic_node( scene::node_data const &Nodedata ) :
std::numeric_limits<double>::max() ); std::numeric_limits<double>::max() );
} }
} // editor } // editor
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -72,7 +72,7 @@ class node_manager {
struct node_data { struct node_data {
double range_min { 0.0 }; double range_min { 0.0 };
double range_max { 0.0 }; double range_max { std::numeric_limits<double>::max() };
std::string name; std::string name;
std::string type; std::string type;
}; };
@@ -86,7 +86,7 @@ public:
// types // types
struct shapenode_data { struct shapenode_data {
// placement and visibility // placement and visibility
bounding_area area; // bounding area, in world coordinates scene::bounding_area area; // bounding area, in world coordinates
bool visible { true }; // visibility flag bool visible { true }; // visibility flag
double rangesquared_min { 0.0 }; // visibility range, min double rangesquared_min { 0.0 }; // visibility range, min
double rangesquared_max { 0.0 }; // visibility range, max double rangesquared_max { 0.0 }; // visibility range, max
@@ -103,7 +103,7 @@ public:
// methods // methods
// restores content of the node from provded input stream // restores content of the node from provded input stream
shape_node & shape_node &
deserialize( cParser &Input, node_data const &Nodedata ); deserialize( cParser &Input, scene::node_data const &Nodedata );
// adds content of provided node to already enclosed geometry. returns: true if merge could be performed // adds content of provided node to already enclosed geometry. returns: true if merge could be performed
bool bool
merge( shape_node &Shape ); merge( shape_node &Shape );
@@ -229,12 +229,15 @@ public:
std::string const & std::string const &
name() const { name() const {
return m_name; } return m_name; }
glm::dvec3 const &
location() {
return m_location; };
void void
location( glm::dvec3 const Location ) { location( glm::dvec3 const Location ) {
m_location = Location; } m_location = Location; }
glm::dvec3 const &
location() const {
return m_location; };
void
visible( bool const Visible ) {
m_visible = Visible; }
bool bool
visible() const { visible() const {
return m_visible; } return m_visible; }

View File

@@ -12,15 +12,19 @@ http://mozilla.org/MPL/2.0/.
#include "globals.h" #include "globals.h"
#include "logs.h" #include "logs.h"
#include "uilayer.h"
namespace simulation { namespace simulation {
state_manager State; state_manager State;
event_manager Events; event_manager Events;
memory_manager Memory; memory_table Memory;
path_table Paths; path_table Paths;
traction_table Traction; traction_table Traction;
instance_manager Instances; powergridsource_table Powergrid;
sound_table Sounds;
instance_table Instances;
vehicle_table Vehicles;
light_array Lights; light_array Lights;
scene::basic_region *Region { nullptr }; scene::basic_region *Region { nullptr };
@@ -44,6 +48,23 @@ state_manager::deserialize( std::string const &Scenariofile ) {
return true; return true;
} }
// legacy method, calculates changes in simulation state over specified time
void
state_manager::update( double const Deltatime, int Iterationcount ) {
// aktualizacja animacji krokiem FPS: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń
if (Deltatime == 0.0) {
// jeśli załączona jest pauza, to tylko obsłużyć ruch w kabinie trzeba
return;
}
auto const totaltime { Deltatime * Iterationcount };
// NOTE: we perform animations first, as they can determine factors like contact with powergrid
TAnimModel::AnimUpdate( totaltime ); // wykonanie zakolejkowanych animacji
simulation::Powergrid.update( totaltime );
simulation::Vehicles.update( Deltatime, Iterationcount );
}
// restores class data from provided stream // restores class data from provided stream
void void
state_manager::deserialize( cParser &Input ) { state_manager::deserialize( cParser &Input ) {
@@ -79,7 +100,11 @@ state_manager::deserialize( cParser &Input ) {
for( auto &function : functionlist ) { for( auto &function : functionlist ) {
functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( importscratchpad ) ) ); functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( importscratchpad ) ) );
} }
// deserialize content from the provided input // deserialize content from the provided input
auto
timelast { std::chrono::steady_clock::now() },
timenow { timelast };
std::string token { Input.getToken<std::string>() }; std::string token { Input.getToken<std::string>() };
while( false == token.empty() ) { while( false == token.empty() ) {
@@ -91,6 +116,14 @@ state_manager::deserialize( cParser &Input ) {
ErrorLog( "Bad scenario: unexpected token \"" + token + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" ); ErrorLog( "Bad scenario: unexpected token \"" + token + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
} }
timenow = std::chrono::steady_clock::now();
if( std::chrono::duration_cast<std::chrono::milliseconds>( timenow - timelast ).count() >= 200 ) {
timelast = timenow;
glfwPollEvents();
UILayer.set_progress( Input.getProgress(), Input.getFullProgress() );
GfxRenderer.Render();
}
token = Input.getToken<std::string>(); token = Input.getToken<std::string>();
} }
} }
@@ -218,6 +251,7 @@ state_manager::deserialize_firstinit( cParser &Input, scene::scratch_data &Scrat
simulation::Paths.InitTracks(); simulation::Paths.InitTracks();
simulation::Traction.InitTraction(); simulation::Traction.InitTraction();
simulation::Events.InitEvents(); simulation::Events.InitEvents();
simulation::Memory.InitCells();
} }
void void
@@ -230,6 +264,8 @@ state_manager::deserialize_light( cParser &Input, scene::scratch_data &Scratchpa
void void
state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ) { state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ) {
auto const inputline = Input.Line(); // cache in case we need to report error
scene::node_data nodedata; scene::node_data nodedata;
// common data and node type indicator // common data and node type indicator
Input.getTokens( 4 ); Input.getTokens( 4 );
@@ -240,13 +276,27 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
>> nodedata.type; >> nodedata.type;
// type-based deserialization. not elegant but it'll do // type-based deserialization. not elegant but it'll do
if( nodedata.type == "dynamic" ) { if( nodedata.type == "dynamic" ) {
// TODO: implement
skip_until( Input, "enddynamic" ); auto *vehicle { deserialize_dynamic( Input, Scratchpad, nodedata ) };
// vehicle import can potentially fail
if( vehicle == nullptr ) { return; }
if( false == simulation::Vehicles.insert( vehicle ) ) {
ErrorLog( "Bad scenario: vehicle with duplicate name, \"" + vehicle->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
}
if( ( vehicle->MoverParameters->CategoryFlag == 1 ) // trains only
&& ( ( vehicle->MoverParameters->SecuritySystem.SystemType != 0 )
|| ( vehicle->MoverParameters->SandCapacity > 0.0 ) ) ) {
// we check for presence of security system or sand load, as a way to determine whether the vehicle is a controllable engine
// NOTE: this isn't 100% precise, e.g. middle EZT module comes with security system, while it has no lights, and some engines
// don't have security systems fitted
simulation::Lights.insert( vehicle );
}
} }
else if( nodedata.type == "track" ) { else if( nodedata.type == "track" ) {
auto const inputline = Input.Line(); // cache in case we need to report error
auto *path { deserialize_path( Input, Scratchpad, nodedata ) }; auto *path { deserialize_path( Input, Scratchpad, nodedata ) };
// duplicates of named tracks are currently experimentally allowed // duplicates of named tracks are currently experimentally allowed
if( simulation::Paths.insert( path ) ) { if( simulation::Paths.insert( path ) ) {
@@ -262,10 +312,10 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
} }
else if( nodedata.type == "traction" ) { else if( nodedata.type == "traction" ) {
auto const inputline = Input.Line(); // cache in case we need to report error
auto *traction { deserialize_traction( Input, Scratchpad, nodedata ) }; auto *traction { deserialize_traction( Input, Scratchpad, nodedata ) };
// duplicates of named tracks are currently discarded // traction loading is optional
if( traction == nullptr ) { return; }
if( simulation::Traction.insert( traction ) ) { if( simulation::Traction.insert( traction ) ) {
simulation::Region->insert_traction( traction, Scratchpad ); simulation::Region->insert_traction( traction, Scratchpad );
} }
@@ -274,18 +324,29 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
} }
} }
else if( nodedata.type == "tractionpowersource" ) { else if( nodedata.type == "tractionpowersource" ) {
// TODO: implement
skip_until( Input, "end" ); auto *powersource { deserialize_tractionpowersource( Input, Scratchpad, nodedata ) };
// traction loading is optional
if( powersource == nullptr ) { return; }
if( simulation::Powergrid.insert( powersource ) ) {
/*
// TODO: implement this
simulation::Region.insert_powersource( powersource, Scratchpad );
*/
}
else {
ErrorLog( "Bad scenario: power grid source with duplicate name, \"" + powersource->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
}
} }
else if( nodedata.type == "model" ) { else if( nodedata.type == "model" ) {
if( nodedata.range_min < 0.0 ) { if( nodedata.range_min < 0.0 ) {
// convert and import 3d terrain // convert and import 3d terrain
// TODO: implement this
} }
else { else {
// regular instance of 3d mesh // regular instance of 3d mesh
auto const inputline = Input.Line(); // cache in case we need to report error
auto *instance { deserialize_model( Input, Scratchpad, nodedata ) }; auto *instance { deserialize_model( Input, Scratchpad, nodedata ) };
// model import can potentially fail // model import can potentially fail
if( instance == nullptr ) { return; } if( instance == nullptr ) { return; }
@@ -313,10 +374,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
} }
else if( nodedata.type == "memcell" ) { else if( nodedata.type == "memcell" ) {
auto const inputline = Input.Line(); // cache in case we need to report error
auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) }; auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) };
// duplicates of named tracks are currently discarded
if( simulation::Memory.insert( memorycell ) ) { if( simulation::Memory.insert( memorycell ) ) {
/* /*
// TODO: implement this // TODO: implement this
@@ -325,10 +383,6 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
} }
else { else {
ErrorLog( "Bad scenario: memory cell with duplicate name, \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); ErrorLog( "Bad scenario: memory cell with duplicate name, \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
/*
delete memorycell;
delete memorycellnode;
*/
} }
} }
else if( nodedata.type == "eventlauncher" ) { else if( nodedata.type == "eventlauncher" ) {
@@ -336,8 +390,14 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
skip_until( Input, "end" ); skip_until( Input, "end" );
} }
else if( nodedata.type == "sound" ) { else if( nodedata.type == "sound" ) {
// TODO: implement
skip_until( Input, "endsound" ); auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) };
if( simulation::Sounds.insert( sound ) ) {
simulation::Region->insert_sound( sound, Scratchpad );
}
else {
ErrorLog( "Bad scenario: sound node with duplicate name, \"" + sound->m_name + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
}
} }
} }
@@ -417,14 +477,68 @@ state_manager::deserialize_time( cParser &Input, scene::scratch_data &Scratchpad
void void
state_manager::deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ) { state_manager::deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ) {
// TODO: implement if( true == Scratchpad.trainset.is_open ) {
skip_until( Input, "endtrainset" ); // shouldn't happen but if it does wrap up currently open trainset and report an error
deserialize_endtrainset( Input, Scratchpad );
ErrorLog( "Bad scenario: encountered nested trainset definitions in file \"" + Input.Name() + "\" (line " + to_string( Input.Line() ) + ")" );
}
Scratchpad.trainset = scene::scratch_data::trainset_data();
Scratchpad.trainset.is_open = true;
Input.getTokens( 4 );
Input
>> Scratchpad.trainset.name
>> Scratchpad.trainset.track
>> Scratchpad.trainset.offset
>> Scratchpad.trainset.velocity;
} }
void void
state_manager::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ) { state_manager::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ) {
// TODO: implement if( ( false == Scratchpad.trainset.is_open )
|| ( true == Scratchpad.trainset.vehicles.empty() ) ) {
// not bloody likely but we better check for it just the same
ErrorLog( "Bad trainset: empty trainset defined in file \"" + Input.Name() + "\" (line " + to_string( Input.Line() - 1 ) + ")" );
Scratchpad.trainset.is_open = false;
return;
}
std::size_t vehicleindex { 0 };
for( auto *vehicle : Scratchpad.trainset.vehicles ) {
// go through list of vehicles in the trainset, coupling them together and checking for potential driver
if( ( vehicle->Mechanik != nullptr )
&& ( vehicle->Mechanik->Primary() ) ) {
// primary driver will receive the timetable for this trainset
Scratchpad.trainset.driver = vehicle;
}
if( vehicleindex > 0 ) {
// from second vehicle on couple it with the previous one
Scratchpad.trainset.vehicles[ vehicleindex - 1 ]->AttachPrev(
vehicle,
Scratchpad.trainset.couplings[ vehicleindex - 1 ] );
}
++vehicleindex;
}
if( Scratchpad.trainset.driver != nullptr ) {
// if present, send timetable to the driver
// wysłanie komendy "Timetable" ustawia odpowiedni tryb jazdy
auto *controller = Scratchpad.trainset.driver->Mechanik;
controller->DirectionInitial();
controller->PutCommand(
"Timetable:" + Scratchpad.trainset.name,
Scratchpad.trainset.velocity,
0,
nullptr );
}
if( Scratchpad.trainset.couplings.back() == coupling::faux ) {
// jeśli ostatni pojazd ma sprzęg 0 to założymy mu końcówki blaszane (jak AI się odpali, to sobie poprawi)
Scratchpad.trainset.vehicles.back()->RaLightsSet( -1, TMoverParameters::light::rearendsignals );
}
// all done
Scratchpad.trainset.is_open = false;
} }
// creates path and its wrapper, restoring class data from provided stream // creates path and its wrapper, restoring class data from provided stream
@@ -448,6 +562,10 @@ state_manager::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad
TTraction * TTraction *
state_manager::deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { state_manager::deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
if( false == Global::bLoadTraction ) {
skip_until( Input, "endtraction" );
return nullptr;
}
// TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done // TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done
auto *traction = new TTraction( Nodedata ); auto *traction = new TTraction( Nodedata );
auto offset = ( auto offset = (
@@ -459,6 +577,22 @@ state_manager::deserialize_traction( cParser &Input, scene::scratch_data &Scratc
return traction; return traction;
} }
TTractionPowerSource *
state_manager::deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
if( false == Global::bLoadTraction ) {
skip_until( Input, "end" );
return nullptr;
}
auto *powersource = new TTractionPowerSource( Nodedata );
powersource->Load( &Input );
// adjust location
powersource->location( transform( powersource->location(), Scratchpad ) );
return powersource;
}
TMemCell * TMemCell *
state_manager::deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { state_manager::deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
@@ -481,7 +615,6 @@ state_manager::deserialize_model( cParser &Input, scene::scratch_data &Scratchpa
>> location.y >> location.y
>> location.z >> location.z
>> rotation.y; >> rotation.y;
// adjust location
auto *instance = new TAnimModel( Nodedata ); auto *instance = new TAnimModel( Nodedata );
instance->RaAnglesSet( Scratchpad.location_rotation + rotation ); // dostosowanie do pochylania linii instance->RaAnglesSet( Scratchpad.location_rotation + rotation ); // dostosowanie do pochylania linii
@@ -495,6 +628,147 @@ state_manager::deserialize_model( cParser &Input, scene::scratch_data &Scratchpa
return instance; return instance;
} }
TDynamicObject *
state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
if( false == Scratchpad.trainset.is_open ) {
// part of trainset data is used when loading standalone vehicles, so clear it just in case
Scratchpad.trainset = scene::scratch_data::trainset_data();
}
auto const inputline { Input.Line() }; // cache in case of errors
// basic attributes
auto const datafolder { Input.getToken<std::string>() };
auto const skinfile { Input.getToken<std::string>() };
auto const mmdfile { Input.getToken<std::string>() };
auto const pathname = (
Scratchpad.trainset.is_open ?
Scratchpad.trainset.track :
Input.getToken<std::string>() );
auto const offset { Input.getToken<double>( false ) };
auto const drivertype { Input.getToken<std::string>() };
auto const couplingparams = (
Scratchpad.trainset.is_open ?
Input.getToken<std::string>() :
"3" );
auto const velocity = (
Scratchpad.trainset.is_open ?
Scratchpad.trainset.velocity :
Input.getToken<float>( false ) );
// extract coupling type and optional parameters
auto const couplingparamsplit = couplingparams.find( '.' );
auto coupling = (
couplingparamsplit != std::string::npos ?
std::atoi( couplingparams.substr( 0, couplingparamsplit ).c_str() ) :
std::atoi( couplingparams.c_str() ) );
if( coupling < 0 ) {
// sprzęg zablokowany (pojazdy nierozłączalne przy manewrach)
coupling = ( -coupling ) | coupling::permanent;
}
if( ( offset != -1.0 )
&& ( std::abs( offset ) > 0.5 ) ) { // maksymalna odległość między sprzęgami - do przemyślenia
// likwidacja sprzęgu, jeśli odległość zbyt duża - to powinno być uwzględniane w fizyce sprzęgów...
coupling = 0;
}
auto const params = (
couplingparamsplit != std::string::npos ?
couplingparams.substr( couplingparamsplit + 1 ) :
"" );
// load amount and type
auto loadcount { Input.getToken<int>( false ) };
auto loadtype = (
loadcount ?
Input.getToken<std::string>() :
"" );
if( loadtype == "enddynamic" ) {
// idiotoodporność: ładunek bez podanego typu nie liczy się jako ładunek
loadcount = 0;
loadtype = "";
}
auto *path = simulation::Paths.find( pathname );
if( path == nullptr ) {
ErrorLog( "Bad scenario: vehicle \"" + Nodedata.name + "\" placed on nonexistent path \"" + pathname + "\" in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
skip_until( Input, "enddynamic" );
return nullptr;
}
if( ( true == Scratchpad.trainset.vehicles.empty() ) // jeśli pierwszy pojazd,
&& ( false == path->asEvent0Name.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
// przesuwamy około pół EU07 dla wstecznej zgodności
Scratchpad.trainset.offset = 8.0;
}
auto *vehicle = new TDynamicObject();
auto const length =
vehicle->Init(
Nodedata.name,
datafolder, skinfile, mmdfile,
path,
( offset == -1.0 ?
Scratchpad.trainset.offset :
Scratchpad.trainset.offset - offset ),
drivertype,
velocity,
Scratchpad.trainset.name,
loadcount, loadtype,
( offset == -1.0 ),
params );
if( length != 0.0 ) { // zero oznacza błąd
// przesunięcie dla kolejnego, minus bo idziemy w stronę punktu 1
Scratchpad.trainset.offset -= length;
// automatically establish permanent connections for couplers which specify them in their definitions
if( ( coupling != 0 )
&& ( vehicle->MoverParameters->Couplers[ ( offset == -1.0 ? 0 : 1 ) ].AllowedFlag & coupling::permanent ) ) {
coupling |= coupling::permanent;
}
if( true == Scratchpad.trainset.is_open ) {
Scratchpad.trainset.vehicles.emplace_back( vehicle );
Scratchpad.trainset.couplings.emplace_back( coupling );
}
}
else {
delete vehicle;
skip_until( Input, "enddynamic" );
return nullptr;
}
auto const destination { Input.getToken<std::string>() };
if( destination != "enddynamic" ) {
// optional vehicle destination parameter
vehicle->asDestination = Input.getToken<std::string>();
skip_until( Input, "enddynamic" );
}
return vehicle;
}
TTextSound *
state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
glm::dvec3 location;
Input.getTokens( 3 );
Input
>> location.x
>> location.y
>> location.z;
// adjust location
location = transform( location, Scratchpad );
auto const soundname { Input.getToken<std::string>() };
auto *sound = new TTextSound( soundname, Nodedata.range_max, location.x, location.y, location.z, false, false, Nodedata.range_min );
sound->name( Nodedata.name );
skip_until( Input, "endsound" );
return sound;
}
// skips content of stream until specified token // skips content of stream until specified token
void void
state_manager::skip_until( cParser &Input, std::string const &Token ) { state_manager::skip_until( cParser &Input, std::string const &Token ) {

View File

@@ -9,14 +9,18 @@ http://mozilla.org/MPL/2.0/.
#pragma once #pragma once
#include "parser.h"
#include "scene.h"
#include "event.h" #include "event.h"
#include "memcell.h" #include "memcell.h"
#include "track.h" #include "track.h"
#include "traction.h" #include "traction.h"
#include "tractionpower.h"
#include "realsound.h"
#include "animmodel.h" #include "animmodel.h"
#include "scene.h" #include "dynobj.h"
#include "driver.h"
#include "lightarray.h" #include "lightarray.h"
#include "parser.h"
namespace simulation { namespace simulation {
@@ -26,6 +30,9 @@ public:
// types // types
// methods // methods
// legacy method, calculates changes in simulation state over specified time
void
update( double dt, int iter );
bool bool
deserialize( std::string const &Scenariofile ); deserialize( std::string const &Scenariofile );
@@ -51,8 +58,11 @@ private:
void deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad );
TTrack * deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TTrack * deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TTraction * deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TTraction * deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TTractionPowerSource * deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TTextSound * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
// skips content of stream until specified token // skips content of stream until specified token
void skip_until( cParser &Input, std::string const &Token ); void skip_until( cParser &Input, std::string const &Token );
// transforms provided location by specifed rotation and offset // transforms provided location by specifed rotation and offset
@@ -61,10 +71,13 @@ private:
extern state_manager State; extern state_manager State;
extern event_manager Events; extern event_manager Events;
extern memory_manager Memory; extern memory_table Memory;
extern path_table Paths; extern path_table Paths;
extern traction_table Traction; extern traction_table Traction;
extern instance_manager Instances; extern powergridsource_table Powergrid;
extern sound_table Sounds;
extern instance_table Instances;
extern vehicle_table Vehicles;
extern light_array Lights; extern light_array Lights;
extern scene::basic_region *Region; extern scene::basic_region *Region;