16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-23 03:59:18 +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();
}
void TAdvancedSound::Free()
{
}
void TAdvancedSound::Init( std::string const &NameOn, std::string const &Name, std::string const &NameOff, double DistanceAttenuation,
vector3 const &pPosition)
void TAdvancedSound::Init( std::string const &NameOn, std::string const &Name, std::string const &NameOff, double DistanceAttenuation, Math3D::vector3 const &pPosition)
{
SoundStart.Init(NameOn, 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;
}
void TAdvancedSound::Load(cParser &Parser, vector3 const &pPosition)
void TAdvancedSound::Load(cParser &Parser, Math3D::vector3 const &pPosition)
{
std::string nameon, name, nameoff;
double attenuation;
@@ -62,7 +57,7 @@ void TAdvancedSound::Load(cParser &Parser, vector3 const &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
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))
{
@@ -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))
{
@@ -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
if( State == ss_Off ) {
return;

View File

@@ -13,13 +13,13 @@ http://mozilla.org/MPL/2.0/.
#include "RealSound.h"
#include "parser.h"
typedef enum
{
enum TSoundState {
ss_Off,
ss_Starting,
ss_Commencing,
ss_ShuttingDown
} TSoundState;
};
class TAdvancedSound
{ // 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:
TAdvancedSound() = default;
~TAdvancedSound();
void Init( std::string const &NameOn, std::string const &Name, std::string const &NameOff, double DistanceAttenuation, vector3 const &pPosition);
void Load(cParser &Parser, vector3 const &pPosition);
void TurnOn(bool ListenerInside, vector3 NewPosition);
void TurnOff(bool ListenerInside, vector3 NewPosition);
void Free();
void Update(bool ListenerInside, vector3 NewPosition);
void UpdateAF(double A, double F, bool ListenerInside, vector3 NewPosition);
void Init( std::string const &NameOn, std::string const &Name, std::string const &NameOff, double DistanceAttenuation, Math3D::vector3 const &pPosition);
void Load(cParser &Parser, Math3D::vector3 const &pPosition);
void TurnOn(bool ListenerInside, Math3D::vector3 NewPosition);
void TurnOff(bool ListenerInside, Math3D::vector3 NewPosition);
void Update(bool ListenerInside, Math3D::vector3 NewPosition);
void UpdateAF(double A, double F, bool ListenerInside, Math3D::vector3 NewPosition);
void CopyIfEmpty(TAdvancedSound &s);
};

View File

@@ -759,22 +759,28 @@ void TAnimModel::LightSet(int n, float v)
{ // ustawienie światła (n) na wartość (v)
if (n >= iMaxNumLights)
return; // przekroczony zakres
lsLights[n] = TLightState(int(v));
switch (lsLights[n])
{ // interpretacja ułamka zależnie od typu
case 0: // ustalenie czasu migotania, t<1s (f>1Hz), np. 0.1 => t=0.1 (f=10Hz)
lsLights[ n ] = TLightState( static_cast<int>( v ) );
switch( lsLights[ n ] ) {
// interpretacja ułamka zależnie od typu
case ls_Off: {
// ustalenie czasu migotania, t<1s (f>1Hz), np. 0.1 => t=0.1 (f=10Hz)
break;
case 1: // ustalenie wypełnienia ułamkiem, np. 1.25 => zapalony przez 1/4 okresu
}
case ls_On: {
// ustalenie wypełnienia ułamkiem, np. 1.25 => zapalony przez 1/4 okresu
break;
case 2: // ustalenie częstotliwości migotania, f<1Hz (t>1s), np. 2.2 => f=0.2Hz (t=5s)
}
case ls_Blink: {
// ustalenie częstotliwości migotania, f<1Hz (t>1s), np. 2.2 => f=0.2Hz (t=5s)
break;
case 3: // 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
}
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;
}
}
};
//---------------------------------------------------------------------------
void TAnimModel::AnimUpdate(double dt)

View File

@@ -176,7 +176,9 @@ private:
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)
typedef enum
enum TCommandType
{ // binarne odpowiedniki komend w komórce pamięci
cm_Unknown, // ciąg nierozpoznany (nie jest komendą)
cm_Ready, // W4 zezwala na odjazd, ale semafor może zatrzymać
@@ -51,6 +51,6 @@ typedef enum
cm_OutsideStation,
cm_Shunt,
cm_Command // komenda pobierana z komórki
} TCommandType;
};
#endif

View File

@@ -4150,7 +4150,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
// Ra 15-01: gałka nastawy hamulca
parser.getTokens();
parser >> asAnimName;
smBrakeMode = mdModel->GetFromName(asAnimName.c_str());
smBrakeMode = mdModel->GetFromName(asAnimName);
// 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
parser.getTokens();
parser >> asAnimName;
smLoadMode = mdModel->GetFromName(asAnimName.c_str());
smLoadMode = mdModel->GetFromName(asAnimName);
// 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
{ // McZapkie-050402: wyszukiwanie kol o nazwie str*
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)
{ //++iAnimatedAxles;
pAnimations[i].smAnimated->WillBeAnimated(); // wyłączenie optymalizacji transformu
@@ -4311,8 +4311,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
}
}
else
ErrorLog("Bad model: " + asFileName + " - missed submodel " +
asAnimName); // brak ramienia
ErrorLog("Bad model: " + asFileName + " - missed submodel " + asAnimName); // brak ramienia
}
}
@@ -4346,8 +4345,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
}
}
else
ErrorLog( "Bad model: " + asFileName + " - missed submodel " +
asAnimName ); // brak ramienia
ErrorLog( "Bad model: " + asFileName + " - missed submodel " + asAnimName ); // brak ramienia
}
}
}
@@ -5393,3 +5391,59 @@ TDynamicObject::ConnectedEnginePowerSource( TDynamicObject const *Caller ) const
// ...if we're still here, report lack of power source
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
TTrackFollower Axle0; // oś z przodu (od sprzęgu 0)
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
// eventy)
int iAxleFirst; // numer pierwszej osi w kierunku ruchu (oś wiążąca pojazd z torem i wyzwalająca eventy)
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!!!
// bool bCameraNear; //blisko kamer są potrzebne dodatkowe obliczenia szczegółów
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 asDestination; // dokąd pojazd ma być kierowany "(stacja):(tor)"
Math3D::matrix4x4 mMatrix; // macierz przekształcenia do renderowania modeli
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 *PrevConnected; // pojazd podłączony od strony sprzęgu 0 (kabina 1)
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;
public: // modele składowe pojazdu
// modele składowe pojazdu
TModel3d *mdModel; // model pudła
TModel3d *mdLoad; // model zmiennego ładunku
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.
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;
public:
public:
inline
material_data const
*Material() const {
return &m_materialdata; }
// 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
private:
private:
int iAnimations; // liczba obiektów animujących
/*
TAnim *pAnimations; // obiekty animujące (zawierają wskaźnik do funkcji wykonującej animację)
*/
std::vector<TAnim> pAnimations;
TSubModel **
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
void
UpdateNone(TAnim *pAnim){}; // animacja pusta (funkcje ustawiania submodeli, gdy blisko kamery)
TSubModel ** 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
void UpdateNone(TAnim *pAnim){}; // animacja pusta (funkcje ustawiania submodeli, gdy blisko kamery)
void UpdateAxle(TAnim *pAnim); // animacja osi
void UpdateBoogie(TAnim *pAnim); // animacja wózka
void UpdateDoorTranslate(TAnim *pAnim); // animacja drzwi - przesuw
@@ -268,8 +264,7 @@ public: // modele składowe pojazdu
TButton btCoupler1; // sprzegi
TButton btCoupler2;
TAirCoupler
btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
TAirCoupler btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
TAirCoupler btCPneumatic2;
TAirCoupler btCPneumatic1r; // ABu: to zeby nie bylo problemow przy laczeniu wagonow,
TAirCoupler btCPneumatic2r; // jesli beda polaczone sprzegami 1<->1 lub 0<->0
@@ -300,8 +295,6 @@ public: // modele składowe pojazdu
TButton btHeadSignals23;
TButton btMechanik1;
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
int iAxles; // McZapkie: to potem mozna skasowac i zastapic iNumAxles
@@ -325,7 +318,6 @@ public: // modele składowe pojazdu
TAdvancedSound sReleaser;
// Winger 010304
// TRealSound rsPanTup; //PSound sPantUp;
TRealSound sPantUp;
TRealSound sPantDown;
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
bool bEnabled; // Ra: wyjechał na portal i ma być usunięty
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
std::string asModel;
@@ -373,26 +363,18 @@ public: // modele składowe pojazdu
TDynamicObject * PrevC(int C);
TDynamicObject * NextC(int C);
double NextDistance(double d = -1.0);
void SetdMoveLen(double dMoveLen)
{
MoverParameters->dMoveLen = dMoveLen;
}
void ResetdMoveLen()
{
MoverParameters->dMoveLen = 0;
}
double GetdMoveLen()
{
return MoverParameters->dMoveLen;
}
void SetdMoveLen(double dMoveLen) {
MoverParameters->dMoveLen = dMoveLen; }
void ResetdMoveLen() {
MoverParameters->dMoveLen = 0; }
double GetdMoveLen() {
return MoverParameters->dMoveLen; }
int GetPneumatic(bool front, bool red);
void SetPneumatic(bool front, bool red);
std::string asName;
std::string GetName()
{
return this ? asName : std::string("");
};
std::string name() const {
return this ? asName : std::string(); };
TRealSound rsDiesielInc; // youBy
TRealSound rscurve; // youBy
@@ -405,7 +387,6 @@ public: // modele składowe pojazdu
TDynamicObject * ABuScanNearestObject(TTrack *Track, double ScanDir, double ScanDist,
int &CouplNr);
TDynamicObject * GetFirstDynamic(int cpl_type, int cf = 1);
// TDynamicObject* GetFirstCabDynamic(int cpl_type);
void ABuSetModelShake( Math3D::vector3 mShake);
// McZapkie-010302
@@ -437,99 +418,65 @@ public: // modele składowe pojazdu
void Move(double fDistance);
void FastMove(double fDistance);
void RenderSounds();
inline Math3D::vector3 GetPosition() const
{
return vPosition;
};
inline Math3D::vector3 HeadPosition()
{
return vCoulpler[iDirection ^ 1];
}; // pobranie współrzędnych czoła
inline Math3D::vector3 RearPosition()
{
return vCoulpler[iDirection];
}; // pobranie współrzędnych tyłu
inline Math3D::vector3 AxlePositionGet()
{
return iAxleFirst ? Axle1.pPosition : Axle0.pPosition;
};
inline Math3D::vector3 VectorFront() const
{
return vFront;
};
inline Math3D::vector3 VectorUp()
{
return vUp;
};
inline Math3D::vector3 VectorLeft() const
{
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();
inline Math3D::vector3 GetPosition() const {
return vPosition; };
// pobranie współrzędnych czoła
inline Math3D::vector3 HeadPosition() {
return vCoulpler[iDirection ^ 1]; };
// pobranie współrzędnych tyłu
inline Math3D::vector3 RearPosition() {
return vCoulpler[iDirection]; };
inline Math3D::vector3 AxlePositionGet() {
return iAxleFirst ? Axle1.pPosition : Axle0.pPosition; };
inline Math3D::vector3 VectorFront() const {
return vFront; };
inline Math3D::vector3 VectorUp() {
return vUp; };
inline Math3D::vector3 VectorLeft() const {
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()); };
// McZapkie-260202
void LoadMMediaFile(std::string BaseDir, std::string TypeName, std::string ReplacableSkin);
inline double ABuGetDirection() const // ABu.
{
return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection());
};
// inline double ABuGetTranslation() //ABu.
// {//zwraca przesunięcie wózka względem Point1 toru
// return (Axle1.GetTrack()==MyTrack?Axle1.GetTranslation():Axle0.GetTranslation());
// };
inline double RaDirectionGet()
{ // zwraca kierunek pojazdu na torze z aktywną osą
return iAxleFirst ? Axle1.GetDirection() : Axle0.GetDirection();
};
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();
};
inline double ABuGetDirection() const { // ABu.
return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection()); };
// zwraca kierunek pojazdu na torze z aktywną osą
inline double RaDirectionGet() {
return iAxleFirst ? Axle1.GetDirection() : Axle0.GetDirection(); };
// zwraca przesunięcie wózka względem Point1 toru z aktywną osią
inline double RaTranslationGet() {
return iAxleFirst ? Axle1.GetTranslation() : Axle0.GetTranslation(); };
// zwraca tor z aktywną osią
inline TTrack * RaTrackGet() {
return iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack(); };
void CouplersDettach(double MinDist, int MyScanDir);
void RadioStop();
void Damage(char flag);
void RaLightsSet(int head, int rear);
// void RaAxleEvent(TEvent *e);
TDynamicObject * FirstFind(int &coupler_nr, int cf = 1);
float GetEPP(); // wyliczanie sredniego cisnienia w PG
int DirectionSet(int d); // ustawienie kierunku w składzie
int DirectionGet()
{
return iDirection + iDirection - 1;
}; // odczyt kierunku w składzie
// odczyt kierunku w składzie
int DirectionGet() {
return iDirection + iDirection - 1; };
int DettachStatus(int dir);
int Dettach(int dir);
TDynamicObject * Neightbour(int &dir);
void CoupleDist();
TDynamicObject * ControlledFind();
void ParamSet(int what, int into);
int RouteWish(TTrack *tr); // zapytanie do AI, po którym segmencie skrzyżowania
// jechać
// zapytanie do AI, po którym segmencie skrzyżowania jechać
int RouteWish(TTrack *tr);
void DestinationSet(std::string to, std::string numer);
std::string TextureTest(std::string const &name);
void OverheadTrack(float o);
@@ -537,4 +484,14 @@ public: // modele składowe pojazdu
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 );
};
//---------------------------------------------------------------------------

246
Event.cpp
View File

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

14
Event.h
View File

@@ -12,6 +12,9 @@ http://mozilla.org/MPL/2.0/.
#include <string>
#include "dumb3d.h"
#include "classes.h"
#include "names.h"
#include "scenenode.h"
#include "evlaunch.h"
enum TEventType {
tp_Unknown,
@@ -61,6 +64,7 @@ union TParam
void *asPointer;
TMemCell *asMemCell;
TGroundNode *nGroundNode;
editor::basic_node *asEditorNode;
glm::dvec3 const *asLocation;
TTrack *asTrack;
TAnimModel *asModel;
@@ -104,7 +108,6 @@ public:
// metody
TEvent(std::string const &m = "");
~TEvent();
void Init();
void Load(cParser *parser, Math3D::vector3 const &org);
static void AddToQuery( TEvent *Event, TEvent *&Start );
std::string CommandGet();
@@ -123,9 +126,12 @@ public:
~event_manager();
// methods
// adds provided event to the collection. returns: true on success
// TODO: return handle instead of pointer
// TBD, TODO: return handle to the event
bool
insert( TEvent *Event );
bool
insert( TEventLauncher *Launcher ) {
return m_launchers.insert( Launcher ); }
// legacy method, returns pointer to specified event, or null
TEvent *
FindEvent( std::string const &Name );
@@ -143,6 +149,7 @@ private:
// types
using event_sequence = std::deque<TEvent *>;
using event_map = std::unordered_map<std::string, std::size_t>;
using eventlauncher_sequence = std::vector<TEventLauncher *>;
// methods
// legacy method, verifies condition for specified event
@@ -158,8 +165,9 @@ private:
// legacy version of the above
TEvent *QueryRootEvent { nullptr };
TEvent *m_workevent { nullptr };
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 "sound.h"
typedef enum
{ // typ ruchu
enum TGaugeType {
// typ ruchu
gt_Unknown, // na razie nie znany
gt_Rotate, // obrót
gt_Move, // przesunięcie równoległe
gt_Wiper, // obrót trzech kolejnych submodeli o ten sam kąt (np. wycieraczka, drzwi
// harmonijkowe)
gt_Wiper, // obrót trzech kolejnych submodeli o ten sam kąt (np. wycieraczka, drzwi harmonijkowe)
gt_Digital // licznik cyfrowy, np. kilometrów
} TGaugeType;
};
// animowany wskaźnik, mogący przyjmować wiele stanów pośrednich
class TGauge {

View File

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

View File

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

View File

@@ -586,7 +586,7 @@ void TGround::Free()
// RootNode=NULL;
nRootDynamic = NULL;
}
#ifdef EU07_USE_OLD_GROUNDCODE
TGroundNode * TGround::DynamicFindAny(std::string const &Name)
{ // wyszukanie pojazdu o podanej nazwie, szukanie po wszystkich (użyć drzewa!)
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
@@ -603,7 +603,7 @@ TGroundNode * TGround::DynamicFind(std::string const &Name)
return Current;
return NULL;
};
#endif
void
TGround::DynamicList(bool all)
{ // 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 *nTrainSetDriver = NULL; // pojazd, któremu zostanie wysłany rozkład
#ifdef EU07_USE_OLD_GROUNDCODE
void TGround::RaTriangleDivider(TGroundNode *node)
{ // tworzy dodatkowe trójkąty i zmiejsza podany
// 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(ntri);
};
#endif
TGroundNode * TGround::AddGroundNode(cParser *parser)
{ // wczytanie wpisu typu "node"
std::string str, str1, str2, str3, str4, Skin, DriverType, asNodeName;
@@ -889,6 +890,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
switch (tmp->iType)
{
#ifdef EU07_USE_OLD_GROUNDCODE
case TP_TRACTION:
tmp->hvTraction = new TTraction( tmp->asName );
parser->getTokens();
@@ -983,7 +985,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
>> tmp->pCenter.y
>> tmp->pCenter.z;
tmp->pCenter += pOrigin;
tmp->psTractionPowerSource = new TTractionPowerSource(tmp);
tmp->psTractionPowerSource = new TTractionPowerSource( tmp->asName );
tmp->psTractionPowerSource->Load(parser);
break;
case TP_MEMCELL:
@@ -1004,6 +1006,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
}
}
break;
#endif
case TP_EVLAUNCH:
parser->getTokens(3);
*parser
@@ -1015,6 +1018,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
tmp->EvLaunch = new TEventLauncher();
tmp->EvLaunch->Load(parser);
break;
#ifdef EU07_USE_OLD_GROUNDCODE
case TP_TRACK:
tmp->pTrack = new TTrack( tmp->asName );
if (Global::iWriteLogEnabled & 4)
@@ -1191,57 +1195,8 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
}
break;
#endif
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 ) {
// legacy leftover: special case, terrain provided as 3d model
tmp->iType = TP_TERRAIN;
@@ -1274,6 +1229,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
}
}
else {
#ifdef EU07_USE_OLD_GROUNDCODE
// regular 3d model
parser->getTokens( 3 );
*parser
@@ -1304,10 +1260,11 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
ErrorLog( "Duplicated model: " + tmp->asName ); // to zgłaszać duplikat
}
}
}
#endif
}
break;
}
#ifdef EU07_USE_OLD_GROUNDCODE
// case TP_GEOMETRY :
case GL_TRIANGLES:
case GL_TRIANGLE_STRIP:
@@ -1510,6 +1467,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
} // koniec wczytywania trójkątów
break;
}
#endif
case GL_LINES:
case GL_LINE_STRIP:
case GL_LINE_LOOP: {
@@ -1859,8 +1817,7 @@ bool TGround::Init(std::string File)
if (nTrainSetDriver) // pojazd, któremu zostanie wysłany rozkład
{ // wysłanie komendy "Timetable" ustawia odpowiedni tryb jazdy
nTrainSetDriver->DynamicObject->Mechanik->DirectionInitial();
nTrainSetDriver->DynamicObject->Mechanik->PutCommand("Timetable:" + asTrainName,
fTrainSetVel, 0, NULL);
nTrainSetDriver->DynamicObject->Mechanik->PutCommand("Timetable:" + asTrainName, fTrainSetVel, 0, NULL);
}
}
if( LastNode ) {
@@ -1926,7 +1883,7 @@ bool TGround::Init(std::string File)
{
ErrorLog("Duplicated event: " + tmp->asName);
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ść
// SafeDelete(tmp); //bezlitośnie usuwamy wszelkie duplikaty, żeby nie
// zaśmiecać drzewka
@@ -1938,7 +1895,7 @@ bool TGround::Init(std::string File)
RootEvent = tmp;
if (!found)
{ // 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 ) ) {
// event uruchamiany automatycznie po starcie
AddToQuery( RootEvent, NULL ); // dodanie do kolejki
@@ -2217,7 +2174,7 @@ bool TGround::InitEvents()
}
else
{ // 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 + "\"");
}
break;
@@ -2241,7 +2198,7 @@ bool TGround::InitEvents()
}
else
{ // 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 + "\"");
}
break;
@@ -2637,7 +2594,7 @@ void TGround::InitTraction()
nTemp = new TGroundNode();
nTemp->iType = TP_TRACTIONPOWERSOURCE;
nTemp->asName = Traction->asPowerSupplyName;
nTemp->psTractionPowerSource = new TTractionPowerSource(nTemp);
nTemp->psTractionPowerSource = new TTractionPowerSource(nTemp->asName);
nTemp->psTractionPowerSource->Init(Traction->NominalVoltage, Traction->MaxCurrent);
nTemp->nNext = nRootOfType[nTemp->iType]; // ostatni dodany dołączamy na końcu
// nowego
@@ -2826,8 +2783,11 @@ void TGround::TrackJoin(TGroundNode *Current)
int iConnection;
if (!Track->CurrentPrev())
{
tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_0(), iConnection,
Current); // Current do pominięcia
#ifdef EU07_USE_OLD_GROUNDCODE
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)
{
case 0:
@@ -2840,7 +2800,11 @@ void TGround::TrackJoin(TGroundNode *Current)
}
if (!Track->CurrentNext())
{
#ifdef EU07_USE_OLD_GROUNDCODE
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)
{
case 0:
@@ -2892,6 +2856,7 @@ bool TGround::InitLaunchers()
return true;
}
#ifdef EU07_USE_OLD_GROUNDCODE
TTrack * TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude)
{ // wyszukiwanie innego toru kończącego się w (Point)
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
for (nCurrent = sr->nRenderWires; nCurrent; nCurrent = nCurrent->nNext3)
if (nCurrent->iType == TP_TRACTION)
if (nCurrent->hvTraction->psSection ==
n->hvTraction->psSection) // jeśli ta sama sekcja
if (nCurrent->hvTraction->psSection == n->hvTraction->psSection) // jeśli ta sama sekcja
if (nCurrent != n) // ale nie jest tym samym
if (nCurrent->hvTraction !=
n->hvTraction
->hvNext[0]) // ale nie jest bezpośrednio podłączonym
if (nCurrent->hvTraction != n->hvTraction->hvNext[0]) // ale nie jest bezpośrednio podłączonym
if (nCurrent->hvTraction != n->hvTraction->hvNext[1])
if (nCurrent->hvTraction->psPower
[k = (glm::dot(
n->hvTraction->vParametric,
nCurrent->hvTraction->vParametric) >= 0 ?
dir ^ 1 :
dir)]) // ma zasilanie z odpowiedniej
// strony
if (nCurrent->hvTraction->fResistance[k] >=
0.0) //żeby się nie propagowały jakieś ujemne
{ // znaleziony kandydat do połączenia
dir)]) // ma zasilanie z odpowiedniej strony
if (nCurrent->hvTraction->fResistance[k] >= 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
if (dist > d)
{ // zapamiętanie nowego najbliższego
if (dist > d) {
// zapamiętanie nowego najbliższego
dist = d; // nowy rekord odległości
nBest = nCurrent;
zg = k; // z którego końca brać wskaźnik
// zasilacza
zg = k; // z którego końca brać wskaźnik zasilacza
}
}
if (nBest) // jak znalezione przęsło z zasilaniem, to podłączenie "równoległe"
{
n->hvTraction->ResistanceCalc(dir, nBest->hvTraction->fResistance[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));
if (nBest) {
// jak znalezione przęsło z zasilaniem, to podłączenie "równoległe"
n->hvTraction->ResistanceCalc(dir, nBest->hvTraction->fResistance[zg], nBest->hvTraction->psPower[zg]);
}
return (nBest ? nBest->hvTraction : nullptr);
};
#ifdef EU07_USE_OLD_GROUNDCODE
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)
if( !Event->iQueued ) // jeśli nie dodany jeszcze do kolejki
{ // 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
QueryRootEvent = QueryRootEvent->evNext; // NULL w skrajnym przypadku
if (tmpEvent->bEnabled)
{ // w zasadzie te wyłączone są skanowane i nie powinny się nigdy w kolejce znaleźć
if( ( false == tmpEvent->m_ignored ) && ( true == tmpEvent->bEnabled ) ) {
// w zasadzie te wyłączone są skanowane i nie powinny się nigdy w kolejce znaleźć
--tmpEvent->iQueued; // teraz moze być ponownie dodany do kolejki
WriteLog( "EVENT LAUNCHED" + ( tmpEvent->Activator ? ( " by " + tmpEvent->Activator->asName ) : "" ) + ": " + tmpEvent->asName );
switch (tmpEvent->Type)
@@ -3222,7 +3174,7 @@ bool TGround::CheckQuery()
// loc.Z= tmpEvent->Params[8].nGroundNode->pCenter.y;
if (Global::iMultiplayer) // potwierdzenie wykonania dla serwera (odczyt
// 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, &tmpEvent->Params[8].nGroundNode->pCenter);
@@ -3355,7 +3307,7 @@ bool TGround::CheckQuery()
0) // jednoznaczne tylko, gdy nie było else
{
if (tmpEvent->Activator)
WyslijEvent(tmpEvent->asName, tmpEvent->Activator->GetName());
WyslijEvent(tmpEvent->asName, tmpEvent->Activator->name());
else
WyslijEvent(tmpEvent->asName, "");
}
@@ -3468,7 +3420,6 @@ bool TGround::CheckQuery()
} // while
return true;
}
#endif
void TGround::UpdatePhys(double dt, int iter)
{ // 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
bool TGround::GetTraction(TDynamicObject *model)
{ // 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
for (node = tmp->nRenderWires; node;
node = node->nNext3) // następny z grupy
if (node->iType ==
TP_TRACTION) // w grupie tej są druty oraz inne linie
if (node->iType == TP_TRACTION) // w grupie tej są druty oraz inne linie
{
vParam =
node->hvTraction
->vParametric; // współczynniki równania parametrycznego
// współczynniki równania parametrycznego
vParam = node->hvTraction->vParametric;
fRaParam = -glm::dot(pant0, vFront);
auto const paramfrontdot = glm::dot( vParam, vFront );
fRaParam =
-( glm::dot( node->hvTraction->pPoint1, vFront ) + fRaParam )
/ ( paramfrontdot != 0.0 ? paramfrontdot : 0.001 ); // div0 trap
if ((fRaParam >= -0.001) ? (fRaParam <= 1.001) : false)
{ // jeśli tylko jest w przedziale, wyznaczyć odległość wzdłuż
// wektorów vUp i vLeft
vStyk = node->hvTraction->pPoint1 +
fRaParam * vParam; // punkt styku płaszczyzny z
// drutem (dla generatora łuku
// el.)
vGdzie = vStyk - pant0; // wektor
fVertical = glm::dot(
vGdzie,
vUp); // musi się mieścić w przedziale ruchu pantografu
{ // jeśli tylko jest w przedziale, wyznaczyć odległość wzdłuż wektorów vUp i vLeft
// punkt styku płaszczyzny z drutem (dla generatora łuku el.)
vStyk = node->hvTraction->pPoint1 + fRaParam * vParam;
// wektor musi się mieścić w przedziale ruchu pantografu
vGdzie = vStyk - pant0;
fVertical = glm::dot( vGdzie, vUp);
if (fVertical >= 0.0) // jeśli ponad pantografem (bo może
// łapać druty spod wiaduktu)
if (Global::bEnableTraction ?
fVertical < p->PantWys - 0.15 :
false) // jeśli drut jest niżej niż 15cm pod
// ślizgiem
{ // przełączamy w tryb połamania, o ile jedzie;
false) {
// jeśli drut jest niżej niż 15cm pod ślizgiem
// przełączamy w tryb połamania, o ile jedzie;
// (bEnableTraction) aby dało się jeździć na
// koślawych
// sceneriach
@@ -3827,18 +3771,7 @@ bool TGround::GetTraction(TDynamicObject *model)
else
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;
};

View File

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

View File

@@ -180,3 +180,15 @@ void TMemCell::AssignEvents(TEvent *e)
{ // powiązanie eventu
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);
};
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 {
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;
}
}

View File

@@ -21,8 +21,7 @@ http://mozilla.org/MPL/2.0/.
#include "mczapkie/mctools.h"
#include "usefull.h"
TRealSound::TRealSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic,
bool freqmod, double rmin)
TRealSound::TRealSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod, double rmin)
{
Init(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin);
}
@@ -32,12 +31,7 @@ TRealSound::~TRealSound()
// 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
pSound = TSoundsManager::GetFromName(SoundName, Dynamic, &fFrequency);
@@ -71,7 +65,7 @@ void TRealSound::Init(std::string const &SoundName, double DistanceAttenuation,
dSoundAtt = -1;
};
double TRealSound::ListenerDistance(vector3 ListenerPosition)
double TRealSound::ListenerDistance( Math3D::vector3 ListenerPosition)
{
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)
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()
{
DWORD stat;
@@ -231,17 +220,14 @@ void TRealSound::ResetPosition()
pSound->SetCurrentPosition(0);
}
TTextSound::TTextSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z,
bool Dynamic, bool freqmod, double rmin)
: TRealSound(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin)
TTextSound::TTextSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod, double rmin) :
TRealSound(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,
bool Dynamic, bool freqmod, double rmin)
void TTextSound::Init(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod, double rmin)
{ // dodatkowo doczytuje plik tekstowy
//TRealSound::Init(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin);
fTime = GetWaveTime();
std::string txt(SoundName);
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
if (FileExists(txt))
{ // wczytanie
/* TFileStream *ts = new TFileStream(txt, fmOpenRead);
asText = AnsiString::StringOfChar(' ', ts->Size);
ts->Read(asText.c_str(), ts->Size);
delete ts;
*/ std::ifstream inputfile( txt );
std::ifstream inputfile( txt );
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())
{ // jeśli ma powiązany tekst

View File

@@ -7,24 +7,25 @@ obtain one at
http://mozilla.org/MPL/2.0/.
*/
#ifndef RealSoundH
#define RealSoundH
#pragma once
#include <string>
#include "Sound.h"
#include "Geometry.h"
class TRealSound
{
protected:
#include "Sound.h"
#include "dumb3d.h"
#include "names.h"
class TRealSound {
protected:
PSound pSound = nullptr;
// char *Nazwa; // dla celow odwszawiania NOTE: currently not used anywhere
double fDistance = 0.0,
fPreviousDistance = 0.0; // dla liczenia Dopplera
double fDistance = 0.0;
double fPreviousDistance = 0.0; // dla liczenia Dopplera
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
public:
vector3 vSoundPosition; // polozenie zrodla dzwieku
public:
std::string m_name;
Math3D::vector3 vSoundPosition; // polozenie zrodla dzwieku
double dSoundAtt = -1.0; // odleglosc polowicznego zaniku dzwieku
double AM = 0.0; // mnoznik amplitudy
double AA = 0.0; // offset amplitudy
@@ -32,37 +33,43 @@ class TRealSound
double FA = 0.0; // offset czestotliwosci
bool bLoopPlay = false; // czy zapętlony dźwięk jest odtwarzany
TRealSound() = default;
TRealSound( std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic,
bool freqmod = false, double rmin = 0.0);
TRealSound( std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod = false, double rmin = 0.0 );
~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);
double ListenerDistance(vector3 ListenerPosition);
void Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition);
void Start();
void Init( std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod = false, double rmin = 0.0 );
double ListenerDistance( Math3D::vector3 ListenerPosition);
void Play(double Volume, int Looping, bool ListenerInside, Math3D::vector3 NewPosition);
void Stop();
void AdjFreq(double Freq, double dt);
void SetPan(int Pan);
double GetWaveTime(); // McZapkie TODO: dorobic dla roznych bps
int GetStatus();
void ResetPosition();
// void FreqReset(float f=22050.0) {fFrequency=f;};
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;
float fTime; // czas trwania
public:
TTextSound(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, bool freqmod = false, double rmin = 0.0);
void Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition);
public:
TTextSound(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, bool freqmod = false, double rmin = 0.0);
void Play(double Volume, int Looping, bool ListenerInside, Math3D::vector3 NewPosition);
};
class TSynthSound
{ // 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
@@ -74,10 +81,16 @@ class TSynthSound
// 41 - "tysiące"
// 42 - indeksy początkowe dla "odjazd"
// 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
// 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;
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
/*
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
// tolerance or integration accuracy.
// 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);
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
if (bCurve)
{ // można by wprowadzić uproszczony wzór dla okręgów płaskich
double t = GetTFromS(fDistance); // aproksymacja dystansu na krzywej Beziera na parametr (t)
p = RaInterpolate(t);
a.x = (1.0 - t) * fRoll1 + (t)*fRoll2; // przechyłka w danym miejscu (zmienia się liniowo)
// 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
auto const t = GetTFromS(fDistance); // aproksymacja dystansu na krzywej Beziera na parametr (t)
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
a.y = atan(t * (t * 3.0 * vA.y + vB.y + vB.y) + vC.y); // pochylenie krzywej (w pionie)
a.z = -atan2(t * (t * 3.0 * vA.x + vB.x + vB.x) + vC.x,
t * (t * 3.0 * vA.z + vB.z + vB.z) + vC.z); // kierunek krzywej w planie
auto const tangent = t * ( t * 3.0 * vA + vB + vB ) + vC;
// pochylenie krzywej (w pionie)
a.y = std::atan( tangent.y );
// kierunek krzywej w planie
a.z = -std::atan2( tangent.x, tangent.z );
}
else
{ // wyliczenie dla odcinka prostego jest prostsze
double t = fDistance / fLength; // zerowych torów nie ma
p = ((1.0 - t) * Point1 + (t)*Point2);
a.x = (1.0 - t) * fRoll1 + (t)*fRoll2; // przechyłka w danym miejscu (zmienia się liniowo)
else {
// wyliczenie dla odcinka prostego jest prostsze
auto const t = fDistance / fLength; // zerowych torów nie ma
p = FastGetPoint( t );
// przechyłka w danym miejscu (zmienia się liniowo)
a.x = interpolate<double>( fRoll1, fRoll2, t );
a.y = fStoop; // pochylenie toru prostego
a.z = fDirection; // kierunek toru w planie
}

View File

@@ -14,37 +14,6 @@ http://mozilla.org/MPL/2.0/.
#include "Classes.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
{ // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny)
private:
@@ -60,7 +29,6 @@ class TSegment
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
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
GetFirstDerivative(double const fTime) const;
@@ -140,10 +108,6 @@ public:
int
RaSegCount() const {
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 "MemCell.h"
#include "Event.h"
#include "simulation.h"
// 101206 Ra: trapezoidalne drogi i tory
// 110720 Ra: rozprucie zwrotnicy i odcinki izolowane
@@ -2651,6 +2652,31 @@ int TTrack::TestPoint(vector3 *Point)
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)
{ // poprawienie przechyłki wymaga wydłużenia podsypki
fTexHeight1 += dh;
@@ -2745,11 +2771,11 @@ TTrack * TTrack::Connected(int s, double &d) const
// legacy method, initializes tracks after deserialization from scenario file
void
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(
simulation::Events.FindEvent( track->asEvent0Name ),
@@ -2776,30 +2802,32 @@ path_table::InitTracks() {
}
switch (track->eType) {
/*
// TODO: re-enable
case tt_Table: {
// obrotnicę też łączymy na starcie z innymi torami
// szukamy modelu o tej samej nazwie
Model = FindGroundNode(Current->asName, TP_MODEL);
auto *instance = simulation::Instances.find( trackname );
// wiązanie toru z modelem obrotnicy
track->RaAssign(
Current,
( Model ?
Model->Model :
nullptr ),
instance,
simulation::Events.FindEvent( trackname + ":done" ),
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
break;
}
// no break on purpose:
// jak coś pójdzie źle, to robimy z tego normalny tor
}
*/
case tt_Normal: {
// tylko proste są podłączane do rozjazdów, stąd dwa rozjazdy się nie połączą ze sobą
if( track->CurrentPrev() == nullptr ) {
// tylko jeśli jeszcze nie podłączony
auto *matchingtrack = simulation::Region.FindTrack( track->CurrentSegment()->FastGetPoint_0(), iConnection, track );
switch( iConnection ) {
std::tie( matchingtrack, connection ) = simulation::Region->find_path( track->CurrentSegment()->FastGetPoint_0(), track );
switch( connection ) {
case -1: // Ra: pierwsza koncepcja zawijania samochodów i statków
// if ((Track->iCategoryFlag&1)==0) //jeśli nie jest torem szynowym
// 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->Switch( 0 );
break;
default:
break;
}
}
if( track->CurrentNext() == nullptr ) {
// tylko jeśli jeszcze nie podłączony
auto *matchingtrack = simulation::Region.FindTrack( track->CurrentSegment()->FastGetPoint_1(), iConnection, track );
switch( iConnection ) {
std::tie( matchingtrack, connection ) = simulation::Region->find_path( track->CurrentSegment()->FastGetPoint_1(), track );
switch( connection ) {
case -1: // Ra: pierwsza koncepcja zawijania samochodów i statków
// if ((Track->iCategoryFlag&1)==0) //jeśli nie jest torem szynowym
// 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)
// tmp->Switch(0);
break;
default:
break;
}
}
break;
@@ -2910,11 +2942,12 @@ path_table::InitTracks() {
else {
// utworzenie automatycznej komórki
// 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 );
isolated->pMemCell = memorycell; // wskaźnik komóki przekazany do odcinka izolowanego
}
isolated = isolated->Next();
}
*/
}

View File

@@ -119,7 +119,6 @@ class TTrack : public editor::basic_node {
friend class opengl_renderer;
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
std::shared_ptr<TSwitchExtension> SwitchExtension; // dodatkowe dane do toru, który jest zwrotnicą
std::shared_ptr<TSegment> Segment;
@@ -234,6 +233,9 @@ public:
void
origin( glm::dvec3 Origin ) {
m_origin = Origin; }
// retrieves list of the track's end points
std::vector<glm::dvec3>
endpoints() const;
#ifdef EU07_USE_OLD_GROUNDCODE
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 ) {}
// legacy constructor
TTraction::TTraction( std::string Name ) {
@@ -173,6 +172,13 @@ TTraction::Load( cParser *parser, glm::dvec3 const &pOrigin ) {
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
#ifdef EU07_USE_OLD_GROUNDCODE
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
void
traction_table::InitTraction() {
/*
//łączenie drutów ze sobą oraz z torami i eventami
// TGroundNode *nCurrent, *nTemp;
// TTraction *tmp; // znalezione przęsło
int iConnection;
std::string name;
int connection { -1 };
TTraction *matchingtraction { nullptr };
for( auto *traction : m_items ) {
// 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
// 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,
// podłączonym do zasilacza o nazwie "*" (gwiazka); "none" nie będzie odpowiednie
nTemp = FindGroundNode(traction->asPowerSupplyName, TP_TRACTIONPOWERSOURCE);
if (nTemp) // jak zasilacz znaleziony
traction->PowerSet(nTemp->psTractionPowerSource); // to podłączyć do przęsła
else if (traction->asPowerSupplyName != "*") // gwiazdka dla przęsła z izolatorem
if (traction->asPowerSupplyName != "none") // dopuszczamy na razie brak podłączenia?
{ // logowanie błędu i utworzenie zasilacza o domyślnej zawartości
ErrorLog("Missed TractionPowerSource: " + traction->asPowerSupplyName);
nTemp = new TGroundNode();
nTemp->iType = TP_TRACTIONPOWERSOURCE;
nTemp->asName = traction->asPowerSupplyName;
nTemp->psTractionPowerSource = new TTractionPowerSource(nTemp);
nTemp->psTractionPowerSource->Init(traction->NominalVoltage, traction->MaxCurrent);
nTemp->nNext = nRootOfType[nTemp->iType]; // ostatni dodany dołączamy na końcu
// nowego
nRootOfType[nTemp->iType] = nTemp; // ustawienie nowego na początku listy
auto *powersource = simulation::Powergrid.find( traction->asPowerSupplyName );
if( powersource ) {
// jak zasilacz znaleziony to podłączyć do przęsła
traction->PowerSet( powersource );
}
else {
if( ( traction->asPowerSupplyName != "*" ) // gwiazdka dla przęsła z izolatorem
&& ( traction->asPowerSupplyName != "none" ) ) { // dopuszczamy na razie brak podłączenia?
// logowanie błędu i utworzenie zasilacza o domyślnej zawartości
ErrorLog( "Bad scenario: traction piece connected to nonexistent power source \"" + traction->asPowerSupplyName + "\"" );
scene::node_data nodedata;
nodedata.name = traction->asPowerSupplyName;
powersource = new TTractionPowerSource( nodedata );
powersource->Init( traction->NominalVoltage, traction->MaxCurrent );
simulation::Powergrid.insert( powersource );
}
}
}
for( auto *traction : m_items ) {
if (!traction->hvNext[0]) // tylko jeśli jeszcze nie podłączony
{
tmp = FindTraction(traction->pPoint1, iConnection, nCurrent);
switch (iConnection)
{
case 0:
traction->Connect(0, tmp, 0);
break;
case 1:
traction->Connect(0, tmp, 1);
if (!traction->hvNext[0]) {
// tylko jeśli jeszcze nie podłączony
std::tie( matchingtraction, connection ) = simulation::Region->find_traction( traction->pPoint1, traction );
switch (connection) {
case 0: {
traction->Connect( 0, matchingtraction, 0 );
break;
}
if (traction->hvNext[0]) // jeśli został podłączony
if (traction->psSection && tmp->psSection) // tylko przęsło z izolatorem może nie
// mieć zasilania, bo ma 2, trzeba
// sprawdzać sąsiednie
if (traction->psSection !=
tmp->psSection) // połączone odcinki mają różne zasilacze
{ // to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo
// błąd
if (traction->psSection->bSection && !tmp->psSection->bSection)
{ //(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji
tmp->PowerSet(traction->psSection); // zastąpienie wskazaniem sekcji
}
else if (!traction->psSection->bSection && tmp->psSection->bSection)
{ //(Traction->psSection) jest podstacją, a (tmp->psSection) nazwą sekcji
traction->PowerSet(tmp->psSection); // zastąpienie wskazaniem sekcji
}
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
{
tmp = FindTraction(traction->pPoint2, iConnection, nCurrent);
switch (iConnection)
{
case 0:
traction->Connect(1, tmp, 0);
break;
case 1:
traction->Connect(1, tmp, 1);
case 1: {
traction->Connect( 0, matchingtraction, 1 );
break;
}
if (traction->hvNext[1]) // jeśli został podłączony
if (traction->psSection && tmp->psSection) // tylko przęsło z izolatorem może nie
// mieć zasilania, bo ma 2, trzeba
// sprawdzać sąsiednie
if (traction->psSection != tmp->psSection)
{ // to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo
// błąd
if (traction->psSection->bSection && !tmp->psSection->bSection)
{ //(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji
tmp->PowerSet(traction->psSection); // zastąpienie wskazaniem sekcji
default: {
break;
}
}
if( traction->hvNext[ 0 ] ) {
// jeśli został podłączony
if( ( traction->psSection != nullptr )
&& ( matchingtraction->psSection != nullptr ) ) {
// tylko przęsło z izolatorem może nie mieć zasilania, bo ma 2, trzeba sprawdzać sąsiednie
if( traction->psSection != matchingtraction->psSection ) {
// połączone odcinki mają różne zasilacze
// to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo błąd
if( ( true == traction->psSection->bSection )
&& ( false == matchingtraction->psSection->bSection ) ) {
//(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji
matchingtraction->PowerSet( traction->psSection ); // zastąpienie wskazaniem sekcji
}
else if( ( false == traction->psSection->bSection ) &&
( true == matchingtraction->psSection->bSection ) ) {
//(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 ) );
}
}
}
}
}
if (!traction->hvNext[1]) {
// tylko jeśli jeszcze nie podłączony
std::tie( matchingtraction, connection ) = simulation::Region->find_traction( traction->pPoint2, traction );
switch (connection) {
case 0: {
traction->Connect( 1, matchingtraction, 0 );
break;
}
case 1: {
traction->Connect( 1, matchingtraction, 1 );
break;
}
default: {
break;
}
}
if( traction->hvNext[ 1 ] ) {
// jeśli został podłączony
if( ( traction->psSection != nullptr )
&& ( matchingtraction->psSection != nullptr ) ) {
// tylko przęsło z izolatorem może nie mieć zasilania, bo ma 2, trzeba sprawdzać sąsiednie
if( traction->psSection != matchingtraction->psSection ) {
// to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo błąd
if( ( true == traction->psSection->bSection )
&& ( false == matchingtraction->psSection->bSection ) ) {
//(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji
matchingtraction->PowerSet( traction->psSection ); // zastąpienie wskazaniem sekcji
}
else if( ( false == traction->psSection->bSection )
&& ( true == matchingtraction->psSection->bSection ) ) {
//(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 if (!traction->psSection->bSection && tmp->psSection->bSection)
{ //(Traction->psSection) jest podstacją, a (tmp->psSection) nazwą sekcji
traction->PowerSet(tmp->psSection); // zastąpienie wskazaniem sekcji
}
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 ) {
// operacje mające na celu wykrywanie bieżni wspólnych i łączenie przęseł naprążania
if (traction->WhereIs()) // oznakowanie przedostatnich przęseł
{ // poszukiwanie bieżni wspólnej dla przedostatnich przęseł, również w celu połączenia
// 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
if( traction->WhereIs() ) {
// true for outer pieces of the traction section
traction->iTries = 5; // oznaczanie końcowych
++iConnection;
++endcount;
}
if (traction->fResistance[0] == 0.0)
{
traction->ResistanceCalc(); // obliczanie przęseł w segmencie z bezpośrednim zasilaniem
// ErrorLog("Section "+nCurrent->hvTraction->asPowerSupplyName+" connected"); //jako
// niby błąd będzie bardziej widoczne
if (traction->fResistance[0] == 0.0) {
// obliczanie przęseł w segmencie z bezpośrednim zasilaniem
traction->ResistanceCalc();
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)
TGroundNode **nEnds = new TGroundNode *[iConnection];
std::vector<TTraction *> ends; ends.reserve( endcount );
for( auto *traction : m_items ) {
//łą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" )
|| ( traction->asParallel == "*" ) ) {
// jeśli nieokreślone
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 );
if (nTemp)
{ // 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 != nullptr ) {
// o ile zostanie znalezione przęsło o takiej nazwie
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
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
}
nTemp->hvParallel = traction; // i na koniec ustawienie wskaźnika zwrotnego
}
if (!traction->hvParallel)
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->hvParallel == nullptr ) {
ErrorLog( "Missed overhead: " + traction->asParallel ); // logowanie braku
}
}
}
delete[] nEnds; // nie potrzebne już
*/
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 );
}
}
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 );
// legacy constructor
TTraction( std::string Name );
virtual ~TTraction() = default;
void Load( cParser *parser, glm::dvec3 const &pOrigin );
// set origin point
void
origin( glm::dvec3 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
// 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

View File

@@ -20,14 +20,12 @@ http://mozilla.org/MPL/2.0/.
//---------------------------------------------------------------------------
TTractionPowerSource::TTractionPowerSource(TGroundNode const *node) :
gMyNode( node )
{
psNode[0] = nullptr; // sekcje zostaną podłączone do zasilaczy
psNode[1] = nullptr;
};
TTractionPowerSource::TTractionPowerSource( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {}
// legacy constructor
TTractionPowerSource::TTractionPowerSource( std::string Name ) {
TTractionPowerSource::~TTractionPowerSource(){};
m_name = Name;
}
void TTractionPowerSource::Init(double const u, double const i)
{ // ustawianie zasilacza przy braku w scenerii
@@ -36,61 +34,67 @@ void TTractionPowerSource::Init(double const u, double const i)
MaxOutputCurrent = i;
};
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::Load(cParser *parser) {
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;
};
bool TTractionPowerSource::Update(double dt)
{ // powinno być wykonane raz na krok fizyki
// if (NominalVoltage * TotalPreviousAdmitance >
// MaxOutputCurrent * 0.00000005) // iloczyn napięcia i admitancji daje prąd
// ErrorLog("Power overload: \"" + gMyNode->asName + "\" with current " + AnsiString(NominalVoltage * TotalPreviousAdmitance) + "A");
if (NominalVoltage * TotalPreviousAdmitance >
MaxOutputCurrent) // iloczyn napięcia i admitancji daje prąd
{
// iloczyn napięcia i admitancji daje prąd
if (NominalVoltage * TotalPreviousAdmitance > MaxOutputCurrent) {
FastFuse = true;
FuseCounter += 1;
if (FuseCounter > FastFuseRepetition)
{
if (FuseCounter > FastFuseRepetition) {
SlowFuse = true;
ErrorLog("Power overload: \"" + gMyNode->asName + "\" disabled for " +
std::to_string(SlowFuseTimeOut) + "s");
ErrorLog( "Power overload: \"" + m_name + "\" disabled for " + std::to_string( SlowFuseTimeOut ) + "s" );
}
else
ErrorLog("Power overload: \"" + gMyNode->asName + "\" disabled for " +
std::to_string(FastFuseTimeOut) + "s");
else {
ErrorLog( "Power overload: \"" + m_name + "\" disabled for " + std::to_string( FastFuseTimeOut ) + "s" );
}
FuseTimer = 0;
}
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");
};
// 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/.
*/
#ifndef TractionPowerH
#define TractionPowerH
#pragma once
#include "scenenode.h"
#include "parser.h" //Tolaris-010603
#include "names.h"
class TGroundNode;
class TTractionPowerSource : public editor::basic_node {
class TTractionPowerSource
{
private:
double NominalVoltage = 0.0;
double VoltageFrequency = 0.0;
@@ -33,27 +33,34 @@ class TTractionPowerSource
bool SlowFuse = false;
double FuseTimer = 0.0;
int FuseCounter = 0;
TGroundNode const *gMyNode = nullptr; // wskaźnik na węzeł rodzica
protected:
public: // zmienne publiczne
TTractionPowerSource *psNode[2]; // zasilanie na końcach dla sekcji
public:
// zmienne publiczne
TTractionPowerSource *psNode[ 2 ] = { nullptr, nullptr }; // zasilanie na końcach dla sekcji
bool bSection = false; // czy jest sekcją
public:
// AnsiString asName;
TTractionPowerSource(TGroundNode const *node);
~TTractionPowerSource();
TTractionPowerSource( scene::node_data const &Nodedata );
// legacy constructor
TTractionPowerSource( std::string Name );
void Init(double const u, double const i);
bool Load(cParser *parser);
bool Render();
bool Update(double dt);
double CurrentGet(double res);
void VoltageSet(double const v)
{
NominalVoltage = v;
};
void VoltageSet(double const v) {
NominalVoltage = v; };
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;
}
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)
{ // powiązanie ręcznego sterowania kabiną z pojazdem
// Global::pUserDynamic=NewDynamicObject; //pojazd renderowany bez trzęsienia
@@ -3587,7 +3579,7 @@ bool TTrain::Update( double const Deltatime )
iDoorNo[i] = p->iAnimType[ANIM_DOORS];
iUnits[i] = iUnitNo;
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][1] = (bPants[iUnitNo - 1][1] || p->MoverParameters->PantRearUp);
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:")
{
pyScreens.init(*parser, DynamicObject->mdKabina, DynamicObject->GetName(),
pyScreens.init(*parser, DynamicObject->mdKabina, DynamicObject->name(),
NewCabNo);
}
// btLampkaUnknown.Init("unknown",mdKabina,false);

View File

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

169
World.cpp
View File

@@ -207,6 +207,13 @@ void TWorld::TrainDelete(TDynamicObject *d)
if (Train)
if (Train->Dynamic() != d)
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ć
Train = NULL;
Controlled = NULL; // tego też już nie ma
@@ -263,13 +270,25 @@ bool TWorld::Init( GLFWwindow *Window ) {
UILayer.set_progress( "Preparing train / Przygotowanie kabiny" );
WriteLog( "Player train init: " + Global::asHumanCtrlVehicle );
#ifdef EU07_USE_OLD_GROUNDCODE
TGroundNode *nPlayerTrain = NULL;
if (Global::asHumanCtrlVehicle != "ghostview")
nPlayerTrain = Ground.DynamicFind(Global::asHumanCtrlVehicle); // szukanie w tych z obsadą
#else
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)
{
Train = new TTrain();
#ifdef EU07_USE_OLD_GROUNDCODE
if (Train->Init(nPlayerTrain->DynamicObject))
#else
if( Train->Init( nPlayerTrain ) )
#endif
{
Controlled = Train->Dynamic();
mvControlled = Controlled->ControlledFind()->MoverParameters;
@@ -522,7 +541,11 @@ void TWorld::OnKeyDown(int cKey)
break;
}
#ifdef EU07_USE_OLD_GROUNDCODE
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 )
&& ( tmp != Controlled ) ) {
@@ -700,7 +723,11 @@ void TWorld::OnKeyDown(int cKey)
*/
if (cKey == Global::Keys[k_Heating]) // Ra: klawisz nie jest najszczęśliwszy
{ // zmiana próżny/ładowny; Ra: zabrane z kabiny
#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 (Global::shiftState ? temp->MoverParameters->IncBrakeMult() :
@@ -743,7 +770,11 @@ void TWorld::OnKeyDown(int cKey)
}
else if (cKey == Global::Keys[k_IncLocalBrakeLevel])
{ // zahamowanie dowolnego pojazdu
#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 (Global::ctrlState)
@@ -762,7 +793,11 @@ void TWorld::OnKeyDown(int cKey)
}
else if (cKey == Global::Keys[k_DecLocalBrakeLevel])
{ // odhamowanie dowolnego pojazdu
#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 (Global::ctrlState)
@@ -915,20 +950,7 @@ void TWorld::FollowView(bool wycisz) {
DistantView();
};
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
bool TWorld::Update() {
Timer::UpdateTimers(Global::iPause != 0);
@@ -955,7 +977,7 @@ bool TWorld::Update()
/*
fTimeBuffer += dt; //[s] dodanie czasu od poprzedniej ramki
*/
m_primaryupdateaccumulator += dt;
// m_primaryupdateaccumulator += dt; // unused for the time being
m_secondaryupdateaccumulator += dt;
/*
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
*/
}
auto const stepdeltatime { dt / updatecount };
// 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?
// 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
#ifdef EU07_USE_OLD_GROUNDCODE
if( true == Global::FullPhysics ) {
// default calculation mode, each step calculated separately
for( int updateidx = 0; updateidx < updatecount; ++updateidx ) {
Ground.Update( dt / updatecount, 1 );
// mixed calculation mode, steps calculated in ~0.05s chunks
while( updatecount >= 5 ) {
Ground.Update( stepdeltatime, 5 );
updatecount -= 5;
}
if( updatecount ) {
Ground.Update( stepdeltatime, updatecount );
}
}
else {
// slightly simplified calculation mode; can lead to errors
Ground.Update( dt / updatecount, updatecount );
// simplified calculation mode; faster but can lead to errors
Ground.Update( stepdeltatime, updatecount );
}
// yB dodał przyspieszacz fizyki
if( (true == DebugModeFlag)
&& (true == Global::bActive) // nie przyspieszać, gdy jedzie w tle :)
@@ -1024,8 +1051,24 @@ bool TWorld::Update()
Ground.Update( dt, 1 );
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 ) {
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
Ground.CheckQuery();
Ground.Update_Hidden();
#else
simulation::Events.CheckQuery();
simulation::Region->update();
#endif
Ground.Update_Hidden();
simulation::Lights.update();
// render time routines follow:
@@ -1119,10 +1163,15 @@ TWorld::Update_Camera( double const Deltatime ) {
Camera.LookAt = Controlled->GetPosition();
}
else {
TDynamicObject *d =
Ground.DynamicNearest( Camera.Pos, 300 ); // szukaj w promieniu 300m
#ifdef EU07_USE_OLD_GROUNDCODE
TDynamicObject *d = Ground.DynamicNearest( Camera.Pos, 300 ); // szukaj w promieniu 300m
if( !d )
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 ) {
// jeśli jakiś jest znaleziony wcześniej
if( 100.0 * LengthSquared3( d->GetPosition() - Camera.Pos ) > LengthSquared3( pDynamicNearest->GetPosition() - Camera.Pos ) ) {
@@ -1305,7 +1354,11 @@ TWorld::Update_UI() {
// timetable
TDynamicObject *tmp =
( FreeFlyModeFlag ?
#ifdef EU07_USE_OLD_GROUNDCODE
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 ) { break; }
@@ -1386,7 +1439,11 @@ TWorld::Update_UI() {
TDynamicObject *tmp =
( FreeFlyModeFlag ?
#ifdef EU07_USE_OLD_GROUNDCODE
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 ) {
@@ -1403,7 +1460,7 @@ TWorld::Update_UI() {
uitextline1 +=
"; C0:" +
( 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 ?
" (" + to_string( tmp->MoverParameters->Couplers[ 0 ].CoupleDist, 1 ) + " m)" :
"" ) :
@@ -1411,7 +1468,7 @@ TWorld::Update_UI() {
uitextline1 +=
" C1:" +
( 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 ?
" (" + to_string( tmp->MoverParameters->Couplers[ 1 ].CoupleDist, 1 ) + " m)" :
"" ) :
@@ -1653,7 +1710,11 @@ TWorld::Update_UI() {
TDynamicObject *tmp =
( FreeFlyModeFlag ?
#ifdef EU07_USE_OLD_GROUNDCODE
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 ) {
break;
@@ -1867,6 +1928,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
Now() + " " + to_string(pRozkaz->iComm) + " " +
std::string(pRozkaz->cString + 11 + i, (unsigned)(pRozkaz->cString[10 + i])) +
" rcvd");
#ifdef EU07_USE_OLD_GROUNDCODE
TGroundNode *t = Ground.DynamicFind(
std::string(pRozkaz->cString + 11 + i,
(unsigned)pRozkaz->cString[10 + i])); // nazwa pojazdu jest druga
@@ -1878,6 +1940,19 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
NULL, stopExt); // floaty są z przodu
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;
case 4: // badanie zajętości toru
@@ -1920,6 +1995,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
" rcvd");
if (pRozkaz->cString[0]) // jeśli długość nazwy jest niezerowa
{ // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7
#ifdef EU07_USE_OLD_GROUNDCODE
TGroundNode *t;
if (pRozkaz->cString[1] == '*')
t = Ground.DynamicFind(
@@ -1929,6 +2005,9 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
pRozkaz->cString + 1, (unsigned)pRozkaz->cString[0])); // nazwa pojazdu
if (t)
Ground.WyslijNamiary(t); // wysłanie informacji o pojeździe
#else
// TODO: implement
#endif
}
else
{ // 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) + " " +
std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) +
" rcvd");
if (pRozkaz->cString[1]) // jeśli długość nazwy jest niezerowa
#ifdef EU07_USE_OLD_GROUNDCODE
if( pRozkaz->cString[ 1 ] ) // jeśli długość nazwy jest niezerowa
{ // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #13
TGroundNode *t;
if (pRozkaz->cString[2] == '*')
if( pRozkaz->cString[ 2 ] == '*' )
t = Ground.DynamicFind(
Global::asHumanCtrlVehicle); // nazwa pojazdu użytkownika
Global::asHumanCtrlVehicle ); // nazwa pojazdu użytkownika
else
t = Ground.DynamicFindAny(
std::string(pRozkaz->cString + 2,
(unsigned)pRozkaz->cString[1])); // nazwa pojazdu
if (t)
{
std::string( pRozkaz->cString + 2,
(unsigned)pRozkaz->cString[ 1 ] ) ); // nazwa pojazdu
if( t ) {
TDynamicObject *d = t->DynamicObject;
while (d)
{
d->Damage(pRozkaz->cString[0]);
while( d ) {
d->Damage( pRozkaz->cString[ 0 ] );
d = d->Next(); // pozostałe też
}
d = t->DynamicObject->Prev();
while (d)
{
d->Damage(pRozkaz->cString[0]);
while( d ) {
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
}
}
// Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0])));
#else
// TODO: implement
#endif
break;
}
};
@@ -2143,7 +2222,7 @@ void TWorld::ChangeDynamic() {
Train->DynamicSet( temp );
Controlled = temp;
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->AIControllFlag ) // tylko jeśli ręcznie prowadzony
{

View File

@@ -25,7 +25,7 @@ struct basic_vertex {
glm::vec2 texture; // uv space
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 )
{}
void serialize( std::ostream& ) const;
@@ -58,7 +58,7 @@ struct geometry_handle {
geometry_handle() :
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 )
{}
// methods
@@ -121,7 +121,7 @@ protected:
unsigned int type; // kind of geometry used by the chunk
vertex_array vertices; // geometry data
// 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 )
{
vertices.swap( Vertices );

View File

@@ -205,23 +205,21 @@ std::string cParser::readToken(bool ToLower, const char *Break)
if (token.compare("include") == 0)
{ // obsługa include
std::string includefile = readToken(ToLower); // nazwa pliku
if (LoadTraction ? true : ((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
if( ( true == LoadTraction )
|| ( ( includefile.find( "tr/" ) == std::string::npos )
&& ( includefile.find( "tra/" ) == std::string::npos ) ) ) {
std::string parameter = readToken(false); // w parametrach nie zmniejszamy
while( (parameter.empty() == false)
&& (parameter.compare("end") != 0) )
{
parameters.push_back(parameter);
parameters.emplace_back(parameter);
parameter = readToken(false);
}
// if (trtest2.find("tr/")!=0)
mIncludeParser = std::make_shared<cParser>(includefile, buffer_FILE, mPath, LoadTraction);
if (mIncludeParser->mSize <= 0)
ErrorLog("Missed include: " + includefile);
ErrorLog("Bad include: can't open file \"" + includefile + "\"" );
}
else {
while( token.compare( "end" ) != 0 ) {

View File

@@ -1602,7 +1602,17 @@ opengl_renderer::Render( scene::basic_region *Region ) {
m_sectionqueue.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
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 ) );
@@ -1903,11 +1913,22 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
switch( m_renderpass.draw_mode ) {
case rendermode::color:
case rendermode::shadows:
case rendermode::pickscenery: {
// render
case rendermode::shadows: {
// opaque parts of instanced models
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
break;
}
@@ -2863,7 +2884,12 @@ opengl_renderer::Render_Alpha( cell_sequence::reverse_iterator First, cell_seque
// translucent parts of instanced models
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;
}

425
scene.cpp
View File

@@ -10,11 +10,28 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "scene.h"
#include "globals.h"
#include "renderer.h"
#include "logs.h"
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
void
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
void
basic_cell::create_geometry( geometrybank_handle const &Bank ) {
@@ -104,17 +246,23 @@ basic_cell::create_geometry( geometrybank_handle const &Bank ) {
#endif
}
// sets center point of the section
// legacy method, updates sounds and polls event launchers within radius around specified point
void
basic_cell::center( glm::dvec3 Center ) {
basic_section::update( glm::dvec3 const &Location, float const Radius ) {
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
auto const squaredradii { std::pow( ( 0.5 * M_SQRT2 * EU07_CELLSIZE + 0.25 * EU07_CELLSIZE ) + Radius, 2 ) };
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
void
basic_section::insert( shape_node Shape ) {
@@ -168,6 +316,96 @@ basic_section::insert( TAnimModel *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
void
basic_section::center( glm::dvec3 Center ) {
@@ -251,6 +489,17 @@ basic_region::~basic_region() {
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
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
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
@@ -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
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
@@ -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
bool
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_region::section( glm::dvec3 const &Location ) {
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 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 &section =
m_sections[

113
scene.h
View File

@@ -30,6 +30,18 @@ struct scratch_data {
std::stack<glm::dvec3> location_offset;
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
@@ -40,6 +52,9 @@ class basic_cell {
public:
// methods
// legacy method, updates sounds and polls event launchers within radius around specified point
void
update();
// adds provided shape to the cell
void
insert( shape_node Shape );
@@ -52,18 +67,42 @@ public:
// adds provided model instance to the cell
void
insert( TAnimModel *Instance );
// generates renderable version of held non-instanced geometry in specified geometry bank
// registers provided path in the lookup directory of the cell
void
create_geometry( geometrybank_handle const &Bank );
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
void
create_geometry( geometrybank_handle const &Bank );
// provides access to bounding area data
bounding_area const &
area() const {
return m_area; }
private:
// types
using shapenode_sequence = std::vector<shape_node>;
using path_sequence = std::vector<TTrack *>;
using path_set = std::set<TTrack *>;
using traction_sequence = std::vector<TTraction *>;
using traction_set = std::set<TTraction *>;
using instance_sequence = std::vector<TAnimModel *>;
// members
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_instancetranslucent;
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
@@ -84,6 +128,9 @@ class basic_section {
public:
// 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
void
insert( shape_node Shape );
@@ -96,12 +143,34 @@ public:
// adds provided model instance to the section
void
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
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
void
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:
// types
@@ -134,6 +203,9 @@ public:
// destructor
~basic_region();
// methods
// legacy method, updates sounds and polls event launchers around camera
void
update();
// inserts provided shape in the region
void
insert_shape( shape_node Shape, scratch_data &Scratchpad );
@@ -146,17 +218,45 @@ public:
// inserts provided instance of 3d model in the region
void
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:
// types
using section_array = std::array<basic_section *, EU07_REGIONSIDESECTIONCOUNT * EU07_REGIONSIDESECTIONCOUNT>;
struct region_scratchpad {
std::vector<basic_section *> sections;
};
// 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
bool
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
RaTriangleDivider( shape_node &Shape, std::deque<shape_node> &Shapes );
// provides access to section enclosing specified point
@@ -165,6 +265,7 @@ private:
// members
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
shape_node &
shape_node::deserialize( cParser &Input, node_data const &Nodedata ) {
shape_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) {
// import common data
m_name = Nodedata.name;
@@ -291,6 +291,5 @@ basic_node::basic_node( scene::node_data const &Nodedata ) :
std::numeric_limits<double>::max() );
}
} // editor
//---------------------------------------------------------------------------

View File

@@ -72,7 +72,7 @@ class node_manager {
struct node_data {
double range_min { 0.0 };
double range_max { 0.0 };
double range_max { std::numeric_limits<double>::max() };
std::string name;
std::string type;
};
@@ -86,7 +86,7 @@ public:
// types
struct shapenode_data {
// 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
double rangesquared_min { 0.0 }; // visibility range, min
double rangesquared_max { 0.0 }; // visibility range, max
@@ -103,7 +103,7 @@ public:
// methods
// restores content of the node from provded input stream
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
bool
merge( shape_node &Shape );
@@ -229,12 +229,15 @@ public:
std::string const &
name() const {
return m_name; }
glm::dvec3 const &
location() {
return m_location; };
void
location( glm::dvec3 const Location ) {
m_location = Location; }
glm::dvec3 const &
location() const {
return m_location; };
void
visible( bool const Visible ) {
m_visible = Visible; }
bool
visible() const {
return m_visible; }

View File

@@ -12,15 +12,19 @@ http://mozilla.org/MPL/2.0/.
#include "globals.h"
#include "logs.h"
#include "uilayer.h"
namespace simulation {
state_manager State;
event_manager Events;
memory_manager Memory;
memory_table Memory;
path_table Paths;
traction_table Traction;
instance_manager Instances;
powergridsource_table Powergrid;
sound_table Sounds;
instance_table Instances;
vehicle_table Vehicles;
light_array Lights;
scene::basic_region *Region { nullptr };
@@ -44,6 +48,23 @@ state_manager::deserialize( std::string const &Scenariofile ) {
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
void
state_manager::deserialize( cParser &Input ) {
@@ -79,7 +100,11 @@ state_manager::deserialize( cParser &Input ) {
for( auto &function : functionlist ) {
functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( importscratchpad ) ) );
}
// deserialize content from the provided input
auto
timelast { std::chrono::steady_clock::now() },
timenow { timelast };
std::string token { Input.getToken<std::string>() };
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 ) + ")" );
}
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>();
}
}
@@ -218,6 +251,7 @@ state_manager::deserialize_firstinit( cParser &Input, scene::scratch_data &Scrat
simulation::Paths.InitTracks();
simulation::Traction.InitTraction();
simulation::Events.InitEvents();
simulation::Memory.InitCells();
}
void
@@ -230,6 +264,8 @@ state_manager::deserialize_light( cParser &Input, scene::scratch_data &Scratchpa
void
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;
// common data and node type indicator
Input.getTokens( 4 );
@@ -240,13 +276,27 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
>> nodedata.type;
// type-based deserialization. not elegant but it'll do
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" ) {
auto const inputline = Input.Line(); // cache in case we need to report error
auto *path { deserialize_path( Input, Scratchpad, nodedata ) };
// duplicates of named tracks are currently experimentally allowed
if( simulation::Paths.insert( path ) ) {
@@ -262,10 +312,10 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
}
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 ) };
// duplicates of named tracks are currently discarded
// traction loading is optional
if( traction == nullptr ) { return; }
if( simulation::Traction.insert( traction ) ) {
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" ) {
// 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" ) {
if( nodedata.range_min < 0.0 ) {
// convert and import 3d terrain
// TODO: implement this
}
else {
// 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 ) };
// model import can potentially fail
if( instance == nullptr ) { return; }
@@ -313,10 +374,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
}
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 ) };
// duplicates of named tracks are currently discarded
if( simulation::Memory.insert( memorycell ) ) {
/*
// TODO: implement this
@@ -325,10 +383,6 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
}
else {
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" ) {
@@ -336,8 +390,14 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
skip_until( Input, "end" );
}
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
state_manager::deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ) {
// TODO: implement
skip_until( Input, "endtrainset" );
if( true == Scratchpad.trainset.is_open ) {
// 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
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
@@ -448,6 +562,10 @@ state_manager::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad
TTraction *
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
auto *traction = new TTraction( Nodedata );
auto offset = (
@@ -459,6 +577,22 @@ state_manager::deserialize_traction( cParser &Input, scene::scratch_data &Scratc
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 *
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.z
>> rotation.y;
// adjust location
auto *instance = new TAnimModel( Nodedata );
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;
}
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
void
state_manager::skip_until( cParser &Input, std::string const &Token ) {

View File

@@ -9,14 +9,18 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include "parser.h"
#include "scene.h"
#include "event.h"
#include "memcell.h"
#include "track.h"
#include "traction.h"
#include "tractionpower.h"
#include "realsound.h"
#include "animmodel.h"
#include "scene.h"
#include "dynobj.h"
#include "driver.h"
#include "lightarray.h"
#include "parser.h"
namespace simulation {
@@ -26,6 +30,9 @@ public:
// types
// methods
// legacy method, calculates changes in simulation state over specified time
void
update( double dt, int iter );
bool
deserialize( std::string const &Scenariofile );
@@ -51,8 +58,11 @@ private:
void deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad );
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 );
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 );
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
void skip_until( cParser &Input, std::string const &Token );
// transforms provided location by specifed rotation and offset
@@ -61,10 +71,13 @@ private:
extern state_manager State;
extern event_manager Events;
extern memory_manager Memory;
extern memory_table Memory;
extern path_table Paths;
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 scene::basic_region *Region;