From cb19354db4214162fa0ea0797b0d7818022e5339 Mon Sep 17 00:00:00 2001 From: Zbigniew Mandziejewicz Date: Fri, 3 Apr 2015 22:00:22 +0800 Subject: [PATCH] Format source code using clang-format --- AdvSound.cpp | 199 +- AdvSound.h | 17 +- AirCoupler.cpp | 85 +- AirCoupler.h | 52 +- AnimModel.cpp | 1348 +++--- AnimModel.h | 262 +- Button.cpp | 85 +- Button.h | 53 +- Camera.cpp | 250 +- Camera.h | 61 +- Classes.h | 56 +- Console.cpp | 465 +- Console.h | 79 +- Console/LPT.cpp | 60 +- Console/LPT.h | 11 +- Console/PoKeys55.cpp | 595 +-- Console/PoKeys55.h | 47 +- Curve.cpp | 124 +- Curve.h | 5 +- Data.h | 806 ++-- Driver.cpp | 8614 ++++++++++++++++++--------------- Driver.h | 602 +-- DynObj.cpp | 8590 ++++++++++++++++++--------------- DynObj.h | 650 +-- EU07.cpp | 1172 ++--- EvLaunch.cpp | 283 +- EvLaunch.h | 46 +- Event.cpp | 1172 ++--- Event.h | 132 +- FadeSound.cpp | 87 +- FadeSound.h | 8 +- Float3d.cpp | 28 +- Float3d.h | 448 +- Forth.h | 2 +- Gauge.cpp | 303 +- Gauge.h | 93 +- Geom.cpp | 163 +- Geom.h | 7 +- Globals.cpp | 1399 +++--- Globals.h | 507 +- Ground.cpp | 8808 ++++++++++++++++++---------------- Ground.h | 665 +-- Logs.cpp | 123 +- Logs.h | 4 +- Machajka.cpp | 110 +- Machajka.h | 19 +- MdlMngr.cpp | 251 +- MdlMngr.h | 32 +- MemCell.cpp | 247 +- MemCell.h | 59 +- Model3d.cpp | 3724 ++++++++------- Model3d.h | 581 +-- Mover.cpp | 1007 ++-- Mover.h | 310 +- Names.cpp | 231 +- Names.h | 85 +- RealSound.cpp | 441 +- RealSound.h | 96 +- ResourceManager.cpp | 34 +- ResourceManager.h | 20 +- Segment.cpp | 1618 ++++--- Segment.h | 195 +- Sound.cpp | 441 +- Sound.h | 64 +- Spline.cpp | 630 ++- Spline.h | 74 +- Spring.cpp | 81 +- Spring.h | 35 +- Texture.cpp | 1200 ++--- Texture.h | 20 +- TextureDDS.cpp | 503 +- TextureDDS.h | 21 +- Timer.cpp | 144 +- Timer.h | 5 +- Track.cpp | 5324 ++++++++++++--------- Track.h | 407 +- Traction.cpp | 1044 ++-- Traction.h | 115 +- TractionPower.cpp | 225 +- TractionPower.h | 66 +- Train.cpp | 10592 +++++++++++++++++++++-------------------- Train.h | 344 +- TrkFoll.cpp | 534 ++- TrkFoll.h | 62 +- VBO.cpp | 124 +- VBO.h | 45 +- World.cpp | 4690 +++++++++--------- World.h | 88 +- dumb3d.cpp | 603 +-- dumb3d.h | 845 ++-- geometry.cpp | 88 +- geometry.h | 8 +- parser.cpp | 311 +- parser.h | 82 +- sky.cpp | 79 +- sky.h | 15 +- usefull.h | 36 +- wavread.cpp | 183 +- wavread.h | 33 +- 99 files changed, 40728 insertions(+), 36059 deletions(-) diff --git a/AdvSound.cpp b/AdvSound.cpp index 8f7b4e41..55e66827 100644 --- a/AdvSound.cpp +++ b/AdvSound.cpp @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------- -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Timer.h" @@ -11,171 +11,166 @@ __fastcall TAdvancedSound::TAdvancedSound() { -// SoundStart=SoundCommencing=SoundShut= NULL; - State=ss_Off; - fTime=0; - fStartLength=0; - fShutLength=0; + // SoundStart=SoundCommencing=SoundShut= NULL; + State = ss_Off; + fTime = 0; + fStartLength = 0; + fShutLength = 0; } __fastcall TAdvancedSound::~TAdvancedSound() -{//Ra: stopowanie się sypie - //SoundStart.Stop(); - //SoundCommencing.Stop(); - //SoundShut.Stop(); +{ // Ra: stopowanie się sypie + // SoundStart.Stop(); + // SoundCommencing.Stop(); + // SoundShut.Stop(); } -void __fastcall TAdvancedSound::Free() -{ -} +void __fastcall TAdvancedSound::Free() {} -void __fastcall TAdvancedSound::Init(char *NameOn, char *Name, char *NameOff, double DistanceAttenuation, vector3 pPosition) +void __fastcall TAdvancedSound::Init(char *NameOn, char *Name, char *NameOff, + double DistanceAttenuation, vector3 pPosition) { - SoundStart.Init(NameOn,DistanceAttenuation,pPosition.x,pPosition.y,pPosition.z,true); - SoundCommencing.Init(Name,DistanceAttenuation,pPosition.x,pPosition.y,pPosition.z,true); - SoundShut.Init(NameOff,DistanceAttenuation,pPosition.x,pPosition.y,pPosition.z,true); - fStartLength=SoundStart.GetWaveTime(); - fShutLength=SoundShut.GetWaveTime(); - SoundStart.AM=1.0; - SoundStart.AA=0.0; - SoundStart.FM=1.0; - SoundStart.FA=0.0; - SoundCommencing.AM=1.0; - SoundCommencing.AA=0.0; - SoundCommencing.FM=1.0; - SoundCommencing.FA=0.0; - defAM=1.0; - defFM=1.0; - SoundShut.AM=1.0; - SoundShut.AA=0.0; - SoundShut.FM=1.0; - SoundShut.FA=0.0; + SoundStart.Init(NameOn, DistanceAttenuation, pPosition.x, pPosition.y, pPosition.z, true); + SoundCommencing.Init(Name, DistanceAttenuation, pPosition.x, pPosition.y, pPosition.z, true); + SoundShut.Init(NameOff, DistanceAttenuation, pPosition.x, pPosition.y, pPosition.z, true); + fStartLength = SoundStart.GetWaveTime(); + fShutLength = SoundShut.GetWaveTime(); + SoundStart.AM = 1.0; + SoundStart.AA = 0.0; + SoundStart.FM = 1.0; + SoundStart.FA = 0.0; + SoundCommencing.AM = 1.0; + SoundCommencing.AA = 0.0; + SoundCommencing.FM = 1.0; + SoundCommencing.FA = 0.0; + defAM = 1.0; + defFM = 1.0; + SoundShut.AM = 1.0; + SoundShut.AA = 0.0; + SoundShut.FM = 1.0; + SoundShut.FA = 0.0; } void __fastcall TAdvancedSound::Load(TQueryParserComp *Parser, vector3 pPosition) { - AnsiString NameOn= Parser->GetNextSymbol().LowerCase(); - AnsiString Name= Parser->GetNextSymbol().LowerCase(); - AnsiString NameOff= Parser->GetNextSymbol().LowerCase(); - double DistanceAttenuation= Parser->GetNextSymbol().ToDouble(); - Init(NameOn.c_str(),Name.c_str(),NameOff.c_str(),DistanceAttenuation,pPosition); + AnsiString NameOn = Parser->GetNextSymbol().LowerCase(); + AnsiString Name = Parser->GetNextSymbol().LowerCase(); + AnsiString NameOff = Parser->GetNextSymbol().LowerCase(); + double DistanceAttenuation = Parser->GetNextSymbol().ToDouble(); + Init(NameOn.c_str(), Name.c_str(), NameOff.c_str(), DistanceAttenuation, pPosition); } void __fastcall TAdvancedSound::TurnOn(bool ListenerInside, vector3 NewPosition) { - //hunter-311211: nie trzeba czekac na ponowne odtworzenie dzwieku, az sie wylaczy - if ((State==ss_Off || State==ss_ShuttingDown) && (SoundStart.AM>0)) + // hunter-311211: nie trzeba czekac na ponowne odtworzenie dzwieku, az sie wylaczy + if ((State == ss_Off || State == ss_ShuttingDown) && (SoundStart.AM > 0)) { SoundStart.ResetPosition(); SoundCommencing.ResetPosition(); - SoundStart.Play(1,0,ListenerInside,NewPosition); -// SoundStart->SetVolume(-10000); - State= ss_Starting; - fTime= 0; + SoundStart.Play(1, 0, ListenerInside, NewPosition); + // SoundStart->SetVolume(-10000); + State = ss_Starting; + fTime = 0; } } void __fastcall TAdvancedSound::TurnOff(bool ListenerInside, vector3 NewPosition) { - if ((State==ss_Commencing || State==ss_Starting) && (SoundShut.AM>0)) + if ((State == ss_Commencing || State == ss_Starting) && (SoundShut.AM > 0)) { SoundStart.Stop(); SoundCommencing.Stop(); SoundShut.ResetPosition(); - SoundShut.Play(1,0,ListenerInside,NewPosition); - State= ss_ShuttingDown; - fTime= fShutLength; -// SoundShut->SetVolume(0); + SoundShut.Play(1, 0, ListenerInside, NewPosition); + State = ss_ShuttingDown; + fTime = fShutLength; + // SoundShut->SetVolume(0); } } void __fastcall TAdvancedSound::Update(bool ListenerInside, vector3 NewPosition) { - if ((State==ss_Commencing) && (SoundCommencing.AM>0)) + if ((State == ss_Commencing) && (SoundCommencing.AM > 0)) { -// SoundCommencing->SetFrequency(); - SoundShut.Stop(); //hunter-311211 - SoundCommencing.Play(1,DSBPLAY_LOOPING,ListenerInside,NewPosition); + // SoundCommencing->SetFrequency(); + SoundShut.Stop(); // hunter-311211 + SoundCommencing.Play(1, DSBPLAY_LOOPING, ListenerInside, NewPosition); } - else - if (State==ss_Starting) + else if (State == ss_Starting) { - fTime+= Timer::GetDeltaTime(); -// SoundStart->SetVolume(-1000*(4-fTime)/4); - if (fTime>=fStartLength) + fTime += Timer::GetDeltaTime(); + // SoundStart->SetVolume(-1000*(4-fTime)/4); + if (fTime >= fStartLength) { - State= ss_Commencing; + State = ss_Commencing; SoundCommencing.ResetPosition(); - SoundCommencing.Play(1,DSBPLAY_LOOPING,ListenerInside,NewPosition); + SoundCommencing.Play(1, DSBPLAY_LOOPING, ListenerInside, NewPosition); SoundStart.Stop(); - } else - SoundStart.Play(1,0,ListenerInside,NewPosition); + SoundStart.Play(1, 0, ListenerInside, NewPosition); } - else - if (State==ss_ShuttingDown) + else if (State == ss_ShuttingDown) { - fTime-= Timer::GetDeltaTime(); -// SoundShut->SetVolume(-1000*(4-fTime)/4); - if (fTime<=0) + fTime -= Timer::GetDeltaTime(); + // SoundShut->SetVolume(-1000*(4-fTime)/4); + if (fTime <= 0) { - State= ss_Off; + State = ss_Off; SoundShut.Stop(); } else - SoundShut.Play(1,0,ListenerInside,NewPosition); + SoundShut.Play(1, 0, ListenerInside, NewPosition); } } -void __fastcall TAdvancedSound::UpdateAF(double A, double F, bool ListenerInside, vector3 NewPosition) -{ //update, ale z amplituda i czestotliwoscia - if ((State==ss_Commencing) && (SoundCommencing.AM>0)) +void __fastcall TAdvancedSound::UpdateAF(double A, double F, bool ListenerInside, + vector3 NewPosition) +{ // update, ale z amplituda i czestotliwoscia + if ((State == ss_Commencing) && (SoundCommencing.AM > 0)) { - SoundShut.Stop(); //hunter-311211 - SoundCommencing.Play(A,DSBPLAY_LOOPING,ListenerInside,NewPosition); + SoundShut.Stop(); // hunter-311211 + SoundCommencing.Play(A, DSBPLAY_LOOPING, ListenerInside, NewPosition); } - else - if (State==ss_Starting) + else if (State == ss_Starting) { - fTime+= Timer::GetDeltaTime(); -// SoundStart->SetVolume(-1000*(4-fTime)/4); - if (fTime>=fStartLength) + fTime += Timer::GetDeltaTime(); + // SoundStart->SetVolume(-1000*(4-fTime)/4); + if (fTime >= fStartLength) { - State= ss_Commencing; + State = ss_Commencing; SoundCommencing.ResetPosition(); - SoundCommencing.Play(A,DSBPLAY_LOOPING,ListenerInside,NewPosition); + SoundCommencing.Play(A, DSBPLAY_LOOPING, ListenerInside, NewPosition); SoundStart.Stop(); } else - SoundStart.Play(A,0,ListenerInside,NewPosition); + SoundStart.Play(A, 0, ListenerInside, NewPosition); } - else - if (State==ss_ShuttingDown) + else if (State == ss_ShuttingDown) { - fTime-= Timer::GetDeltaTime(); -// SoundShut->SetVolume(-1000*(4-fTime)/4); - if (fTime<=0) + fTime -= Timer::GetDeltaTime(); + // SoundShut->SetVolume(-1000*(4-fTime)/4); + if (fTime <= 0) { - State= ss_Off; + State = ss_Off; SoundShut.Stop(); } else - SoundShut.Play(A,0,ListenerInside,NewPosition); + SoundShut.Play(A, 0, ListenerInside, NewPosition); } - SoundCommencing.AdjFreq(F,Timer::GetDeltaTime()); + SoundCommencing.AdjFreq(F, Timer::GetDeltaTime()); } void __fastcall TAdvancedSound::CopyIfEmpty(TAdvancedSound &s) -{//skopiowanie, gdyby był potrzebny, a nie został wczytany - if ((fStartLength>0.0)||(fShutLength>0.0)) return; //coś jest - SoundStart=s.SoundStart; - SoundCommencing=s.SoundCommencing; - SoundShut=s.SoundShut; - State=s.State; - fStartLength=s.fStartLength; - fShutLength=s.fShutLength; - defAM=s.defAM; - defFM=s.defFM; +{ // skopiowanie, gdyby był potrzebny, a nie został wczytany + if ((fStartLength > 0.0) || (fShutLength > 0.0)) + return; // coś jest + SoundStart = s.SoundStart; + SoundCommencing = s.SoundCommencing; + SoundShut = s.SoundShut; + State = s.State; + fStartLength = s.fStartLength; + fShutLength = s.fShutLength; + defAM = s.defAM; + defFM = s.defFM; }; - diff --git a/AdvSound.h b/AdvSound.h index 66d961cd..75771d7c 100644 --- a/AdvSound.h +++ b/AdvSound.h @@ -6,10 +6,16 @@ #include "RealSound.h" #include "QueryParserComp.hpp" -typedef enum {ss_Off, ss_Starting, ss_Commencing, ss_ShuttingDown} TSoundState; +typedef enum +{ + 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) +{ // klasa dźwięków mających początek, dowolnie długi środek oraz zakończenie (np. Rp1) TRealSound SoundStart; TRealSound SoundCommencing; TRealSound SoundShut; @@ -20,17 +26,18 @@ class TAdvancedSound double defAM; double defFM; -public: + public: __fastcall TAdvancedSound(); __fastcall ~TAdvancedSound(); - void __fastcall Init(char *NameOn, char *Name, char *NameOff, double DistanceAttenuation, vector3 pPosition); + void __fastcall Init(char *NameOn, char *Name, char *NameOff, double DistanceAttenuation, + vector3 pPosition); void __fastcall Load(TQueryParserComp *Parser, vector3 pPosition); void __fastcall TurnOn(bool ListenerInside, vector3 NewPosition); void __fastcall TurnOff(bool ListenerInside, vector3 NewPosition); void __fastcall Free(); void __fastcall Update(bool ListenerInside, vector3 NewPosition); void __fastcall UpdateAF(double A, double F, bool ListenerInside, vector3 NewPosition); - void __fastcall CopyIfEmpty(TAdvancedSound &s); + void __fastcall CopyIfEmpty(TAdvancedSound &s); }; //--------------------------------------------------------------------------- diff --git a/AirCoupler.cpp b/AirCoupler.cpp index 18e7e061..9405a7db 100644 --- a/AirCoupler.cpp +++ b/AirCoupler.cpp @@ -1,71 +1,68 @@ //--------------------------------------------------------------------------- -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "AirCoupler.h" #include "Timer.h" -__fastcall TAirCoupler::TAirCoupler() -{ - Clear(); -} +__fastcall TAirCoupler::TAirCoupler() { Clear(); } -__fastcall TAirCoupler::~TAirCoupler() -{ -} +__fastcall TAirCoupler::~TAirCoupler() {} int __fastcall TAirCoupler::GetStatus() -{//zwraca 1, jeśli istnieje model prosty, 2 gdy skośny - int x=0; - if (pModelOn) x=1; - if (pModelxOn) x=2; - return x; +{ // zwraca 1, jeśli istnieje model prosty, 2 gdy skośny + int x = 0; + if (pModelOn) + x = 1; + if (pModelxOn) + x = 2; + return x; } void __fastcall TAirCoupler::Clear() -{//zerowanie wskaźników - pModelOn=NULL; - pModelOff=NULL; - pModelxOn=NULL; - bOn=false; - bxOn=false; +{ // zerowanie wskaźników + pModelOn = NULL; + pModelOff = NULL; + pModelxOn = NULL; + bOn = false; + bxOn = false; } - void __fastcall TAirCoupler::Init(AnsiString asName, TModel3d *pModel) -{//wyszukanie submodeli - if (!pModel) return; //nie ma w czym szukać - pModelOn=pModel->GetFromName(AnsiString(asName+"_on").c_str()); //połączony na wprost - pModelOff=pModel->GetFromName(AnsiString(asName+"_off").c_str()); //odwieszony - pModelxOn=pModel->GetFromName(AnsiString(asName+"_xon").c_str()); //połączony na skos +{ // wyszukanie submodeli + if (!pModel) + return; // nie ma w czym szukać + pModelOn = pModel->GetFromName(AnsiString(asName + "_on").c_str()); // połączony na wprost + pModelOff = pModel->GetFromName(AnsiString(asName + "_off").c_str()); // odwieszony + pModelxOn = pModel->GetFromName(AnsiString(asName + "_xon").c_str()); // połączony na skos } void __fastcall TAirCoupler::Load(TQueryParserComp *Parser, TModel3d *pModel) { - AnsiString str=Parser->GetNextSymbol().LowerCase(); - if (pModel) - Init(str,pModel); - else - { - pModelOn=NULL; - pModelxOn=NULL; - pModelOff=NULL; - } + AnsiString str = Parser->GetNextSymbol().LowerCase(); + if (pModel) + Init(str, pModel); + else + { + pModelOn = NULL; + pModelxOn = NULL; + pModelOff = NULL; + } } void __fastcall TAirCoupler::Update() { -// if ((pModelOn!=NULL) && (pModelOn!=NULL)) - { - if (pModelOn) - pModelOn->iVisible=bOn; - if (pModelOff) - pModelOff->iVisible=!(bOn||bxOn); - if (pModelxOn) - pModelxOn->iVisible=bxOn; - } + // if ((pModelOn!=NULL) && (pModelOn!=NULL)) + { + if (pModelOn) + pModelOn->iVisible = bOn; + if (pModelOff) + pModelOff->iVisible = !(bOn || bxOn); + if (pModelxOn) + pModelxOn->iVisible = bxOn; + } } //--------------------------------------------------------------------------- diff --git a/AirCoupler.h b/AirCoupler.h index 8a966dfe..42fca9bd 100644 --- a/AirCoupler.h +++ b/AirCoupler.h @@ -8,24 +8,40 @@ class TAirCoupler { -private: -// TButtonType eType; - TSubModel *pModelOn,*pModelOff,*pModelxOn; - bool bOn; - bool bxOn; - void __fastcall Update(); -public: - __fastcall TAirCoupler(); - __fastcall ~TAirCoupler(); - void __fastcall Clear(); - inline void TurnOn() { bOn=true; bxOn=false; Update(); }; - inline void TurnOff() { bOn=false; bxOn=false; Update(); }; - inline void TurnxOn() { bOn=false; bxOn=true; Update(); }; -// inline bool Active() { if ((pModelOn)||(pModelOff)) return true; return false;}; - int __fastcall GetStatus(); - void __fastcall Init(AnsiString asName, TModel3d *pModel); - void __fastcall Load(TQueryParserComp *Parser, TModel3d *pModel); -// bool __fastcall Render(); + private: + // TButtonType eType; + TSubModel *pModelOn, *pModelOff, *pModelxOn; + bool bOn; + bool bxOn; + void __fastcall Update(); + + public: + __fastcall TAirCoupler(); + __fastcall ~TAirCoupler(); + void __fastcall Clear(); + inline void TurnOn() + { + bOn = true; + bxOn = false; + Update(); + }; + inline void TurnOff() + { + bOn = false; + bxOn = false; + Update(); + }; + inline void TurnxOn() + { + bOn = false; + bxOn = true; + Update(); + }; + // inline bool Active() { if ((pModelOn)||(pModelOff)) return true; return false;}; + int __fastcall GetStatus(); + void __fastcall Init(AnsiString asName, TModel3d *pModel); + void __fastcall Load(TQueryParserComp *Parser, TModel3d *pModel); + // bool __fastcall Render(); }; //--------------------------------------------------------------------------- diff --git a/AnimModel.cpp b/AnimModel.cpp index ff53f48f..6b737952 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -5,348 +5,392 @@ */ -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "AnimModel.h" #include "usefull.h" #include "Timer.h" #include "MdlMngr.h" -//McZapkie: +// McZapkie: #include "Texture.h" #include "Globals.h" //--------------------------------------------------------------------------- #pragma package(smart_init) //--------------------------------------------------------------------------- - -__fastcall TAnimAdvanced::TAnimAdvanced() -{ -}; -__fastcall TAnimAdvanced::~TAnimAdvanced() -{ - //delete[] pVocaloidMotionData; //plik został zmodyfikowany +__fastcall TAnimAdvanced::TAnimAdvanced(){}; +__fastcall TAnimAdvanced::~TAnimAdvanced(){ + // delete[] pVocaloidMotionData; //plik został zmodyfikowany }; int __fastcall TAnimAdvanced::SortByBone() -{//sortowanie pliku animacji w celu optymalniejszego wykonania - //rekordy zostają ułożone wg kolejnych ramek dla każdej kości - //ułożenie kości alfabetycznie nie jest niezbędne, ale upraszcza sortowanie bąbelkowe - TAnimVocaloidFrame buf; //bufor roboczy (przydało by się pascalowe Swap() - int i,j,k,swaps=0,last=iMovements-1,e; - for (i=0;i0) - k=j; //trzeba zamienić - ten pod j jest mniejszy - else if (!e) - if (pMovementData[k].iFrame>pMovementData[j].iFrame) - k=j; //numer klatki pod j jest mniejszy - } - if (k>i) - {//jeśli trzeba przestawić - //buf=pMovementData[i]; - //pMovementData[i]=pMovementData[k]; - //pMovementData[k]=buf; - memcpy(&buf,pMovementData+i,sizeof(TAnimVocaloidFrame)); - memcpy(pMovementData+i,pMovementData+k,sizeof(TAnimVocaloidFrame)); - memcpy(pMovementData+k,&buf,sizeof(TAnimVocaloidFrame)); - ++swaps; - } - } - return swaps; +{ // sortowanie pliku animacji w celu optymalniejszego wykonania + // rekordy zostają ułożone wg kolejnych ramek dla każdej kości + // ułożenie kości alfabetycznie nie jest niezbędne, ale upraszcza sortowanie bąbelkowe + TAnimVocaloidFrame buf; // bufor roboczy (przydało by się pascalowe Swap() + int i, j, k, swaps = 0, last = iMovements - 1, e; + for (i = 0; i < iMovements; ++i) + for (j = 0; j < 15; ++j) + if (pMovementData[i].cBone[j] == '\0') // jeśli znacznik końca + for (++j; j < 15; ++j) + pMovementData[i].cBone[j] = '\0'; // zerowanie bajtów za znacznikiem końca + for (i = 0; i < last; ++i) // do przedostatniego + { // dopóki nie posortowane + j = i; // z którym porównywać + k = i; // z którym zamienić (nie trzeba zamieniać, jeśli ==i) + while (++j < iMovements) + { + e = strcmp(pMovementData[k].cBone, + pMovementData[j].cBone); // numery trzeba porównywać inaczej + if (e > 0) + k = j; // trzeba zamienić - ten pod j jest mniejszy + else if (!e) + if (pMovementData[k].iFrame > pMovementData[j].iFrame) + k = j; // numer klatki pod j jest mniejszy + } + if (k > i) + { // jeśli trzeba przestawić + // buf=pMovementData[i]; + // pMovementData[i]=pMovementData[k]; + // pMovementData[k]=buf; + memcpy(&buf, pMovementData + i, sizeof(TAnimVocaloidFrame)); + memcpy(pMovementData + i, pMovementData + k, sizeof(TAnimVocaloidFrame)); + memcpy(pMovementData + k, &buf, sizeof(TAnimVocaloidFrame)); + ++swaps; + } + } + return swaps; }; __fastcall TAnimContainer::TAnimContainer() { - pNext=NULL; - vRotateAngles=vector3(0.0f,0.0f,0.0f); //aktualne kąty obrotu - vDesiredAngles=vector3(0.0f,0.0f,0.0f); //docelowe kąty obrotu - fRotateSpeed=0.0; - vTranslation=vector3(0.0f,0.0f,0.0f); //aktualne przesunięcie - vTranslateTo=vector3(0.0f,0.0f,0.0f); //docelowe przesunięcie - fTranslateSpeed=0.0; - fAngleSpeed=0.0; - pSubModel=NULL; - iAnim=0; //położenie początkowe - pMovementData=NULL; //nie ma zaawansowanej animacji - mAnim=NULL; //nie ma macierzy obrotu dla submodelu - evDone=NULL; //powiadamianie o zakończeniu animacji - acAnimNext=NULL; //na razie jest poza listą + pNext = NULL; + vRotateAngles = vector3(0.0f, 0.0f, 0.0f); // aktualne kąty obrotu + vDesiredAngles = vector3(0.0f, 0.0f, 0.0f); // docelowe kąty obrotu + fRotateSpeed = 0.0; + vTranslation = vector3(0.0f, 0.0f, 0.0f); // aktualne przesunięcie + vTranslateTo = vector3(0.0f, 0.0f, 0.0f); // docelowe przesunięcie + fTranslateSpeed = 0.0; + fAngleSpeed = 0.0; + pSubModel = NULL; + iAnim = 0; // położenie początkowe + pMovementData = NULL; // nie ma zaawansowanej animacji + mAnim = NULL; // nie ma macierzy obrotu dla submodelu + evDone = NULL; // powiadamianie o zakończeniu animacji + acAnimNext = NULL; // na razie jest poza listą } __fastcall TAnimContainer::~TAnimContainer() { - SafeDelete(pNext); - delete mAnim; //AnimContainer jest właścicielem takich macierzy + SafeDelete(pNext); + delete mAnim; // AnimContainer jest właścicielem takich macierzy } bool __fastcall TAnimContainer::Init(TSubModel *pNewSubModel) { - fRotateSpeed=0.0f; - pSubModel=pNewSubModel; - return (pSubModel!=NULL); + fRotateSpeed = 0.0f; + pSubModel = pNewSubModel; + return (pSubModel != NULL); } void __fastcall TAnimContainer::SetRotateAnim(vector3 vNewRotateAngles, double fNewRotateSpeed) { - if (!this) return; //wywoływane z eventu, gdy brak modelu - vDesiredAngles=vNewRotateAngles; - fRotateSpeed=fNewRotateSpeed; - iAnim|=1; -/* //Ra 2014-07: jeśli model nie jest renderowany, to obliczyć czas animacji i dodać event wewnętrzny - //można by też ustawić czas początku animacji zamiast pobierać czas ramki i liczyć różnicę -*/ - if (evDone) - {//dołączyć model do listy aniomowania, żeby animacje były przeliczane również bez wyświetlania - if (iAnim>=0) - {//jeśli nie jest jeszcze na liście animacyjnej - acAnimNext=TAnimModel::acAnimList; //pozostałe doklić sobie jako ogon - TAnimModel::acAnimList=this; //a wstawić się na początek - iAnim|=0x80000000; //dodany do listy - } - } + if (!this) + return; // wywoływane z eventu, gdy brak modelu + vDesiredAngles = vNewRotateAngles; + fRotateSpeed = fNewRotateSpeed; + iAnim |= 1; + /* //Ra 2014-07: jeśli model nie jest renderowany, to obliczyć czas animacji i dodać event + wewnętrzny + //można by też ustawić czas początku animacji zamiast pobierać czas ramki i liczyć różnicę + */ + if (evDone) + { // dołączyć model do listy aniomowania, żeby animacje były przeliczane również bez + // wyświetlania + if (iAnim >= 0) + { // jeśli nie jest jeszcze na liście animacyjnej + acAnimNext = TAnimModel::acAnimList; // pozostałe doklić sobie jako ogon + TAnimModel::acAnimList = this; // a wstawić się na początek + iAnim |= 0x80000000; // dodany do listy + } + } } void __fastcall TAnimContainer::SetTranslateAnim(vector3 vNewTranslate, double fNewSpeed) { - if (!this) return; //wywoływane z eventu, gdy brak modelu - vTranslateTo=vNewTranslate; - fTranslateSpeed=fNewSpeed; - iAnim|=2; -/* //Ra 2014-07: jeśli model nie jest renderowany, to obliczyć czas animacji i dodać event wewnętrzny - //można by też ustawić czas początku animacji zamiast pobierać czas ramki i liczyć różnicę -*/ - if (evDone) - {//dołączyć model do listy aniomowania, żeby animacje były przeliczane również bez wyświetlania - if (iAnim>=0) - {//jeśli nie jest jeszcze na liście animacyjnej - acAnimNext=TAnimModel::acAnimList; //pozostałe doklić sobie jako ogon - TAnimModel::acAnimList=this; //a wstawić się na początek - iAnim|=0x80000000; //dodany do listy - } - } + if (!this) + return; // wywoływane z eventu, gdy brak modelu + vTranslateTo = vNewTranslate; + fTranslateSpeed = fNewSpeed; + iAnim |= 2; + /* //Ra 2014-07: jeśli model nie jest renderowany, to obliczyć czas animacji i dodać event + wewnętrzny + //można by też ustawić czas początku animacji zamiast pobierać czas ramki i liczyć różnicę + */ + if (evDone) + { // dołączyć model do listy aniomowania, żeby animacje były przeliczane również bez + // wyświetlania + if (iAnim >= 0) + { // jeśli nie jest jeszcze na liście animacyjnej + acAnimNext = TAnimModel::acAnimList; // pozostałe doklić sobie jako ogon + TAnimModel::acAnimList = this; // a wstawić się na początek + iAnim |= 0x80000000; // dodany do listy + } + } } void __fastcall TAnimContainer::AnimSetVMD(double fNewSpeed) { - if (!this) return; //wywoływane z eventu, gdy brak modelu - //skala do ustalenia, "cal" japoński (sun) to nieco ponad 3cm - //X-w lewo, Y-w górę, Z-do tyłu - //minimalna wysokość to -7.66, a nadal musi być ponad podłogą - //if (pMovementData->iFrame>0) return; //tylko pierwsza ramka - vTranslateTo=vector3(0.1*pMovementData->f3Vector.x,0.1*pMovementData->f3Vector.z,0.1*pMovementData->f3Vector.y); - if (LengthSquared3(vTranslateTo)>0.0?true:LengthSquared3(vTranslation)>0.0) - {//jeśli ma być przesunięte albo jest przesunięcie - iAnim|=2; //wyłączy się samo - if (fNewSpeed>0.0) - fTranslateSpeed=fNewSpeed; //prędkość jest mnożnikiem, nie podlega skalowaniu - else //za późno na animacje, trzeba przestawić - vTranslation=vTranslateTo; - } - //if ((qCurrent.w<1.0)||(pMovementData->qAngle.w<1.0)) - {//jeśli jest jakiś obrót - if (!mAnim) - {mAnim=new float4x4(); //będzie potrzebna macierz animacji - mAnim->Identity(); //jedynkowanie na początek - } - iAnim|=4; //animacja kwaternionowa - qStart=qCurrent; //potrzebna początkowa do interpolacji - //---+ - też niby dobrze, ale nie tak trąca włosy na początku (macha w dół) - //-+-+ - dłoń ma w górze zamiast na pasie w pozycji początkowej - //+--+ - głowa do tyłu (broda w górę) w pozycji początkowej - //--++ - pozycja początkowa dobra, trąca u góry, ale z rękami jakoś nie tak, kółko w przeciwną stronę - //++++ - kładzie się brzuchem do góry - //-+++ - ręce w górze na początku, zamiast w dół, łokieć jakby w przeciwną stronę - //+-++ - nie podnosi ręki do głowy - //++-+ - dłoń ma w górze zamiast na pasie - qDesired=Normalize(float4(-pMovementData->qAngle.x,-pMovementData->qAngle.z,-pMovementData->qAngle.y,pMovementData->qAngle.w)); //tu trzeba będzie osie zamienić - if (fNewSpeed>0.0) - {fAngleSpeed=fNewSpeed; //wtedy animować za pomocą interpolacji - fAngleCurrent=0.0; //początek interpolacji - } - else - {//za późno na animację, można tylko przestawić w docelowe miejsce - fAngleSpeed=0.0; - fAngleCurrent=1.0; //interpolacja zakończona - qCurrent=qDesired; - } - } - //if (!strcmp(pSubModel->pName,"?Z?“?^?[")) //jak główna kość - //if (!strcmp(pSubModel->pName,"Ť¶‚‚Ü?ć‚h‚j")) //IK lewej stopy - // WriteLog(AnsiString(pMovementData->iFrame)+": "+AnsiString(pMovementData->f3Vector.x)+" "+AnsiString(pMovementData->f3Vector.y)+" "+AnsiString(pMovementData->f3Vector.z)); + if (!this) + return; // wywoływane z eventu, gdy brak modelu + // skala do ustalenia, "cal" japoński (sun) to nieco ponad 3cm + // X-w lewo, Y-w górę, Z-do tyłu + // minimalna wysokość to -7.66, a nadal musi być ponad podłogą + // if (pMovementData->iFrame>0) return; //tylko pierwsza ramka + vTranslateTo = vector3(0.1 * pMovementData->f3Vector.x, 0.1 * pMovementData->f3Vector.z, + 0.1 * pMovementData->f3Vector.y); + if (LengthSquared3(vTranslateTo) > 0.0 ? true : LengthSquared3(vTranslation) > 0.0) + { // jeśli ma być przesunięte albo jest przesunięcie + iAnim |= 2; // wyłączy się samo + if (fNewSpeed > 0.0) + fTranslateSpeed = fNewSpeed; // prędkość jest mnożnikiem, nie podlega skalowaniu + else // za późno na animacje, trzeba przestawić + vTranslation = vTranslateTo; + } + // if ((qCurrent.w<1.0)||(pMovementData->qAngle.w<1.0)) + { // jeśli jest jakiś obrót + if (!mAnim) + { + mAnim = new float4x4(); // będzie potrzebna macierz animacji + mAnim->Identity(); // jedynkowanie na początek + } + iAnim |= 4; // animacja kwaternionowa + qStart = qCurrent; // potrzebna początkowa do interpolacji + //---+ - też niby dobrze, ale nie tak trąca włosy na początku (macha w dół) + //-+-+ - dłoń ma w górze zamiast na pasie w pozycji początkowej + //+--+ - głowa do tyłu (broda w górę) w pozycji początkowej + //--++ - pozycja początkowa dobra, trąca u góry, ale z rękami jakoś nie tak, kółko w + //przeciwną stronę + //++++ - kładzie się brzuchem do góry + //-+++ - ręce w górze na początku, zamiast w dół, łokieć jakby w przeciwną stronę + //+-++ - nie podnosi ręki do głowy + //++-+ - dłoń ma w górze zamiast na pasie + qDesired = Normalize(float4(-pMovementData->qAngle.x, -pMovementData->qAngle.z, + -pMovementData->qAngle.y, + pMovementData->qAngle.w)); // tu trzeba będzie osie zamienić + if (fNewSpeed > 0.0) + { + fAngleSpeed = fNewSpeed; // wtedy animować za pomocą interpolacji + fAngleCurrent = 0.0; // początek interpolacji + } + else + { // za późno na animację, można tylko przestawić w docelowe miejsce + fAngleSpeed = 0.0; + fAngleCurrent = 1.0; // interpolacja zakończona + qCurrent = qDesired; + } + } + // if (!strcmp(pSubModel->pName,"?Z?“?^?[")) //jak główna kość + // if (!strcmp(pSubModel->pName,"Ť¶‚‚Ü?ć‚h‚j")) //IK lewej stopy + // WriteLog(AnsiString(pMovementData->iFrame)+": "+AnsiString(pMovementData->f3Vector.x)+" + // "+AnsiString(pMovementData->f3Vector.y)+" "+AnsiString(pMovementData->f3Vector.z)); } void __fastcall TAnimContainer::UpdateModel() -{//przeliczanie animacji wykonać tylko raz na model - if (pSubModel) //pozbyć się tego - sprawdzać wcześniej - { - if (fTranslateSpeed!=0.0) - { - vector3 dif=vTranslateTo-vTranslation; //wektor w kierunku docelowym - double l=LengthSquared3(dif); //długość wektora potrzebnego przemieszczenia - if (l>=0.0001) - {//jeśli do przemieszczenia jest ponad 1cm - vector3 s=SafeNormalize(dif); //jednostkowy wektor kierunku - s=s*(fTranslateSpeed*Timer::GetDeltaTime()); //przemieszczenie w podanym czasie z daną prędkością - if (LengthSquared3(s)= 0.0001) + { // jeśli do przemieszczenia jest ponad 1cm + vector3 s = SafeNormalize(dif); // jednostkowy wektor kierunku + s = s * + (fTranslateSpeed * + Timer::GetDeltaTime()); // przemieszczenie w podanym czasie z daną prędkością + if (LengthSquared3(s) < l) //żeby nie jechało na drugą stronę + vTranslation += s; + else + vTranslation = vTranslateTo; // koniec animacji, "koniec animowania" uruchomi + // się w następnej klatce + } + else + { // koniec animowania + vTranslation = vTranslateTo; + fTranslateSpeed = 0.0; // wyłączenie przeliczania wektora + if (LengthSquared3(vTranslation) <= 0.0001) // jeśli jest w punkcie początkowym + iAnim &= ~2; // wyłączyć zmianę pozycji submodelu + if (evDone) + Global::AddToQuery(evDone, NULL); // wykonanie eventu informującego o + // zakończeniu + } + } + if (fRotateSpeed != 0) + { -/* - double dif= fDesiredAngle-fAngle; - double s= fRotateSpeed*sign(dif)*Timer::GetDeltaTime(); - if ((abs(s)-abs(dif))>0) - fAngle= fDesiredAngle; - else - fAngle+= s; + /* + double dif= fDesiredAngle-fAngle; + double s= fRotateSpeed*sign(dif)*Timer::GetDeltaTime(); + if ((abs(s)-abs(dif))>0) + fAngle= fDesiredAngle; + else + fAngle+= s; - while (fAngle>360) fAngle-= 360; - while (fAngle<-360) fAngle+= 360; - pSubModel->SetRotate(vRotateAxis,fAngle); -*/ + while (fAngle>360) fAngle-= 360; + while (fAngle<-360) fAngle+= 360; + pSubModel->SetRotate(vRotateAxis,fAngle); + */ - bool anim=false; - vector3 dif=vDesiredAngles-vRotateAngles; - double s; - s=fRotateSpeed*sign(dif.x)*Timer::GetDeltaTime(); - if (fabs(s)>=fabs(dif.x)) - vRotateAngles.x=vDesiredAngles.x; - else - {vRotateAngles.x+=s; anim=true;} - s=fRotateSpeed*sign(dif.y)*Timer::GetDeltaTime(); - if (fabs(s)>=fabs(dif.y)) - vRotateAngles.y=vDesiredAngles.y; - else - {vRotateAngles.y+=s; anim=true;} - s=fRotateSpeed*sign(dif.z)*Timer::GetDeltaTime(); - if (fabs(s)>=fabs(dif.z)) - vRotateAngles.z=vDesiredAngles.z; - else - {vRotateAngles.z+=s; anim=true;} - while (vRotateAngles.x>= 360) vRotateAngles.x-=360; - while (vRotateAngles.x<=-360) vRotateAngles.x+=360; - while (vRotateAngles.y>= 360) vRotateAngles.y-=360; - while (vRotateAngles.y<=-360) vRotateAngles.y+=360; - while (vRotateAngles.z>= 360) vRotateAngles.z-=360; - while (vRotateAngles.z<=-360) vRotateAngles.z+=360; - if (vRotateAngles.x==0.0) - if (vRotateAngles.y==0.0) - if (vRotateAngles.z==0.0) - iAnim&=~1; //kąty są zerowe - if (!anim) - {//nie potrzeba przeliczać już - fRotateSpeed=0.0; - if (evDone) Global::AddToQuery(evDone,NULL); //wykonanie eventu informującego o zakończeniu - } - } - if (fAngleSpeed!=0.0) - {//obrót kwaternionu (interpolacja) - } - } + bool anim = false; + vector3 dif = vDesiredAngles - vRotateAngles; + double s; + s = fRotateSpeed * sign(dif.x) * Timer::GetDeltaTime(); + if (fabs(s) >= fabs(dif.x)) + vRotateAngles.x = vDesiredAngles.x; + else + { + vRotateAngles.x += s; + anim = true; + } + s = fRotateSpeed * sign(dif.y) * Timer::GetDeltaTime(); + if (fabs(s) >= fabs(dif.y)) + vRotateAngles.y = vDesiredAngles.y; + else + { + vRotateAngles.y += s; + anim = true; + } + s = fRotateSpeed * sign(dif.z) * Timer::GetDeltaTime(); + if (fabs(s) >= fabs(dif.z)) + vRotateAngles.z = vDesiredAngles.z; + else + { + vRotateAngles.z += s; + anim = true; + } + while (vRotateAngles.x >= 360) + vRotateAngles.x -= 360; + while (vRotateAngles.x <= -360) + vRotateAngles.x += 360; + while (vRotateAngles.y >= 360) + vRotateAngles.y -= 360; + while (vRotateAngles.y <= -360) + vRotateAngles.y += 360; + while (vRotateAngles.z >= 360) + vRotateAngles.z -= 360; + while (vRotateAngles.z <= -360) + vRotateAngles.z += 360; + if (vRotateAngles.x == 0.0) + if (vRotateAngles.y == 0.0) + if (vRotateAngles.z == 0.0) + iAnim &= ~1; // kąty są zerowe + if (!anim) + { // nie potrzeba przeliczać już + fRotateSpeed = 0.0; + if (evDone) + Global::AddToQuery(evDone, NULL); // wykonanie eventu informującego o + // zakończeniu + } + } + if (fAngleSpeed != 0.0) + { // obrót kwaternionu (interpolacja) + } + } }; void __fastcall TAnimContainer::PrepareModel() -{//tutaj zostawić tylko ustawienie submodelu, przeliczanie ma być w UpdateModel() - if (pSubModel) //pozbyć się tego - sprawdzać wcześniej - { - //nanoszenie animacji na wzorzec - if (iAnim&1) //zmieniona pozycja względem początkowej - pSubModel->SetRotateXYZ(vRotateAngles); //ustawia typ animacji - if (iAnim&2) //zmieniona pozycja względem początkowej - pSubModel->SetTranslate(vTranslation); - if (iAnim&4) //zmieniona pozycja względem początkowej - { - if (fAngleSpeed>0.0f) - {fAngleCurrent+=fAngleSpeed*Timer::GetDeltaTime(); //aktualny parametr interpolacji - if (fAngleCurrent>=1.0f) - {//interpolacja zakończona, ustawienie na pozycję końcową - qCurrent=qDesired; - fAngleSpeed=0.0; //wyłączenie przeliczania wektora - if (evDone) Global::AddToQuery(evDone,NULL); //wykonanie eventu informującego o zakończeniu +{ // tutaj zostawić tylko ustawienie submodelu, przeliczanie ma być w UpdateModel() + if (pSubModel) // pozbyć się tego - sprawdzać wcześniej + { + // nanoszenie animacji na wzorzec + if (iAnim & 1) // zmieniona pozycja względem początkowej + pSubModel->SetRotateXYZ(vRotateAngles); // ustawia typ animacji + if (iAnim & 2) // zmieniona pozycja względem początkowej + pSubModel->SetTranslate(vTranslation); + if (iAnim & 4) // zmieniona pozycja względem początkowej + { + if (fAngleSpeed > 0.0f) + { + fAngleCurrent += + fAngleSpeed * Timer::GetDeltaTime(); // aktualny parametr interpolacji + if (fAngleCurrent >= 1.0f) + { // interpolacja zakończona, ustawienie na pozycję końcową + qCurrent = qDesired; + fAngleSpeed = 0.0; // wyłączenie przeliczania wektora + if (evDone) + Global::AddToQuery(evDone, + NULL); // wykonanie eventu informującego o zakończeniu + } + else + { // obliczanie pozycji pośredniej + // normalizacja jest wymagana do interpolacji w następnej animacji + qCurrent = Normalize( + Slerp(qStart, qDesired, fAngleCurrent)); // interpolacja sferyczna kąta + // qCurrent=Slerp(qStart,qDesired,fAngleCurrent); //interpolacja sferyczna kąta + if (qCurrent.w == + 1.0) // rozpoznać brak obrotu i wyłączyć w iAnim w takim przypadku + iAnim &= ~4; // kąty są zerowe + } + } + mAnim->Quaternion(&qCurrent); // wypełnienie macierzy (wymaga normalizacji?) + pSubModel->mAnimMatrix = mAnim; // użyczenie do submodelu (na czas renderowania!) + } } - else - {//obliczanie pozycji pośredniej - //normalizacja jest wymagana do interpolacji w następnej animacji - qCurrent=Normalize(Slerp(qStart,qDesired,fAngleCurrent)); //interpolacja sferyczna kąta - //qCurrent=Slerp(qStart,qDesired,fAngleCurrent); //interpolacja sferyczna kąta - if (qCurrent.w==1.0) //rozpoznać brak obrotu i wyłączyć w iAnim w takim przypadku - iAnim&=~4; //kąty są zerowe - } - } - mAnim->Quaternion(&qCurrent); //wypełnienie macierzy (wymaga normalizacji?) - pSubModel->mAnimMatrix=mAnim; //użyczenie do submodelu (na czas renderowania!) - } - } - //if (!strcmp(pSubModel->pName,"?Z?“?^?[")) //jak główna kość - // WriteLog(AnsiString(pMovementData->iFrame)+": "+AnsiString(iAnim)+" "+AnsiString(vTranslation.x)+" "+AnsiString(vTranslation.y)+" "+AnsiString(vTranslation.z)); + // if (!strcmp(pSubModel->pName,"?Z?“?^?[")) //jak główna kość + // WriteLog(AnsiString(pMovementData->iFrame)+": "+AnsiString(iAnim)+" + // "+AnsiString(vTranslation.x)+" "+AnsiString(vTranslation.y)+" "+AnsiString(vTranslation.z)); } void __fastcall TAnimContainer::UpdateModelIK() -{//odwrotna kinematyka wyliczana dopiero po ustawieniu macierzy w submodelach - if (pSubModel) //pozbyć się tego - sprawdzać wcześniej - { - if (pSubModel->b_Anim&at_IK) - {//odwrotna kinematyka - float3 d,k; - TSubModel *ch=pSubModel->ChildGet(); - switch (pSubModel->b_Anim) - { - case at_IK11: //stopa: ustawić w kierunku czubka (pierwszy potomny) - d=ch->Translation1Get(); //wektor względem aktualnego układu (nie uwzględnia obrotu) - k=float3(RadToDeg(atan2(d.z,hypot(d.x,d.y))),0.0,-RadToDeg(atan2(d.y,d.x))); //proste skierowanie na punkt - pSubModel->SetRotateIK1(k); - //if (!strcmp(pSubModel->pName,"?Z?“?^?[")) //jak główna kość - // WriteLog("--> "+AnsiString(k.x)+" "+AnsiString(k.y)+" "+AnsiString(k.z)); - //Ra: to już jest dobrze, może być inna ćwiartka i znak - break; - case at_IK22: //udo: ustawić w kierunku pierwszej potomnej pierwszej potomnej (kostki) - //pozycję kostki należy określić względem kości centralnej (+biodro może być pochylone) - //potem wyliczyć ewentualne odchylenie w tej i następnej - //w sumie to proste, jak wyznaczenie kątów w trójkącie o znanej długości boków... - d=ch->Translation2Get(); //wektor względem aktualnego układu (nie uwzględnia obrotu) - //if () - {//kość IK jest dalej niż pozycja spoczynkowa - k=float3(RadToDeg(atan2(d.z,hypot(d.x,d.y))),0.0,-RadToDeg(atan2(d.y,d.x))); //proste skierowanie na punkt - pSubModel->SetRotateIK1(k); - } - break; - } - } - } +{ // odwrotna kinematyka wyliczana dopiero po ustawieniu macierzy w submodelach + if (pSubModel) // pozbyć się tego - sprawdzać wcześniej + { + if (pSubModel->b_Anim & at_IK) + { // odwrotna kinematyka + float3 d, k; + TSubModel *ch = pSubModel->ChildGet(); + switch (pSubModel->b_Anim) + { + case at_IK11: // stopa: ustawić w kierunku czubka (pierwszy potomny) + d = ch->Translation1Get(); // wektor względem aktualnego układu (nie uwzględnia + // obrotu) + k = float3(RadToDeg(atan2(d.z, hypot(d.x, d.y))), 0.0, + -RadToDeg(atan2(d.y, d.x))); // proste skierowanie na punkt + pSubModel->SetRotateIK1(k); + // if (!strcmp(pSubModel->pName,"?Z?“?^?[")) //jak główna kość + // WriteLog("--> "+AnsiString(k.x)+" "+AnsiString(k.y)+" "+AnsiString(k.z)); + // Ra: to już jest dobrze, może być inna ćwiartka i znak + break; + case at_IK22: // udo: ustawić w kierunku pierwszej potomnej pierwszej potomnej (kostki) + // pozycję kostki należy określić względem kości centralnej (+biodro może być + // pochylone) + // potem wyliczyć ewentualne odchylenie w tej i następnej + // w sumie to proste, jak wyznaczenie kątów w trójkącie o znanej długości boków... + d = ch->Translation2Get(); // wektor względem aktualnego układu (nie uwzględnia + // obrotu) + // if () + { // kość IK jest dalej niż pozycja spoczynkowa + k = float3(RadToDeg(atan2(d.z, hypot(d.x, d.y))), 0.0, + -RadToDeg(atan2(d.y, d.x))); // proste skierowanie na punkt + pSubModel->SetRotateIK1(k); + } + break; + } + } + } } bool __fastcall TAnimContainer::InMovement() -{//czy trwa animacja - informacja dla obrotnicy - return (fRotateSpeed!=0.0)||(fTranslateSpeed!=0.0); +{ // czy trwa animacja - informacja dla obrotnicy + return (fRotateSpeed != 0.0) || (fTranslateSpeed != 0.0); } void __fastcall TAnimContainer::EventAssign(TEvent *ev) -{//przypisanie eventu wykonywanego po zakończeniu animacji - evDone=ev; -}; +{ // przypisanie eventu wykonywanego po zakończeniu animacji evDone = ev; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ @@ -354,434 +398,460 @@ void __fastcall TAnimContainer::EventAssign(TEvent *ev) __fastcall TAnimModel::TAnimModel() { - pRoot=NULL; - pModel=NULL; - iNumLights=0; - fBlinkTimer=0; - ReplacableSkinId[0]=0; - ReplacableSkinId[1]=0; - ReplacableSkinId[2]=0; - ReplacableSkinId[3]=0; - ReplacableSkinId[4]=0; - for (int i=0;igetTokens(); //nazwa modelu - *parser >> token; - str=AnsiString(token.c_str()); - parser->getTokens(1,false); //tekstura (zmienia na małe) - *parser >> token; - if (!Init(str,AnsiString(token.c_str()))) - {if (str!="notload") - {//gdy brak modelu - if (ter) //jeśli teren - {if (str.SubString(str.Length()-3,4)==".t3d") - str[str.Length()-2]='e'; - Global::asTerrainModel=str; - WriteLog(AnsiString("Terrain model \""+str+"\" will be created.")); - } - else - ErrorLog(AnsiString("Missed file: "+str)); - } - } - else - {//wiązanie świateł, o ile model wczytany - LightsOn[0]=pModel->GetFromName("Light_On00"); - LightsOn[1]=pModel->GetFromName("Light_On01"); - LightsOn[2]=pModel->GetFromName("Light_On02"); - LightsOn[3]=pModel->GetFromName("Light_On03"); - LightsOn[4]=pModel->GetFromName("Light_On04"); - LightsOn[5]=pModel->GetFromName("Light_On05"); - LightsOn[6]=pModel->GetFromName("Light_On06"); - LightsOn[7]=pModel->GetFromName("Light_On07"); - LightsOff[0]=pModel->GetFromName("Light_Off00"); - LightsOff[1]=pModel->GetFromName("Light_Off01"); - LightsOff[2]=pModel->GetFromName("Light_Off02"); - LightsOff[3]=pModel->GetFromName("Light_Off03"); - LightsOff[4]=pModel->GetFromName("Light_Off04"); - LightsOff[5]=pModel->GetFromName("Light_Off05"); - LightsOff[6]=pModel->GetFromName("Light_Off06"); - LightsOff[7]=pModel->GetFromName("Light_Off07"); - } - for (int i=0;igetTokens(); // nazwa modelu + *parser >> token; + str = AnsiString(token.c_str()); + parser->getTokens(1, false); // tekstura (zmienia na małe) + *parser >> token; + if (!Init(str, AnsiString(token.c_str()))) + { + if (str != "notload") + { // gdy brak modelu + if (ter) // jeśli teren + { + if (str.SubString(str.Length() - 3, 4) == ".t3d") + str[str.Length() - 2] = 'e'; + Global::asTerrainModel = str; + WriteLog(AnsiString("Terrain model \"" + str + "\" will be created.")); + } + else + ErrorLog(AnsiString("Missed file: " + str)); + } + } + else + { // wiązanie świateł, o ile model wczytany + LightsOn[0] = pModel->GetFromName("Light_On00"); + LightsOn[1] = pModel->GetFromName("Light_On01"); + LightsOn[2] = pModel->GetFromName("Light_On02"); + LightsOn[3] = pModel->GetFromName("Light_On03"); + LightsOn[4] = pModel->GetFromName("Light_On04"); + LightsOn[5] = pModel->GetFromName("Light_On05"); + LightsOn[6] = pModel->GetFromName("Light_On06"); + LightsOn[7] = pModel->GetFromName("Light_On07"); + LightsOff[0] = pModel->GetFromName("Light_Off00"); + LightsOff[1] = pModel->GetFromName("Light_Off01"); + LightsOff[2] = pModel->GetFromName("Light_Off02"); + LightsOff[3] = pModel->GetFromName("Light_Off03"); + LightsOff[4] = pModel->GetFromName("Light_Off04"); + LightsOff[5] = pModel->GetFromName("Light_Off05"); + LightsOff[6] = pModel->GetFromName("Light_Off06"); + LightsOff[7] = pModel->GetFromName("Light_Off07"); + } + for (int i = 0; i < iMaxNumLights; ++i) + if (LightsOn[i] || LightsOff[i]) // Ra: zlikwidowałem wymóg istnienia obu + iNumLights = i + 1; + int i = 0; + int ti; - parser->getTokens(); - *parser >> token; + parser->getTokens(); + *parser >> token; - if (token.compare( "lights" ) == 0) - { - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - do - { - ti=str.ToDouble(); //stan światła jest liczbą z ułamkiem - LightSet(i,ti); - i++; - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - } while (str!="endmodel"); - } - return true; + if (token.compare("lights") == 0) + { + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + do + { + ti = str.ToDouble(); // stan światła jest liczbą z ułamkiem + LightSet(i, ti); + i++; + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + } while (str != "endmodel"); + } + return true; } -TAnimContainer* __fastcall TAnimModel::AddContainer(char *pName) -{//dodanie sterowania submodelem dla egzemplarza - if (!pModel) return NULL; - TSubModel *tsb=pModel->GetFromName(pName); - if (tsb) - { - TAnimContainer *tmp=new TAnimContainer(); - tmp->Init(tsb); - tmp->pNext=pRoot; - pRoot=tmp; - return tmp; - } - return NULL; +TAnimContainer *__fastcall TAnimModel::AddContainer(char *pName) +{ // dodanie sterowania submodelem dla egzemplarza + if (!pModel) + return NULL; + TSubModel *tsb = pModel->GetFromName(pName); + if (tsb) + { + TAnimContainer *tmp = new TAnimContainer(); + tmp->Init(tsb); + tmp->pNext = pRoot; + pRoot = tmp; + return tmp; + } + return NULL; } -TAnimContainer* __fastcall TAnimModel::GetContainer(char *pName) -{//szukanie/dodanie sterowania submodelem dla egzemplarza - if (!pName) return pRoot; //pobranie pierwszego (dla obrotnicy) - TAnimContainer *pCurrent; - for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) - //if (pCurrent->GetName()==pName) - if (stricmp(pCurrent->NameGet(),pName)==0) - return pCurrent; - return AddContainer(pName); +TAnimContainer *__fastcall TAnimModel::GetContainer(char *pName) +{ // szukanie/dodanie sterowania submodelem dla egzemplarza + if (!pName) + return pRoot; // pobranie pierwszego (dla obrotnicy) + TAnimContainer *pCurrent; + for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext) + // if (pCurrent->GetName()==pName) + if (stricmp(pCurrent->NameGet(), pName) == 0) + return pCurrent; + return AddContainer(pName); } void __fastcall TAnimModel::RaAnimate() -{//przeliczenie animacji - jednorazowo na klatkę - //Ra 2F1I: to by można pomijać dla modeli bez animacji, których jest większość - TAnimContainer *pCurrent; - for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) - if (!pCurrent->evDone) //jeśli jest bez eventu - pCurrent->UpdateModel(); //przeliczenie animacji każdego submodelu - //if () //tylko dla modeli z IK !!!! - for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) //albo osobny łańcuch - pCurrent->UpdateModelIK(); //przeliczenie odwrotnej kinematyki +{ // przeliczenie animacji - jednorazowo na klatkę + // Ra 2F1I: to by można pomijać dla modeli bez animacji, których jest większość + TAnimContainer *pCurrent; + for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext) + if (!pCurrent->evDone) // jeśli jest bez eventu + pCurrent->UpdateModel(); // przeliczenie animacji każdego submodelu + // if () //tylko dla modeli z IK !!!! + for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext) // albo osobny łańcuch + pCurrent->UpdateModelIK(); // przeliczenie odwrotnej kinematyki }; void __fastcall TAnimModel::RaPrepare() -{//ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza - fBlinkTimer-=Timer::GetDeltaTime(); - if (fBlinkTimer<=0) fBlinkTimer=fOffTime; - bool state; //stan światła - for (int i=0;iiVisible=state; - if (LightsOff[i]) LightsOff[i]->iVisible=!state; - } - TSubModel::iInstance=(int)this; //żeby nie robić cudzych animacji - TSubModel::pasText=&asText; //przekazanie tekstu do wyświetlacza (!!!! do przemyślenia) - if (pAdvanced) //jeśli jest zaawansowana animacja - Advanced(); //wykonać co tam trzeba - TAnimContainer *pCurrent; - for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) - pCurrent->PrepareModel(); //ustawienie animacji egzemplarza dla każdego submodelu - //if () //tylko dla modeli z IK !!!! - // for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) //albo osobny łańcuch - // pCurrent->UpdateModelIK(); //przeliczenie odwrotnej kinematyki +{ // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza + fBlinkTimer -= Timer::GetDeltaTime(); + if (fBlinkTimer <= 0) + fBlinkTimer = fOffTime; + bool state; // stan światła + for (int i = 0; i < iNumLights; i++) + { + switch (lsLights[i]) + { + case ls_Blink: // migotanie + state = fBlinkTimer < fOnTime; + break; + case ls_Dark: // zapalone, gdy ciemno + state = Global::fLuminance <= fDark; + break; + default: // zapalony albo zgaszony + state = (lsLights[i] == ls_On); + } + if (LightsOn[i]) + LightsOn[i]->iVisible = state; + if (LightsOff[i]) + LightsOff[i]->iVisible = !state; + } + TSubModel::iInstance = (int)this; //żeby nie robić cudzych animacji + TSubModel::pasText = &asText; // przekazanie tekstu do wyświetlacza (!!!! do przemyślenia) + if (pAdvanced) // jeśli jest zaawansowana animacja + Advanced(); // wykonać co tam trzeba + TAnimContainer *pCurrent; + for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext) + pCurrent->PrepareModel(); // ustawienie animacji egzemplarza dla każdego submodelu + // if () //tylko dla modeli z IK !!!! + // for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) //albo osobny łańcuch + // pCurrent->UpdateModelIK(); //przeliczenie odwrotnej kinematyki } -void __fastcall TAnimModel::RenderVBO(vector3 pPosition,double fAngle) -{//sprawdza światła i rekurencyjnie renderuje TModel3d - RaAnimate(); //jednorazowe przeliczenie animacji - RaPrepare(); - if (pModel) //renderowanie rekurencyjne submodeli - pModel->RaRender(pPosition,fAngle,ReplacableSkinId,iTexAlpha); +void __fastcall TAnimModel::RenderVBO(vector3 pPosition, double fAngle) +{ // sprawdza światła i rekurencyjnie renderuje TModel3d + RaAnimate(); // jednorazowe przeliczenie animacji + RaPrepare(); + if (pModel) // renderowanie rekurencyjne submodeli + pModel->RaRender(pPosition, fAngle, ReplacableSkinId, iTexAlpha); } -void __fastcall TAnimModel::RenderAlphaVBO(vector3 pPosition,double fAngle) +void __fastcall TAnimModel::RenderAlphaVBO(vector3 pPosition, double fAngle) { - RaPrepare(); - if (pModel) //renderowanie rekurencyjne submodeli - pModel->RaRenderAlpha(pPosition,fAngle,ReplacableSkinId,iTexAlpha); + RaPrepare(); + if (pModel) // renderowanie rekurencyjne submodeli + pModel->RaRenderAlpha(pPosition, fAngle, ReplacableSkinId, iTexAlpha); }; -void __fastcall TAnimModel::RenderDL(vector3 pPosition,double fAngle) +void __fastcall TAnimModel::RenderDL(vector3 pPosition, double fAngle) { - RaAnimate(); //jednorazowe przeliczenie animacji - RaPrepare(); - if (pModel) //renderowanie rekurencyjne submodeli - pModel->Render(pPosition,fAngle,ReplacableSkinId,iTexAlpha); + RaAnimate(); // jednorazowe przeliczenie animacji + RaPrepare(); + if (pModel) // renderowanie rekurencyjne submodeli + pModel->Render(pPosition, fAngle, ReplacableSkinId, iTexAlpha); } -void __fastcall TAnimModel::RenderAlphaDL(vector3 pPosition,double fAngle) +void __fastcall TAnimModel::RenderAlphaDL(vector3 pPosition, double fAngle) { - RaPrepare(); - if (pModel) - pModel->RenderAlpha(pPosition,fAngle,ReplacableSkinId,iTexAlpha); + RaPrepare(); + if (pModel) + pModel->RenderAlpha(pPosition, fAngle, ReplacableSkinId, iTexAlpha); }; int __fastcall TAnimModel::Flags() -{//informacja dla TGround, czy ma być w Render, RenderAlpha, czy RenderMixed - int i=pModel?pModel->Flags():0; //pobranie flag całego modelu - if (ReplacableSkinId[1]>0) //jeśli ma wymienną teksturę 0 - i|=(i&0x01010001)*((iTexAlpha&1)?0x20:0x10); - //if (ReplacableSkinId[2]>0) //jeśli ma wymienną teksturę 1 - // i|=(i&0x02020002)*((iTexAlpha&1)?0x10:0x08); - //if (ReplacableSkinId[3]>0) //jeśli ma wymienną teksturę 2 - // i|=(i&0x04040004)*((iTexAlpha&1)?0x08:0x04); - //if (ReplacableSkinId[4]>0) //jeśli ma wymienną teksturę 3 - // i|=(i&0x08080008)*((iTexAlpha&1)?0x04:0x02); - return i; +{ // informacja dla TGround, czy ma być w Render, RenderAlpha, czy RenderMixed + int i = pModel ? pModel->Flags() : 0; // pobranie flag całego modelu + if (ReplacableSkinId[1] > 0) // jeśli ma wymienną teksturę 0 + i |= (i & 0x01010001) * ((iTexAlpha & 1) ? 0x20 : 0x10); + // if (ReplacableSkinId[2]>0) //jeśli ma wymienną teksturę 1 + // i|=(i&0x02020002)*((iTexAlpha&1)?0x10:0x08); + // if (ReplacableSkinId[3]>0) //jeśli ma wymienną teksturę 2 + // i|=(i&0x04040004)*((iTexAlpha&1)?0x08:0x04); + // if (ReplacableSkinId[4]>0) //jeśli ma wymienną teksturę 3 + // i|=(i&0x08080008)*((iTexAlpha&1)?0x04:0x02); + return i; }; //----------------------------------------------------------------------------- -//2011-03-16 cztery nowe funkcje renderowania z możliwością pochylania obiektów +// 2011-03-16 cztery nowe funkcje renderowania z możliwością pochylania obiektów //----------------------------------------------------------------------------- -void __fastcall TAnimModel::RenderDL(vector3* vPosition) +void __fastcall TAnimModel::RenderDL(vector3 *vPosition) { - RaAnimate(); //jednorazowe przeliczenie animacji - RaPrepare(); - if (pModel) //renderowanie rekurencyjne submodeli - pModel->Render(vPosition,&vAngle,ReplacableSkinId,iTexAlpha); + RaAnimate(); // jednorazowe przeliczenie animacji + RaPrepare(); + if (pModel) // renderowanie rekurencyjne submodeli + pModel->Render(vPosition, &vAngle, ReplacableSkinId, iTexAlpha); }; -void __fastcall TAnimModel::RenderAlphaDL(vector3* vPosition) +void __fastcall TAnimModel::RenderAlphaDL(vector3 *vPosition) { - RaPrepare(); - if (pModel) //renderowanie rekurencyjne submodeli - pModel->RenderAlpha(vPosition,&vAngle,ReplacableSkinId,iTexAlpha); + RaPrepare(); + if (pModel) // renderowanie rekurencyjne submodeli + pModel->RenderAlpha(vPosition, &vAngle, ReplacableSkinId, iTexAlpha); }; -void __fastcall TAnimModel::RenderVBO(vector3* vPosition) +void __fastcall TAnimModel::RenderVBO(vector3 *vPosition) { - RaAnimate(); //jednorazowe przeliczenie animacji - RaPrepare(); - if (pModel) //renderowanie rekurencyjne submodeli - pModel->RaRender(vPosition,&vAngle,ReplacableSkinId,iTexAlpha); + RaAnimate(); // jednorazowe przeliczenie animacji + RaPrepare(); + if (pModel) // renderowanie rekurencyjne submodeli + pModel->RaRender(vPosition, &vAngle, ReplacableSkinId, iTexAlpha); }; -void __fastcall TAnimModel::RenderAlphaVBO(vector3* vPosition) +void __fastcall TAnimModel::RenderAlphaVBO(vector3 *vPosition) { - RaPrepare(); - if (pModel) //renderowanie rekurencyjne submodeli - pModel->RaRenderAlpha(vPosition,&vAngle,ReplacableSkinId,iTexAlpha); + RaPrepare(); + if (pModel) // renderowanie rekurencyjne submodeli + pModel->RaRenderAlpha(vPosition, &vAngle, ReplacableSkinId, iTexAlpha); }; //--------------------------------------------------------------------------- bool __fastcall TAnimModel::TerrainLoaded() -{//zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy - return (this?pModel!=NULL:false); -}; +{ // zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy + return (this ? pModel != NULL : false); }; int __fastcall TAnimModel::TerrainCount() -{//zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy - return pModel?pModel->TerrainCount():0; -}; -TSubModel* __fastcall TAnimModel::TerrainSquare(int n) -{//pobieranie wskaźników do pierwszego submodelu - return pModel?pModel->TerrainSquare(n):0; +{ // zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy + return pModel ? pModel->TerrainCount() : 0; }; +TSubModel *__fastcall TAnimModel::TerrainSquare(int n) +{ // pobieranie wskaźników do pierwszego submodelu + return pModel ? pModel->TerrainSquare(n) : 0; }; void __fastcall TAnimModel::TerrainRenderVBO(int n) -{//renderowanie terenu z VBO - if (pModel) pModel->TerrainRenderVBO(n); +{ // renderowanie terenu z VBO + if (pModel) + pModel->TerrainRenderVBO(n); }; //--------------------------------------------------------------------------- void __fastcall TAnimModel::Advanced() -{//wykonanie zaawansowanych animacji na submodelach - pAdvanced->fCurrent+=pAdvanced->fFrequency*Timer::GetDeltaTime(); //aktualna ramka zmiennoprzecinkowo - int frame=floor(pAdvanced->fCurrent); //numer klatki jako int - TAnimContainer *pCurrent; - if (pAdvanced->fCurrent>=pAdvanced->fLast) - {//animacja została zakończona - delete pAdvanced; - pAdvanced=NULL; //dalej już nic - for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) - if (pCurrent->pMovementData) //jeśli obsługiwany tabelką animacji - pCurrent->pMovementData=NULL; //usuwanie wskaźników - } - else - {//coś trzeba poanimować - wszystkie animowane submodele są w tym łańcuchu - for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) - if (pCurrent->pMovementData) //jeśli obsługiwany tabelką animacji - if (frame>=pCurrent->pMovementData->iFrame) //koniec czekania - if (!strcmp(pCurrent->pMovementData->cBone,(pCurrent->pMovementData+1)->cBone)) - {//jak kolejna ramka dotyczy tego samego submodelu, ustawić animację do kolejnej ramki - ++pCurrent->pMovementData; //kolejna klatka - pCurrent->AnimSetVMD(pAdvanced->fFrequency/(double(pCurrent->pMovementData->iFrame)-pAdvanced->fCurrent)); - } - else - pCurrent->pMovementData=NULL; //inna nazwa, animowanie zakończone w aktualnym położeniu - } +{ // wykonanie zaawansowanych animacji na submodelach + pAdvanced->fCurrent += + pAdvanced->fFrequency * Timer::GetDeltaTime(); // aktualna ramka zmiennoprzecinkowo + int frame = floor(pAdvanced->fCurrent); // numer klatki jako int + TAnimContainer *pCurrent; + if (pAdvanced->fCurrent >= pAdvanced->fLast) + { // animacja została zakończona + delete pAdvanced; + pAdvanced = NULL; // dalej już nic + for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext) + if (pCurrent->pMovementData) // jeśli obsługiwany tabelką animacji + pCurrent->pMovementData = NULL; // usuwanie wskaźników + } + else + { // coś trzeba poanimować - wszystkie animowane submodele są w tym łańcuchu + for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext) + if (pCurrent->pMovementData) // jeśli obsługiwany tabelką animacji + if (frame >= pCurrent->pMovementData->iFrame) // koniec czekania + if (!strcmp(pCurrent->pMovementData->cBone, + (pCurrent->pMovementData + 1)->cBone)) + { // jak kolejna ramka dotyczy tego samego submodelu, ustawić animację do + // kolejnej ramki + ++pCurrent->pMovementData; // kolejna klatka + pCurrent->AnimSetVMD( + pAdvanced->fFrequency / + (double(pCurrent->pMovementData->iFrame) - pAdvanced->fCurrent)); + } + else + pCurrent->pMovementData = + NULL; // inna nazwa, animowanie zakończone w aktualnym położeniu + } }; -void __fastcall TAnimModel::AnimationVND(void* pData, double a, double b, double c, double d) -{//rozpoczęcie wykonywania animacji z podanego pliku - //tabela w pliku musi być posortowana wg klatek dla kolejnych kości! - //skrócone nagranie ma 3:42 = 222 sekundy, animacja kończy się na klatce 6518 - //daje to 29.36 (~=30) klatek na sekundę - //w opisach jest podawane 24 albo 36 jako standard => powiedzmy, parametr (d) to FPS animacji - delete pAdvanced; //usunięcie ewentualnego poprzedniego - pAdvanced=NULL; //gdyby się nie udało rozpoznać pliku - if (AnsiString((char*)pData)=="Vocaloid Motion Data 0002") - { - pAdvanced=new TAnimAdvanced(); - pAdvanced->pVocaloidMotionData=(char*)pData; //podczepienie pliku danych - pAdvanced->iMovements=*((int*)(((char*)pData)+50)); //numer ostatniej klatki - pAdvanced->pMovementData=(TAnimVocaloidFrame*)(((char*)pData)+54); //rekordy animacji - //WriteLog(sizeof(TAnimVocaloidFrame)); - pAdvanced->fFrequency=d; - pAdvanced->fCurrent=0.0; //aktualna ramka - pAdvanced->fLast=0.0; //ostatnia ramka -/* - if (0) //jeśli włączone sortowanie plików VMD (trochę się przeciąga) - if (pAdvanced->SortByBone()) //próba posortowania - {//zapisać posortowany plik, jeśli dokonano zmian - TFileStream *fs=new TFileStream("models\\1.vmd",fmCreate); - fs->Write(pData,2198342); //2948728); - delete fs; - } -*/ +void __fastcall TAnimModel::AnimationVND(void *pData, double a, double b, double c, double d) +{ // rozpoczęcie wykonywania animacji z podanego pliku + // tabela w pliku musi być posortowana wg klatek dla kolejnych kości! + // skrócone nagranie ma 3:42 = 222 sekundy, animacja kończy się na klatce 6518 + // daje to 29.36 (~=30) klatek na sekundę + // w opisach jest podawane 24 albo 36 jako standard => powiedzmy, parametr (d) to FPS animacji + delete pAdvanced; // usunięcie ewentualnego poprzedniego + pAdvanced = NULL; // gdyby się nie udało rozpoznać pliku + if (AnsiString((char *)pData) == "Vocaloid Motion Data 0002") + { + pAdvanced = new TAnimAdvanced(); + pAdvanced->pVocaloidMotionData = (char *)pData; // podczepienie pliku danych + pAdvanced->iMovements = *((int *)(((char *)pData) + 50)); // numer ostatniej klatki + pAdvanced->pMovementData = (TAnimVocaloidFrame *)(((char *)pData) + 54); // rekordy animacji + // WriteLog(sizeof(TAnimVocaloidFrame)); + pAdvanced->fFrequency = d; + pAdvanced->fCurrent = 0.0; // aktualna ramka + pAdvanced->fLast = 0.0; // ostatnia ramka + /* + if (0) //jeśli włączone sortowanie plików VMD (trochę się przeciąga) + if (pAdvanced->SortByBone()) //próba posortowania + {//zapisać posortowany plik, jeśli dokonano zmian + TFileStream *fs=new TFileStream("models\\1.vmd",fmCreate); + fs->Write(pData,2198342); //2948728); + delete fs; + } + */ - int i,j,k,idx; - AnsiString name; - TAnimContainer *pSub; - for (i=0;iiMovements;++i) - {if (strcmp(pAdvanced->pMovementData[i].cBone,name.c_str())) - {//jeśli pozycja w tabelce nie była wyszukiwana w submodelach - pSub=GetContainer(pAdvanced->pMovementData[i].cBone); //szukanie - if (pSub) //znaleziony - {pSub->pMovementData=pAdvanced->pMovementData+i; //gotów do animowania - pSub->AnimSetVMD(0.0); //usuawienie pozycji początkowej (powinna być zerowa, inaczej będzie skok) + int i, j, k, idx; + AnsiString name; + TAnimContainer *pSub; + for (i = 0; i < pAdvanced->iMovements; ++i) + { + if (strcmp(pAdvanced->pMovementData[i].cBone, name.c_str())) + { // jeśli pozycja w tabelce nie była wyszukiwana w submodelach + pSub = GetContainer(pAdvanced->pMovementData[i].cBone); // szukanie + if (pSub) // znaleziony + { + pSub->pMovementData = pAdvanced->pMovementData + i; // gotów do animowania + pSub->AnimSetVMD(0.0); // usuawienie pozycji początkowej (powinna być zerowa, + // inaczej będzie skok) + } + name = AnsiString(pAdvanced->pMovementData[i].cBone); // nowa nazwa do pomijania + } + if (pAdvanced->fLast < pAdvanced->pMovementData[i].iFrame) + pAdvanced->fLast = pAdvanced->pMovementData[i].iFrame; + } + /* + for (i=0;iiMovements;++i) + if + (AnsiString(pAdvanced->pMovementData[i+1].cBone)!=AnsiString(pAdvanced->pMovementData[i].cBone)) + {//generowane dla ostatniej klatki danej kości + name=""; + for (j=0;j<15;j++) + name+=IntToHex((unsigned char)pAdvanced->pMovementData[i].cBone[j],2); + WriteLog(name+"," + +AnsiString(pAdvanced->pMovementData[i].cBone)+"," + +AnsiString(idx)+"," //indeks + +AnsiString(i+1-idx)+"," //ile pozycji animacji + +AnsiString(k)+"," //pierwsza klatka + +AnsiString(pAdvanced->pMovementData[i].iFrame)+"," //ostatnia klatka + +AnsiString(pAdvanced->pMovementData[i].f3Vector.x)+"," + +AnsiString(pAdvanced->pMovementData[i].f3Vector.y)+"," + +AnsiString(pAdvanced->pMovementData[i].f3Vector.z)+"," + +AnsiString(pAdvanced->pMovementData[i].fAngle[0])+"," + +AnsiString(pAdvanced->pMovementData[i].fAngle[1])+"," + +AnsiString(pAdvanced->pMovementData[i].fAngle[2])+"," + +AnsiString(pAdvanced->pMovementData[i].fAngle[3]) + + ); + idx=i+1; + k=pAdvanced->pMovementData[i+1].iFrame; //pierwsza klatka następnego + } + else + if (pAdvanced->pMovementData[i].iFrame>0) + if ((k>pAdvanced->pMovementData[i].iFrame)||(k==0)) + k=pAdvanced->pMovementData[i].iFrame; //pierwsza niezerowa ramka + */ + /* + for (i=0;iiMovements;++i) + if (AnsiString(pAdvanced->pMovementData[i].cBone)=="\x89\x45\x90\x65\x8E\x77\x82\x4F") + {name=""; + for (j=0;j<15;j++) + name+=IntToHex((unsigned char)pAdvanced->pMovementData[i].cBone[j],2); + WriteLog(name+"," + +AnsiString(i)+"," //pozycja w tabeli + +AnsiString(pAdvanced->pMovementData[i].iFrame)+"," //pierwsza klatka + ); + } + */ } - name=AnsiString(pAdvanced->pMovementData[i].cBone); //nowa nazwa do pomijania - } - if (pAdvanced->fLastpMovementData[i].iFrame) - pAdvanced->fLast=pAdvanced->pMovementData[i].iFrame; - } -/* - for (i=0;iiMovements;++i) - if (AnsiString(pAdvanced->pMovementData[i+1].cBone)!=AnsiString(pAdvanced->pMovementData[i].cBone)) - {//generowane dla ostatniej klatki danej kości - name=""; - for (j=0;j<15;j++) - name+=IntToHex((unsigned char)pAdvanced->pMovementData[i].cBone[j],2); - WriteLog(name+"," - +AnsiString(pAdvanced->pMovementData[i].cBone)+"," - +AnsiString(idx)+"," //indeks - +AnsiString(i+1-idx)+"," //ile pozycji animacji - +AnsiString(k)+"," //pierwsza klatka - +AnsiString(pAdvanced->pMovementData[i].iFrame)+"," //ostatnia klatka - +AnsiString(pAdvanced->pMovementData[i].f3Vector.x)+"," - +AnsiString(pAdvanced->pMovementData[i].f3Vector.y)+"," - +AnsiString(pAdvanced->pMovementData[i].f3Vector.z)+"," - +AnsiString(pAdvanced->pMovementData[i].fAngle[0])+"," - +AnsiString(pAdvanced->pMovementData[i].fAngle[1])+"," - +AnsiString(pAdvanced->pMovementData[i].fAngle[2])+"," - +AnsiString(pAdvanced->pMovementData[i].fAngle[3]) - - ); - idx=i+1; - k=pAdvanced->pMovementData[i+1].iFrame; //pierwsza klatka następnego - } - else - if (pAdvanced->pMovementData[i].iFrame>0) - if ((k>pAdvanced->pMovementData[i].iFrame)||(k==0)) - k=pAdvanced->pMovementData[i].iFrame; //pierwsza niezerowa ramka -*/ -/* - for (i=0;iiMovements;++i) - if (AnsiString(pAdvanced->pMovementData[i].cBone)=="\x89\x45\x90\x65\x8E\x77\x82\x4F") - {name=""; - for (j=0;j<15;j++) - name+=IntToHex((unsigned char)pAdvanced->pMovementData[i].cBone[j],2); - WriteLog(name+"," - +AnsiString(i)+"," //pozycja w tabeli - +AnsiString(pAdvanced->pMovementData[i].iFrame)+"," //pierwsza klatka - ); - } -*/ - } }; //--------------------------------------------------------------------------- -void __fastcall 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) - break; - case 1: //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) - 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 - break; - } +void __fastcall 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) + break; + case 1: // 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) + 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 + break; + } }; //--------------------------------------------------------------------------- void __fastcall TAnimModel::AnimUpdate(double dt) -{//wykonanie zakolejkowanych animacji, nawet gdy modele nie są aktualnie wyświetlane - TAnimContainer *p=TAnimModel::acAnimList; - while (p) - {//jeśli w ogóle jest co animować - //if ((*p)->fTranslateSpeed==0.0) - // if ((*p)->fRotateSpeed==0.0) - // {//jak się naanimował, to usunąć z listy - // *p=(*p)->ListRemove(); //zwraca wskaźnik do kolejnego z listy - // } - p->UpdateModel(); - p=p->acAnimNext; //na razie bez usuwania z listy, bo głównie obrotnica na nią wchodzi - } +{ // wykonanie zakolejkowanych animacji, nawet gdy modele nie są aktualnie wyświetlane + TAnimContainer *p = TAnimModel::acAnimList; + while (p) + { // jeśli w ogóle jest co animować + // if ((*p)->fTranslateSpeed==0.0) + // if ((*p)->fRotateSpeed==0.0) + // {//jak się naanimował, to usunąć z listy + // *p=(*p)->ListRemove(); //zwraca wskaźnik do kolejnego z listy + // } + p->UpdateModel(); + p = p->acAnimNext; // na razie bez usuwania z listy, bo głównie obrotnica na nią wchodzi + } }; //--------------------------------------------------------------------------- - diff --git a/AnimModel.h b/AnimModel.h index 3d5eed7b..8081d285 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -5,144 +5,162 @@ #include "Model3d.h" -const int iMaxNumLights=8; +const int iMaxNumLights = 8; -//typy stanu świateł -typedef enum { - ls_Off=0, //zgaszone - ls_On=1, //zapalone - ls_Blink=2, //migające - ls_Dark=3 //Ra: zapalajce się automatycznie, gdy zrobi się ciemno +// typy stanu świateł +typedef enum +{ + ls_Off = 0, // zgaszone + ls_On = 1, // zapalone + ls_Blink = 2, // migające + ls_Dark = 3 // Ra: zapalajce się automatycznie, gdy zrobi się ciemno } TLightState; class TAnimVocaloidFrame -{//ramka animacji typu Vocaloid Motion Data z programu MikuMikuDance -public: - char cBone[15]; //nazwa kości, może być po japońsku - int iFrame; //numer ramki - float3 f3Vector; //przemieszczenie - float4 qAngle; //kwaternion obrotu - char cBezier[64]; //krzywe Béziera do interpolacji dla x,y,z i obrotu +{ // ramka animacji typu Vocaloid Motion Data z programu MikuMikuDance + public: + char cBone[15]; // nazwa kości, może być po japońsku + int iFrame; // numer ramki + float3 f3Vector; // przemieszczenie + float4 qAngle; // kwaternion obrotu + char cBezier[64]; // krzywe Béziera do interpolacji dla x,y,z i obrotu }; class TEvent; class TAnimContainer -{//opakowanie submodelu, określające animację egzemplarza - obsługiwane jako lista -friend class TAnimModel; -private: - vector3 vRotateAngles; //dla obrotów Eulera - vector3 vDesiredAngles; - double fRotateSpeed; - vector3 vTranslation; - vector3 vTranslateTo; - double fTranslateSpeed; //może tu dać wektor? - float4 qCurrent; //aktualny interpolowany - float4 qStart; //pozycja początkowa (0 dla interpolacji) - float4 qDesired; //pozycja końcowa (1 dla interpolacji) - float fAngleCurrent; //parametr interpolacyjny: 0=start, 1=docelowy - float fAngleSpeed; //zmiana parametru interpolacji w sekundach - TSubModel *pSubModel; - float4x4 *mAnim; //macierz do animacji kwaternionowych - //dla kinematyki odwróconej używane są kwaterniony - float fLength; //długość kości dla IK - int iAnim; //animacja: +1-obrót Eulera, +2-przesuw, +4-obrót kwaternionem, +8-IK - //+0x80000000: animacja z eventem, wykonywana poza wyświetlaniem - //+0x100: pierwszy stopień IK - obrócić w stronę pierwszego potomnego (dziecka) - //+0x200: drugi stopień IK - dostosować do pozycji potomnego potomnego (wnuka) - union - {//mogą być animacje klatkowe różnego typu, wskaźniki używa AnimModel - TAnimVocaloidFrame *pMovementData; //wskaźnik do klatki - }; - TEvent *evDone; //ewent wykonywany po zakończeniu animacji, np. zapór, obrotnicy -public: - TAnimContainer *pNext; - TAnimContainer *acAnimNext; //lista animacji z eventem, które muszą być przeliczane również bez wyświetlania - __fastcall TAnimContainer(); - __fastcall ~TAnimContainer(); - bool __fastcall Init(TSubModel *pNewSubModel); - //std::string inline __fastcall GetName() { return std::string(pSubModel?pSubModel->asName.c_str():""); }; - //std::string inline __fastcall GetName() { return std::string(pSubModel?pSubModel->pName:""); }; - char* __fastcall NameGet() {return (pSubModel?pSubModel->pName:NULL);}; - //void __fastcall SetRotateAnim(vector3 vNewRotateAxis, double fNewDesiredAngle, double fNewRotateSpeed, bool bResetAngle=false); - void __fastcall SetRotateAnim(vector3 vNewRotateAngles, double fNewRotateSpeed); - void __fastcall SetTranslateAnim(vector3 vNewTranslate, double fNewSpeed); - void __fastcall AnimSetVMD(double fNewSpeed); - void __fastcall PrepareModel(); - void __fastcall UpdateModel(); - void __fastcall UpdateModelIK(); - bool __fastcall InMovement(); //czy w trakcie animacji? - double _fastcall AngleGet() {return vRotateAngles.z;}; //jednak ostatnia, T3D ma inny układ - vector3 _fastcall TransGet() {return vector3(-vTranslation.x,vTranslation.z,vTranslation.y);}; //zmiana, bo T3D ma inny układ - void __fastcall WillBeAnimated() {if (pSubModel) pSubModel->WillBeAnimated();}; - void __fastcall EventAssign(TEvent *ev); - TEvent* __fastcall Event() {return evDone;}; +{ // opakowanie submodelu, określające animację egzemplarza - obsługiwane jako lista + friend class TAnimModel; + + private: + vector3 vRotateAngles; // dla obrotów Eulera + vector3 vDesiredAngles; + double fRotateSpeed; + vector3 vTranslation; + vector3 vTranslateTo; + double fTranslateSpeed; // może tu dać wektor? + float4 qCurrent; // aktualny interpolowany + float4 qStart; // pozycja początkowa (0 dla interpolacji) + float4 qDesired; // pozycja końcowa (1 dla interpolacji) + float fAngleCurrent; // parametr interpolacyjny: 0=start, 1=docelowy + float fAngleSpeed; // zmiana parametru interpolacji w sekundach + TSubModel *pSubModel; + float4x4 *mAnim; // macierz do animacji kwaternionowych + // dla kinematyki odwróconej używane są kwaterniony + float fLength; // długość kości dla IK + int iAnim; // animacja: +1-obrót Eulera, +2-przesuw, +4-obrót kwaternionem, +8-IK + //+0x80000000: animacja z eventem, wykonywana poza wyświetlaniem + //+0x100: pierwszy stopień IK - obrócić w stronę pierwszego potomnego (dziecka) + //+0x200: drugi stopień IK - dostosować do pozycji potomnego potomnego (wnuka) + union + { // mogą być animacje klatkowe różnego typu, wskaźniki używa AnimModel + TAnimVocaloidFrame *pMovementData; // wskaźnik do klatki + }; + TEvent *evDone; // ewent wykonywany po zakończeniu animacji, np. zapór, obrotnicy + public: + TAnimContainer *pNext; + TAnimContainer *acAnimNext; // lista animacji z eventem, które muszą być przeliczane również bez + // wyświetlania + __fastcall TAnimContainer(); + __fastcall ~TAnimContainer(); + bool __fastcall Init(TSubModel *pNewSubModel); + // std::string inline __fastcall GetName() { return + // std::string(pSubModel?pSubModel->asName.c_str():""); }; + // std::string inline __fastcall GetName() { return std::string(pSubModel?pSubModel->pName:""); + // }; + char *__fastcall NameGet() { return (pSubModel ? pSubModel->pName : NULL); }; + // void __fastcall SetRotateAnim(vector3 vNewRotateAxis, double fNewDesiredAngle, double + // fNewRotateSpeed, bool bResetAngle=false); + void __fastcall SetRotateAnim(vector3 vNewRotateAngles, double fNewRotateSpeed); + void __fastcall SetTranslateAnim(vector3 vNewTranslate, double fNewSpeed); + void __fastcall AnimSetVMD(double fNewSpeed); + void __fastcall PrepareModel(); + void __fastcall UpdateModel(); + void __fastcall UpdateModelIK(); + bool __fastcall InMovement(); // czy w trakcie animacji? + double _fastcall AngleGet() { return vRotateAngles.z; }; // jednak ostatnia, T3D ma inny układ + vector3 _fastcall TransGet() + { + return vector3(-vTranslation.x, vTranslation.z, vTranslation.y); + }; // zmiana, bo T3D ma inny układ + void __fastcall WillBeAnimated() + { + if (pSubModel) + pSubModel->WillBeAnimated(); + }; + void __fastcall EventAssign(TEvent *ev); + TEvent *__fastcall Event() { return evDone; }; }; class TAnimAdvanced -{//obiekt zaawansowanej animacji submodelu -public: - TAnimVocaloidFrame *pMovementData; - unsigned char *pVocaloidMotionData; //plik animacyjny dla egzemplarza (z eventu) - double fFrequency; //przeliczenie czasu rzeczywistego na klatki animacji - double fCurrent; //klatka animacji wyświetlona w poprzedniej klatce renderingu - double fLast; //klatka kończąca animację - int iMovements; - __fastcall TAnimAdvanced(); - __fastcall ~TAnimAdvanced(); - int __fastcall SortByBone(); +{ // obiekt zaawansowanej animacji submodelu + public: + TAnimVocaloidFrame *pMovementData; + unsigned char *pVocaloidMotionData; // plik animacyjny dla egzemplarza (z eventu) + double fFrequency; // przeliczenie czasu rzeczywistego na klatki animacji + double fCurrent; // klatka animacji wyświetlona w poprzedniej klatce renderingu + double fLast; // klatka kończąca animację + int iMovements; + __fastcall TAnimAdvanced(); + __fastcall ~TAnimAdvanced(); + int __fastcall SortByBone(); }; class TAnimModel -{//opakowanie modelu, określające stan egzemplarza -private: - TAnimContainer *pRoot; //pojemniki sterujące, tylko dla aniomowanych submodeli - TModel3d *pModel; - double fBlinkTimer; - int iNumLights; - TSubModel *LightsOn[iMaxNumLights]; //Ra: te wskaźniki powinny być w ramach TModel3d - TSubModel *LightsOff[iMaxNumLights]; - vector3 vAngle; //bazowe obroty egzemplarza względem osi - int iTexAlpha; //żeby nie sprawdzać za każdym razem, dla 4 wymiennych tekstur - AnsiString asText; //tekst dla wyświetlacza znakowego - TAnimAdvanced *pAdvanced; - void __fastcall Advanced(); - TLightState lsLights[iMaxNumLights]; - float fDark; //poziom zapalanie światła (powinno być chyba powiązane z danym światłem?) - float fOnTime,fOffTime; //były stałymi, teraz mogą być zmienne dla każdego egzemplarza -private: - void __fastcall RaAnimate(); //przeliczenie animacji egzemplarza - void __fastcall RaPrepare(); //ustawienie animacji egzemplarza na wzorcu -public: - GLuint ReplacableSkinId[5]; //McZapkie-020802: zmienialne skory - static TAnimContainer *acAnimList; //lista animacji z eventem, które muszą być przeliczane również bez wyświetlania - __fastcall TAnimModel(); - __fastcall ~TAnimModel(); - bool __fastcall Init(TModel3d *pNewModel); - bool __fastcall Init(AnsiString asName,AnsiString asReplacableTexture); - bool __fastcall Load(cParser *parser, bool ter=false); - TAnimContainer* __fastcall AddContainer(char *pName); - TAnimContainer* __fastcall GetContainer(char *pName); - void __fastcall RenderDL(vector3 pPosition=vector3(0,0,0),double fAngle=0); - void __fastcall RenderAlphaDL(vector3 pPosition=vector3(0,0,0),double fAngle=0); - void __fastcall RenderVBO(vector3 pPosition=vector3(0,0,0),double fAngle=0); - void __fastcall RenderAlphaVBO(vector3 pPosition=vector3(0,0,0),double fAngle=0); - void __fastcall RenderDL(vector3* vPosition); - void __fastcall RenderAlphaDL(vector3* vPosition); - void __fastcall RenderVBO(vector3* vPosition); - void __fastcall RenderAlphaVBO(vector3* vPosition); - int __fastcall Flags(); - void __fastcall RaAnglesSet(double a,double b,double c) - {vAngle.x=a; vAngle.y=b; vAngle.z=c;}; - bool __fastcall TerrainLoaded(); - int __fastcall TerrainCount(); - TSubModel* __fastcall TerrainSquare(int n); - void __fastcall TerrainRenderVBO(int n); - void __fastcall AnimationVND(void* pData, double a, double b, double c, double d); - void __fastcall LightSet(int n,float v); - static void __fastcall AnimUpdate(double dt); +{ // opakowanie modelu, określające stan egzemplarza + private: + TAnimContainer *pRoot; // pojemniki sterujące, tylko dla aniomowanych submodeli + TModel3d *pModel; + double fBlinkTimer; + int iNumLights; + TSubModel *LightsOn[iMaxNumLights]; // Ra: te wskaźniki powinny być w ramach TModel3d + TSubModel *LightsOff[iMaxNumLights]; + vector3 vAngle; // bazowe obroty egzemplarza względem osi + int iTexAlpha; //żeby nie sprawdzać za każdym razem, dla 4 wymiennych tekstur + AnsiString asText; // tekst dla wyświetlacza znakowego + TAnimAdvanced *pAdvanced; + void __fastcall Advanced(); + TLightState lsLights[iMaxNumLights]; + float fDark; // poziom zapalanie światła (powinno być chyba powiązane z danym światłem?) + float fOnTime, fOffTime; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza + private: + void __fastcall RaAnimate(); // przeliczenie animacji egzemplarza + void __fastcall RaPrepare(); // ustawienie animacji egzemplarza na wzorcu + public: + GLuint ReplacableSkinId[5]; // McZapkie-020802: zmienialne skory + static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane + // również bez wyświetlania + __fastcall TAnimModel(); + __fastcall ~TAnimModel(); + bool __fastcall Init(TModel3d *pNewModel); + bool __fastcall Init(AnsiString asName, AnsiString asReplacableTexture); + bool __fastcall Load(cParser *parser, bool ter = false); + TAnimContainer *__fastcall AddContainer(char *pName); + TAnimContainer *__fastcall GetContainer(char *pName); + void __fastcall RenderDL(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0); + void __fastcall RenderAlphaDL(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0); + void __fastcall RenderVBO(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0); + void __fastcall RenderAlphaVBO(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0); + void __fastcall RenderDL(vector3 *vPosition); + void __fastcall RenderAlphaDL(vector3 *vPosition); + void __fastcall RenderVBO(vector3 *vPosition); + void __fastcall RenderAlphaVBO(vector3 *vPosition); + int __fastcall Flags(); + void __fastcall RaAnglesSet(double a, double b, double c) + { + vAngle.x = a; + vAngle.y = b; + vAngle.z = c; + }; + bool __fastcall TerrainLoaded(); + int __fastcall TerrainCount(); + TSubModel *__fastcall TerrainSquare(int n); + void __fastcall TerrainRenderVBO(int n); + void __fastcall AnimationVND(void *pData, double a, double b, double c, double d); + void __fastcall LightSet(int n, float v); + static void __fastcall AnimUpdate(double dt); }; -TAnimContainer *TAnimModel::acAnimList=NULL; +TAnimContainer *TAnimModel::acAnimList = NULL; //--------------------------------------------------------------------------- #endif diff --git a/Button.cpp b/Button.cpp index 06cae4c2..aac0d1b5 100644 --- a/Button.cpp +++ b/Button.cpp @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------- -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Button.h" @@ -13,58 +13,61 @@ __fastcall TButton::TButton() { - iFeedbackBit=0; - Clear(); + iFeedbackBit = 0; + Clear(); }; -__fastcall TButton::~TButton() -{ -}; +__fastcall TButton::~TButton(){}; void __fastcall TButton::Clear(int i) { - pModelOn=NULL; - pModelOff=NULL; - bOn=false; - if (i>=0) FeedbackBitSet(i); - Update(); //kasowanie bitu Feedback, o ile jakiś ustawiony + pModelOn = NULL; + pModelOff = NULL; + bOn = false; + if (i >= 0) + FeedbackBitSet(i); + Update(); // kasowanie bitu Feedback, o ile jakiś ustawiony }; -void __fastcall TButton::Init(AnsiString asName,TModel3d *pModel,bool bNewOn) +void __fastcall TButton::Init(AnsiString asName, TModel3d *pModel, bool bNewOn) { - if (!pModel) return; //nie ma w czym szukać - pModelOn=pModel->GetFromName(AnsiString(asName+"_on").c_str()); - pModelOff=pModel->GetFromName(AnsiString(asName+"_off").c_str()); - bOn=bNewOn; - Update(); + if (!pModel) + return; // nie ma w czym szukać + pModelOn = pModel->GetFromName(AnsiString(asName + "_on").c_str()); + pModelOff = pModel->GetFromName(AnsiString(asName + "_off").c_str()); + bOn = bNewOn; + Update(); }; -void __fastcall TButton::Load(TQueryParserComp *Parser,TModel3d *pModel1,TModel3d *pModel2) +void __fastcall TButton::Load(TQueryParserComp *Parser, TModel3d *pModel1, TModel3d *pModel2) { - AnsiString str=Parser->GetNextSymbol().LowerCase(); - if (pModel1) - {//poszukiwanie submodeli w modelu - Init(str,pModel1,false); - if (pModel2) - if (!pModelOn&&!pModelOff) - Init(str,pModel2,false); //może w drugim będzie (jak nie w kabinie, to w zewnętrznym) - } - else - { - pModelOn=NULL; - pModelOff=NULL; - } + AnsiString str = Parser->GetNextSymbol().LowerCase(); + if (pModel1) + { // poszukiwanie submodeli w modelu + Init(str, pModel1, false); + if (pModel2) + if (!pModelOn && !pModelOff) + Init(str, pModel2, + false); // może w drugim będzie (jak nie w kabinie, to w zewnętrznym) + } + else + { + pModelOn = NULL; + pModelOff = NULL; + } }; void __fastcall TButton::Update() { - if (pModelOn) pModelOn->iVisible=bOn; - if (pModelOff) pModelOff->iVisible=!bOn; - if (iFeedbackBit) //jeżeli generuje informację zwrotną - {if (bOn) //zapalenie - Console::BitsSet(iFeedbackBit); - else - Console::BitsClear(iFeedbackBit); - } + if (pModelOn) + pModelOn->iVisible = bOn; + if (pModelOff) + pModelOff->iVisible = !bOn; + if (iFeedbackBit) // jeżeli generuje informację zwrotną + { + if (bOn) // zapalenie + Console::BitsSet(iFeedbackBit); + else + Console::BitsClear(iFeedbackBit); + } }; - diff --git a/Button.h b/Button.h index 39da15b9..075e7918 100644 --- a/Button.h +++ b/Button.h @@ -7,24 +7,41 @@ #include "QueryParserComp.hpp" class TButton -{//animacja dwustanowa, włącza jeden z dwóch submodeli (jednego z nich może nie być) -private: - TSubModel *pModelOn,*pModelOff; //submodel dla stanu załączonego i wyłączonego - bool bOn; - int iFeedbackBit; //Ra: bit informacji zwrotnej, do wyprowadzenia na pulpit - void __fastcall Update(); -public: - __fastcall TButton(); - __fastcall ~TButton(); - void __fastcall Clear(int i=-1); - inline void FeedbackBitSet(int i) {iFeedbackBit=1<M_PI) - Yaw-=2*M_PI; - else if (Yaw<-M_PI) - Yaw+=2*M_PI; - if (Type==tp_Follow) //jeżeli jazda z pojazdem - { - Fix(Pitch,-M_PI_4,M_PI_4); //ograniczenie kąta spoglądania w dół i w górę - //Fix(Yaw,-M_PI,M_PI); - } + // McZapkie-170402: zeby mysz dzialala zawsze if (Type==tp_Follow) + Pitch += y; + Yaw += -x; + if (Yaw > M_PI) + Yaw -= 2 * M_PI; + else if (Yaw < -M_PI) + Yaw += 2 * M_PI; + if (Type == tp_Follow) // jeżeli jazda z pojazdem + { + Fix(Pitch, -M_PI_4, M_PI_4); // ograniczenie kąta spoglądania w dół i w górę + // Fix(Yaw,-M_PI,M_PI); + } } void __fastcall TCamera::Update() { - //ABu: zmiana i uniezaleznienie predkosci od FPS - double a= (Console::Pressed(VK_SHIFT)?5.00:1.00); + // ABu: zmiana i uniezaleznienie predkosci od FPS + double a = (Console::Pressed(VK_SHIFT) ? 5.00 : 1.00); if (Console::Pressed(VK_CONTROL)) - a=a*100; -// OldVelocity=Velocity; - if (FreeFlyModeFlag==true) - Type=tp_Free; + a = a * 100; + // OldVelocity=Velocity; + if (FreeFlyModeFlag == true) + Type = tp_Free; else - Type=tp_Follow; - if (Type==tp_Free) + Type = tp_Follow; + if (Type == tp_Free) { - if (Console::Pressed(Global::Keys[k_MechUp])) Velocity.y+=a; - if (Console::Pressed(Global::Keys[k_MechDown])) Velocity.y-=a; -//McZapkie-170402: zeby nie bylo konfliktow -/* - if (Console::Pressed(VkKeyScan('d'))) - Velocity.x+= a*Timer::GetDeltaTime(); - if (Console::Pressed(VkKeyScan('a'))) - Velocity.x-= a*Timer::GetDeltaTime(); - if (Console::Pressed(VkKeyScan('w'))) - Velocity.z-= a*Timer::GetDeltaTime(); - if (Console::Pressed(VkKeyScan('s'))) - Velocity.z+= a*Timer::GetDeltaTime(); + if (Console::Pressed(Global::Keys[k_MechUp])) + Velocity.y += a; + if (Console::Pressed(Global::Keys[k_MechDown])) + Velocity.y -= a; + // McZapkie-170402: zeby nie bylo konfliktow + /* + if (Console::Pressed(VkKeyScan('d'))) + Velocity.x+= a*Timer::GetDeltaTime(); + if (Console::Pressed(VkKeyScan('a'))) + Velocity.x-= a*Timer::GetDeltaTime(); + if (Console::Pressed(VkKeyScan('w'))) + Velocity.z-= a*Timer::GetDeltaTime(); + if (Console::Pressed(VkKeyScan('s'))) + Velocity.z+= a*Timer::GetDeltaTime(); - if (Console::Pressed(VK_NUMPAD4) || Console::Pressed(VK_NUMPAD7) || Console::Pressed(VK_NUMPAD1)) - Yaw+= +1*M_PI*Timer::GetDeltaTime(); + if (Console::Pressed(VK_NUMPAD4) || Console::Pressed(VK_NUMPAD7) || + Console::Pressed(VK_NUMPAD1)) + Yaw+= +1*M_PI*Timer::GetDeltaTime(); - if (Console::Pressed(VK_NUMPAD6) || Console::Pressed(VK_NUMPAD9) || Console::Pressed(VK_NUMPAD3)) - Yaw+= -1*M_PI*Timer::GetDeltaTime(); + if (Console::Pressed(VK_NUMPAD6) || Console::Pressed(VK_NUMPAD9) || + Console::Pressed(VK_NUMPAD3)) + Yaw+= -1*M_PI*Timer::GetDeltaTime(); - if (Pressed(VK_NUMPAD2) || Console::Pressed(VK_NUMPAD1) || Console::Pressed(VK_NUMPAD3)) - Pitch+= -1*M_PI*Timer::GetDeltaTime(); + if (Pressed(VK_NUMPAD2) || Console::Pressed(VK_NUMPAD1) || + Console::Pressed(VK_NUMPAD3)) + Pitch+= -1*M_PI*Timer::GetDeltaTime(); - if (Console::Pressed(VK_NUMPAD8) || Console::Pressed(VK_NUMPAD7) || Console::Pressed(VK_NUMPAD9)) - Pitch+= +1*M_PI*Timer::GetDeltaTime(); - if (Console::Pressed(VkKeyScan('.'))) - Roll+= -1*M_PI*Timer::GetDeltaTime(); - if (Console::Pressed(VkKeyScan(','))) - Roll+= +1*M_PI*Timer::GetDeltaTime(); + if (Console::Pressed(VK_NUMPAD8) || Console::Pressed(VK_NUMPAD7) || + Console::Pressed(VK_NUMPAD9)) + Pitch+= +1*M_PI*Timer::GetDeltaTime(); + if (Console::Pressed(VkKeyScan('.'))) + Roll+= -1*M_PI*Timer::GetDeltaTime(); + if (Console::Pressed(VkKeyScan(','))) + Roll+= +1*M_PI*Timer::GetDeltaTime(); - if (Console::Pressed(VK_NUMPAD5)) - Pitch=Roll= 0.0f; -*/ + if (Console::Pressed(VK_NUMPAD5)) + Pitch=Roll= 0.0f; + */ -//McZapkie-170402: poruszanie i rozgladanie we free takie samo jak w follow - if (Console::Pressed(Global::Keys[k_MechRight])) Velocity.x+=a; - if (Console::Pressed(Global::Keys[k_MechLeft])) Velocity.x-=a; - if (Console::Pressed(Global::Keys[k_MechForward])) Velocity.z-=a; - if (Console::Pressed(Global::Keys[k_MechBackward])) Velocity.z+=a; -//gora-dol - //if (Console::Pressed(VK_NUMPAD9)) Pos.y+=0.1; - //if (Console::Pressed(VK_NUMPAD3)) Pos.y-=0.1; + // McZapkie-170402: poruszanie i rozgladanie we free takie samo jak w follow + if (Console::Pressed(Global::Keys[k_MechRight])) + Velocity.x += a; + if (Console::Pressed(Global::Keys[k_MechLeft])) + Velocity.x -= a; + if (Console::Pressed(Global::Keys[k_MechForward])) + Velocity.z -= a; + if (Console::Pressed(Global::Keys[k_MechBackward])) + Velocity.z += a; + // gora-dol + // if (Console::Pressed(VK_NUMPAD9)) Pos.y+=0.1; + // if (Console::Pressed(VK_NUMPAD3)) Pos.y-=0.1; -//McZapkie: zeby nie hustalo przy malym FPS: -// Velocity= (Velocity+OldVelocity)/2; -// matrix4x4 mat; - vector3 Vec=Velocity; + // McZapkie: zeby nie hustalo przy malym FPS: + // Velocity= (Velocity+OldVelocity)/2; + // matrix4x4 mat; + vector3 Vec = Velocity; Vec.RotateY(Yaw); - Pos=Pos+Vec*Timer::GetDeltaRenderTime(); //czas bez pauzy - Velocity=Velocity/2; //płynne hamowanie ruchu -// double tmp= 10*DeltaTime; -// Velocity+= -Velocity*10 * Timer::GetDeltaTime();//( tmp<1 ? tmp : 1 ); -// Type= tp_Free; + Pos = Pos + Vec * Timer::GetDeltaRenderTime(); // czas bez pauzy + Velocity = Velocity / 2; // płynne hamowanie ruchu + // double tmp= 10*DeltaTime; + // Velocity+= -Velocity*10 * Timer::GetDeltaTime();//( tmp<1 ? tmp : 1 ); + // Type= tp_Free; } - } vector3 __fastcall TCamera::GetDirection() { matrix4x4 mat; vector3 Vec; - Vec= vector3(0,0,1); + Vec = vector3(0, 0, 1); Vec.RotateY(Yaw); return (Normalize(Vec)); } -//bool __fastcall TCamera::GetMatrix(matrix4x4 &Matrix) +// bool __fastcall TCamera::GetMatrix(matrix4x4 &Matrix) bool __fastcall TCamera::SetMatrix() { - glRotated(-Roll*180.0f/M_PI,0,0,1); //po wyłączeniu tego kręci się pojazd, a sceneria nie - glRotated(-Pitch*180.0f/M_PI,1,0,0); - glRotated(-Yaw*180.0f/M_PI,0,1,0); //w zewnętrznym widoku: kierunek patrzenia + glRotated(-Roll * 180.0f / M_PI, 0, 0, 1); // po wyłączeniu tego kręci się pojazd, a sceneria + // nie + glRotated(-Pitch * 180.0f / M_PI, 1, 0, 0); + glRotated(-Yaw * 180.0f / M_PI, 0, 1, 0); // w zewnętrznym widoku: kierunek patrzenia - if (Type==tp_Follow) + if (Type == tp_Follow) { -// gluLookAt(Pos.x+pOffset.x,Pos.y+pOffset.y,Pos.z+pOffset.z, -// LookAt.x+pOffset.x,LookAt.y+pOffset.y,LookAt.z+pOffset.z,vUp.x,vUp.y,vUp.z); -// gluLookAt(Pos.x+pOffset.x,Pos.y+pOffset.y,Pos.z+pOffset.z, -// LookAt.x+pOffset.x,LookAt.y+pOffset.y,LookAt.z+pOffset.z,vUp.x,vUp.y,vUp.z); - gluLookAt(Pos.x,Pos.y,Pos.z,LookAt.x,LookAt.y,LookAt.z,vUp.x,vUp.y,vUp.z); //Ra: pOffset is zero -// gluLookAt(Pos.x,Pos.y,Pos.z,Pos.x+Velocity.x,Pos.y+Velocity.y,Pos.z+Velocity.z,0,1,0); -// return true; + // gluLookAt(Pos.x+pOffset.x,Pos.y+pOffset.y,Pos.z+pOffset.z, + // LookAt.x+pOffset.x,LookAt.y+pOffset.y,LookAt.z+pOffset.z,vUp.x,vUp.y,vUp.z); + // gluLookAt(Pos.x+pOffset.x,Pos.y+pOffset.y,Pos.z+pOffset.z, + // LookAt.x+pOffset.x,LookAt.y+pOffset.y,LookAt.z+pOffset.z,vUp.x,vUp.y,vUp.z); + gluLookAt(Pos.x, Pos.y, Pos.z, LookAt.x, LookAt.y, LookAt.z, vUp.x, vUp.y, + vUp.z); // Ra: pOffset is zero + // gluLookAt(Pos.x,Pos.y,Pos.z,Pos.x+Velocity.x,Pos.y+Velocity.y,Pos.z+Velocity.z,0,1,0); + // return true; } - if (Type==tp_Satelite) - Pitch= M_PI*0.5; + if (Type == tp_Satelite) + Pitch = M_PI * 0.5; - if (Type!=tp_Follow) + if (Type != tp_Follow) { - glTranslated(-Pos.x,-Pos.y,-Pos.z); //nie zmienia kierunku patrzenia + glTranslated(-Pos.x, -Pos.y, -Pos.z); // nie zmienia kierunku patrzenia } - Global::SetCameraPosition(Pos); //było +pOffset + Global::SetCameraPosition(Pos); // było +pOffset return true; } void __fastcall TCamera::SetCabMatrix(vector3 &p) -{//ustawienie widoku z kamery bez przesunięcia robionego przez OpenGL - nie powinno tak trząść - glRotated(-Roll*180.0f/M_PI,0,0,1); - glRotated(-Pitch*180.0f/M_PI,1,0,0); - glRotated(-Yaw*180.0f/M_PI,0,1,0); //w zewnętrznym widoku: kierunek patrzenia - if (Type==tp_Follow) - gluLookAt(Pos.x-p.x,Pos.y-p.y,Pos.z-p.z,LookAt.x-p.x,LookAt.y-p.y,LookAt.z-p.z,vUp.x,vUp.y,vUp.z); //Ra: pOffset is zero +{ // ustawienie widoku z kamery bez przesunięcia robionego przez OpenGL - nie powinno tak trząść + glRotated(-Roll * 180.0f / M_PI, 0, 0, 1); + glRotated(-Pitch * 180.0f / M_PI, 1, 0, 0); + glRotated(-Yaw * 180.0f / M_PI, 0, 1, 0); // w zewnętrznym widoku: kierunek patrzenia + if (Type == tp_Follow) + gluLookAt(Pos.x - p.x, Pos.y - p.y, Pos.z - p.z, LookAt.x - p.x, LookAt.y - p.y, + LookAt.z - p.z, vUp.x, vUp.y, vUp.z); // Ra: pOffset is zero } void __fastcall TCamera::RaLook() -{//zmiana kierunku patrzenia - przelicza Yaw - vector3 where=LookAt-Pos+vector3(0,3,0); //trochę w górę od szyn - if ((where.x!=0.0)||(where.z!=0.0)) - Yaw=atan2(-where.x,-where.z); //kąt horyzontalny - double l=Length3(where); - if (l>0.0) - Pitch=asin(where.y/l); //kąt w pionie +{ // zmiana kierunku patrzenia - przelicza Yaw + vector3 where = LookAt - Pos + vector3(0, 3, 0); // trochę w górę od szyn + if ((where.x != 0.0) || (where.z != 0.0)) + Yaw = atan2(-where.x, -where.z); // kąt horyzontalny + double l = Length3(where); + if (l > 0.0) + Pitch = asin(where.y / l); // kąt w pionie }; void __fastcall TCamera::Stop() -{//wyłącznie bezwładnego ruchu po powrocie do kabiny - Type=tp_Follow; - Velocity=vector3(0,0,0); +{ // wyłącznie bezwładnego ruchu po powrocie do kabiny + Type = tp_Follow; + Velocity = vector3(0, 0, 0); }; - - - - diff --git a/Camera.h b/Camera.h index 1a77315e..0325940d 100644 --- a/Camera.h +++ b/Camera.h @@ -2,46 +2,45 @@ #ifndef CameraH #define CameraH - #include "dumb3d.h" using namespace Math3D; //--------------------------------------------------------------------------- enum TCameraType -{//tryby pracy kamery - tp_Follow, //jazda z pojazdem - tp_Free, //stoi na scenerii - tp_Satelite //widok z góry (nie używany) +{ // tryby pracy kamery + tp_Follow, // jazda z pojazdem + tp_Free, // stoi na scenerii + tp_Satelite // widok z góry (nie używany) }; class TCamera { -private: - vector3 pOffset; //nie używane (zerowe) -public: //McZapkie: potrzebuje do kiwania na boki - double Pitch; - double Yaw; //w środku: 0=do przodu; na zewnątrz: 0=na południe - double Roll; - TCameraType Type; - vector3 Pos; //współrzędne obserwatora - vector3 LookAt; //współrzędne punktu, na który ma patrzeć - vector3 vUp; - vector3 Velocity; - vector3 OldVelocity; //lepiej usredniac zeby nie bylo rozbiezne przy malym FPS - vector3 CrossPos; - double CrossDist; - void __fastcall Init(vector3 NPos, vector3 NAngle); - void __fastcall Reset() { Pitch=Yaw=Roll= 0; }; - void __fastcall OnCursorMove(double x, double y); - void __fastcall Update(); - vector3 __fastcall GetDirection(); - //vector3 inline __fastcall GetCrossPos() { return Pos+GetDirection()*CrossDist+CrossPos; }; + private: + vector3 pOffset; // nie używane (zerowe) + public: // McZapkie: potrzebuje do kiwania na boki + double Pitch; + double Yaw; // w środku: 0=do przodu; na zewnątrz: 0=na południe + double Roll; + TCameraType Type; + vector3 Pos; // współrzędne obserwatora + vector3 LookAt; // współrzędne punktu, na który ma patrzeć + vector3 vUp; + vector3 Velocity; + vector3 OldVelocity; // lepiej usredniac zeby nie bylo rozbiezne przy malym FPS + vector3 CrossPos; + double CrossDist; + void __fastcall Init(vector3 NPos, vector3 NAngle); + void __fastcall Reset() { Pitch = Yaw = Roll = 0; }; + void __fastcall OnCursorMove(double x, double y); + void __fastcall Update(); + vector3 __fastcall GetDirection(); + // vector3 inline __fastcall GetCrossPos() { return Pos+GetDirection()*CrossDist+CrossPos; }; - bool __fastcall SetMatrix(); - void __fastcall SetCabMatrix(vector3 &p); - void __fastcall RaLook(); - void __fastcall Stop(); - //bool __fastcall GetMatrix(matrix4x4 &Matrix); - vector3 PtNext, PtPrev; + bool __fastcall SetMatrix(); + void __fastcall SetCabMatrix(vector3 &p); + void __fastcall RaLook(); + void __fastcall Stop(); + // bool __fastcall GetMatrix(matrix4x4 &Matrix); + vector3 PtNext, PtPrev; }; #endif diff --git a/Classes.h b/Classes.h index eb617dec..dc553b79 100644 --- a/Classes.h +++ b/Classes.h @@ -3,24 +3,24 @@ #ifndef ClassesH #define ClassesH //--------------------------------------------------------------------------- -//Ra: zestaw klas do robienia wskaźników, aby uporządkować nagłówki +// Ra: zestaw klas do robienia wskaźników, aby uporządkować nagłówki //--------------------------------------------------------------------------- -class TTrack; //odcinek trajektorii +class TTrack; // odcinek trajektorii class TEvent; -class TTrain; //pojazd sterowany -class TDynamicObject; //pojazd w scenerii -class TGroundNode; //statyczny obiekt scenerii -class TAnimModel; //opakowanie egzemplarz modelu -class TAnimContainer; //fragment opakowania egzemplarza modelu -//class TModel3d; //siatka modelu wspólna dla egzemplarzy -class TSubModel; //fragment modelu (tu do wyświetlania terenu) -class TMemCell; //komórka pamięci +class TTrain; // pojazd sterowany +class TDynamicObject; // pojazd w scenerii +class TGroundNode; // statyczny obiekt scenerii +class TAnimModel; // opakowanie egzemplarz modelu +class TAnimContainer; // fragment opakowania egzemplarza modelu +// class TModel3d; //siatka modelu wspólna dla egzemplarzy +class TSubModel; // fragment modelu (tu do wyświetlania terenu) +class TMemCell; // komórka pamięci class cParser; -class TRealSound; //dźwięk ze współrzędnymi XYZ -class TTextSound; //dźwięk ze stenogramem +class TRealSound; // dźwięk ze współrzędnymi XYZ +class TTextSound; // dźwięk ze stenogramem class TEventLauncher; -class TTraction; //drut -class TTractionPowerSource; //zasilanie drutów +class TTraction; // drut +class TTractionPowerSource; // zasilanie drutów class TMoverParameters; namespace _mover @@ -31,24 +31,24 @@ class TRotation; namespace Mtable { -class TTrainParameters; //rozkład jazdy +class TTrainParameters; // rozkład jazdy }; -class TController; //obiekt sterujący pociągiem (AI) -class TNames; //obiekt sortujący nazwy +class TController; // obiekt sterujący pociągiem (AI) +class TNames; // obiekt sortujący nazwy typedef enum -{//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ć - cm_SetVelocity, - cm_ShuntVelocity, - cm_SetProximityVelocity, - cm_ChangeDirection, - cm_PassengerStopPoint, - cm_OutsideStation, - cm_Shunt, - cm_Command //komenda pobierana z komórki +{ // 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ć + cm_SetVelocity, + cm_ShuntVelocity, + cm_SetProximityVelocity, + cm_ChangeDirection, + cm_PassengerStopPoint, + cm_OutsideStation, + cm_Shunt, + cm_Command // komenda pobierana z komórki } TCommandType; #endif diff --git a/Console.cpp b/Console.cpp index e08b0591..c5c66941 100644 --- a/Console.cpp +++ b/Console.cpp @@ -11,9 +11,9 @@ //--------------------------------------------------------------------------- #pragma package(smart_init) -//Ra: klasa statyczna gromadząca sygnały sterujące oraz informacje zwrotne -//Ra: stan wejścia zmieniany klawiaturą albo dedykowanym urządzeniem -//Ra: stan wyjścia zmieniany przez symulację (mierniki, kontrolki) +// Ra: klasa statyczna gromadząca sygnały sterujące oraz informacje zwrotne +// Ra: stan wejścia zmieniany klawiaturą albo dedykowanym urządzeniem +// Ra: stan wyjścia zmieniany przez symulację (mierniki, kontrolki) /******************************* Do klawisza klawiatury przypisana jest maska bitowa oraz numer wejścia. @@ -73,275 +73,278 @@ public static Int32 GetScreenSaverTimeout() }; */ -//Ra: do poprawienia -void SetLedState(char Code,bool bOn) -{//Ra: bajer do migania LED-ami w klawiaturze - if (Win32Platform==VER_PLATFORM_WIN32_NT) - { - //WriteLog(AnsiString(int(GetAsyncKeyState(Code)))); - if (bool(GetAsyncKeyState(Code))!=bOn) - { - keybd_event(Code,MapVirtualKey(Code,0),KEYEVENTF_EXTENDEDKEY,0); - keybd_event(Code,MapVirtualKey(Code,0),KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP,0); - } - } - else - { - TKeyboardState KBState; - GetKeyboardState(KBState); - KBState[Code]=bOn?1:0; - SetKeyboardState(KBState); - }; +// Ra: do poprawienia +void SetLedState(char Code, bool bOn) +{ // Ra: bajer do migania LED-ami w klawiaturze + if (Win32Platform == VER_PLATFORM_WIN32_NT) + { + // WriteLog(AnsiString(int(GetAsyncKeyState(Code)))); + if (bool(GetAsyncKeyState(Code)) != bOn) + { + keybd_event(Code, MapVirtualKey(Code, 0), KEYEVENTF_EXTENDEDKEY, 0); + keybd_event(Code, MapVirtualKey(Code, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); + } + } + else + { + TKeyboardState KBState; + GetKeyboardState(KBState); + KBState[Code] = bOn ? 1 : 0; + SetKeyboardState(KBState); + }; }; //--------------------------------------------------------------------------- -int Console::iBits=0; //zmienna statyczna - obiekt Console jest jednen wspólny -int Console::iMode=0; -int Console::iConfig=0; -TPoKeys55 *Console::PoKeys55[2]={NULL,NULL}; -TLPT *Console::LPT=NULL; -int Console::iSwitch[8]; //bistabilne w kabinie, załączane z [Shift], wyłączane bez -int Console::iButton[8]; //monostabilne w kabinie, załączane podczas trzymania klawisza +int Console::iBits = 0; // zmienna statyczna - obiekt Console jest jednen wspólny +int Console::iMode = 0; +int Console::iConfig = 0; +TPoKeys55 *Console::PoKeys55[2] = {NULL, NULL}; +TLPT *Console::LPT = NULL; +int Console::iSwitch[8]; // bistabilne w kabinie, załączane z [Shift], wyłączane bez +int Console::iButton[8]; // monostabilne w kabinie, załączane podczas trzymania klawisza __fastcall Console::Console() { - PoKeys55[0]=PoKeys55[1]=NULL; - for (int i=0;i<8;++i) - {//zerowanie przełączników - iSwitch[i]=0; //bity 0..127 - bez [Ctrl], 128..255 - z [Ctrl] - iButton[i]=0; //bity 0..127 - bez [Shift], 128..255 - z [Shift] - } + PoKeys55[0] = PoKeys55[1] = NULL; + for (int i = 0; i < 8; ++i) + { // zerowanie przełączników + iSwitch[i] = 0; // bity 0..127 - bez [Ctrl], 128..255 - z [Ctrl] + iButton[i] = 0; // bity 0..127 - bez [Shift], 128..255 - z [Shift] + } }; __fastcall Console::~Console() { - delete PoKeys55[0]; - delete PoKeys55[1]; + delete PoKeys55[0]; + delete PoKeys55[1]; }; -void __fastcall Console::ModeSet(int m,int h) -{//ustawienie trybu pracy - iMode=m; - iConfig=h; +void __fastcall Console::ModeSet(int m, int h) +{ // ustawienie trybu pracy + iMode = m; + iConfig = h; }; int __fastcall Console::On() -{//załączenie konsoli (np. nawiązanie komunikacji) - iSwitch[0]=iSwitch[1]=iSwitch[2]=iSwitch[3]=0; //bity 0..127 - bez [Ctrl] - iSwitch[4]=iSwitch[5]=iSwitch[6]=iSwitch[7]=0; //bity 128..255 - z [Ctrl] - switch (iMode) - {case 1: //kontrolki klawiatury - case 2: //kontrolki klawiatury - iConfig=0; //licznik użycia Scroll Lock - break; - case 3: //LPT - LPT=new TLPT(); //otwarcie inpout32.dll - if (LPT?LPT->Connect(iConfig):false) - {//wysłać 0? - BitsUpdate(-1); //aktualizacjia stanów, bo przy wczytywaniu mogło być nieaktywne - WriteLog("Feedback Mode 3: InpOut32.dll OK"); - } - else - {//połączenie nie wyszło, ma być NULL - delete LPT; - LPT=NULL; - } - break; - case 4: //PoKeys - PoKeys55[0]=new TPoKeys55(); - if (PoKeys55[0]?PoKeys55[0]->Connect():false) - {WriteLog("Found "+PoKeys55[0]->Version()); - BitsUpdate(-1); //aktualizacjia stanów, bo przy wczytywaniu mogło być nieaktywne - } - else - {//połączenie nie wyszło, ma być NULL - delete PoKeys55[0]; - PoKeys55[0]=NULL; - } - break; - } - return 0; +{ // załączenie konsoli (np. nawiązanie komunikacji) + iSwitch[0] = iSwitch[1] = iSwitch[2] = iSwitch[3] = 0; // bity 0..127 - bez [Ctrl] + iSwitch[4] = iSwitch[5] = iSwitch[6] = iSwitch[7] = 0; // bity 128..255 - z [Ctrl] + switch (iMode) + { + case 1: // kontrolki klawiatury + case 2: // kontrolki klawiatury + iConfig = 0; // licznik użycia Scroll Lock + break; + case 3: // LPT + LPT = new TLPT(); // otwarcie inpout32.dll + if (LPT ? LPT->Connect(iConfig) : false) + { // wysłać 0? + BitsUpdate(-1); // aktualizacjia stanów, bo przy wczytywaniu mogło być nieaktywne + WriteLog("Feedback Mode 3: InpOut32.dll OK"); + } + else + { // połączenie nie wyszło, ma być NULL + delete LPT; + LPT = NULL; + } + break; + case 4: // PoKeys + PoKeys55[0] = new TPoKeys55(); + if (PoKeys55[0] ? PoKeys55[0]->Connect() : false) + { + WriteLog("Found " + PoKeys55[0]->Version()); + BitsUpdate(-1); // aktualizacjia stanów, bo przy wczytywaniu mogło być nieaktywne + } + else + { // połączenie nie wyszło, ma być NULL + delete PoKeys55[0]; + PoKeys55[0] = NULL; + } + break; + } + return 0; }; void __fastcall Console::Off() -{//wyłączenie informacji zwrotnych (reset pulpitu) - BitsClear(-1); - if ((iMode==1)||(iMode==2)) - if (iConfig&1) //licznik użycia Scroll Lock - {//bez sensu to jest, ale mi się samo włącza - SetLedState(VK_SCROLL,true); //przyciśnięty - SetLedState(VK_SCROLL,false); //zwolniony - } - delete PoKeys55[0]; PoKeys55[0]=NULL; - delete PoKeys55[1]; PoKeys55[1]=NULL; - delete LPT; LPT=NULL; +{ // wyłączenie informacji zwrotnych (reset pulpitu) + BitsClear(-1); + if ((iMode == 1) || (iMode == 2)) + if (iConfig & 1) // licznik użycia Scroll Lock + { // bez sensu to jest, ale mi się samo włącza + SetLedState(VK_SCROLL, true); // przyciśnięty + SetLedState(VK_SCROLL, false); // zwolniony + } + delete PoKeys55[0]; + PoKeys55[0] = NULL; + delete PoKeys55[1]; + PoKeys55[1] = NULL; + delete LPT; + LPT = NULL; }; -void __fastcall Console::BitsSet(int mask,int entry) -{//ustawienie bitów o podanej masce (mask) na wejściu (entry) - if ((iBits&mask)!=mask) //jeżeli zmiana - {int old=iBits; //poprzednie stany - iBits|=mask; - BitsUpdate(old^iBits); //1 dla bitów zmienionych - } +void __fastcall Console::BitsSet(int mask, int entry) +{ // ustawienie bitów o podanej masce (mask) na wejściu (entry) + if ((iBits & mask) != mask) // jeżeli zmiana + { + int old = iBits; // poprzednie stany + iBits |= mask; + BitsUpdate(old ^ iBits); // 1 dla bitów zmienionych + } }; -void __fastcall Console::BitsClear(int mask,int entry) -{//zerowanie bitów o podanej masce (mask) na wejściu (entry) - if (iBits&mask) //jeżeli zmiana - {int old=iBits; //poprzednie stany - iBits&=~mask; - BitsUpdate(old^iBits); //1 dla bitów zmienionych - } +void __fastcall Console::BitsClear(int mask, int entry) +{ // zerowanie bitów o podanej masce (mask) na wejściu (entry) + if (iBits & mask) // jeżeli zmiana + { + int old = iBits; // poprzednie stany + iBits &= ~mask; + BitsUpdate(old ^ iBits); // 1 dla bitów zmienionych + } }; void __fastcall Console::BitsUpdate(int mask) -{//aktualizacja stanu interfejsu informacji zwrotnej; (mask) - zakres zmienianych bitów - switch (iMode) - {case 1: //sterowanie światełkami klawiatury: CA/SHP+opory - if (mask&3) //gdy SHP albo CA - SetLedState(VK_CAPITAL,iBits&3); - if (mask&4) //gdy jazda na oporach - {//Scroll Lock ma jakoś dziwnie... zmiana stanu na przeciwny - SetLedState(VK_SCROLL,true); //przyciśnięty - SetLedState(VK_SCROLL,false); //zwolniony - ++iConfig; //licznik użycia Scroll Lock - } - break; - case 2: //sterowanie światełkami klawiatury: CA+SHP - if (mask&2) //gdy CA - SetLedState(VK_CAPITAL,iBits&2); - if (mask&1) //gdy SHP - {//Scroll Lock ma jakoś dziwnie... zmiana stanu na przeciwny - SetLedState(VK_SCROLL,true); //przyciśnięty - SetLedState(VK_SCROLL,false); //zwolniony - ++iConfig; //licznik użycia Scroll Lock - } - break; - case 3: //LPT Marcela z modyfikacją (jazda na oporach zamiast brzęczyka) - if (LPT) - LPT->Out(iBits); - break; - case 4: //PoKeys55 wg Marcela - wersja druga z końca 2012 - if (PoKeys55[0]) - {//pewnie trzeba będzie to dodatkowo buforować i oczekiwać na potwierdzenie - if (mask&0x0001) //b0 gdy SHP - PoKeys55[0]->Write(0x40,23-1,iBits&0x0001?1:0); - if (mask&0x0002) //b1 gdy zmieniony CA - PoKeys55[0]->Write(0x40,24-1,iBits&0x0002?1:0); - if (mask&0x0004) //b2 gdy jazda na oporach - PoKeys55[0]->Write(0x40,32-1,iBits&0x0004?1:0); - if (mask&0x0008) //b3 Lampka WS (wyłącznika szybkiego) - PoKeys55[0]->Write(0x40,25-1,iBits&0x0008?1:0); - if (mask&0x0010) //b4 Lampka przekaźnika nadmiarowego silników trakcyjnych - PoKeys55[0]->Write(0x40,27-1,iBits&0x0010?1:0); - if (mask&0x0020) //b5 Lampka styczników liniowych - PoKeys55[0]->Write(0x40,29-1,iBits&0x0020?1:0); - if (mask&0x0040) //b6 Lampka poślizgu - PoKeys55[0]->Write(0x40,30-1,iBits&0x0040?1:0); - if (mask&0x0080) //b7 Lampka "przetwornicy" - PoKeys55[0]->Write(0x40,28-1,iBits&0x0080?1:0); - if (mask&0x0100) //b8 Kontrolka przekaźnika nadmiarowego sprężarki - PoKeys55[0]->Write(0x40,33-1,iBits&0x0100?1:0); - if (mask&0x0200) //b9 Kontrolka sygnalizacji wentylatorów i oporów - PoKeys55[0]->Write(0x40,26-1,iBits&0x0200?1:0); - if (mask&0x0400) //b10 Kontrolka wysokiego rozruchu - PoKeys55[0]->Write(0x40,31-1,iBits&0x0400?1:0); - if (mask&0x0800) //b11 Kontrolka ogrzewania pociągu - PoKeys55[0]->Write(0x40,34-1,iBits&0x0800?1:0); - if (mask&0x1000) //b12 Ciśnienie w cylindrach do odbijania w haslerze - PoKeys55[0]->Write(0x40,52-1,iBits&0x1000?1:0); - if (mask&0x2000) //b13 Prąd na silnikach do odbijania w haslerze - PoKeys55[0]->Write(0x40,53-1,iBits&0x2000?1:0); - } - break; - } +{ // aktualizacja stanu interfejsu informacji zwrotnej; (mask) - zakres zmienianych bitów + switch (iMode) + { + case 1: // sterowanie światełkami klawiatury: CA/SHP+opory + if (mask & 3) // gdy SHP albo CA + SetLedState(VK_CAPITAL, iBits & 3); + if (mask & 4) // gdy jazda na oporach + { // Scroll Lock ma jakoś dziwnie... zmiana stanu na przeciwny + SetLedState(VK_SCROLL, true); // przyciśnięty + SetLedState(VK_SCROLL, false); // zwolniony + ++iConfig; // licznik użycia Scroll Lock + } + break; + case 2: // sterowanie światełkami klawiatury: CA+SHP + if (mask & 2) // gdy CA + SetLedState(VK_CAPITAL, iBits & 2); + if (mask & 1) // gdy SHP + { // Scroll Lock ma jakoś dziwnie... zmiana stanu na przeciwny + SetLedState(VK_SCROLL, true); // przyciśnięty + SetLedState(VK_SCROLL, false); // zwolniony + ++iConfig; // licznik użycia Scroll Lock + } + break; + case 3: // LPT Marcela z modyfikacją (jazda na oporach zamiast brzęczyka) + if (LPT) + LPT->Out(iBits); + break; + case 4: // PoKeys55 wg Marcela - wersja druga z końca 2012 + if (PoKeys55[0]) + { // pewnie trzeba będzie to dodatkowo buforować i oczekiwać na potwierdzenie + if (mask & 0x0001) // b0 gdy SHP + PoKeys55[0]->Write(0x40, 23 - 1, iBits & 0x0001 ? 1 : 0); + if (mask & 0x0002) // b1 gdy zmieniony CA + PoKeys55[0]->Write(0x40, 24 - 1, iBits & 0x0002 ? 1 : 0); + if (mask & 0x0004) // b2 gdy jazda na oporach + PoKeys55[0]->Write(0x40, 32 - 1, iBits & 0x0004 ? 1 : 0); + if (mask & 0x0008) // b3 Lampka WS (wyłącznika szybkiego) + PoKeys55[0]->Write(0x40, 25 - 1, iBits & 0x0008 ? 1 : 0); + if (mask & 0x0010) // b4 Lampka przekaźnika nadmiarowego silników trakcyjnych + PoKeys55[0]->Write(0x40, 27 - 1, iBits & 0x0010 ? 1 : 0); + if (mask & 0x0020) // b5 Lampka styczników liniowych + PoKeys55[0]->Write(0x40, 29 - 1, iBits & 0x0020 ? 1 : 0); + if (mask & 0x0040) // b6 Lampka poślizgu + PoKeys55[0]->Write(0x40, 30 - 1, iBits & 0x0040 ? 1 : 0); + if (mask & 0x0080) // b7 Lampka "przetwornicy" + PoKeys55[0]->Write(0x40, 28 - 1, iBits & 0x0080 ? 1 : 0); + if (mask & 0x0100) // b8 Kontrolka przekaźnika nadmiarowego sprężarki + PoKeys55[0]->Write(0x40, 33 - 1, iBits & 0x0100 ? 1 : 0); + if (mask & 0x0200) // b9 Kontrolka sygnalizacji wentylatorów i oporów + PoKeys55[0]->Write(0x40, 26 - 1, iBits & 0x0200 ? 1 : 0); + if (mask & 0x0400) // b10 Kontrolka wysokiego rozruchu + PoKeys55[0]->Write(0x40, 31 - 1, iBits & 0x0400 ? 1 : 0); + if (mask & 0x0800) // b11 Kontrolka ogrzewania pociągu + PoKeys55[0]->Write(0x40, 34 - 1, iBits & 0x0800 ? 1 : 0); + if (mask & 0x1000) // b12 Ciśnienie w cylindrach do odbijania w haslerze + PoKeys55[0]->Write(0x40, 52 - 1, iBits & 0x1000 ? 1 : 0); + if (mask & 0x2000) // b13 Prąd na silnikach do odbijania w haslerze + PoKeys55[0]->Write(0x40, 53 - 1, iBits & 0x2000 ? 1 : 0); + } + break; + } }; -bool __fastcall Console::Pressed(int x) -{//na razie tak - czyta się tylko klawiatura - return Global::bActive&&(GetKeyState(x)<0); -}; +bool __fastcall Console::Pressed(int x) { // na razie tak - czyta się tylko klawiatura return Global::bActive && (GetKeyState(x) < 0); }; -void __fastcall Console::ValueSet(int x,double y) -{//ustawienie wartości (y) na kanale analogowym (x) - if (iMode==4) - if (PoKeys55[0]) - { - PoKeys55[0]->PWM(x,(((Global::fCalibrateOut[x][3]*y)+Global::fCalibrateOut[x][2])*y+Global::fCalibrateOut[x][1])*y+Global::fCalibrateOut[x][0]); //zakres <0;1> - } +void __fastcall Console::ValueSet(int x, double y) +{ // ustawienie wartości (y) na kanale analogowym (x) + if (iMode == 4) + if (PoKeys55[0]) + { + PoKeys55[0]->PWM( + x, (((Global::fCalibrateOut[x][3] * y) + Global::fCalibrateOut[x][2]) * y + + Global::fCalibrateOut[x][1]) * + y + + Global::fCalibrateOut[x][0]); // zakres <0;1> + } }; void __fastcall Console::Update() -{//funkcja powinna być wywoływana regularnie, np. raz w każdej ramce ekranowej - if (iMode==4) - if (PoKeys55[0]) - if (PoKeys55[0]->Update((Global::iPause&8)>0)) - {//wykrycie przestawionych przełączników? - Global::iPause&=~8; - } - else - {//błąd komunikacji - zapauzować symulację? - if (!(Global::iPause&8)) //jeśli jeszcze nie oflagowana - Global::iTextMode=VK_F1; //pokazanie czasu/pauzy - Global::iPause|=8; //tak??? - PoKeys55[0]->Connect(); //próba ponownego podłączenia - } +{ // funkcja powinna być wywoływana regularnie, np. raz w każdej ramce ekranowej + if (iMode == 4) + if (PoKeys55[0]) + if (PoKeys55[0]->Update((Global::iPause & 8) > 0)) + { // wykrycie przestawionych przełączników? + Global::iPause &= ~8; + } + else + { // błąd komunikacji - zapauzować symulację? + if (!(Global::iPause & 8)) // jeśli jeszcze nie oflagowana + Global::iTextMode = VK_F1; // pokazanie czasu/pauzy + Global::iPause |= 8; // tak??? + PoKeys55[0]->Connect(); // próba ponownego podłączenia + } }; float __fastcall Console::AnalogGet(int x) -{//pobranie wartości analogowej - if (iMode==4) - if (PoKeys55[0]) - return PoKeys55[0]->fAnalog[x]; - return -1.0; +{ // pobranie wartości analogowej + if (iMode == 4) + if (PoKeys55[0]) + return PoKeys55[0]->fAnalog[x]; + return -1.0; }; unsigned char __fastcall Console::DigitalGet(int x) -{//pobranie wartości cyfrowej - if (iMode==4) - if (PoKeys55[0]) - return PoKeys55[0]->iInputs[x]; - return 0; +{ // pobranie wartości cyfrowej + if (iMode == 4) + if (PoKeys55[0]) + return PoKeys55[0]->iInputs[x]; + return 0; }; void __fastcall Console::OnKeyDown(int k) -{//naciśnięcie klawisza z powoduje wyłączenie, a - if (k&0x10000) //jeśli [Shift] - {//ustawienie bitu w tabeli przełączników bistabilnych - if (k&0x20000) //jeśli [Ctrl], to zestaw dodatkowy - iSwitch[4+(char(k)>>5)]|=1<<(k&31); //załącz bistabliny dodatkowy - else - {//z [Shift] włączenie bitu bistabilnego i dodatkowego monostabilnego - iSwitch[char(k)>>5]|=1<<(k&31); //załącz bistabliny podstawowy - iButton[4+(char(k)>>5)]|=(1<<(k&31)); //załącz monostabilny dodatkowy - } - } - else - {//zerowanie bitu w tabeli przełączników bistabilnych - if (k&0x20000) //jeśli [Ctrl], to zestaw dodatkowy - iSwitch[4+(char(k)>>5)]&=~(1<<(k&31)); //wyłącz bistabilny dodatkowy - else - {iSwitch[char(k)>>5]&=~(1<<(k&31)); //wyłącz bistabilny podstawowy - iButton[char(k)>>5]|=1<<(k&31); //załącz monostabilny podstawowy - } - } +{ // naciśnięcie klawisza z powoduje wyłączenie, a + if (k & 0x10000) // jeśli [Shift] + { // ustawienie bitu w tabeli przełączników bistabilnych + if (k & 0x20000) // jeśli [Ctrl], to zestaw dodatkowy + iSwitch[4 + (char(k) >> 5)] |= 1 << (k & 31); // załącz bistabliny dodatkowy + else + { // z [Shift] włączenie bitu bistabilnego i dodatkowego monostabilnego + iSwitch[char(k) >> 5] |= 1 << (k & 31); // załącz bistabliny podstawowy + iButton[4 + (char(k) >> 5)] |= (1 << (k & 31)); // załącz monostabilny dodatkowy + } + } + else + { // zerowanie bitu w tabeli przełączników bistabilnych + if (k & 0x20000) // jeśli [Ctrl], to zestaw dodatkowy + iSwitch[4 + (char(k) >> 5)] &= ~(1 << (k & 31)); // wyłącz bistabilny dodatkowy + else + { + iSwitch[char(k) >> 5] &= ~(1 << (k & 31)); // wyłącz bistabilny podstawowy + iButton[char(k) >> 5] |= 1 << (k & 31); // załącz monostabilny podstawowy + } + } }; void __fastcall Console::OnKeyUp(int k) -{//puszczenie klawisza w zasadzie nie ma znaczenia dla iSwitch, ale zeruje iButton - if ((k&0x20000)==0) //monostabilne tylko bez [Ctrl] - if (k&0x10000) //jeśli [Shift] - iButton[4+(char(k)>>5)]&=~(1<<(k&31)); //wyłącz monostabilny dodatkowy - else - iButton[char(k)>>5]&=~(1<<(k&31)); //wyłącz monostabilny podstawowy +{ // puszczenie klawisza w zasadzie nie ma znaczenia dla iSwitch, ale zeruje iButton + if ((k & 0x20000) == 0) // monostabilne tylko bez [Ctrl] + if (k & 0x10000) // jeśli [Shift] + iButton[4 + (char(k) >> 5)] &= ~(1 << (k & 31)); // wyłącz monostabilny dodatkowy + else + iButton[char(k) >> 5] &= ~(1 << (k & 31)); // wyłącz monostabilny podstawowy }; -int __fastcall Console::KeyDownConvert(int k) -{ - return int(ktTable[k&0x3FF].iDown); -}; -int __fastcall Console::KeyUpConvert(int k) -{ - return int(ktTable[k&0x3FF].iUp); -}; - +int __fastcall Console::KeyDownConvert(int k) { return int(ktTable[k & 0x3FF].iDown); }; +int __fastcall Console::KeyUpConvert(int k) { return int(ktTable[k & 0x3FF].iUp); }; diff --git a/Console.h b/Console.h index 00d8e3fc..bc858ebb 100644 --- a/Console.h +++ b/Console.h @@ -3,53 +3,52 @@ #ifndef ConsoleH #define ConsoleH //--------------------------------------------------------------------------- -class TConsoleDevice; //urządzenie podłączalne za pomocą DLL +class TConsoleDevice; // urządzenie podłączalne za pomocą DLL class TPoKeys55; class TLPT; -//klasy konwersji znaków wprowadzanych z klawiatury +// klasy konwersji znaków wprowadzanych z klawiatury class TKeyTrans -{//przekodowanie kodu naciśnięcia i zwolnienia klawisza -public: - short int iDown,iUp; +{ // przekodowanie kodu naciśnięcia i zwolnienia klawisza + public: + short int iDown, iUp; }; class Console -{//Ra: klasa statyczna gromadząca sygnały sterujące oraz informacje zwrotne - //Ra: stan wejścia zmieniany klawiaturą albo dedykowanym urządzeniem - //Ra: stan wyjścia zmieniany przez symulację (mierniki, kontrolki) -private: - static int iMode; //tryb pracy - static int iConfig; //dodatkowa informacja o sprzęcie (np. numer LPT) - static int iBits; //podstawowy zestaw lampek - static TPoKeys55 *PoKeys55[2]; //może ich być kilka - static TLPT *LPT; - static void __fastcall BitsUpdate(int mask); - //zmienne dla trybu "jednokabinowego", potrzebne do współpracy z pulpitem (PoKeys) - //używając klawiatury, każdy pojazd powinien mieć własny stan przełączników - //bazowym sterowaniem jest wirtualny strumień klawiatury - //przy zmianie kabiny z PoKeys, do kabiny są wysyłane stany tych przycisków - static int iSwitch[8]; //bistabilne w kabinie, załączane z [Shift], wyłączane bez - static int iButton[8]; //monostabilne w kabinie, załączane podczas trzymania klawisza - static TKeyTrans ktTable[4*256]; //tabela wczesnej konwersji klawiatury -public: - __fastcall Console(); - __fastcall ~Console(); - static void __fastcall ModeSet(int m,int h=0); - static void __fastcall BitsSet(int mask,int entry=0); - static void __fastcall BitsClear(int mask,int entry=0); - static int __fastcall On(); - static void __fastcall Off(); - static bool __fastcall Pressed(int x); - static void __fastcall ValueSet(int x,double y); - static void __fastcall Update(); - static float __fastcall AnalogGet(int x); - static unsigned char __fastcall DigitalGet(int x); - static void __fastcall OnKeyDown(int k); - static void __fastcall OnKeyUp(int k); - static int __fastcall KeyDownConvert(int k); - static int __fastcall KeyUpConvert(int k); +{ // Ra: klasa statyczna gromadząca sygnały sterujące oraz informacje zwrotne + // Ra: stan wejścia zmieniany klawiaturą albo dedykowanym urządzeniem + // Ra: stan wyjścia zmieniany przez symulację (mierniki, kontrolki) + private: + static int iMode; // tryb pracy + static int iConfig; // dodatkowa informacja o sprzęcie (np. numer LPT) + static int iBits; // podstawowy zestaw lampek + static TPoKeys55 *PoKeys55[2]; // może ich być kilka + static TLPT *LPT; + static void __fastcall BitsUpdate(int mask); + // zmienne dla trybu "jednokabinowego", potrzebne do współpracy z pulpitem (PoKeys) + // używając klawiatury, każdy pojazd powinien mieć własny stan przełączników + // bazowym sterowaniem jest wirtualny strumień klawiatury + // przy zmianie kabiny z PoKeys, do kabiny są wysyłane stany tych przycisków + static int iSwitch[8]; // bistabilne w kabinie, załączane z [Shift], wyłączane bez + static int iButton[8]; // monostabilne w kabinie, załączane podczas trzymania klawisza + static TKeyTrans ktTable[4 * 256]; // tabela wczesnej konwersji klawiatury + public: + __fastcall Console(); + __fastcall ~Console(); + static void __fastcall ModeSet(int m, int h = 0); + static void __fastcall BitsSet(int mask, int entry = 0); + static void __fastcall BitsClear(int mask, int entry = 0); + static int __fastcall On(); + static void __fastcall Off(); + static bool __fastcall Pressed(int x); + static void __fastcall ValueSet(int x, double y); + static void __fastcall Update(); + static float __fastcall AnalogGet(int x); + static unsigned char __fastcall DigitalGet(int x); + static void __fastcall OnKeyDown(int k); + static void __fastcall OnKeyUp(int k); + static int __fastcall KeyDownConvert(int k); + static int __fastcall KeyUpConvert(int k); }; #endif - diff --git a/Console/LPT.cpp b/Console/LPT.cpp index a83293e0..ac53f6cc 100644 --- a/Console/LPT.cpp +++ b/Console/LPT.cpp @@ -3,44 +3,42 @@ #include "LPT.h" #include -//LPT na USB: -//USB\VID_067B&PID_2305&REV_0200 +// LPT na USB: +// USB\VID_067B&PID_2305&REV_0200 //{9d7debbc-c85d-11d1-9eb4-006008c3a19a} -//USB\VID_067B&PID_2305\5&1E41AFF0&0&2 -//IEEE-1284 Controller +// USB\VID_067B&PID_2305\5&1E41AFF0&0&2 +// IEEE-1284 Controller HINSTANCE hDLL; -typedef USHORT (__stdcall *InPortType)(USHORT BasePort); -typedef void (__stdcall *OutPortType)(USHORT BasePort, USHORT value); +typedef USHORT(__stdcall *InPortType)(USHORT BasePort); +typedef void(__stdcall *OutPortType)(USHORT BasePort, USHORT value); InPortType InPort; OutPortType OutPort; bool __fastcall TLPT::Connect(int port) { - //ladowanie dll-ki - hDLL=LoadLibrary("inpout32.dll"); - if (hDLL) - { - InPort=(InPortType)GetProcAddress(hDLL,"Inp32"); - OutPort=(OutPortType)GetProcAddress(hDLL,"Out32"); - } - else - return false; //MessageBox(NULL,"ERROR","Błąd przy ładowaniu pliku",MB_OK); - address=port; //&0xFFFFFC; //ostatnie 2 bity mają być zerowe -> a niech sobie OUT-ują, gdzie chcą - switch (address) //nie dotyczy 0x3BC - {case 0x0378: - case 0x0278: - OutPort(address+0x402,0); //SPP, czyli jednokierunkowe wyjście - break; - case 0xBC00: - case 0xBD00: - OutPort(address+0x006,0); //0xBC06? czysta improwizacja - } - return bool(OutPort); -}; - -void __fastcall TLPT::Out(int x) -{//wysłanie bajtu do portu - OutPort(address,x); + // ladowanie dll-ki + hDLL = LoadLibrary("inpout32.dll"); + if (hDLL) + { + InPort = (InPortType)GetProcAddress(hDLL, "Inp32"); + OutPort = (OutPortType)GetProcAddress(hDLL, "Out32"); + } + else + return false; // MessageBox(NULL,"ERROR","Błąd przy ładowaniu pliku",MB_OK); + address = + port; //&0xFFFFFC; //ostatnie 2 bity mają być zerowe -> a niech sobie OUT-ują, gdzie chcą + switch (address) // nie dotyczy 0x3BC + { + case 0x0378: + case 0x0278: + OutPort(address + 0x402, 0); // SPP, czyli jednokierunkowe wyjście + break; + case 0xBC00: + case 0xBD00: + OutPort(address + 0x006, 0); // 0xBC06? czysta improwizacja + } + return bool(OutPort); }; +void __fastcall TLPT::Out(int x) { // wysłanie bajtu do portu OutPort(address, x); }; diff --git a/Console/LPT.h b/Console/LPT.h index 15311eab..ed8ef7b4 100644 --- a/Console/LPT.h +++ b/Console/LPT.h @@ -6,10 +6,11 @@ class TLPT { -private: - int address; -public: - bool __fastcall Connect(int port); - void __fastcall Out(int x); + private: + int address; + + public: + bool __fastcall Connect(int port); + void __fastcall Out(int x); }; #endif diff --git a/Console/PoKeys55.cpp b/Console/PoKeys55.cpp index c4778b37..c8cdd50c 100644 --- a/Console/PoKeys55.cpp +++ b/Console/PoKeys55.cpp @@ -6,311 +6,360 @@ #include "PoKeys55.h" //--------------------------------------------------------------------------- #pragma package(smart_init) -//HIDscaner: http://forum.simflight.com/topic/68257-latest-lua-package-for-fsuipc-and-wideclient/ +// HIDscaner: http://forum.simflight.com/topic/68257-latest-lua-package-for-fsuipc-and-wideclient/ //#define MY_DEVICE_ID "Vid_04d8&Pid_003F" //#define MY_DEVICE_ID "Vid_1dc3&Pid_1001&Rev_1000&MI_01" -//HID\Vid_1dc3&Pid_1001&Rev_1000&MI_01 - MI_01 to jest interfejs komunikacyjny (00-joystick, 02-klawiatura) +// HID\Vid_1dc3&Pid_1001&Rev_1000&MI_01 - MI_01 to jest interfejs komunikacyjny (00-joystick, +// 02-klawiatura) -HANDLE WriteHandle=INVALID_HANDLE_VALUE; -HANDLE ReadHandle =INVALID_HANDLE_VALUE; -//GUID InterfaceClassGuid={0x4d1e55b2,0xf16f,0x11cf,0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}; +HANDLE WriteHandle = INVALID_HANDLE_VALUE; +HANDLE ReadHandle = INVALID_HANDLE_VALUE; +// GUID InterfaceClassGuid={0x4d1e55b2,0xf16f,0x11cf,0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}; //{4d1e55b2-f16f-11cf-88cb-001111000030} __fastcall TPoKeys55::TPoKeys55() { - cRequest=0; - iPWMbits=1; - iFaza=0; - iLastCommand=0; - fAnalog[0]=fAnalog[1]=fAnalog[2]=fAnalog[3]=fAnalog[4]=fAnalog[5]=fAnalog[6]=-1.0; - iPWM[0]=iPWM[1]=iPWM[2]=iPWM[3]=iPWM[4]=iPWM[5]=iPWM[6]=0; - iPWM[7]=4096; - iInputs[0]=0; //czy normalnie są w stanie wysokim? - iRepeats=0; - bNoError=true; + cRequest = 0; + iPWMbits = 1; + iFaza = 0; + iLastCommand = 0; + fAnalog[0] = fAnalog[1] = fAnalog[2] = fAnalog[3] = fAnalog[4] = fAnalog[5] = fAnalog[6] = -1.0; + iPWM[0] = iPWM[1] = iPWM[2] = iPWM[3] = iPWM[4] = iPWM[5] = iPWM[6] = 0; + iPWM[7] = 4096; + iInputs[0] = 0; // czy normalnie są w stanie wysokim? + iRepeats = 0; + bNoError = true; }; //--------------------------------------------------------------------------- -__fastcall TPoKeys55::~TPoKeys55() -{ - Close(); -}; +__fastcall TPoKeys55::~TPoKeys55() { Close(); }; //--------------------------------------------------------------------------- bool __fastcall TPoKeys55::Close() -{//rozłączenie komunikacji - if (WriteHandle!=INVALID_HANDLE_VALUE) - CloseHandle(WriteHandle); - WriteHandle=INVALID_HANDLE_VALUE; - if (ReadHandle!=INVALID_HANDLE_VALUE) - CloseHandle(ReadHandle); - ReadHandle=INVALID_HANDLE_VALUE; +{ // rozłączenie komunikacji + if (WriteHandle != INVALID_HANDLE_VALUE) + CloseHandle(WriteHandle); + WriteHandle = INVALID_HANDLE_VALUE; + if (ReadHandle != INVALID_HANDLE_VALUE) + CloseHandle(ReadHandle); + ReadHandle = INVALID_HANDLE_VALUE; }; //--------------------------------------------------------------------------- bool __fastcall TPoKeys55::Connect() -{//Ra: to jest do wyczyszcznia z niepotrzebnych zmiennych i komunikatów - Close(); - GUID InterfaceClassGuid={0x4d1e55b2,0xf16f,0x11cf,0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}; //wszystkie HID tak mają - HDEVINFO DeviceInfoTable; - PSP_DEVICE_INTERFACE_DATA InterfaceDataStructure=new SP_DEVICE_INTERFACE_DATA; - PSP_DEVICE_INTERFACE_DETAIL_DATA DetailedInterfaceDataStructure=new SP_DEVICE_INTERFACE_DETAIL_DATA; - SP_DEVINFO_DATA DevInfoData; - DWORD InterfaceIndex=0; - //DWORD StatusLastError=0; - DWORD dwRegType; - DWORD dwRegSize; - DWORD StructureSize=0; - PBYTE PropertyValueBuffer; - bool MatchFound; - DWORD ErrorStatus; - HDEVINFO hDevInfo; - String DeviceIDFromRegistry; - String DeviceIDToFind="Vid_1dc3&Pid_1001&Rev_1000&MI_01"; - //First populate a list of plugged in devices (by specifying "DIGCF_PRESENT"), which are of the specified class GUID. - DeviceInfoTable=SetupDiGetClassDevs(&InterfaceClassGuid,NULL,NULL,DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); - //Now look through the list we just populated. We are trying to see if any of them match our device. - while (true) - { - InterfaceDataStructure->cbSize=sizeof(SP_DEVICE_INTERFACE_DATA); - if (SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &InterfaceClassGuid, InterfaceIndex, InterfaceDataStructure)) - { - ErrorStatus=GetLastError(); - if (ERROR_NO_MORE_ITEMS==ErrorStatus) //Did we reach the end of the list of matching devices in the DeviceInfoTable? - {//Cound not find the device. Must not have been attached. - SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need. - //ShowMessage("Erreur: Sortie1"); +{ // Ra: to jest do wyczyszcznia z niepotrzebnych zmiennych i komunikatów + Close(); + GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, + 0x11, 0x11, 0x00, 0x00, 0x30}; // wszystkie HID tak mają + HDEVINFO DeviceInfoTable; + PSP_DEVICE_INTERFACE_DATA InterfaceDataStructure = new SP_DEVICE_INTERFACE_DATA; + PSP_DEVICE_INTERFACE_DETAIL_DATA DetailedInterfaceDataStructure = + new SP_DEVICE_INTERFACE_DETAIL_DATA; + SP_DEVINFO_DATA DevInfoData; + DWORD InterfaceIndex = 0; + // DWORD StatusLastError=0; + DWORD dwRegType; + DWORD dwRegSize; + DWORD StructureSize = 0; + PBYTE PropertyValueBuffer; + bool MatchFound; + DWORD ErrorStatus; + HDEVINFO hDevInfo; + String DeviceIDFromRegistry; + String DeviceIDToFind = "Vid_1dc3&Pid_1001&Rev_1000&MI_01"; + // First populate a list of plugged in devices (by specifying "DIGCF_PRESENT"), which are of the + // specified class GUID. + DeviceInfoTable = + SetupDiGetClassDevs(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + // Now look through the list we just populated. We are trying to see if any of them match our + // device. + while (true) + { + InterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + if (SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &InterfaceClassGuid, InterfaceIndex, + InterfaceDataStructure)) + { + ErrorStatus = GetLastError(); + if (ERROR_NO_MORE_ITEMS == ErrorStatus) // Did we reach the end of the list of matching + // devices in the DeviceInfoTable? + { // Cound not find the device. Must not have been attached. + SetupDiDestroyDeviceInfoList( + DeviceInfoTable); // Clean up the old structure we no longer need. + // ShowMessage("Erreur: Sortie1"); + return false; + } + } + else // Else some other kind of unknown error ocurred... + { + ErrorStatus = GetLastError(); + SetupDiDestroyDeviceInfoList( + DeviceInfoTable); // Clean up the old structure we no longer need. + // ShowMessage("Erreur: Sortie2"); + return false; + } + // Now retrieve the hardware ID from the registry. The hardware ID contains the VID and PID, + // which we will then + // check to see if it is the correct device or not. + // Initialize an appropriate SP_DEVINFO_DATA structure. We need this structure for + // SetupDiGetDeviceRegistryProperty(). + DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + SetupDiEnumDeviceInfo(DeviceInfoTable, InterfaceIndex, &DevInfoData); + // First query for the size of the hardware ID, so we can know how big a buffer to allocate + // for the data. + SetupDiGetDeviceRegistryProperty(DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, + &dwRegType, NULL, 0, &dwRegSize); + // Allocate a buffer for the hardware ID. + // PropertyValueBuffer=(BYTE*)malloc(dwRegSize); + PropertyValueBuffer = new char[dwRegSize]; + if (PropertyValueBuffer == NULL) // if null,error,couldn't allocate enough memory + { // Can't really recover from this situation,just exit instead. + // ShowMessage("Allocation PropertyValueBuffer impossible"); + SetupDiDestroyDeviceInfoList( + DeviceInfoTable); // Clean up the old structure we no longer need. + return false; + } + // Retrieve the hardware IDs for the current device we are looking at. PropertyValueBuffer + // gets filled with a + // REG_MULTI_SZ (array of null terminated strings). To find a device,we only care about the + // very first string in the + // buffer,which will be the "device ID". The device ID is a string which contains the VID + // and PID,in the example + // format "Vid_04d8&Pid_003f". + SetupDiGetDeviceRegistryProperty(DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, + &dwRegType, PropertyValueBuffer, dwRegSize, NULL); + // Now check if the first string in the hardware ID matches the device ID of my USB device. + // ListBox1->Items->Add((char*)PropertyValueBuffer); + DeviceIDFromRegistry = StrPas((char *)PropertyValueBuffer); + // free(PropertyValueBuffer); //No longer need the PropertyValueBuffer,free the memory to + // prevent potential memory leaks + delete PropertyValueBuffer; // No longer need the PropertyValueBuffer,free the memory to + // prevent potential memory leaks + // Convert both strings to lower case. This makes the code more robust/portable accross OS + // Versions + DeviceIDFromRegistry = DeviceIDFromRegistry.LowerCase(); + DeviceIDToFind = DeviceIDToFind.LowerCase(); + // Now check if the hardware ID we are looking at contains the correct VID/PID + MatchFound = (DeviceIDFromRegistry.AnsiPos(DeviceIDToFind) > 0); + if (MatchFound == true) + { + // Device must have been found. Open read and write handles. In order to do this,we + // will need the actual device path first. + // We can get the path by calling SetupDiGetDeviceInterfaceDetail(),however,we have to + // call this function twice: The first + // time to get the size of the required structure/buffer to hold the detailed interface + // data,then a second time to actually + // get the structure (after we have allocated enough memory for the structure.) + DetailedInterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + // First call populates "StructureSize" with the correct value + SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, NULL, NULL, + &StructureSize, NULL); + DetailedInterfaceDataStructure = + (PSP_DEVICE_INTERFACE_DETAIL_DATA)(malloc(StructureSize)); // Allocate enough memory + if (DetailedInterfaceDataStructure == + NULL) // if null,error,couldn't allocate enough memory + { // Can't really recover from this situation,just exit instead. + SetupDiDestroyDeviceInfoList( + DeviceInfoTable); // Clean up the old structure we no longer need. + return false; + } + DetailedInterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + // Now call SetupDiGetDeviceInterfaceDetail() a second time to receive the goods. + SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, + DetailedInterfaceDataStructure, StructureSize, NULL, + NULL); + // We now have the proper device path,and we can finally open read and write handles to + // the device. + // We store the handles in the global variables "WriteHandle" and "ReadHandle",which we + // will use later to actually communicate. + WriteHandle = CreateFile((DetailedInterfaceDataStructure->DevicePath), GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + ErrorStatus = GetLastError(); + // if (ErrorStatus==ERROR_SUCCESS) + // ToggleLedBtn->Enabled=true;//Make button no longer greyed out + ReadHandle = CreateFile((DetailedInterfaceDataStructure->DevicePath), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + ErrorStatus = GetLastError(); + if (ErrorStatus == ERROR_SUCCESS) + { + // GetPushbuttonState->Enabled=true;//Make button no longer greyed out + // StateLabel->Enabled=true;//Make label no longer greyed out + } + SetupDiDestroyDeviceInfoList( + DeviceInfoTable); // Clean up the old structure we no longer need. + iRepeats = 0; // nowe szanse na podłączenie + return true; + } + InterfaceIndex++; + // Keep looping until we either find a device with matching VID and PID,or until we run out + // of items. + } // end of while(true) + // ShowMessage("Sortie"); return false; - } - } - else //Else some other kind of unknown error ocurred... - { - ErrorStatus=GetLastError(); - SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need. - //ShowMessage("Erreur: Sortie2"); - return false; - } - //Now retrieve the hardware ID from the registry. The hardware ID contains the VID and PID, which we will then - //check to see if it is the correct device or not. - //Initialize an appropriate SP_DEVINFO_DATA structure. We need this structure for SetupDiGetDeviceRegistryProperty(). - DevInfoData.cbSize=sizeof(SP_DEVINFO_DATA); - SetupDiEnumDeviceInfo(DeviceInfoTable,InterfaceIndex,&DevInfoData); - //First query for the size of the hardware ID, so we can know how big a buffer to allocate for the data. - SetupDiGetDeviceRegistryProperty(DeviceInfoTable,&DevInfoData,SPDRP_HARDWAREID,&dwRegType,NULL,0,&dwRegSize); - //Allocate a buffer for the hardware ID. - //PropertyValueBuffer=(BYTE*)malloc(dwRegSize); - PropertyValueBuffer=new char[dwRegSize]; - if (PropertyValueBuffer==NULL) //if null,error,couldn't allocate enough memory - {//Can't really recover from this situation,just exit instead. - //ShowMessage("Allocation PropertyValueBuffer impossible"); - SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need. - return false; - } - //Retrieve the hardware IDs for the current device we are looking at. PropertyValueBuffer gets filled with a - //REG_MULTI_SZ (array of null terminated strings). To find a device,we only care about the very first string in the - //buffer,which will be the "device ID". The device ID is a string which contains the VID and PID,in the example - //format "Vid_04d8&Pid_003f". - SetupDiGetDeviceRegistryProperty(DeviceInfoTable,&DevInfoData,SPDRP_HARDWAREID,&dwRegType,PropertyValueBuffer,dwRegSize,NULL); - //Now check if the first string in the hardware ID matches the device ID of my USB device. - //ListBox1->Items->Add((char*)PropertyValueBuffer); - DeviceIDFromRegistry=StrPas((char*)PropertyValueBuffer); - //free(PropertyValueBuffer); //No longer need the PropertyValueBuffer,free the memory to prevent potential memory leaks - delete PropertyValueBuffer; //No longer need the PropertyValueBuffer,free the memory to prevent potential memory leaks - //Convert both strings to lower case. This makes the code more robust/portable accross OS Versions - DeviceIDFromRegistry=DeviceIDFromRegistry.LowerCase(); - DeviceIDToFind=DeviceIDToFind.LowerCase(); - //Now check if the hardware ID we are looking at contains the correct VID/PID - MatchFound=(DeviceIDFromRegistry.AnsiPos(DeviceIDToFind)>0); - if (MatchFound==true) - { - //Device must have been found. Open read and write handles. In order to do this,we will need the actual device path first. - //We can get the path by calling SetupDiGetDeviceInterfaceDetail(),however,we have to call this function twice: The first - //time to get the size of the required structure/buffer to hold the detailed interface data,then a second time to actually - //get the structure (after we have allocated enough memory for the structure.) - DetailedInterfaceDataStructure->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - //First call populates "StructureSize" with the correct value - SetupDiGetDeviceInterfaceDetail(DeviceInfoTable,InterfaceDataStructure,NULL,NULL,&StructureSize,NULL); - DetailedInterfaceDataStructure=(PSP_DEVICE_INTERFACE_DETAIL_DATA)(malloc(StructureSize)); //Allocate enough memory - if (DetailedInterfaceDataStructure==NULL) //if null,error,couldn't allocate enough memory - {//Can't really recover from this situation,just exit instead. - SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need. - return false; - } - DetailedInterfaceDataStructure->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - //Now call SetupDiGetDeviceInterfaceDetail() a second time to receive the goods. - SetupDiGetDeviceInterfaceDetail(DeviceInfoTable,InterfaceDataStructure,DetailedInterfaceDataStructure,StructureSize,NULL,NULL); - //We now have the proper device path,and we can finally open read and write handles to the device. - //We store the handles in the global variables "WriteHandle" and "ReadHandle",which we will use later to actually communicate. - WriteHandle=CreateFile((DetailedInterfaceDataStructure->DevicePath),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,0); - ErrorStatus=GetLastError(); - //if (ErrorStatus==ERROR_SUCCESS) - // ToggleLedBtn->Enabled=true;//Make button no longer greyed out - ReadHandle=CreateFile((DetailedInterfaceDataStructure->DevicePath),GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,0); - ErrorStatus=GetLastError(); - if (ErrorStatus==ERROR_SUCCESS) - { - //GetPushbuttonState->Enabled=true;//Make button no longer greyed out - //StateLabel->Enabled=true;//Make label no longer greyed out - } - SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need. - iRepeats=0; //nowe szanse na podłączenie - return true; - } - InterfaceIndex++; - //Keep looping until we either find a device with matching VID and PID,or until we run out of items. - }//end of while(true) - //ShowMessage("Sortie"); - return false; } //--------------------------------------------------------------------------- -bool __fastcall TPoKeys55::Write(unsigned char c,unsigned char b3,unsigned char b4,unsigned char b5) +bool __fastcall TPoKeys55::Write(unsigned char c, unsigned char b3, unsigned char b4, + unsigned char b5) { - DWORD BytesWritten=0; - OutputBuffer[0]=0; //The first byte is the "Report ID" and does not get transmitted over the USB bus. Always set=0. - OutputBuffer[1]=0xBB; //0xBB - bajt rozpoznawczy dla PoKeys55 - OutputBuffer[2]=iLastCommand=c; //operacja: 0x31: blokowy odczyt wejść - OutputBuffer[3]=b3; //np. numer pinu (o 1 mniej niż numer na płytce) - OutputBuffer[4]=b4; - OutputBuffer[5]=b5; - OutputBuffer[6]=0; - OutputBuffer[7]=++cRequest; //numer żądania - OutputBuffer[8]=0; - for (int i=0;i<8;++i) - OutputBuffer[8]+=OutputBuffer[i]; //czy sumować też od 9 do 64? - //The basic Windows I/O functions WriteFile() and ReadFile() can be used to read and write to HID class USB devices - //(once we have the read and write handles to the device, which are obtained with CreateFile()). - //The following call to WriteFile() sends 64 bytes of data to the USB device. - WriteFile(WriteHandle,&OutputBuffer,65,&BytesWritten,0); //Blocking function, unless an "overlapped" structure is used - return (BytesWritten==65); - //Read(); //odczyt trzeba zrobić inaczej - w tym miejscu będzie za szybko i nic się nie odczyta + DWORD BytesWritten = 0; + OutputBuffer[0] = 0; // The first byte is the "Report ID" and does not get transmitted over the + // USB bus. Always set=0. + OutputBuffer[1] = 0xBB; // 0xBB - bajt rozpoznawczy dla PoKeys55 + OutputBuffer[2] = iLastCommand = c; // operacja: 0x31: blokowy odczyt wejść + OutputBuffer[3] = b3; // np. numer pinu (o 1 mniej niż numer na płytce) + OutputBuffer[4] = b4; + OutputBuffer[5] = b5; + OutputBuffer[6] = 0; + OutputBuffer[7] = ++cRequest; // numer żądania + OutputBuffer[8] = 0; + for (int i = 0; i < 8; ++i) + OutputBuffer[8] += OutputBuffer[i]; // czy sumować też od 9 do 64? + // The basic Windows I/O functions WriteFile() and ReadFile() can be used to read and write to + // HID class USB devices + //(once we have the read and write handles to the device, which are obtained with CreateFile()). + // The following call to WriteFile() sends 64 bytes of data to the USB device. + WriteFile(WriteHandle, &OutputBuffer, 65, &BytesWritten, + 0); // Blocking function, unless an "overlapped" structure is used + return (BytesWritten == 65); + // Read(); //odczyt trzeba zrobić inaczej - w tym miejscu będzie za szybko i nic się nie odczyta } //--------------------------------------------------------------------------- bool __fastcall TPoKeys55::Read() { - DWORD BytesRead=0; - InputBuffer[0]=0; //The first byte is the "Report ID" and does not get transmitted over the USB bus. Always set=0. - //Now get the response packet from the firmware. - //The following call to ReadFIle() retrieves 64 bytes of data from the USB device. - ReadFile(ReadHandle,&InputBuffer,65,&BytesRead,0); //Blocking function,unless an "overlapped" structure is used - //InputPacketBuffer[0] is the report ID, which we don't care about. - //InputPacketBuffer[1] is an echo back of the command. - //InputPacketBuffer[2] contains the I/O port pin value for the pushbutton. - return (BytesRead==65)?InputBuffer[7]==cRequest:false; + DWORD BytesRead = 0; + InputBuffer[0] = 0; // The first byte is the "Report ID" and does not get transmitted over the + // USB bus. Always set=0. + // Now get the response packet from the firmware. + // The following call to ReadFIle() retrieves 64 bytes of data from the USB device. + ReadFile(ReadHandle, &InputBuffer, 65, &BytesRead, + 0); // Blocking function,unless an "overlapped" structure is used + // InputPacketBuffer[0] is the report ID, which we don't care about. + // InputPacketBuffer[1] is an echo back of the command. + // InputPacketBuffer[2] contains the I/O port pin value for the pushbutton. + return (BytesRead == 65) ? InputBuffer[7] == cRequest : false; } //--------------------------------------------------------------------------- bool __fastcall TPoKeys55::ReadLoop(int i) -{//próbuje odczytać (i) razy - do - {if (Read()) return true; - Sleep(1); //trochę poczekać, aż odpowie - } - while (--i); - return false; +{ // próbuje odczytać (i) razy + do + { + if (Read()) + return true; + Sleep(1); // trochę poczekać, aż odpowie + } while (--i); + return false; } //--------------------------------------------------------------------------- AnsiString __fastcall TPoKeys55::Version() -{//zwraca numer wersji, funkcja nieoptymalna czasowo (czeka na odpowiedź) - if (!WriteHandle) return ""; - Write(0x00,0); //0x00 - Read serial number, version - if (ReadLoop(10)) - {//3: serial MSB; 4: serial LSB; 5: software version (v(1+[4-7]).([0-3])); 6: revision number - AnsiString s="PoKeys55 #"+AnsiString((InputBuffer[3]<<8)+InputBuffer[4]); - s+=" v"+AnsiString(1+(InputBuffer[5]>>4))+"."+AnsiString(InputBuffer[5]&15)+"."+AnsiString(InputBuffer[6]); -/* //Ra: pozyskiwanie daty można sobie darować, jest poniekąd bez sensu - Write(0x04,0); //0x04 - Read build date: drugi argument zmieniać od 0 do 2, uzyskując kolejno po 4 znaki - if (ReadLoop(5)) - {//2: 0x04; 3-6: char 1-4, 5-8, 9-11; (83-65-112-32-32-49-32-50-48-49-49-0=="Sep 1 2011") - s+=" ("+AnsiString((char*)InputBuffer+3,4); - Write(0x04,1); //0x04 - Read build date: drugi argument zmieniać od 0 do 2, uzyskując kolejno po 4 znaki - if (ReadLoop(5)) - {s+=AnsiString((char*)InputBuffer+3,4); - Write(0x04,2); //0x04 - Read build date: drugi argument zmieniać od 0 do 2, uzyskując kolejno po 4 znaki - if (ReadLoop(5)) - s+=AnsiString((char*)InputBuffer+3,3); - } - s+=")"; - } -*/ - return s; - } - return ""; +{ // zwraca numer wersji, funkcja nieoptymalna czasowo (czeka na odpowiedź) + if (!WriteHandle) + return ""; + Write(0x00, 0); // 0x00 - Read serial number, version + if (ReadLoop(10)) + { // 3: serial MSB; 4: serial LSB; 5: software version (v(1+[4-7]).([0-3])); 6: revision number + AnsiString s = "PoKeys55 #" + AnsiString((InputBuffer[3] << 8) + InputBuffer[4]); + s += " v" + AnsiString(1 + (InputBuffer[5] >> 4)) + "." + AnsiString(InputBuffer[5] & 15) + + "." + AnsiString(InputBuffer[6]); + /* //Ra: pozyskiwanie daty można sobie darować, jest poniekąd bez sensu + Write(0x04,0); //0x04 - Read build date: drugi argument zmieniać od 0 do 2, uzyskując + kolejno po 4 znaki + if (ReadLoop(5)) + {//2: 0x04; 3-6: char 1-4, 5-8, 9-11; (83-65-112-32-32-49-32-50-48-49-49-0=="Sep 1 2011") + s+=" ("+AnsiString((char*)InputBuffer+3,4); + Write(0x04,1); //0x04 - Read build date: drugi argument zmieniać od 0 do 2, uzyskując + kolejno po 4 znaki + if (ReadLoop(5)) + {s+=AnsiString((char*)InputBuffer+3,4); + Write(0x04,2); //0x04 - Read build date: drugi argument zmieniać od 0 do 2, uzyskując + kolejno po 4 znaki + if (ReadLoop(5)) + s+=AnsiString((char*)InputBuffer+3,3); + } + s+=")"; + } + */ + return s; + } + return ""; }; -bool __fastcall TPoKeys55::PWM(int x,float y) -{//ustawienie wskazanego PWM (@12Mhz: 12000=1ms=1000Hz) - //iPWM[7]=1024; //1024==85333.3333333333ns=11718.75Hz - iPWM[x]=int(0.5f+0x0FFF*y)&0x0FFF; //0x0FFF=4095 - return true; +bool __fastcall TPoKeys55::PWM(int x, float y) +{ // ustawienie wskazanego PWM (@12Mhz: 12000=1ms=1000Hz) + // iPWM[7]=1024; //1024==85333.3333333333ns=11718.75Hz + iPWM[x] = int(0.5f + 0x0FFF * y) & 0x0FFF; // 0x0FFF=4095 + return true; } bool __fastcall TPoKeys55::Update(bool pause) -{//funkcja powinna być wywoływana regularnie, np. raz w każdej ramce ekranowej - if (pause) - {//specjalna procedura, jeśli utracone połączenie spowodowało pauzę - iLastCommand=0; //połączenie zostało na nowo otwarte - //iFaza=0; //jeden błąd i podtrzymanie pauzy jest kontynuowane - } - switch (iFaza) - {case 0: //uaktualnienie PWM raz na jakiś czas - OutputBuffer[9]=0x3F; //maska użytych PWM - *((int*)(OutputBuffer+10))=iPWM[0]; //PWM1 (pin 22) - *((int*)(OutputBuffer+14))=iPWM[1]; //PWM2 (pin 21) - *((int*)(OutputBuffer+18))=iPWM[2]; //PWM3 (pin 20) - *((int*)(OutputBuffer+22))=iPWM[3]; //PWM4 (pin 19) - *((int*)(OutputBuffer+26))=iPWM[4]; //PWM5 (pin 18) - *((int*)(OutputBuffer+30))=iPWM[5]; //PWM6 (pin 17) - *((int*)(OutputBuffer+34))=iPWM[7]; //PWM period - if (Write(0xCB,1)) //wysłanie ustawień (1-ustaw, 0-odczyt) - iRepeats=0; //informacja, że poszło dobrze - ++iFaza; //ta faza została zakończona - //iRepeats=0; - break; - case 1: //odczyt wejść analogowych - komenda i przetwarzanie - if (iLastCommand!=0x3A) //asynchroniczne ustawienie kontrolki może namieszać - Write(0x3A,0); //0x3A - Analog inputs reading – all analog inputs in one command - else if (Read()) - {//jest odebrana ramka i zgodność numeru żądania - fAnalog[0]=((InputBuffer[21]<<8)+InputBuffer[22])/4095.0f; //pin 47 - fAnalog[1]=((InputBuffer[19]<<8)+InputBuffer[20])/4095.0f; //pin 46 - fAnalog[2]=((InputBuffer[17]<<8)+InputBuffer[18])/4095.0f; //pin 45 - fAnalog[3]=((InputBuffer[15]<<8)+InputBuffer[16])/4095.0f; //pin 44 - fAnalog[4]=((InputBuffer[13]<<8)+InputBuffer[14])/4095.0f; //pin 43 - fAnalog[5]=((InputBuffer[11]<<8)+InputBuffer[12])/4095.0f; //pin 42 - fAnalog[6]=((InputBuffer[ 9]<<8)+InputBuffer[10])/4095.0f; //pin 41 - ++iFaza; //skoro odczytano, można przejść do kolejnej fazy - iRepeats=0; //zerowanie licznika prób - } - else ++iRepeats; //licznik nieudanych prób - break; - case 2: //odczyt wejść cyfrowych - komenda i przetwarzanie - if (iLastCommand!=0x31) //asynchroniczne ustawienie kontrolki może namieszać - Write(0x31,0); //0x31: blokowy odczyt wejść - else if (Read()) - {//jest odebrana ramka i zgodność numeru żądania - iInputs[0]=*((int*)(InputBuffer+3)); //odczyt 32 bitów - iFaza=3; //skoro odczytano, można kolejny cykl - iRepeats=0; //zerowanie licznika prób - } - else ++iRepeats; //licznik nieudanych prób - break; - case 3: //ustawienie wyjść analogowych, 0..4095 mapować na 0..65520 (<<4) - if (Write(0x41,43-1,(iPWM[6]>>4),(iPWM[6]<<4))) //wysłanie ustawień - iRepeats=0; //informacja, że poszło dobrze - iFaza=0; //++iFaza; //ta faza została zakończona - //powinno jeszcze przyjść potwierdzenie o kodzie 0x41 - break; - default: - iFaza=0; //na wypadek, gdyby zbłądziło po jakichś zmianach w kodzie - //iRepeats=0; - } - if (!iRepeats) - bNoError=true; //jest OK - else if (iRepeats>=10) //youBy 2014-07: przy 5 powtórzeniach sieje mi pauzą po 2 razy na sekundę, a przy 10 jest ok - {//przekroczenie liczby prób wymusza kolejną fazę - ++iFaza; - iRepeats=1; //w nowej fazie nowe szanse, ale nie od 0! - bNoError=false; //zgłosić błąd - } - return (bNoError); //true oznacza prawidłowe działanie - //czy w przypadku błędu komunikacji z PoKeys włączać pauzę? - //dopiero poprawne podłączenie zeruje licznik prób +{ // funkcja powinna być wywoływana regularnie, np. raz w każdej ramce ekranowej + if (pause) + { // specjalna procedura, jeśli utracone połączenie spowodowało pauzę + iLastCommand = 0; // połączenie zostało na nowo otwarte + // iFaza=0; //jeden błąd i podtrzymanie pauzy jest kontynuowane + } + switch (iFaza) + { + case 0: // uaktualnienie PWM raz na jakiś czas + OutputBuffer[9] = 0x3F; // maska użytych PWM + *((int *)(OutputBuffer + 10)) = iPWM[0]; // PWM1 (pin 22) + *((int *)(OutputBuffer + 14)) = iPWM[1]; // PWM2 (pin 21) + *((int *)(OutputBuffer + 18)) = iPWM[2]; // PWM3 (pin 20) + *((int *)(OutputBuffer + 22)) = iPWM[3]; // PWM4 (pin 19) + *((int *)(OutputBuffer + 26)) = iPWM[4]; // PWM5 (pin 18) + *((int *)(OutputBuffer + 30)) = iPWM[5]; // PWM6 (pin 17) + *((int *)(OutputBuffer + 34)) = iPWM[7]; // PWM period + if (Write(0xCB, 1)) // wysłanie ustawień (1-ustaw, 0-odczyt) + iRepeats = 0; // informacja, że poszło dobrze + ++iFaza; // ta faza została zakończona + // iRepeats=0; + break; + case 1: // odczyt wejść analogowych - komenda i przetwarzanie + if (iLastCommand != 0x3A) // asynchroniczne ustawienie kontrolki może namieszać + Write(0x3A, 0); // 0x3A - Analog inputs reading – all analog inputs in one command + else if (Read()) + { // jest odebrana ramka i zgodność numeru żądania + fAnalog[0] = ((InputBuffer[21] << 8) + InputBuffer[22]) / 4095.0f; // pin 47 + fAnalog[1] = ((InputBuffer[19] << 8) + InputBuffer[20]) / 4095.0f; // pin 46 + fAnalog[2] = ((InputBuffer[17] << 8) + InputBuffer[18]) / 4095.0f; // pin 45 + fAnalog[3] = ((InputBuffer[15] << 8) + InputBuffer[16]) / 4095.0f; // pin 44 + fAnalog[4] = ((InputBuffer[13] << 8) + InputBuffer[14]) / 4095.0f; // pin 43 + fAnalog[5] = ((InputBuffer[11] << 8) + InputBuffer[12]) / 4095.0f; // pin 42 + fAnalog[6] = ((InputBuffer[9] << 8) + InputBuffer[10]) / 4095.0f; // pin 41 + ++iFaza; // skoro odczytano, można przejść do kolejnej fazy + iRepeats = 0; // zerowanie licznika prób + } + else + ++iRepeats; // licznik nieudanych prób + break; + case 2: // odczyt wejść cyfrowych - komenda i przetwarzanie + if (iLastCommand != 0x31) // asynchroniczne ustawienie kontrolki może namieszać + Write(0x31, 0); // 0x31: blokowy odczyt wejść + else if (Read()) + { // jest odebrana ramka i zgodność numeru żądania + iInputs[0] = *((int *)(InputBuffer + 3)); // odczyt 32 bitów + iFaza = 3; // skoro odczytano, można kolejny cykl + iRepeats = 0; // zerowanie licznika prób + } + else + ++iRepeats; // licznik nieudanych prób + break; + case 3: // ustawienie wyjść analogowych, 0..4095 mapować na 0..65520 (<<4) + if (Write(0x41, 43 - 1, (iPWM[6] >> 4), (iPWM[6] << 4))) // wysłanie ustawień + iRepeats = 0; // informacja, że poszło dobrze + iFaza = 0; //++iFaza; //ta faza została zakończona + // powinno jeszcze przyjść potwierdzenie o kodzie 0x41 + break; + default: + iFaza = 0; // na wypadek, gdyby zbłądziło po jakichś zmianach w kodzie + // iRepeats=0; + } + if (!iRepeats) + bNoError = true; // jest OK + else if (iRepeats >= 10) // youBy 2014-07: przy 5 powtórzeniach sieje mi pauzą po 2 razy na + // sekundę, a przy 10 jest ok + { // przekroczenie liczby prób wymusza kolejną fazę + ++iFaza; + iRepeats = 1; // w nowej fazie nowe szanse, ale nie od 0! + bNoError = false; // zgłosić błąd + } + return (bNoError); // true oznacza prawidłowe działanie + // czy w przypadku błędu komunikacji z PoKeys włączać pauzę? + // dopiero poprawne podłączenie zeruje licznik prób }; - diff --git a/Console/PoKeys55.h b/Console/PoKeys55.h index 29da7b22..ab22d5c3 100644 --- a/Console/PoKeys55.h +++ b/Console/PoKeys55.h @@ -3,29 +3,30 @@ #define PoKeys55H //--------------------------------------------------------------------------- class TPoKeys55 -{//komunikacja z PoKeys bez określania przeznaczenia pinów - unsigned char cRequest; //numer żądania do sprawdzania odpowiedzi - unsigned char OutputBuffer[65]; //Allocate a memory buffer equal to our endpoint size + 1 - unsigned char InputBuffer[65]; //Allocate a memory buffer equal to our endpoint size + 1 - int iPWM[8]; //0-5:wyjścia PWM,6:analogowe,7:częstotliwośc PWM - int iPWMbits; - int iLastCommand; - int iFaza; - int iRepeats; //liczba powtórzeń - bool bNoError; //zerowany po przepełnieniu licznika powtórzeń, ustawiany po udanej operacji -public: - float fAnalog[7]; //wejścia analogowe, stan <0.0,1.0> - int iInputs[8]; - __fastcall TPoKeys55(); - __fastcall ~TPoKeys55(); - bool __fastcall Connect(); - bool __fastcall Close(); - bool __fastcall Write(unsigned char c,unsigned char b3,unsigned char b4=0,unsigned char b5=0); - bool __fastcall Read(); - bool __fastcall ReadLoop(int i); - AnsiString __fastcall Version(); - bool __fastcall PWM(int x,float y); - bool __fastcall Update(bool pause); +{ // komunikacja z PoKeys bez określania przeznaczenia pinów + unsigned char cRequest; // numer żądania do sprawdzania odpowiedzi + unsigned char OutputBuffer[65]; // Allocate a memory buffer equal to our endpoint size + 1 + unsigned char InputBuffer[65]; // Allocate a memory buffer equal to our endpoint size + 1 + int iPWM[8]; // 0-5:wyjścia PWM,6:analogowe,7:częstotliwośc PWM + int iPWMbits; + int iLastCommand; + int iFaza; + int iRepeats; // liczba powtórzeń + bool bNoError; // zerowany po przepełnieniu licznika powtórzeń, ustawiany po udanej operacji + public: + float fAnalog[7]; // wejścia analogowe, stan <0.0,1.0> + int iInputs[8]; + __fastcall TPoKeys55(); + __fastcall ~TPoKeys55(); + bool __fastcall Connect(); + bool __fastcall Close(); + bool __fastcall Write(unsigned char c, unsigned char b3, unsigned char b4 = 0, + unsigned char b5 = 0); + bool __fastcall Read(); + bool __fastcall ReadLoop(int i); + AnsiString __fastcall Version(); + bool __fastcall PWM(int x, float y); + bool __fastcall Update(bool pause); }; //--------------------------------------------------------------------------- #endif diff --git a/Curve.cpp b/Curve.cpp index 85e36dfd..0fba7d7d 100644 --- a/Curve.cpp +++ b/Curve.cpp @@ -1,110 +1,109 @@ //--------------------------------------------------------------------------- -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Curve.h" - __fastcall TCurve::TCurve() { - Values= NULL; - iNumValues= 0; - iNumCols= 0; + Values = NULL; + iNumValues = 0; + iNumCols = 0; } __fastcall TCurve::~TCurve() { - for (int i=0; i=iNumValues) - return Values[iNumValues-1][c]; - p-= floor(p); - return Values[a][c]*(1.0f-p)+Values[b][c]*(p); + int a = floor(p); + int b = ceil(p); + if (a < 0) + return Values[0][c]; + if (b >= iNumValues) + return Values[iNumValues - 1][c]; + p -= floor(p); + return Values[a][c] * (1.0f - p) + Values[b][c] * (p); } bool __fastcall TCurve::SetValue(int c, float p, float v) { - int a= floor(p); - int b= ceil(p); - if (a<0) - return false; - if (b>=iNumValues) + int a = floor(p); + int b = ceil(p); + if (a < 0) return false; - p-= floor(p); - if (p<0.5) - Values[a][c]= v; + if (b >= iNumValues) + return false; + p -= floor(p); + if (p < 0.5) + Values[a][c] = v; else - Values[b][c]= v; + Values[b][c] = v; return true; } bool __fastcall TCurve::Load(TQueryParserComp *Parser) { - DecimalSeparator= '.'; + DecimalSeparator = '.'; AnsiString Token; - int n= Parser->GetNextSymbol().ToInt(); - int c= Parser->GetNextSymbol().ToInt(); - Init(n,c); + int n = Parser->GetNextSymbol().ToInt(); + int c = Parser->GetNextSymbol().ToInt(); + Init(n, c); - n=0; + n = 0; int i; - while (!Parser->EOF && nEOF && n < iNumValues) { - for (i=0; iGetNextSymbol().ToDouble(); + for (i = 0; i < iNumCols; i++) + Values[n][i] = Parser->GetNextSymbol().ToDouble(); n++; } - DecimalSeparator= ','; + DecimalSeparator = ','; } bool __fastcall TCurve::LoadFromFile(AnsiString asName) { - DecimalSeparator= '.'; + DecimalSeparator = '.'; TFileStream *fs; - fs= new TFileStream(asName, fmOpenRead | fmShareCompat ); - AnsiString str= "xxx"; - int size= fs->Size; + fs = new TFileStream(asName, fmOpenRead | fmShareCompat); + AnsiString str = "xxx"; + int size = fs->Size; str.SetLength(size); - fs->Read(str.c_str(),size); - str+= ""; + fs->Read(str.c_str(), size); + str += ""; delete fs; TQueryParserComp *Parser; - Parser= new TQueryParserComp(NULL); - Parser->TextToParse= str; + Parser = new TQueryParserComp(NULL); + Parser->TextToParse = str; Parser->First(); Load(Parser); delete Parser; - DecimalSeparator= ','; + DecimalSeparator = ','; } #include @@ -112,28 +111,27 @@ bool __fastcall TCurve::LoadFromFile(AnsiString asName) bool __fastcall TCurve::SaveToFile(AnsiString asName) { - DecimalSeparator= '.'; - FILE *stream=NULL; + DecimalSeparator = '.'; + FILE *stream = NULL; stream = fopen(asName.c_str(), "w"); AnsiString str; - str= AnsiString(iNumValues); + str = AnsiString(iNumValues); fprintf(stream, str.c_str()); fprintf(stream, "\n"); - for (int i=0; iCommand(); - double value1=evEvent->ValueGet(1); - double value2=evEvent->ValueGet(2); - if (command==cm_ShuntVelocity) - {//prędkość manewrową zapisać, najwyżej AI zignoruje przy analizie tabelki - fVelNext=value1; //powinno być value2, bo druga określa "za"? - iFlags|=0x200; - } - else if (command==cm_SetVelocity) - {//w semaforze typu "m" jest ShuntVelocity dla Ms2 i SetVelocity dla S1 - //SetVelocity * 0 -> można jechać, ale stanąć przed - //SetVelocity 0 20 -> stanąć przed, potem można jechać 20 (SBL) - //SetVelocity -1 100 -> można jechać, przy następnym ograniczenie (SBL) - //SetVelocity 40 -1 -> PutValues: jechać 40 aż do minięcia (koniec ograniczenia( - fVelNext=value1; - iFlags&=~0xE00; //nie manewrowa, nie przystanek, nie zatrzymać na SBL - if (value1==0.0) //jeśli pierwsza zerowa - if (value2!=0.0) //a druga nie - {//S1 na SBL, można przejechać po zatrzymaniu (tu nie mamy prędkości ani odległości) - fVelNext=value2; //normalnie będzie zezwolenie na jazdę, aby się usunął z tabelki - iFlags|=0x800; //flaga, że ma zatrzymać; na pewno nie zezwoli na manewry - } - } - else if (command==cm_PassengerStopPoint) //nie ma dostępu do rozkładu - {//przystanek, najwyżej AI zignoruje przy analizie tabelki - if ((iFlags&0x400)==0) - fVelNext=0.0; //TrainParams->IsStop()?0.0:-1.0; //na razie tak - iFlags|=0x400; //niestety nie da się w tym miejscu współpracować z rozkładem - } - else if (command==cm_SetProximityVelocity) - {//ignorować - fVelNext=-1; - } - else if (command==cm_OutsideStation) - {//w trybie manewrowym: skanować od niej wstecz i stanąć po wyjechaniu za sygnalizator i zmienić kierunek - //w trybie pociągowym: można przyspieszyć do wskazanej prędkości (po zjechaniu z rozjazdów) - fVelNext=-1; - iFlags|=0x2100; //W5 - } - else - {//inna komenda w evencie skanowanym powoduje zatrzymanie i wysłanie tej komendy - iFlags&=~0xE00; //nie manewrowa, nie przystanek, nie zatrzymać na SBL - fVelNext=0; //jak nieznana komenda w komórce sygnałowej, to ma stać - } +{ // sprawdzenie typu komendy w evencie i określenie prędkości + TCommandType command = evEvent->Command(); + double value1 = evEvent->ValueGet(1); + double value2 = evEvent->ValueGet(2); + if (command == cm_ShuntVelocity) + { // prędkość manewrową zapisać, najwyżej AI zignoruje przy analizie tabelki + fVelNext = value1; // powinno być value2, bo druga określa "za"? + iFlags |= 0x200; + } + else if (command == cm_SetVelocity) + { // w semaforze typu "m" jest ShuntVelocity dla Ms2 i SetVelocity dla S1 + // SetVelocity * 0 -> można jechać, ale stanąć przed + // SetVelocity 0 20 -> stanąć przed, potem można jechać 20 (SBL) + // SetVelocity -1 100 -> można jechać, przy następnym ograniczenie (SBL) + // SetVelocity 40 -1 -> PutValues: jechać 40 aż do minięcia (koniec ograniczenia( + fVelNext = value1; + iFlags &= ~0xE00; // nie manewrowa, nie przystanek, nie zatrzymać na SBL + if (value1 == 0.0) // jeśli pierwsza zerowa + if (value2 != 0.0) // a druga nie + { // S1 na SBL, można przejechać po zatrzymaniu (tu nie mamy prędkości ani odległości) + fVelNext = value2; // normalnie będzie zezwolenie na jazdę, aby się usunął z tabelki + iFlags |= 0x800; // flaga, że ma zatrzymać; na pewno nie zezwoli na manewry + } + } + else if (command == cm_PassengerStopPoint) // nie ma dostępu do rozkładu + { // przystanek, najwyżej AI zignoruje przy analizie tabelki + if ((iFlags & 0x400) == 0) + fVelNext = 0.0; // TrainParams->IsStop()?0.0:-1.0; //na razie tak + iFlags |= 0x400; // niestety nie da się w tym miejscu współpracować z rozkładem + } + else if (command == cm_SetProximityVelocity) + { // ignorować + fVelNext = -1; + } + else if (command == cm_OutsideStation) + { // w trybie manewrowym: skanować od niej wstecz i stanąć po wyjechaniu za sygnalizator i + // zmienić kierunek + // w trybie pociągowym: można przyspieszyć do wskazanej prędkości (po zjechaniu z rozjazdów) + fVelNext = -1; + iFlags |= 0x2100; // W5 + } + else + { // inna komenda w evencie skanowanym powoduje zatrzymanie i wysłanie tej komendy + iFlags &= ~0xE00; // nie manewrowa, nie przystanek, nie zatrzymać na SBL + fVelNext = 0; // jak nieznana komenda w komórce sygnałowej, to ma stać + } }; -bool __fastcall TSpeedPos::Update(vector3 *p,vector3 *dir,double &len) -{//przeliczenie odległości od punktu (*p), w kierunku (*dir), zaczynając od pojazdu - //dla kolejnych pozycji podawane są współrzędne poprzedniego obiektu w (*p) - vector3 v=vPos-*p; //wektor od poprzedniego obiektu (albo pojazdu) do punktu zmiany - fDist=v.Length(); //długość wektora to odległość pomiędzy czołem a sygnałem albo początkiem toru - //v.SafeNormalize(); //normalizacja w celu określenia znaku (nie potrzebna?) - if (len==0.0) - {//jeżeli liczymy względem pojazdu - double iska=dir?dir->x*v.x+dir->z*v.z:fDist; //iloczyn skalarny to rzut na chwilową prostą ruchu - if (iska<0.0) //iloczyn skalarny jest ujemny, gdy punkt jest z tyłu - {//jeśli coś jest z tyłu, to dokładna odległość nie ma już większego znaczenia - fDist=-fDist; //potrzebne do badania wyjechania składem poza ograniczenie - if (iFlags&32) //32 ustawione, gdy obiekt już został minięty - {//jeśli minięty (musi być minięty również przez końcówkę składu) - } - else - {iFlags^=32; //32-minięty - będziemy liczyć odległość względem przeciwnego końca toru (nadal może być z przodu i ogdaniczać) - if ((iFlags&0x43)==3) //tylko jeśli (istotny) tor, bo eventy są punktowe - if (trTrack) //może być NULL, jeśli koniec toru (????) - vPos=(iFlags&4)?trTrack->CurrentSegment()->FastGetPoint_0():trTrack->CurrentSegment()->FastGetPoint_1(); //drugi koniec istotny - } - } - else if (fDist<50.0) //przy dużym kącie łuku iloczyn skalarny bardziej zaniży odległość niż cięciwa - fDist=iska; //ale przy małych odległościach rzut na chwilową prostą ruchu da dokładniejsze wartości - } - if (fDist>0.0) //nie może być 0.0, a przypadkiem mogło by się trafić i było by źle - if ((iFlags&32)==0) //32 ustawione, gdy obiekt już został minięty - {//jeśli obiekt nie został minięty, można od niego zliczać narastająco (inaczej może być problem z wektorem kierunku) - len=fDist=len+fDist; //zliczanie dlugości narastająco - *p=vPos; //nowy punkt odniesienia - *dir=Normalize(v); //nowy wektor kierunku od poprzedniego obiektu do aktualnego - } - if (iFlags&2) //jeśli tor - { - if (trTrack) //może być NULL, jeśli koniec toru (???) - {fVelNext=trTrack->VelocityGet(); //aktualizacja prędkości (może być zmieniana eventem) - int i; - if ((i=iFlags&0xF0000000)!=0) - {//jeśli skrzyżowanie, ograniczyć prędkość przy skręcaniu - if (abs(i)>0x10000000) //±1 to jazda na wprost, ±2 nieby też, ale z przecięciem głównej drogi - chyba że jest równorzędne... - fVelNext=30.0; //uzależnić prędkość od promienia; albo niech będzie ograniczona w skrzyżowaniu (velocity z ujemną wartością) - if ((iFlags&32)==0) //jeśli nie wjechał - if (trTrack->iNumDynamics>0) //a skrzyżowanie zawiera pojazd - fVelNext=0.0; //to zabronić wjazdu (chyba że ten z przodu też jedzie prosto) - } - if (iFlags&8) //jeśli odcinek zmienny - {if (bool(trTrack->GetSwitchState()&1)!=bool(iFlags&16)) //czy stan się zmienił? - {//Ra: zakładam, że są tylko 2 możliwe stany - iFlags^=16; - //fVelNext=trTrack->VelocityGet(); //nowa prędkość - if ((iFlags&32)==0) return true; //jeszcze trzeba skanowanie wykonać od tego toru - //problem jest chyba, jeśli zwrotnica się przełoży zaraz po zjechaniu z niej - //na Mydelniczce potrafi skanować na wprost mimo pojechania na bok +bool __fastcall TSpeedPos::Update(vector3 *p, vector3 *dir, double &len) +{ // przeliczenie odległości od punktu (*p), w kierunku (*dir), zaczynając od pojazdu + // dla kolejnych pozycji podawane są współrzędne poprzedniego obiektu w (*p) + vector3 v = vPos - *p; // wektor od poprzedniego obiektu (albo pojazdu) do punktu zmiany + fDist = + v.Length(); // długość wektora to odległość pomiędzy czołem a sygnałem albo początkiem toru + // v.SafeNormalize(); //normalizacja w celu określenia znaku (nie potrzebna?) + if (len == 0.0) + { // jeżeli liczymy względem pojazdu + double iska = dir ? dir->x * v.x + dir->z * v.z : + fDist; // iloczyn skalarny to rzut na chwilową prostą ruchu + if (iska < 0.0) // iloczyn skalarny jest ujemny, gdy punkt jest z tyłu + { // jeśli coś jest z tyłu, to dokładna odległość nie ma już większego znaczenia + fDist = -fDist; // potrzebne do badania wyjechania składem poza ograniczenie + if (iFlags & 32) // 32 ustawione, gdy obiekt już został minięty + { // jeśli minięty (musi być minięty również przez końcówkę składu) + } + else + { + iFlags ^= 32; // 32-minięty - będziemy liczyć odległość względem przeciwnego końca + // toru (nadal może być z przodu i ogdaniczać) + if ((iFlags & 0x43) == 3) // tylko jeśli (istotny) tor, bo eventy są punktowe + if (trTrack) // może być NULL, jeśli koniec toru (????) + vPos = + (iFlags & 4) ? + trTrack->CurrentSegment()->FastGetPoint_0() : + trTrack->CurrentSegment()->FastGetPoint_1(); // drugi koniec istotny + } + } + else if (fDist < 50.0) // przy dużym kącie łuku iloczyn skalarny bardziej zaniży odległość + // niż cięciwa + fDist = iska; // ale przy małych odległościach rzut na chwilową prostą ruchu da + // dokładniejsze wartości } - //poniższe nie dotyczy trybu łączenia? - if ((iFlags&32)?false:trTrack->iNumDynamics>0) //jeśli jeszcze nie wjechano na tor, a coś na nim jest - fDist-=30.0,fVelNext=0.0; //to niech stanie w zwiększonej odległości - //else if (fVelNext==0.0) //jeśli została wyzerowana - // fVelNext=trTrack->VelocityGet(); //odczyt prędkości - } - } - } - else if (iFlags&0x100) //jeśli event - {//odczyt komórki pamięci najlepiej by było zrobić jako notyfikację, czyli zmiana komórki wywoła jakąś podaną funkcję - CommandCheck(); //sprawdzenie typu komendy w evencie i określenie prędkości - } - return false; + if (fDist > 0.0) // nie może być 0.0, a przypadkiem mogło by się trafić i było by źle + if ((iFlags & 32) == 0) // 32 ustawione, gdy obiekt już został minięty + { // jeśli obiekt nie został minięty, można od niego zliczać narastająco (inaczej może być + // problem z wektorem kierunku) + len = fDist = len + fDist; // zliczanie dlugości narastająco + *p = vPos; // nowy punkt odniesienia + *dir = Normalize(v); // nowy wektor kierunku od poprzedniego obiektu do aktualnego + } + if (iFlags & 2) // jeśli tor + { + if (trTrack) // może być NULL, jeśli koniec toru (???) + { + fVelNext = trTrack->VelocityGet(); // aktualizacja prędkości (może być zmieniana + // eventem) + int i; + if ((i = iFlags & 0xF0000000) != 0) + { // jeśli skrzyżowanie, ograniczyć prędkość przy skręcaniu + if (abs(i) > 0x10000000) //±1 to jazda na wprost, ±2 nieby też, ale z przecięciem + //głównej drogi - chyba że jest równorzędne... + fVelNext = 30.0; // uzależnić prędkość od promienia; albo niech będzie + // ograniczona w skrzyżowaniu (velocity z ujemną wartością) + if ((iFlags & 32) == 0) // jeśli nie wjechał + if (trTrack->iNumDynamics > 0) // a skrzyżowanie zawiera pojazd + fVelNext = + 0.0; // to zabronić wjazdu (chyba że ten z przodu też jedzie prosto) + } + if (iFlags & 8) // jeśli odcinek zmienny + { + if (bool(trTrack->GetSwitchState() & 1) != + bool(iFlags & 16)) // czy stan się zmienił? + { // Ra: zakładam, że są tylko 2 możliwe stany + iFlags ^= 16; + // fVelNext=trTrack->VelocityGet(); //nowa prędkość + if ((iFlags & 32) == 0) + return true; // jeszcze trzeba skanowanie wykonać od tego toru + // problem jest chyba, jeśli zwrotnica się przełoży zaraz po zjechaniu z niej + // na Mydelniczce potrafi skanować na wprost mimo pojechania na bok + } + // poniższe nie dotyczy trybu łączenia? + if ((iFlags & 32) ? false : + trTrack->iNumDynamics > + 0) // jeśli jeszcze nie wjechano na tor, a coś na nim jest + fDist -= 30.0, fVelNext = 0.0; // to niech stanie w zwiększonej odległości + // else if (fVelNext==0.0) //jeśli została wyzerowana + // fVelNext=trTrack->VelocityGet(); //odczyt prędkości + } + } + } + else if (iFlags & 0x100) // jeśli event + { // odczyt komórki pamięci najlepiej by było zrobić jako notyfikację, czyli zmiana komórki + // wywoła jakąś podaną funkcję + CommandCheck(); // sprawdzenie typu komendy w evencie i określenie prędkości + } + return false; }; AnsiString __fastcall TSpeedPos::TableText() -{//pozycja tabelki prędkości - if (iFlags&0x1) - {//o ile pozycja istotna - if (iFlags&0x2) //jeśli tor - return "Flags=#"+IntToHex(iFlags,8)+", Dist="+FloatToStrF(fDist,ffFixed,7,1)+", Vel="+AnsiString(fVelNext)+", Track="+trTrack->NameGet(); - else if (iFlags&0x100) //jeśli event - return "Flags=#"+IntToHex(iFlags,8)+", Dist="+FloatToStrF(fDist,ffFixed,7,1)+", Vel="+AnsiString(fVelNext)+", Event="+evEvent->asName; - } - return "Empty"; +{ // pozycja tabelki prędkości + if (iFlags & 0x1) + { // o ile pozycja istotna + if (iFlags & 0x2) // jeśli tor + return "Flags=#" + IntToHex(iFlags, 8) + ", Dist=" + FloatToStrF(fDist, ffFixed, 7, 1) + + ", Vel=" + AnsiString(fVelNext) + ", Track=" + trTrack->NameGet(); + else if (iFlags & 0x100) // jeśli event + return "Flags=#" + IntToHex(iFlags, 8) + ", Dist=" + FloatToStrF(fDist, ffFixed, 7, 1) + + ", Vel=" + AnsiString(fVelNext) + ", Event=" + evEvent->asName; + } + return "Empty"; } -bool __fastcall TSpeedPos::Set(TEvent *e,double d) -{//zapamiętanie zdarzenia - fDist=d; - iFlags=0x101; //event+istotny - evEvent=e; - vPos=e->PositionGet(); //współrzędne eventu albo komórki pamięci (zrzutować na tor?) - CommandCheck(); //sprawdzenie typu komendy w evencie i określenie prędkości - return fVelNext==0.0; //true gdy zatrzymanie, wtedy nie ma po co skanować dalej +bool __fastcall TSpeedPos::Set(TEvent *e, double d) +{ // zapamiętanie zdarzenia + fDist = d; + iFlags = 0x101; // event+istotny + evEvent = e; + vPos = e->PositionGet(); // współrzędne eventu albo komórki pamięci (zrzutować na tor?) + CommandCheck(); // sprawdzenie typu komendy w evencie i określenie prędkości + return fVelNext == 0.0; // true gdy zatrzymanie, wtedy nie ma po co skanować dalej }; -void __fastcall TSpeedPos::Set(TTrack *t,double d,int f) -{//zapamiętanie zmiany prędkości w torze - fDist=d; //odległość do początku toru - trTrack=t; //TODO: (t) może być NULL i nie odczytamy końca poprzedniego :/ - if (trTrack) - {iFlags=f|(trTrack->eType==tt_Normal?2:10); //zapamiętanie kierunku wraz z typem - if (iFlags&8) if (trTrack->GetSwitchState()&1) iFlags|=16; - fVelNext=trTrack->VelocityGet(); - if (trTrack->iDamageFlag&128) fVelNext=0.0; //jeśli uszkodzony, to też stój - if (iFlags&64) - fVelNext=(trTrack->iCategoryFlag&1)?0.0:20.0; //jeśli koniec, to pociąg stój, a samochód zwolnij - vPos=(bool(iFlags&4)!=bool(iFlags&64))?trTrack->CurrentSegment()->FastGetPoint_1():trTrack->CurrentSegment()->FastGetPoint_0(); - } +void __fastcall TSpeedPos::Set(TTrack *t, double d, int f) +{ // zapamiętanie zmiany prędkości w torze + fDist = d; // odległość do początku toru + trTrack = t; // TODO: (t) może być NULL i nie odczytamy końca poprzedniego :/ + if (trTrack) + { + iFlags = f | (trTrack->eType == tt_Normal ? 2 : 10); // zapamiętanie kierunku wraz z typem + if (iFlags & 8) + if (trTrack->GetSwitchState() & 1) + iFlags |= 16; + fVelNext = trTrack->VelocityGet(); + if (trTrack->iDamageFlag & 128) + fVelNext = 0.0; // jeśli uszkodzony, to też stój + if (iFlags & 64) + fVelNext = (trTrack->iCategoryFlag & 1) ? + 0.0 : + 20.0; // jeśli koniec, to pociąg stój, a samochód zwolnij + vPos = (bool(iFlags & 4) != bool(iFlags & 64)) ? + trTrack->CurrentSegment()->FastGetPoint_1() : + trTrack->CurrentSegment()->FastGetPoint_0(); + } }; //--------------------------------------------------------------------------- @@ -271,1135 +300,1460 @@ void __fastcall TSpeedPos::Set(TTrack *t,double d,int f) //--------------------------------------------------------------------------- void __fastcall TController::TableClear() -{//wyczyszczenie tablicy - iFirst=iLast=0; - iTableDirection=0; //nieznany - for (int i=0;i0)?Track->evEvent2:Track->evEvent1; - if (!e) return NULL; - if (e->bEnabled) return NULL; - //jednak wszystkie W4 do tabelki, bo jej czyszczenie na przystanku wprowadza zamieszanie - return e; +TEvent *__fastcall TController::CheckTrackEvent(double fDirection, TTrack *Track) +{ // sprawdzanie eventów na podanym torze do podstawowego skanowania + TEvent *e = (fDirection > 0) ? Track->evEvent2 : Track->evEvent1; + if (!e) + return NULL; + if (e->bEnabled) + return NULL; + // jednak wszystkie W4 do tabelki, bo jej czyszczenie na przystanku wprowadza zamieszanie + return e; } bool __fastcall TController::TableAddNew() -{//zwiększenie użytej tabelki o jeden rekord - iLast=(iLast+1)%iSpeedTableSize; - //TODO: jeszcze sprawdzić, czy się na iFirst nie nałoży - //TODO: wstawić tu wywołanie odtykacza - teraz jest to w TableTraceRoute() - //TODO: jeśli ostatnia pozycja zajęta, ustawiać dodatkowe flagi - teraz jest to w TableTraceRoute() - //TODO: przydało by się też posortować tabelkę wg odległości (ale nie w tym miejscu) - return true; //false gdy się nałoży +{ // zwiększenie użytej tabelki o jeden rekord + iLast = (iLast + 1) % iSpeedTableSize; + // TODO: jeszcze sprawdzić, czy się na iFirst nie nałoży + // TODO: wstawić tu wywołanie odtykacza - teraz jest to w TableTraceRoute() + // TODO: jeśli ostatnia pozycja zajęta, ustawiać dodatkowe flagi - teraz jest to w + // TableTraceRoute() + // TODO: przydało by się też posortować tabelkę wg odległości (ale nie w tym miejscu) + return true; // false gdy się nałoży }; bool __fastcall TController::TableNotFound(TEvent *e) -{//sprawdzenie, czy nie został już dodany do tabelki (np. podwójne W4 robi problemy) - int i,j=(iLast+1)%iSpeedTableSize; //j, aby sprawdzić też ostatnią pozycję - for (i=iFirst;i!=j;i=(i+1)%iSpeedTableSize) - if ((sSpeedTable[i].iFlags&0x101)==0x101) //o ile używana pozycja - if (sSpeedTable[i].evEvent==e) - return false; //już jest, drugi raz dodawać nie ma po co - return true; //nie ma, czyli można dodać +{ // sprawdzenie, czy nie został już dodany do tabelki (np. podwójne W4 robi problemy) + int i, j = (iLast + 1) % iSpeedTableSize; // j, aby sprawdzić też ostatnią pozycję + for (i = iFirst; i != j; i = (i + 1) % iSpeedTableSize) + if ((sSpeedTable[i].iFlags & 0x101) == 0x101) // o ile używana pozycja + if (sSpeedTable[i].evEvent == e) + return false; // już jest, drugi raz dodawać nie ma po co + return true; // nie ma, czyli można dodać }; -void __fastcall TController::TableTraceRoute(double fDistance,TDynamicObject *pVehicle) -{//skanowanie trajektorii na odległość (fDistance) od (pVehicle) w kierunku przodu składu i uzupełnianie tabelki - if (!iDirection) //kierunek pojazdu z napędem - {//jeśli kierunek jazdy nie jest okreslony - iTableDirection=0; //czekamy na ustawienie kierunku - } - TTrack *pTrack; //zaczynamy od ostatniego analizowanego toru - //double fDistChVel=-1; //odległość do toru ze zmianą prędkości - double fTrackLength; //długość aktualnego toru (krótsza dla pierwszego) - double fCurrentDistance; //aktualna przeskanowana długość - TEvent *pEvent; - double fLastDir; //kierunek na ostatnim torze - if (iTableDirection!=iDirection) - {//jeśli zmiana kierunku, zaczynamy od toru ze wskazanym pojazdem - pTrack=pVehicle->RaTrackGet(); //odcinek, na którym stoi - fLastDir=pVehicle->DirectionGet()*pVehicle->RaDirectionGet(); //ustalenie kierunku skanowania na torze - fCurrentDistance=0; //na razie nic nie przeskanowano - fTrackLength=pVehicle->RaTranslationGet(); //pozycja na tym torze (odległość od Point1) - if (fLastDir>0) //jeśli w kierunku Point2 toru - fTrackLength=pTrack->Length()-fTrackLength; //przeskanowana zostanie odległość do Point2 - fLastVel=pTrack->VelocityGet(); //aktualna prędkość - iTableDirection=iDirection; //ustalenie w jakim kierunku jest wypełniana tabelka względem pojazdu - iFirst=iLast=0; - tLast=NULL; //żaden nie sprawdzony - } - else - {//kontynuacja skanowania od ostatnio sprawdzonego toru (w ostatniej pozycji zawsze jest tor) - if (sSpeedTable[iLast].iFlags&0x10000) //zatkanie - {//jeśli zapełniła się tabelka - if ((iLast+1)%iSpeedTableSize==iFirst) //jeśli nadal jest zapełniona - return; //nic się nie da zrobić - if ((iLast+2)%iSpeedTableSize==iFirst) //musi być jeszcze miejsce wolne na ewentualny event, bo tor jeszcze nie sprawdzony - return; //już lepiej, ale jeszcze nie tym razem - sSpeedTable[iLast].iFlags&=0xBE; //kontynuować próby doskanowania - } - else - if (VelNext==0) return; //znaleziono semafor lub tor z prędkością zero i nie ma co dalej sprawdzać - pTrack=sSpeedTable[iLast].trTrack; //ostatnio sprawdzony tor - if (!pTrack) return; //koniec toru, to nie ma co sprawdzać (nie ma prawa tak być) - fLastDir=sSpeedTable[iLast].iFlags&4?-1.0:1.0; //flaga ustawiona, gdy Point2 toru jest bliżej - fCurrentDistance=sSpeedTable[iLast].fDist; //aktualna odległość do jego Point1 - fTrackLength=sSpeedTable[iLast].iFlags&0x60?0.0:pTrack->Length(); //nie doliczać długości gdy: 32-minięty początek, 64-jazda do końca toru - } - if (fCurrentDistanceVelocityGet()==0.0) //zatrzymanie - || (pTrack->iAction) //jeśli tor ma własności istotne dla skanowania - || (pTrack->VelocityGet()!=fLastVel)) //następuje zmiana prędkości - {//odcinek dodajemy do tabelki, gdy jest istotny dla ruchu - if (TableAddNew()) - {//teraz dodatkowo zapamiętanie wybranego segmentu dla skrzyżowania - sSpeedTable[iLast].Set(pTrack,fCurrentDistance,fLastDir<0?5:1); //dodanie odcinka do tabelki z flagą kierunku wejścia - if (pTrack->eType==tt_Cross) //na skrzyżowaniach trzeba wybrać segment, po którym pojedzie pojazd - {//dopiero tutaj jest ustalany kierunek segmentu na skrzyżowaniu - sSpeedTable[iLast].iFlags|=(pTrack->CrossSegment((fLastDir<0)?tLast->iPrevDirection:tLast->iNextDirection,iRouteWanted)&15)<<28; //ostatnie 4 bity pola flag - sSpeedTable[iLast].iFlags&=~4; //usunięcie flagi kierunku, bo może być błędna - if (sSpeedTable[iLast].iFlags<0) sSpeedTable[iLast].iFlags|=4; //ustawienie flagi kierunku na podstawie wybranego segmentu - if (int(fLastDir)*sSpeedTable[iLast].iFlags<0) fLastDir=-fLastDir; - if (AIControllFlag) //dla AI na razie losujemy kierunek na kolejnym skrzyżowaniu - iRouteWanted=1+random(3); - } - } +void __fastcall TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) +{ // skanowanie trajektorii na odległość (fDistance) od (pVehicle) w kierunku przodu składu i + // uzupełnianie tabelki + if (!iDirection) // kierunek pojazdu z napędem + { // jeśli kierunek jazdy nie jest okreslony + iTableDirection = 0; // czekamy na ustawienie kierunku } - else if ((pTrack->fRadius!=0.0) //odległość na łuku lepiej aproksymować cięciwami - || (tLast?tLast->fRadius!=0.0:false)) //koniec łuku też jest istotny - {//albo dla liczenia odległości przy pomocy cięciw - te usuwać po przejechaniu - if (TableAddNew()) - sSpeedTable[iLast].Set(pTrack,fCurrentDistance,fLastDir<0?0x85:0x81); //dodanie odcinka do tabelki + TTrack *pTrack; // zaczynamy od ostatniego analizowanego toru + // double fDistChVel=-1; //odległość do toru ze zmianą prędkości + double fTrackLength; // długość aktualnego toru (krótsza dla pierwszego) + double fCurrentDistance; // aktualna przeskanowana długość + TEvent *pEvent; + double fLastDir; // kierunek na ostatnim torze + if (iTableDirection != iDirection) + { // jeśli zmiana kierunku, zaczynamy od toru ze wskazanym pojazdem + pTrack = pVehicle->RaTrackGet(); // odcinek, na którym stoi + fLastDir = pVehicle->DirectionGet() * + pVehicle->RaDirectionGet(); // ustalenie kierunku skanowania na torze + fCurrentDistance = 0; // na razie nic nie przeskanowano + fTrackLength = pVehicle->RaTranslationGet(); // pozycja na tym torze (odległość od Point1) + if (fLastDir > 0) // jeśli w kierunku Point2 toru + fTrackLength = + pTrack->Length() - fTrackLength; // przeskanowana zostanie odległość do Point2 + fLastVel = pTrack->VelocityGet(); // aktualna prędkość + iTableDirection = + iDirection; // ustalenie w jakim kierunku jest wypełniana tabelka względem pojazdu + iFirst = iLast = 0; + tLast = NULL; //żaden nie sprawdzony } - } - fCurrentDistance+=fTrackLength; //doliczenie kolejnego odcinka do przeskanowanej długości - tLast=pTrack; //odhaczenie, że sprawdzony - //Track->ScannedFlag=true; //do pokazywania przeskanowanych torów - fLastVel=pTrack->VelocityGet(); //prędkość na poprzednio sprawdzonym odcinku - pTrack=pTrack->Neightbour((pTrack->eType==tt_Cross)?(sSpeedTable[iLast].iFlags>>28):int(fLastDir),fLastDir); //może być NULL -/* - if (fLastDir>0) - {//jeśli szukanie od Point1 w kierunku Point2 - pTrack=pTrack->CurrentNext(); //może być NULL - if (pTrack) //jeśli dalej brakuje toru, to zostajemy na tym samym, z tą samą orientacją - if (tLast->iNextDirection) - fLastDir=-fLastDir; //można by zamiętać i zmienić tylko jeśli jest pTrack - } - else //if (fDirection<0) - {//jeśli szukanie od Point2 w kierunku Point1 - pTrack=pTrack->CurrentPrev(); //może być NULL - if (pTrack) //jeśli dalej brakuje toru, to zostajemy na tym samym, z tą samą orientacją - if (!tLast->iPrevDirection) - fLastDir=-fLastDir; - } -*/ - if (pTrack) - {//jeśli kolejny istnieje - if (tLast) - if (pTrack->VelocityGet()<0?tLast->VelocityGet()>0:pTrack->VelocityGet()>tLast->VelocityGet()) - {//jeśli kolejny ma większą prędkość niż poprzedni, to zapamiętać poprzedni (do czasu wyjechania) - if ((sSpeedTable[iLast].iFlags&3)==3?(sSpeedTable[iLast].trTrack!=tLast):true) //jeśli nie był dodany do tabelki - if (TableAddNew()) - sSpeedTable[iLast].Set(tLast,fCurrentDistance,(fLastDir>0?pTrack->iPrevDirection:pTrack->iNextDirection)?1:5); //zapisanie toru z ograniczeniem prędkości - } - if (((iLast+3)%iSpeedTableSize==iFirst)?true:((iLast+2)%iSpeedTableSize==iFirst)) //czy tabelka się nie zatka? - {//jest ryzyko nieznalezienia ograniczenia - ograniczyć prędkość do pozwalającej na zatrzymanie na końcu przeskanowanej drogi - TablePurger(); //usunąć pilnie zbędne pozycje - if (((iLast+3)%iSpeedTableSize==iFirst)?true:((iLast+2)%iSpeedTableSize==iFirst)) //czy tabelka się nie zatka? - {//jeśli odtykacz nie pomógł (TODO: zwiększyć rozmiar tabelki) - if (TableAddNew()) - sSpeedTable[iLast].Set(pTrack,fCurrentDistance,fLastDir<0?0x10045:0x10041); //zapisanie toru jako końcowego (ogranicza prędkosć) - //zapisać w logu, że należy poprawić scenerię? - return; //nie skanujemy dalej, bo nie ma miejsca - } + else + { // kontynuacja skanowania od ostatnio sprawdzonego toru (w ostatniej pozycji zawsze jest tor) + if (sSpeedTable[iLast].iFlags & 0x10000) // zatkanie + { // jeśli zapełniła się tabelka + if ((iLast + 1) % iSpeedTableSize == iFirst) // jeśli nadal jest zapełniona + return; // nic się nie da zrobić + if ((iLast + 2) % iSpeedTableSize == iFirst) // musi być jeszcze miejsce wolne na + // ewentualny event, bo tor jeszcze nie + // sprawdzony + return; // już lepiej, ale jeszcze nie tym razem + sSpeedTable[iLast].iFlags &= 0xBE; // kontynuować próby doskanowania + } + else if (VelNext == 0) + return; // znaleziono semafor lub tor z prędkością zero i nie ma co dalej sprawdzać + pTrack = sSpeedTable[iLast].trTrack; // ostatnio sprawdzony tor + if (!pTrack) + return; // koniec toru, to nie ma co sprawdzać (nie ma prawa tak być) + fLastDir = sSpeedTable[iLast].iFlags & 4 ? + -1.0 : + 1.0; // flaga ustawiona, gdy Point2 toru jest bliżej + fCurrentDistance = sSpeedTable[iLast].fDist; // aktualna odległość do jego Point1 + fTrackLength = + sSpeedTable[iLast].iFlags & 0x60 ? 0.0 : pTrack->Length(); // nie doliczać długości gdy: + // 32-minięty początek, + // 64-jazda do końca toru + } + if (fCurrentDistance < fDistance) + { // jeśli w ogóle jest po co analizować + --iLast; // jak coś się znajdzie, zostanie wpisane w tę pozycję, którą właśnie odczytano + while (fCurrentDistance < fDistance) + { + if (pTrack != tLast) // ostatni zapisany w tabelce nie był jeszcze sprawdzony + { // jeśli tor nie był jeszcze sprawdzany + if ((pEvent = CheckTrackEvent(fLastDir, pTrack)) != + NULL) // jeśli jest semafor na tym torze + { // trzeba sprawdzić tabelkę, bo dodawanie drugi raz tego samego przystanku nie + // jest korzystne + if (TableNotFound(pEvent)) // jeśli nie ma + if (TableAddNew()) + { + if (sSpeedTable[iLast].Set(pEvent, + fCurrentDistance)) // dodanie odczytu sygnału + fDistance = fCurrentDistance; // jeśli sygnał stop, to nie ma + // potrzeby dalej skanować + } + } // event dodajemy najpierw, żeby móc sprawdzić, czy tor został dodany po + // odczytaniu prędkości następnego + if ((pTrack->VelocityGet() == 0.0) // zatrzymanie + || (pTrack->iAction) // jeśli tor ma własności istotne dla skanowania + || (pTrack->VelocityGet() != fLastVel)) // następuje zmiana prędkości + { // odcinek dodajemy do tabelki, gdy jest istotny dla ruchu + if (TableAddNew()) + { // teraz dodatkowo zapamiętanie wybranego segmentu dla skrzyżowania + sSpeedTable[iLast].Set( + pTrack, fCurrentDistance, + fLastDir < 0 ? + 5 : + 1); // dodanie odcinka do tabelki z flagą kierunku wejścia + if (pTrack->eType == tt_Cross) // na skrzyżowaniach trzeba wybrać segment, + // po którym pojedzie pojazd + { // dopiero tutaj jest ustalany kierunek segmentu na skrzyżowaniu + sSpeedTable[iLast].iFlags |= + (pTrack->CrossSegment((fLastDir < 0) ? tLast->iPrevDirection : + tLast->iNextDirection, + iRouteWanted) & + 15) + << 28; // ostatnie 4 bity pola flag + sSpeedTable[iLast].iFlags &= + ~4; // usunięcie flagi kierunku, bo może być błędna + if (sSpeedTable[iLast].iFlags < 0) + sSpeedTable[iLast].iFlags |= + 4; // ustawienie flagi kierunku na podstawie wybranego segmentu + if (int(fLastDir) * sSpeedTable[iLast].iFlags < 0) + fLastDir = -fLastDir; + if (AIControllFlag) // dla AI na razie losujemy kierunek na kolejnym + // skrzyżowaniu + iRouteWanted = 1 + random(3); + } + } + } + else if ((pTrack->fRadius != 0.0) // odległość na łuku lepiej aproksymować cięciwami + || (tLast ? tLast->fRadius != 0.0 : false)) // koniec łuku też jest istotny + { // albo dla liczenia odległości przy pomocy cięciw - te usuwać po przejechaniu + if (TableAddNew()) + sSpeedTable[iLast].Set(pTrack, fCurrentDistance, + fLastDir < 0 ? 0x85 : + 0x81); // dodanie odcinka do tabelki + } + } + fCurrentDistance += + fTrackLength; // doliczenie kolejnego odcinka do przeskanowanej długości + tLast = pTrack; // odhaczenie, że sprawdzony + // Track->ScannedFlag=true; //do pokazywania przeskanowanych torów + fLastVel = pTrack->VelocityGet(); // prędkość na poprzednio sprawdzonym odcinku + pTrack = pTrack->Neightbour( + (pTrack->eType == tt_Cross) ? (sSpeedTable[iLast].iFlags >> 28) : int(fLastDir), + fLastDir); // może być NULL + /* + if (fLastDir>0) + {//jeśli szukanie od Point1 w kierunku Point2 + pTrack=pTrack->CurrentNext(); //może być NULL + if (pTrack) //jeśli dalej brakuje toru, to zostajemy na tym samym, z tą samą + orientacją + if (tLast->iNextDirection) + fLastDir=-fLastDir; //można by zamiętać i zmienić tylko jeśli jest pTrack + } + else //if (fDirection<0) + {//jeśli szukanie od Point2 w kierunku Point1 + pTrack=pTrack->CurrentPrev(); //może być NULL + if (pTrack) //jeśli dalej brakuje toru, to zostajemy na tym samym, z tą samą + orientacją + if (!tLast->iPrevDirection) + fLastDir=-fLastDir; + } + */ + if (pTrack) + { // jeśli kolejny istnieje + if (tLast) + if (pTrack->VelocityGet() < 0 ? tLast->VelocityGet() > 0 : + pTrack->VelocityGet() > tLast->VelocityGet()) + { // jeśli kolejny ma większą prędkość niż poprzedni, to zapamiętać poprzedni + // (do czasu wyjechania) + if ((sSpeedTable[iLast].iFlags & 3) == 3 ? + (sSpeedTable[iLast].trTrack != tLast) : + true) // jeśli nie był dodany do tabelki + if (TableAddNew()) + sSpeedTable[iLast].Set( + tLast, fCurrentDistance, + (fLastDir > 0 ? pTrack->iPrevDirection : + pTrack->iNextDirection) ? + 1 : + 5); // zapisanie toru z ograniczeniem prędkości + } + if (((iLast + 3) % iSpeedTableSize == iFirst) ? + true : + ((iLast + 2) % iSpeedTableSize == iFirst)) // czy tabelka się nie zatka? + { // jest ryzyko nieznalezienia ograniczenia - ograniczyć prędkość do pozwalającej + // na zatrzymanie na końcu przeskanowanej drogi + TablePurger(); // usunąć pilnie zbędne pozycje + if (((iLast + 3) % iSpeedTableSize == iFirst) ? + true : + ((iLast + 2) % iSpeedTableSize == iFirst)) // czy tabelka się nie zatka? + { // jeśli odtykacz nie pomógł (TODO: zwiększyć rozmiar tabelki) + if (TableAddNew()) + sSpeedTable[iLast].Set( + pTrack, fCurrentDistance, + fLastDir < 0 ? + 0x10045 : + 0x10041); // zapisanie toru jako końcowego (ogranicza prędkosć) + // zapisać w logu, że należy poprawić scenerię? + return; // nie skanujemy dalej, bo nie ma miejsca + } + } + fTrackLength = pTrack->Length(); // zwiększenie skanowanej odległości tylko jeśli + // istnieje dalszy tor + } + else + { // definitywny koniec skanowania, chyba że dalej puszczamy samochód po gruncie... + if (TableAddNew()) // kolejny, bo się cofnęliśmy o 1 + sSpeedTable[iLast].Set( + tLast, fCurrentDistance, + fLastDir < 0 ? 0x45 : 0x41); // zapisanie ostatniego sprawdzonego toru + return; // to ostatnia pozycja, bo NULL nic nie da, a może się podpiąć obrotnica, + // czy jakieś transportery + } + } + if (TableAddNew()) + sSpeedTable[iLast].Set(pTrack, fCurrentDistance, + fLastDir < 0 ? 4 : 0); // zapisanie ostatniego sprawdzonego toru } - fTrackLength=pTrack->Length(); //zwiększenie skanowanej odległości tylko jeśli istnieje dalszy tor - } - else - {//definitywny koniec skanowania, chyba że dalej puszczamy samochód po gruncie... - if (TableAddNew()) //kolejny, bo się cofnęliśmy o 1 - sSpeedTable[iLast].Set(tLast,fCurrentDistance,fLastDir<0?0x45:0x41); //zapisanie ostatniego sprawdzonego toru - return; //to ostatnia pozycja, bo NULL nic nie da, a może się podpiąć obrotnica, czy jakieś transportery - } - } - if (TableAddNew()) - sSpeedTable[iLast].Set(pTrack,fCurrentDistance,fLastDir<0?4:0); //zapisanie ostatniego sprawdzonego toru - } }; void __fastcall TController::TableCheck(double fDistance) -{//przeliczenie odległości w tabelce, ewentualnie doskanowanie (bez analizy prędkości itp.) - if (iTableDirection!=iDirection) - TableTraceRoute(fDistance,pVehicles[1]); //jak zmiana kierunku, to skanujemy od końca składu - else if (iTableDirection) - {//trzeba sprawdzić, czy coś się zmieniło - vector3 dir=pVehicles[0]->VectorFront()*pVehicles[0]->DirectionGet(); //wektor kierunku jazdy - vector3 pos=pVehicles[0]->HeadPosition(); //zaczynamy od pozycji pojazdu - //double lastspeed=-1; //prędkość na torze do usunięcia - double len=0.0; //odległość będziemy zliczać narastająco - for (int i=iFirst;i!=iLast;i=(i+1)%iSpeedTableSize) - {//aktualizacja rekordów z wyjątkiem ostatniego - if (sSpeedTable[i].iFlags&1) //jeśli pozycja istotna - {if (sSpeedTable[i].Update(&pos,&dir,len)) - {iLast=i; //wykryta zmiana zwrotnicy - konieczne ponowne przeskanowanie dalszej części - break; //nie kontynuujemy pętli, trzeba doskanować ciąg dalszy +{ // przeliczenie odległości w tabelce, ewentualnie doskanowanie (bez analizy prędkości itp.) + if (iTableDirection != iDirection) + TableTraceRoute(fDistance, + pVehicles[1]); // jak zmiana kierunku, to skanujemy od końca składu + else if (iTableDirection) + { // trzeba sprawdzić, czy coś się zmieniło + vector3 dir = + pVehicles[0]->VectorFront() * pVehicles[0]->DirectionGet(); // wektor kierunku jazdy + vector3 pos = pVehicles[0]->HeadPosition(); // zaczynamy od pozycji pojazdu + // double lastspeed=-1; //prędkość na torze do usunięcia + double len = 0.0; // odległość będziemy zliczać narastająco + for (int i = iFirst; i != iLast; i = (i + 1) % iSpeedTableSize) + { // aktualizacja rekordów z wyjątkiem ostatniego + if (sSpeedTable[i].iFlags & 1) // jeśli pozycja istotna + { + if (sSpeedTable[i].Update(&pos, &dir, len)) + { + iLast = i; // wykryta zmiana zwrotnicy - konieczne ponowne przeskanowanie + // dalszej części + break; // nie kontynuujemy pętli, trzeba doskanować ciąg dalszy + } + if (sSpeedTable[i].iFlags & 2) // jeśli odcinek + { + if (sSpeedTable[i].fDist < -fLength) // a skład wyjechał całą długością poza + { // degradacja pozycji + sSpeedTable[i].iFlags &= ~1; // nie liczy się + } + else if ((sSpeedTable[i].iFlags & 0xF0000028) == + 0x20) // jest z tyłu (najechany) i nie jest zwrotnicą ani skrzyżowaniem + if (sSpeedTable[i].fVelNext < 0) // a nie ma ograniczenia prędkości + sSpeedTable[i].iFlags = + 0; // to nie ma go po co trzymać (odtykacz usunie ze środka) + } + else if (sSpeedTable[i].iFlags & 0x100) // jeśli event + { + if (sSpeedTable[i].fDist < (sSpeedTable[i].evEvent->Type == tp_PutValues ? + -fLength : + 0)) // jeśli jest z tyłu + if ((mvOccupied->CategoryFlag & 1) ? false : + sSpeedTable[i].fDist < -fLength) + { // pociąg staje zawsze, a samochód tylko jeśli nie przejedzie całą + // długością (może być zaskoczony zmianą) + sSpeedTable[i].iFlags &= ~1; // degradacja pozycji dla samochodu; + // semafory usuwane tylko przy sprawdzaniu, + // bo wysyłają komendy + } + } + // if (sSpeedTable[i].fDist<-20.0*fLength) //jeśli to coś jest 20 razy dalej niż + // długość składu + //{sSpeedTable[i].iFlags&=~1; //to jest to jakby błąd w scenerii + // //WriteLog("Error: too distant object in scan table"); + //} + // if (sSpeedTable[i].fDist>20.0*fLength) //jeśli to coś jest 20 razy dalej niż + // długość składu + //{sSpeedTable[i].iFlags&=~1; //to jest to jakby błąd w scenerii + // //WriteLog("Error: too distant object in scan table"); + //} + } + if (i == iFirst) // jeśli jest pierwszą pozycją tabeli + { // pozbycie się początkowej pozycji + if ((sSpeedTable[i].iFlags & 1) == + 0) // jeśli pozycja istotna (po Update() może się zmienić) + // if (iFirst!=iLast) //ostatnia musi zostać - to załatwia for() + iFirst = (iFirst + 1) % + iSpeedTableSize; // kolejne sprawdzanie będzie już od następnej pozycji + } + } + sSpeedTable[iLast].Update(&pos, &dir, len); // aktualizacja ostatniego + if (sSpeedTable[iLast].fDist < fDistance) + TableTraceRoute(fDistance, pVehicles[1]); // doskanowanie dalszego odcinka } - if (sSpeedTable[i].iFlags&2) //jeśli odcinek - {if (sSpeedTable[i].fDist<-fLength) //a skład wyjechał całą długością poza - {//degradacja pozycji - sSpeedTable[i].iFlags&=~1; //nie liczy się - } - else if ((sSpeedTable[i].iFlags&0xF0000028)==0x20) //jest z tyłu (najechany) i nie jest zwrotnicą ani skrzyżowaniem - if (sSpeedTable[i].fVelNext<0) //a nie ma ograniczenia prędkości - sSpeedTable[i].iFlags=0; //to nie ma go po co trzymać (odtykacz usunie ze środka) - } - else if (sSpeedTable[i].iFlags&0x100) //jeśli event - {if (sSpeedTable[i].fDist<(sSpeedTable[i].evEvent->Type==tp_PutValues?-fLength:0)) //jeśli jest z tyłu - if ((mvOccupied->CategoryFlag&1)?false:sSpeedTable[i].fDist<-fLength) - {//pociąg staje zawsze, a samochód tylko jeśli nie przejedzie całą długością (może być zaskoczony zmianą) - sSpeedTable[i].iFlags&=~1; //degradacja pozycji dla samochodu; semafory usuwane tylko przy sprawdzaniu, bo wysyłają komendy - } - } - //if (sSpeedTable[i].fDist<-20.0*fLength) //jeśli to coś jest 20 razy dalej niż długość składu - //{sSpeedTable[i].iFlags&=~1; //to jest to jakby błąd w scenerii - // //WriteLog("Error: too distant object in scan table"); - //} - //if (sSpeedTable[i].fDist>20.0*fLength) //jeśli to coś jest 20 razy dalej niż długość składu - //{sSpeedTable[i].iFlags&=~1; //to jest to jakby błąd w scenerii - // //WriteLog("Error: too distant object in scan table"); - //} - } - if (i==iFirst) //jeśli jest pierwszą pozycją tabeli - {//pozbycie się początkowej pozycji - if ((sSpeedTable[i].iFlags&1)==0) //jeśli pozycja istotna (po Update() może się zmienić) - //if (iFirst!=iLast) //ostatnia musi zostać - to załatwia for() - iFirst=(iFirst+1)%iSpeedTableSize; //kolejne sprawdzanie będzie już od następnej pozycji - } - } - sSpeedTable[iLast].Update(&pos,&dir,len); //aktualizacja ostatniego - if (sSpeedTable[iLast].fDist0;--k,i=(i+1)%iSpeedTableSize) - {//sprawdzenie rekordów od (iFirst) do (iLast), o ile są istotne - if (sSpeedTable[i].iFlags&1) //badanie istotności - {//o ile dana pozycja tabelki jest istotna - if (sSpeedTable[i].iFlags&0x400) - {//jeśli przystanek, trzeba obsłużyć wg rozkładu - if (sSpeedTable[i].evEvent->CommandGet()!=asNextStop) - {//jeśli nazwa nie jest zgodna - if (sSpeedTable[i].fDist<-fLength) //jeśli został przejechany - sSpeedTable[i].iFlags=0; //to można usunąć (nie mogą być usuwane w skanowaniu) - continue; //ignorowanie jakby nie było tej pozycji - } - else if (iDrivigFlags&moveStopPoint) //jeśli pomijanie W4, to nie sprawdza czasu odjazdu - {//tylko gdy nazwa zatrzymania się zgadza - if (!TrainParams->IsStop()) - {//jeśli nie ma tu postoju - sSpeedTable[i].fVelNext=-1; //maksymalna prędkość w tym miejscu - if (sSpeedTable[i].fDist<200.0) //przy 160km/h jedzie 44m/s, to da dokładność rzędu 5 sekund - {//zaliczamy posterunek w pewnej odległości przed (choć W4 nie zasłania już semafora) +TCommandType __fastcall TController::TableUpdate(double &fVelDes, double &fDist, double &fNext, + double &fAcc) +{ // ustalenie parametrów, zwraca typ komendy, jeśli sygnał podaje prędkość do jazdy + // fVelDes - prędkość zadana + // fDist - dystans w jakim należy rozważyć ruch + // fNext - prędkość na końcu tego dystansu + // fAcc - zalecane przyspieszenie w chwili obecnej - kryterium wyboru dystansu + double a; // przyspieszenie + double v; // prędkość + double d; // droga + TCommandType go = cm_Unknown; + eSignNext = NULL; + int i, k = iLast - iFirst + 1; + if (k < 0) + k += iSpeedTableSize; // ilość pozycji do przeanalizowania + iDrivigFlags &= + ~(moveTrackEnd | moveSwitchFound); // te flagi są ustawiane tutaj, w razie potrzeby + for (i = iFirst; k > 0; --k, i = (i + 1) % iSpeedTableSize) + { // sprawdzenie rekordów od (iFirst) do (iLast), o ile są istotne + if (sSpeedTable[i].iFlags & 1) // badanie istotności + { // o ile dana pozycja tabelki jest istotna + if (sSpeedTable[i].iFlags & 0x400) + { // jeśli przystanek, trzeba obsłużyć wg rozkładu + if (sSpeedTable[i].evEvent->CommandGet() != asNextStop) + { // jeśli nazwa nie jest zgodna + if (sSpeedTable[i].fDist < -fLength) // jeśli został przejechany + sSpeedTable[i].iFlags = + 0; // to można usunąć (nie mogą być usuwane w skanowaniu) + continue; // ignorowanie jakby nie było tej pozycji + } + else if (iDrivigFlags & + moveStopPoint) // jeśli pomijanie W4, to nie sprawdza czasu odjazdu + { // tylko gdy nazwa zatrzymania się zgadza + if (!TrainParams->IsStop()) + { // jeśli nie ma tu postoju + sSpeedTable[i].fVelNext = -1; // maksymalna prędkość w tym miejscu + if (sSpeedTable[i].fDist < + 200.0) // przy 160km/h jedzie 44m/s, to da dokładność rzędu 5 sekund + { // zaliczamy posterunek w pewnej odległości przed (choć W4 nie zasłania + // już semafora) #if LOGSTOPS - WriteLog(pVehicle->asName+" as "+TrainParams->TrainName+": at "+AnsiString(GlobalTime->hh)+":"+AnsiString(GlobalTime->mm)+" skipped "+asNextStop); //informacja + WriteLog(pVehicle->asName + " as " + TrainParams->TrainName + ": at " + + AnsiString(GlobalTime->hh) + ":" + AnsiString(GlobalTime->mm) + + " skipped " + asNextStop); // informacja #endif - fLastStopExpDist=mvOccupied->DistCounter+0.250+0.001*fLength; //przy jakim dystansie (stanie licznika) ma przesunąć na następny postój - TrainParams->UpdateMTable(GlobalTime->hh,GlobalTime->mm,asNextStop.SubString(20,asNextStop.Length())); - TrainParams->StationIndexInc(); //przejście do następnej - asNextStop=TrainParams->NextStop(); //pobranie kolejnego miejsca zatrzymania - //TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie jest dobry pomysł - sSpeedTable[i].iFlags=0; //nie liczy się już - sSpeedTable[i].fVelNext=-1; //jechać - continue; //nie analizować prędkości - } - } //koniec obsługi przelotu na W4 - else - {//zatrzymanie na W4 - if (!eSignNext) eSignNext=sSpeedTable[i].evEvent; - if (mvOccupied->Vel>0.3) //jeśli jedzie (nie trzeba czekać, aż się drgania wytłumią - drzwi zamykane od 1.0) - sSpeedTable[i].fVelNext=0; //to będzie zatrzymanie - //else if ((iDrivigFlags&moveStopCloser)?sSpeedTable[i].fDist<=fMaxProximityDist*(AIControllFlag?1.0:10.0):true) - else if ((iDrivigFlags&moveStopCloser)?sSpeedTable[i].fDist+fLength<=Max0R(sSpeedTable[i].evEvent->ValueGet(2),fMaxProximityDist+fLength):true) - //Ra 2F1I: odległość plus długość pociągu musi być mniejsza od długości peronu, chyba że pociąg jest dłuższy, to wtedy minimalna - //jeśli długość peronu ((sSpeedTable[i].evEvent->ValueGet(2)) nie podana, przyjąć odległość fMinProximityDist - {//jeśli się zatrzymał przy W4, albo stał w momencie zobaczenia W4 - if (!AIControllFlag) //AI tylko sobie otwiera drzwi - iDrivigFlags&=~moveStopCloser; //w razie przełączenia na AI ma nie podciągać do W4, gdy użytkownik zatrzymał za daleko - if ((iDrivigFlags&moveDoorOpened)==0) - {//drzwi otwierać jednorazowo - iDrivigFlags|=moveDoorOpened; //nie wykonywać drugi raz - if (mvOccupied->DoorOpenCtrl==1) //(mvOccupied->TrainType==dt_EZT) - {//otwieranie drzwi w EZT - if (AIControllFlag) //tylko AI otwiera drzwi EZT, użytkownik musi samodzielnie - if (!mvOccupied->DoorLeftOpened&&!mvOccupied->DoorRightOpened) - {//otwieranie drzwi - int p2=int(floor(sSpeedTable[i].evEvent->ValueGet(2)))%10; //p7=platform side (1:left, 2:right, 3:both) - int lewe=(iDirection>0)?1:2; //jeśli jedzie do tyłu, to drzwi otwiera odwrotnie - int prawe=(iDirection>0)?2:1; - if (p2&lewe) mvOccupied->DoorLeft(true); - if (p2&prawe) mvOccupied->DoorRight(true); - //if (p2&3) //żeby jeszcze poczekał chwilę, zanim zamknie - // WaitingSet(10); //10 sekund (wziąć z rozkładu????) - } - } - else - {//otwieranie drzwi w składach wagonowych - docelowo wysyłać komendę zezwolenia na otwarcie drzwi - int p7,lewe,prawe; //p7=platform side (1:left, 2:right, 3:both) - p7=int(floor(sSpeedTable[i].evEvent->ValueGet(2)))%10; //tu będzie jeszcze długość peronu zaokrąglona do 10m (20m bezpieczniej, bo nie modyfikuje bitu 1) - TDynamicObject *p=pVehicles[0]; //pojazd na czole składu - while (p) - {//otwieranie drzwi w pojazdach - flaga zezwolenia była by lepsza - lewe=(p->DirectionGet()>0)?1:2; //jeśli jedzie do tyłu, to drzwi otwiera odwrotnie - prawe=3-lewe; - p->MoverParameters->BatterySwitch(true); //wagony muszą mieć baterię załączoną do otwarcia drzwi... - if (p7&lewe) p->MoverParameters->DoorLeft(true); - if (p7&prawe) p->MoverParameters->DoorRight(true); - p=p->Next(); //pojazd podłączony z tyłu (patrząc od czoła) - } - //if (p7&3) //żeby jeszcze poczekał chwilę, zanim zamknie - // WaitingSet(10); //10 sekund (wziąć z rozkładu????) - } - if (fStopTime>-5) //na końcu rozkładu się ustawia 60s i tu by było skrócenie - WaitingSet(10); //10 sekund (wziąć z rozkładu????) - czekanie niezależne od sposobu obsługi drzwi, bo opóźnia również kierownika - } - if (TrainParams->UpdateMTable(GlobalTime->hh,GlobalTime->mm,asNextStop.SubString(20,asNextStop.Length()))) - {//to się wykona tylko raz po zatrzymaniu na W4 - if (TrainParams->CheckTrainLatency()<0.0) - iDrivigFlags|=moveLate; //odnotowano spóźnienie - else - iDrivigFlags&=~moveLate; //przyjazd o czasie - if (TrainParams->DirectionChange()) //jeśli "@" w rozkładzie, to wykonanie dalszych komend - {//wykonanie kolejnej komendy, nie dotyczy ostatniej stacji - if (iDrivigFlags&movePushPull) //SN61 ma się też nie ruszać, chyba że ma wagony - {iDrivigFlags|=moveStopHere; //EZT ma stać przy peronie - if (OrderNextGet()!=Change_direction) - {OrderPush(Change_direction); //zmiana kierunku - OrderPush(TrainParams->StationIndexStationCount?Obey_train:Shunt); //to dalej wg rozkładu - } - } - else //a dla lokomotyw... - iDrivigFlags&=~(moveStopPoint|moveStopHere); //pozwolenie na przejechanie za W4 przed czasem i nie ma stać - JumpToNextOrder(); //przejście do kolejnego rozkazu (zmiana kierunku, odczepianie) - iDrivigFlags&=~moveStopCloser; //ma nie podjeżdżać pod W4 po przeciwnej stronie - sSpeedTable[i].iFlags=0; //ten W4 nie liczy się już zupełnie (nie wyśle SetVelocity) - sSpeedTable[i].fVelNext=-1; //jechać - continue; //nie analizować prędkości - } - } - if (OrderCurrentGet()==Shunt) - {OrderNext(Obey_train); //uruchomić jazdę pociągową - CheckVehicles(); //zmienić światła - } - if (TrainParams->StationIndexStationCount) - {//jeśli są dalsze stacje, czekamy do godziny odjazdu - if (TrainParams->IsTimeToGo(GlobalTime->hh,GlobalTime->mm)) - {//z dalszą akcją czekamy do godziny odjazdu - //if (TrainParams->CheckTrainLatency()<0.0) //jak się ma odjazd do czasu odjazdu? - // iDrivigFlags|=moveLate1; //oflagować, gdy odjazd ze spóźnieniem, będzie jechał forsowniej - fLastStopExpDist=mvOccupied->DistCounter+0.050+0.001*fLength; //przy jakim dystansie (stanie licznika) ma przesunąć na następny postój - // Controlled-> //zapisać odległość do przejechania - TrainParams->StationIndexInc(); //przejście do następnej - asNextStop=TrainParams->NextStop(); //pobranie kolejnego miejsca zatrzymania - //TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie jest dobry pomysł + fLastStopExpDist = mvOccupied->DistCounter + 0.250 + + 0.001 * fLength; // przy jakim dystansie (stanie + // licznika) ma przesunąć na + // następny postój + TrainParams->UpdateMTable( + GlobalTime->hh, GlobalTime->mm, + asNextStop.SubString(20, asNextStop.Length())); + TrainParams->StationIndexInc(); // przejście do następnej + asNextStop = + TrainParams->NextStop(); // pobranie kolejnego miejsca zatrzymania + // TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie + // jest dobry pomysł + sSpeedTable[i].iFlags = 0; // nie liczy się już + sSpeedTable[i].fVelNext = -1; // jechać + continue; // nie analizować prędkości + } + } // koniec obsługi przelotu na W4 + else + { // zatrzymanie na W4 + if (!eSignNext) + eSignNext = sSpeedTable[i].evEvent; + if (mvOccupied->Vel > 0.3) // jeśli jedzie (nie trzeba czekać, aż się + // drgania wytłumią - drzwi zamykane od 1.0) + sSpeedTable[i].fVelNext = 0; // to będzie zatrzymanie + // else if + // ((iDrivigFlags&moveStopCloser)?sSpeedTable[i].fDist<=fMaxProximityDist*(AIControllFlag?1.0:10.0):true) + else if ((iDrivigFlags & moveStopCloser) ? + sSpeedTable[i].fDist + fLength <= + Max0R(sSpeedTable[i].evEvent->ValueGet(2), + fMaxProximityDist + fLength) : + true) + // Ra 2F1I: odległość plus długość pociągu musi być mniejsza od długości + // peronu, chyba że pociąg jest dłuższy, to wtedy minimalna + // jeśli długość peronu ((sSpeedTable[i].evEvent->ValueGet(2)) nie podana, + // przyjąć odległość fMinProximityDist + { // jeśli się zatrzymał przy W4, albo stał w momencie zobaczenia W4 + if (!AIControllFlag) // AI tylko sobie otwiera drzwi + iDrivigFlags &= ~moveStopCloser; // w razie przełączenia na AI ma + // nie podciągać do W4, gdy + // użytkownik zatrzymał za daleko + if ((iDrivigFlags & moveDoorOpened) == 0) + { // drzwi otwierać jednorazowo + iDrivigFlags |= moveDoorOpened; // nie wykonywać drugi raz + if (mvOccupied->DoorOpenCtrl == 1) //(mvOccupied->TrainType==dt_EZT) + { // otwieranie drzwi w EZT + if (AIControllFlag) // tylko AI otwiera drzwi EZT, użytkownik + // musi samodzielnie + if (!mvOccupied->DoorLeftOpened && + !mvOccupied->DoorRightOpened) + { // otwieranie drzwi + int p2 = + int(floor(sSpeedTable[i].evEvent->ValueGet(2))) % + 10; // p7=platform side (1:left, 2:right, 3:both) + int lewe = (iDirection > 0) ? 1 : 2; // jeśli jedzie do + // tyłu, to drzwi + // otwiera + // odwrotnie + int prawe = (iDirection > 0) ? 2 : 1; + if (p2 & lewe) + mvOccupied->DoorLeft(true); + if (p2 & prawe) + mvOccupied->DoorRight(true); + // if (p2&3) //żeby jeszcze poczekał chwilę, zanim + // zamknie + // WaitingSet(10); //10 sekund (wziąć z rozkładu????) + } + } + else + { // otwieranie drzwi w składach wagonowych - docelowo wysyłać + // komendę zezwolenia na otwarcie drzwi + int p7, lewe, + prawe; // p7=platform side (1:left, 2:right, 3:both) + p7 = int(floor(sSpeedTable[i].evEvent->ValueGet(2))) % + 10; // tu będzie jeszcze długość peronu zaokrąglona do 10m + // (20m bezpieczniej, bo nie modyfikuje bitu 1) + TDynamicObject *p = pVehicles[0]; // pojazd na czole składu + while (p) + { // otwieranie drzwi w pojazdach - flaga zezwolenia była by + // lepsza + lewe = (p->DirectionGet() > 0) ? 1 : 2; // jeśli jedzie do + // tyłu, to drzwi + // otwiera odwrotnie + prawe = 3 - lewe; + p->MoverParameters->BatterySwitch(true); // wagony muszą + // mieć baterię + // załączoną do + // otwarcia + // drzwi... + if (p7 & lewe) + p->MoverParameters->DoorLeft(true); + if (p7 & prawe) + p->MoverParameters->DoorRight(true); + p = p->Next(); // pojazd podłączony z tyłu (patrząc od + // czoła) + } + // if (p7&3) //żeby jeszcze poczekał chwilę, zanim zamknie + // WaitingSet(10); //10 sekund (wziąć z rozkładu????) + } + if (fStopTime > + -5) // na końcu rozkładu się ustawia 60s i tu by było skrócenie + WaitingSet(10); // 10 sekund (wziąć z rozkładu????) - czekanie + // niezależne od sposobu obsługi drzwi, bo + // opóźnia również kierownika + } + if (TrainParams->UpdateMTable( + GlobalTime->hh, GlobalTime->mm, + asNextStop.SubString(20, asNextStop.Length()))) + { // to się wykona tylko raz po zatrzymaniu na W4 + if (TrainParams->CheckTrainLatency() < 0.0) + iDrivigFlags |= moveLate; // odnotowano spóźnienie + else + iDrivigFlags &= ~moveLate; // przyjazd o czasie + if (TrainParams->DirectionChange()) // jeśli "@" w rozkładzie, to + // wykonanie dalszych komend + { // wykonanie kolejnej komendy, nie dotyczy ostatniej stacji + if (iDrivigFlags & movePushPull) // SN61 ma się też nie ruszać, + // chyba że ma wagony + { + iDrivigFlags |= moveStopHere; // EZT ma stać przy peronie + if (OrderNextGet() != Change_direction) + { + OrderPush(Change_direction); // zmiana kierunku + OrderPush(TrainParams->StationIndex < + TrainParams->StationCount ? + Obey_train : + Shunt); // to dalej wg rozkładu + } + } + else // a dla lokomotyw... + iDrivigFlags &= + ~(moveStopPoint | moveStopHere); // pozwolenie na + // przejechanie za W4 + // przed czasem i nie + // ma stać + JumpToNextOrder(); // przejście do kolejnego rozkazu (zmiana + // kierunku, odczepianie) + iDrivigFlags &= ~moveStopCloser; // ma nie podjeżdżać pod W4 po + // przeciwnej stronie + sSpeedTable[i].iFlags = 0; // ten W4 nie liczy się już zupełnie + // (nie wyśle SetVelocity) + sSpeedTable[i].fVelNext = -1; // jechać + continue; // nie analizować prędkości + } + } + if (OrderCurrentGet() == Shunt) + { + OrderNext(Obey_train); // uruchomić jazdę pociągową + CheckVehicles(); // zmienić światła + } + if (TrainParams->StationIndex < TrainParams->StationCount) + { // jeśli są dalsze stacje, czekamy do godziny odjazdu + if (TrainParams->IsTimeToGo(GlobalTime->hh, GlobalTime->mm)) + { // z dalszą akcją czekamy do godziny odjazdu + // if (TrainParams->CheckTrainLatency()<0.0) //jak się ma odjazd + // do czasu odjazdu? + // iDrivigFlags|=moveLate1; //oflagować, gdy odjazd ze + // spóźnieniem, będzie jechał forsowniej + fLastStopExpDist = + mvOccupied->DistCounter + 0.050 + + 0.001 * fLength; // przy jakim dystansie (stanie licznika) + // ma przesunąć na następny postój + // Controlled-> //zapisać odległość do przejechania + TrainParams->StationIndexInc(); // przejście do następnej + asNextStop = + TrainParams + ->NextStop(); // pobranie kolejnego miejsca zatrzymania +// TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie jest dobry pomysł #if LOGSTOPS - WriteLog(pVehicle->asName+" as "+TrainParams->TrainName+": at "+AnsiString(GlobalTime->hh)+":"+AnsiString(GlobalTime->mm)+" next "+asNextStop); //informacja + WriteLog(pVehicle->asName + " as " + TrainParams->TrainName + + ": at " + AnsiString(GlobalTime->hh) + ":" + + AnsiString(GlobalTime->mm) + " next " + + asNextStop); // informacja #endif - if (int(floor(sSpeedTable[i].evEvent->ValueGet(1)))&1) - iDrivigFlags|=moveStopHere; //nie podjeżdżać do semafora, jeśli droga nie jest wolna - iDrivigFlags|=moveStopCloser; //do następnego W4 podjechać blisko (z dociąganiem) - iDrivigFlags&=~moveStartHorn; //bez trąbienia przed odjazdem - sSpeedTable[i].iFlags=0; //nie liczy się już zupełnie (nie wyśle SetVelocity) - sSpeedTable[i].fVelNext=-1; //można jechać za W4 - if (go==cm_Unknown) //jeśli nie było komendy wcześniej - go=cm_Ready; //gotów do odjazdu z W4 (semafor może zatrzymać) - if (tsGuardSignal) //jeśli mamy głos kierownika, to odegrać - iDrivigFlags|=moveGuardSignal; - continue; //nie analizować prędkości - } //koniec startu z zatrzymania - } //koniec obsługi początkowych stacji - else - {//jeśli dojechaliśmy do końca rozkładu + if (int(floor(sSpeedTable[i].evEvent->ValueGet(1))) & 1) + iDrivigFlags |= moveStopHere; // nie podjeżdżać do semafora, + // jeśli droga nie jest wolna + iDrivigFlags |= moveStopCloser; // do następnego W4 podjechać + // blisko (z dociąganiem) + iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed odjazdem + sSpeedTable[i].iFlags = + 0; // nie liczy się już zupełnie (nie wyśle SetVelocity) + sSpeedTable[i].fVelNext = -1; // można jechać za W4 + if (go == cm_Unknown) // jeśli nie było komendy wcześniej + go = cm_Ready; // gotów do odjazdu z W4 (semafor może + // zatrzymać) + if (tsGuardSignal) // jeśli mamy głos kierownika, to odegrać + iDrivigFlags |= moveGuardSignal; + continue; // nie analizować prędkości + } // koniec startu z zatrzymania + } // koniec obsługi początkowych stacji + else + { // jeśli dojechaliśmy do końca rozkładu #if LOGSTOPS - WriteLog(pVehicle->asName+" as "+TrainParams->TrainName+": at "+AnsiString(GlobalTime->hh)+":"+AnsiString(GlobalTime->mm)+" end of route."); //informacja + WriteLog(pVehicle->asName + " as " + TrainParams->TrainName + + ": at " + AnsiString(GlobalTime->hh) + ":" + + AnsiString(GlobalTime->mm) + + " end of route."); // informacja #endif - asNextStop=TrainParams->NextStop(); //informacja o końcu trasy - TrainParams->NewName("none"); //czyszczenie nieaktualnego rozkładu - //TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie jest dobry pomysł - iDrivigFlags&=~(moveStopCloser|moveStopPoint); //ma nie podjeżdżać pod W4 i ma je pomijać - sSpeedTable[i].iFlags=0; //W4 nie liczy się już (nie wyśle SetVelocity) - sSpeedTable[i].fVelNext=-1; //można jechać za W4 - fLastStopExpDist=-1.0f; //nie ma rozkładu, nie ma usuwania stacji - WaitingSet(60); //tak ze 2 minuty, aż wszyscy wysiądą - JumpToNextOrder(); //wykonanie kolejnego rozkazu (Change_direction albo Shunt) - iDrivigFlags|=moveStopHere|moveStartHorn; //ma się nie ruszać aż do momentu podania sygnału - continue; //nie analizować prędkości - } //koniec obsługi ostatniej stacji - } //if (MoverParameters->Vel==0.0) - } //koniec obsługi zatrzymania na W4 - } //koniec warunku pomijania W4 podczas zmiany czoła - else - {//skoro pomijanie, to jechać i ignorować W4 - sSpeedTable[i].iFlags=0; //W4 nie liczy się już (nie zatrzymuje jazdy) - sSpeedTable[i].fVelNext=-1; - continue; //nie analizować prędkości - } - } //koniec obsługi W4 - v=sSpeedTable[i].fVelNext; //odczyt prędkości do zmiennej pomocniczej - if (sSpeedTable[i].iFlags&8) //zwrotnice są usuwane z tabelki dopiero po zjechaniu z nich - iDrivigFlags|=moveSwitchFound; //rozjazd z przodu/pod ogranicza np. sens skanowania wstecz - else if (sSpeedTable[i].iFlags&0x100) //W4 może się deaktywować - {//jeżeli event, może być potrzeba wysłania komendy, aby ruszył - if (sSpeedTable[i].iFlags&0x2000) - {//jeśli W5, to reakcja zależna od trybu jazdy - if (OrderCurrentGet()&Obey_train) - {//w trybie pociągowym: można przyspieszyć do wskazanej prędkości (po zjechaniu z rozjazdów) - v=-1.0; //ignorować? - if (sSpeedTable[i].fDist<0.0) //jeśli wskaźnik został minięty - {VelSignal=v; //!!! ustawienie, gdy przejechany jest lepsze niż wcale, ale to jeszcze nie to -// iStationStart=TrainParams->StationIndex; //zaktualizować wyświetlanie rozkładu - } - else if (!(iDrivigFlags&moveSwitchFound)) //jeśli rozjazdy już minięte - VelSignal=v; //!!! to też koniec ograniczenia - } - else - {//w trybie manewrowym: skanować od niego wstecz, stanąć po wyjechaniu za sygnalizator i zmienić kierunek - v=0.0; //zmiana kierunku może być podanym sygnałem, ale wypadało by zmienić światło wcześniej - if (!(iDrivigFlags&moveSwitchFound)) //jeśli nie ma rozjazdu - iDrivigFlags|=moveTrackEnd; //to dalsza jazda trwale ograniczona (W5, koniec toru) - } - } - else if (sSpeedTable[i].iFlags&0x800) - {//jeśli S1 na SBL - if (mvOccupied->Vel<2.0) //stanąć nie musi, ale zwolnić przynajmniej - if (sSpeedTable[i].fDistValueGet(1); //to ma 0 odczytywać - } - if ((mvOccupied->CategoryFlag&1)?sSpeedTable[i].fDist>pVehicles[0]->fTrackBlock-20.0:false) //jak sygnał jest dalej niż zawalidroga - v=0.0; //to może być podany dla tamtego: jechać tak, jakby tam stop był - else - {//zawalidrogi nie ma (albo pojazd jest samochodem), sprawdzić sygnał - if (sSpeedTable[i].iFlags&0x200) //jeśli Tm - w zasadzie to sprawdzić komendę! - {//jeśli podana prędkość manewrowa - if ((OrderCurrentGet()&Obey_train)?v==0.0:false) - {//jeśli tryb pociągowy a tarcze ma ShuntVelocity 0 0 - v=-1; //ignorować, chyba że prędkość stanie się niezerowa - if (sSpeedTable[i].iFlags&0x20) //a jak przejechana - sSpeedTable[i].iFlags=0; //to można usunąć, bo podstawowy automat usuwa tylko niezerowe - } - else - if (go<=cm_Ready) //jeśli jeszcze nie ma komendy - if (v!=0.0) //komenda jest tylko gdy ma jechać, bo stoi na podstawie tabelki - {//jeśli nie było komendy wcześniej - pierwsza się liczy - ustawianie VelSignal - go=cm_ShuntVelocity; //w trybie pociągowym tylko jeśli włącza tryb manewrowy (v!=0.0) - //Ra 2014-06: (VelSignal) nie może być tu ustawiane, bo Tm może być daleko - //VelSignal=v; //nie do końca tak, to jest druga prędkość - if (VelSignal==0.0) VelSignal=v; //aby stojący ruszył - if (sSpeedTable[i].fDist<0.0) //jeśli przejechany - {VelSignal=v; //!!! ustawienie, gdy przejechany jest lepsze niż wcale, ale to jeszcze nie to - sSpeedTable[i].iFlags=0; //to można usunąć (nie mogą być usuwane w skanowaniu) - } - } - } - else //if (sSpeedTable[i].iFlags&0x100) //jeśli semafor !!! Komendę trzeba sprawdzić !!!! - if (go<=cm_Ready) //jeśli nie było komendy wcześniej - pierwsza się liczy - ustawianie VelSignal - if (v<0.0?true:v>=1.0) //bo wartość 0.1 służy do hamowania tylko - {go=cm_SetVelocity; //może odjechać - //Ra 2014-06: (VelSignal) nie może być tu ustawiane, bo semafor może być daleko - //VelSignal=v; //nie do końca tak, to jest druga prędkość; -1 nie wpisywać... - if (VelSignal==0.0) VelSignal=v; //aby stojący ruszył - if (sSpeedTable[i].fDist<0.0) //jeśli przejechany - {VelSignal=v; //!!! ustawienie, gdy przejechany jest lepsze niż wcale, ale to jeszcze nie to - if (sSpeedTable[i].iFlags&0x100) //jeśli semafor - if ((sSpeedTable[i].evEvent!=eSignSkip)?true:(sSpeedTable[i].fVelNext!=0.0)) //ale inny niż ten, na którym minięto S1, chyba że się już zmieniło - iDrivigFlags&=~moveVisibility; //sygnał zezwalający na jazdę wyłącza jazdę na widoczność (S1 na SBL) - sSpeedTable[i].iFlags=0; //to można usunąć (nie mogą być usuwane w skanowaniu) - } - } - else if (sSpeedTable[i].evEvent->StopCommand()) - {//jeśli prędkość jest zerowa, a komórka zawiera komendę - eSignNext=sSpeedTable[i].evEvent; //dla informacji - if (iDrivigFlags&moveStopHere) //jeśli ma stać, dostaje komendę od razu - go=cm_Command; //komenda z komórki, do wykonania po zatrzymaniu - else if (sSpeedTable[i].fDist<=20.0) //jeśli ma dociągnąć, to niech dociąga (moveStopCloser dotyczy dociągania do W4, nie semafora) - go=cm_Command; //komenda z komórki, do wykonania po zatrzymaniu - } - } //jeśli nie ma zawalidrogi - } //jeśli event - if (v>=0.0) - {//pozycje z prędkością -1 można spokojnie pomijać - d=sSpeedTable[i].fDist; - if ((sSpeedTable[i].iFlags&0x20)?false:d>0.0) //sygnał lub ograniczenie z przodu (+32=przejechane) - {//2014-02: jeśli stoi, a ma do przejechania kawałek, to niech jedzie - if ((mvOccupied->Vel==0.0)?((sSpeedTable[i].iFlags&0x501)==0x501)&&(d>fMaxProximityDist):false) - a=(iDrivigFlags&moveStopCloser)?fAcc:0.0; //ma podjechać bliżej - czy na pewno w tym miejscu taki warunek? - else - {a=(v*v-mvOccupied->Vel*mvOccupied->Vel)/(25.92*d); //przyspieszenie: ujemne, gdy trzeba hamować - if (d=1.0) //EU06 się zawieszało po dojechaniu na koniec toru postojowego - if (d<-fLength) - continue; //zapętlenie, jeśli już wyjechał za ten odcinek - if (v1.0 i się tu nie załapuje - //if (mvOccupied->Vel>10.0) - fAcc=a; //zalecane przyspieszenie (nie musi być uwzględniane przez AI) - fNext=v; //istotna jest prędkość na końcu tego odcinka - fDist=d; //dlugość odcinka - } - else if ((fAcc>0)&&(v>0)&&(v<=fNext)) - {//jeśli nie ma wskazań do hamowania, można podać drogę i prędkość na jej końcu - fNext=v; //istotna jest prędkość na końcu tego odcinka - fDist=d; //dlugość odcinka (kolejne pozycje mogą wydłużać drogę, jeśli prędkość jest stała) - } - } //if (v>=0.0) - if (fNext>=0.0) - {//jeśli ograniczenie - if ((sSpeedTable[i].iFlags&0x101)==0x101) //tylko sygnał przypisujemy - if (!eSignNext) //jeśli jeszcze nic nie zapisane tam - eSignNext=sSpeedTable[i].evEvent; //dla informacji - if (fNext==0.0) - break; //nie ma sensu analizować tabelki dalej - } - } //if (sSpeedTable[i].iFlags&1) - } //for - return go; + asNextStop = TrainParams->NextStop(); // informacja o końcu trasy + TrainParams->NewName("none"); // czyszczenie nieaktualnego rozkładu + // TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to + // nie jest dobry pomysł + iDrivigFlags &= + ~(moveStopCloser | + moveStopPoint); // ma nie podjeżdżać pod W4 i ma je pomijać + sSpeedTable[i].iFlags = + 0; // W4 nie liczy się już (nie wyśle SetVelocity) + sSpeedTable[i].fVelNext = -1; // można jechać za W4 + fLastStopExpDist = -1.0f; // nie ma rozkładu, nie ma usuwania stacji + WaitingSet(60); // tak ze 2 minuty, aż wszyscy wysiądą + JumpToNextOrder(); // wykonanie kolejnego rozkazu (Change_direction + // albo Shunt) + iDrivigFlags |= moveStopHere | moveStartHorn; // ma się nie ruszać + // aż do momentu + // podania sygnału + continue; // nie analizować prędkości + } // koniec obsługi ostatniej stacji + } // if (MoverParameters->Vel==0.0) + } // koniec obsługi zatrzymania na W4 + } // koniec warunku pomijania W4 podczas zmiany czoła + else + { // skoro pomijanie, to jechać i ignorować W4 + sSpeedTable[i].iFlags = 0; // W4 nie liczy się już (nie zatrzymuje jazdy) + sSpeedTable[i].fVelNext = -1; + continue; // nie analizować prędkości + } + } // koniec obsługi W4 + v = sSpeedTable[i].fVelNext; // odczyt prędkości do zmiennej pomocniczej + if (sSpeedTable[i].iFlags & + 8) // zwrotnice są usuwane z tabelki dopiero po zjechaniu z nich + iDrivigFlags |= + moveSwitchFound; // rozjazd z przodu/pod ogranicza np. sens skanowania wstecz + else if (sSpeedTable[i].iFlags & 0x100) // W4 może się deaktywować + { // jeżeli event, może być potrzeba wysłania komendy, aby ruszył + if (sSpeedTable[i].iFlags & 0x2000) + { // jeśli W5, to reakcja zależna od trybu jazdy + if (OrderCurrentGet() & Obey_train) + { // w trybie pociągowym: można przyspieszyć do wskazanej prędkości (po + // zjechaniu z rozjazdów) + v = -1.0; // ignorować? + if (sSpeedTable[i].fDist < 0.0) // jeśli wskaźnik został minięty + { + VelSignal = v; //!!! ustawienie, gdy przejechany jest lepsze niż wcale, + //ale to jeszcze nie to + // iStationStart=TrainParams->StationIndex; //zaktualizować + // wyświetlanie rozkładu + } + else if (!(iDrivigFlags & moveSwitchFound)) // jeśli rozjazdy już minięte + VelSignal = v; //!!! to też koniec ograniczenia + } + else + { // w trybie manewrowym: skanować od niego wstecz, stanąć po wyjechaniu za + // sygnalizator i zmienić kierunek + v = 0.0; // zmiana kierunku może być podanym sygnałem, ale wypadało by + // zmienić światło wcześniej + if (!(iDrivigFlags & moveSwitchFound)) // jeśli nie ma rozjazdu + iDrivigFlags |= moveTrackEnd; // to dalsza jazda trwale ograniczona (W5, + // koniec toru) + } + } + else if (sSpeedTable[i].iFlags & 0x800) + { // jeśli S1 na SBL + if (mvOccupied->Vel < 2.0) // stanąć nie musi, ale zwolnić przynajmniej + if (sSpeedTable[i].fDist < fMaxProximityDist) // jest w maksymalnym zasięgu + { + eSignSkip = sSpeedTable[i] + .evEvent; // to można go pominąć (wziąć drugą prędkosć) + iDrivigFlags |= moveVisibility; // jazda na widoczność - skanować + // możliwość kolizji i nie podjeżdżać + // zbyt blisko + // usunąć flagę po podjechaniu blisko semafora zezwalającego na jazdę + // ostrożnie interpretować sygnały - semafor może zezwalać na jazdę + // pociągu z przodu! + } + if (eSignSkip != sSpeedTable[i].evEvent) // jeśli ten SBL nie jest do pominięcia + v = sSpeedTable[i].evEvent->ValueGet(1); // to ma 0 odczytywać + } + if ((mvOccupied->CategoryFlag & 1) ? + sSpeedTable[i].fDist > pVehicles[0]->fTrackBlock - 20.0 : + false) // jak sygnał jest dalej niż zawalidroga + v = 0.0; // to może być podany dla tamtego: jechać tak, jakby tam stop był + else + { // zawalidrogi nie ma (albo pojazd jest samochodem), sprawdzić sygnał + if (sSpeedTable[i].iFlags & 0x200) // jeśli Tm - w zasadzie to sprawdzić + // komendę! + { // jeśli podana prędkość manewrowa + if ((OrderCurrentGet() & Obey_train) ? v == 0.0 : false) + { // jeśli tryb pociągowy a tarcze ma ShuntVelocity 0 0 + v = -1; // ignorować, chyba że prędkość stanie się niezerowa + if (sSpeedTable[i].iFlags & 0x20) // a jak przejechana + sSpeedTable[i].iFlags = 0; // to można usunąć, bo podstawowy automat + // usuwa tylko niezerowe + } + else if (go <= cm_Ready) // jeśli jeszcze nie ma komendy + if (v != 0.0) // komenda jest tylko gdy ma jechać, bo stoi na podstawie + // tabelki + { // jeśli nie było komendy wcześniej - pierwsza się liczy - ustawianie + // VelSignal + go = cm_ShuntVelocity; // w trybie pociągowym tylko jeśli włącza + // tryb manewrowy (v!=0.0) + // Ra 2014-06: (VelSignal) nie może być tu ustawiane, bo Tm może być + // daleko + // VelSignal=v; //nie do końca tak, to jest druga prędkość + if (VelSignal == 0.0) + VelSignal = v; // aby stojący ruszył + if (sSpeedTable[i].fDist < 0.0) // jeśli przejechany + { + VelSignal = v; //!!! ustawienie, gdy przejechany jest lepsze niż + //wcale, ale to jeszcze nie to + sSpeedTable[i].iFlags = + 0; // to można usunąć (nie mogą być usuwane w skanowaniu) + } + } + } + else // if (sSpeedTable[i].iFlags&0x100) //jeśli semafor !!! Komendę trzeba + // sprawdzić !!!! + if (go <= cm_Ready) // jeśli nie było komendy wcześniej - pierwsza się liczy + // - ustawianie VelSignal + if (v < 0.0 ? true : v >= 1.0) // bo wartość 0.1 służy do hamowania tylko + { + go = cm_SetVelocity; // może odjechać + // Ra 2014-06: (VelSignal) nie może być tu ustawiane, bo semafor może + // być daleko + // VelSignal=v; //nie do końca tak, to jest druga prędkość; -1 nie + // wpisywać... + if (VelSignal == 0.0) + VelSignal = v; // aby stojący ruszył + if (sSpeedTable[i].fDist < 0.0) // jeśli przejechany + { + VelSignal = v; //!!! ustawienie, gdy przejechany jest lepsze niż + //wcale, ale to jeszcze nie to + if (sSpeedTable[i].iFlags & 0x100) // jeśli semafor + if ((sSpeedTable[i].evEvent != eSignSkip) ? + true : + (sSpeedTable[i].fVelNext != 0.0)) // ale inny niż ten, + // na którym minięto + // S1, chyba że się + // już zmieniło + iDrivigFlags &= ~moveVisibility; // sygnał zezwalający na + // jazdę wyłącza jazdę na + // widoczność (S1 na SBL) + sSpeedTable[i].iFlags = + 0; // to można usunąć (nie mogą być usuwane w skanowaniu) + } + } + else if (sSpeedTable[i].evEvent->StopCommand()) + { // jeśli prędkość jest zerowa, a komórka zawiera komendę + eSignNext = sSpeedTable[i].evEvent; // dla informacji + if (iDrivigFlags & + moveStopHere) // jeśli ma stać, dostaje komendę od razu + go = cm_Command; // komenda z komórki, do wykonania po zatrzymaniu + else if (sSpeedTable[i].fDist <= 20.0) // jeśli ma dociągnąć, to niech + // dociąga (moveStopCloser + // dotyczy dociągania do W4, nie + // semafora) + go = cm_Command; // komenda z komórki, do wykonania po zatrzymaniu + } + } // jeśli nie ma zawalidrogi + } // jeśli event + if (v >= 0.0) + { // pozycje z prędkością -1 można spokojnie pomijać + d = sSpeedTable[i].fDist; + if ((sSpeedTable[i].iFlags & 0x20) ? + false : + d > 0.0) // sygnał lub ograniczenie z przodu (+32=przejechane) + { // 2014-02: jeśli stoi, a ma do przejechania kawałek, to niech jedzie + if ((mvOccupied->Vel == 0.0) ? + ((sSpeedTable[i].iFlags & 0x501) == 0x501) && (d > fMaxProximityDist) : + false) + a = (iDrivigFlags & moveStopCloser) ? fAcc : 0.0; // ma podjechać bliżej - + // czy na pewno w tym + // miejscu taki warunek? + else + { + a = (v * v - mvOccupied->Vel * mvOccupied->Vel) / + (25.92 * d); // przyspieszenie: ujemne, gdy trzeba hamować + if (d < fMinProximityDist) // jak jest już blisko + if (v < fVelDes) + fVelDes = v; // ograniczenie aktualnej prędkości + } + } + else if (sSpeedTable[i].iFlags & 2) // jeśli tor + { // tor ogranicza prędkość, dopóki cały skład nie przejedzie, + // d=fLength+d; //zamiana na długość liczoną do przodu + if (v >= 1.0) // EU06 się zawieszało po dojechaniu na koniec toru postojowego + if (d < -fLength) + continue; // zapętlenie, jeśli już wyjechał za ten odcinek + if (v < fVelDes) + fVelDes = + v; // ograniczenie aktualnej prędkości aż do wyjechania za ograniczenie + // if (v==0.0) fAcc=-0.9; //hamowanie jeśli stop + continue; // i tyle wystarczy + } + else // event trzyma tylko jeśli VelNext=0, nawet po przejechaniu (nie powinno + // dotyczyć samochodów?) + a = (v == 0.0 ? -1.0 : fAcc); // ruszanie albo hamowanie + if (a < fAcc) + { // mniejsze przyspieszenie to mniejsza możliwość rozpędzenia się albo konieczność + // hamowania + // jeśli droga wolna, to może być a>1.0 i się tu nie załapuje + // if (mvOccupied->Vel>10.0) + fAcc = a; // zalecane przyspieszenie (nie musi być uwzględniane przez AI) + fNext = v; // istotna jest prędkość na końcu tego odcinka + fDist = d; // dlugość odcinka + } + else if ((fAcc > 0) && (v > 0) && (v <= fNext)) + { // jeśli nie ma wskazań do hamowania, można podać drogę i prędkość na jej końcu + fNext = v; // istotna jest prędkość na końcu tego odcinka + fDist = d; // dlugość odcinka (kolejne pozycje mogą wydłużać drogę, jeśli + // prędkość jest stała) + } + } // if (v>=0.0) + if (fNext >= 0.0) + { // jeśli ograniczenie + if ((sSpeedTable[i].iFlags & 0x101) == 0x101) // tylko sygnał przypisujemy + if (!eSignNext) // jeśli jeszcze nic nie zapisane tam + eSignNext = sSpeedTable[i].evEvent; // dla informacji + if (fNext == 0.0) + break; // nie ma sensu analizować tabelki dalej + } + } // if (sSpeedTable[i].iFlags&1) + } // for + return go; }; void __fastcall TController::TablePurger() -{//odtykacz: usuwa mniej istotne pozycje ze środka tabelki, aby uniknąć zatkania - //(np. brak ograniczenia pomiędzy zwrotnicami, usunięte sygnały, minięte odcinki łuku) - int i,j,k=iLast-iFirst; //może być 15 albo 16 pozycji, ostatniej nie ma co sprawdzać - if (k<0) k+=iSpeedTableSize; //ilość pozycji do przeanalizowania - for (i=iFirst;k>0;--k,i=(i+1)%iSpeedTableSize) - {//sprawdzenie rekordów od (iFirst) do (iLast), o ile są istotne - if ((sSpeedTable[i].iFlags&1)?(sSpeedTable[i].fVelNext<0)&&((sSpeedTable[i].iFlags&0xAB)==0xA3):true) - {//jeśli jest to minięty (0x20) tor (0x03) do liczenia cięciw (0x80), a nie zwrotnica (0x08) - for (;k>0;--k,i=(i+1)%iSpeedTableSize) - sSpeedTable[i]=sSpeedTable[(i+1)%iSpeedTableSize]; //skopiowanie - //WriteLog("Odtykacz usuwa pozycję"); - iLast=(iLast-1+iSpeedTableSize)%iSpeedTableSize; //cofnięcie z zawinięciem - return; - } - } - //jeśli powyższe odtykane nie pomoże, można usunąć coś więcej, albo powiększyć tabelkę - TSpeedPos *t=new TSpeedPos[iSpeedTableSize+16]; //zwiększenie - k=iLast-iFirst+1; //tym razem wszystkie - if (k<0) k+=iSpeedTableSize; //ilość pozycji do przeanalizowania - for (j=-1,i=iFirst;k>0;--k) - {//przepisywanie rekordów iFirst..iLast na 0..k - t[++j]=sSpeedTable[i]; - i=(i+1)%iSpeedTableSize; //kolejna pozycja mogą być zawinięta - } - iFirst=0; //teraz będzie od zera - iLast=j; //ostatnia - delete[] sSpeedTable; //to już nie potrzebne - sSpeedTable=t; //bo jest nowe - iSpeedTableSize+=16; - //WriteLog("Tabelka powiększona do "+AnsiString(iSpeedTableSize)+" pozycji"); +{ // odtykacz: usuwa mniej istotne pozycje ze środka tabelki, aby uniknąć zatkania + //(np. brak ograniczenia pomiędzy zwrotnicami, usunięte sygnały, minięte odcinki łuku) + int i, j, k = iLast - iFirst; // może być 15 albo 16 pozycji, ostatniej nie ma co sprawdzać + if (k < 0) + k += iSpeedTableSize; // ilość pozycji do przeanalizowania + for (i = iFirst; k > 0; --k, i = (i + 1) % iSpeedTableSize) + { // sprawdzenie rekordów od (iFirst) do (iLast), o ile są istotne + if ((sSpeedTable[i].iFlags & 1) ? + (sSpeedTable[i].fVelNext < 0) && ((sSpeedTable[i].iFlags & 0xAB) == 0xA3) : + true) + { // jeśli jest to minięty (0x20) tor (0x03) do liczenia cięciw (0x80), a nie zwrotnica + // (0x08) + for (; k > 0; --k, i = (i + 1) % iSpeedTableSize) + sSpeedTable[i] = sSpeedTable[(i + 1) % iSpeedTableSize]; // skopiowanie + // WriteLog("Odtykacz usuwa pozycję"); + iLast = (iLast - 1 + iSpeedTableSize) % iSpeedTableSize; // cofnięcie z zawinięciem + return; + } + } + // jeśli powyższe odtykane nie pomoże, można usunąć coś więcej, albo powiększyć tabelkę + TSpeedPos *t = new TSpeedPos[iSpeedTableSize + 16]; // zwiększenie + k = iLast - iFirst + 1; // tym razem wszystkie + if (k < 0) + k += iSpeedTableSize; // ilość pozycji do przeanalizowania + for (j = -1, i = iFirst; k > 0; --k) + { // przepisywanie rekordów iFirst..iLast na 0..k + t[++j] = sSpeedTable[i]; + i = (i + 1) % iSpeedTableSize; // kolejna pozycja mogą być zawinięta + } + iFirst = 0; // teraz będzie od zera + iLast = j; // ostatnia + delete[] sSpeedTable; // to już nie potrzebne + sSpeedTable = t; // bo jest nowe + iSpeedTableSize += 16; + // WriteLog("Tabelka powiększona do "+AnsiString(iSpeedTableSize)+" pozycji"); }; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- -__fastcall TController::TController -(bool AI, - TDynamicObject *NewControll, - bool InitPsyche, - bool primary //czy ma aktywnie prowadzić? -) +__fastcall TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, + bool primary // czy ma aktywnie prowadzić? + ) { - iEngineActive=0; - LastUpdatedTime=0.0; - ElapsedTime=0.0; - //inicjalizacja zmiennych - Psyche=InitPsyche; - VelDesired=0.0; //prędkosć początkowa - VelforDriver=-1; - LastReactionTime=0.0; - HelpMeFlag=false; - //fProximityDist=1; //nie używane - ActualProximityDist=1; - vCommandLocation.x=0; - vCommandLocation.y=0; - vCommandLocation.z=0; - VelSignal=0.0; //normalnie na początku ma stać, no chyba że jedzie - VelLimit=-1.0; //brak ograniczenia prędkości - VelNext=120.0; - AIControllFlag=AI; - pVehicle=NewControll; - ControllingSet(); //utworzenie połączenia do sterowanego pojazdu - pVehicles[0]=pVehicle->GetFirstDynamic(0); //pierwszy w kierunku jazdy (Np. Pc1) - pVehicles[1]=pVehicle->GetFirstDynamic(1); //ostatni w kierunku jazdy (końcówki) -/* - switch (mvOccupied->CabNo) - { - case -1: SendCtrlBroadcast("CabActivisation",1); break; - case 1: SendCtrlBroadcast("CabActivisation",2); break; - default: AIControllFlag:=False; //na wszelki wypadek - } -*/ - iDirection=0; - iDirectionOrder=mvOccupied->CabNo; //1=do przodu (w kierunku sprzęgu 0) - VehicleName=mvOccupied->Name; - //TrainParams=NewTrainParams; - //if (TrainParams) - // asNextStop=TrainParams->NextStop(); - //else - TrainParams=new TTrainParameters("none"); //rozkład jazdy - //OrderCommand=""; - //OrderValue=0; - OrdersClear(); - MaxVelFlag=false; MinVelFlag=false; //Ra: to nie jest używane - iDriverFailCount=0; - Need_TryAgain=false; //true, jeśli druga pozycja w elektryku nie załapała - Need_BrakeRelease=true; - deltalog=0.05;//1.0; + iEngineActive = 0; + LastUpdatedTime = 0.0; + ElapsedTime = 0.0; + // inicjalizacja zmiennych + Psyche = InitPsyche; + VelDesired = 0.0; // prędkosć początkowa + VelforDriver = -1; + LastReactionTime = 0.0; + HelpMeFlag = false; + // fProximityDist=1; //nie używane + ActualProximityDist = 1; + vCommandLocation.x = 0; + vCommandLocation.y = 0; + vCommandLocation.z = 0; + VelSignal = 0.0; // normalnie na początku ma stać, no chyba że jedzie + VelLimit = -1.0; // brak ograniczenia prędkości + VelNext = 120.0; + AIControllFlag = AI; + pVehicle = NewControll; + ControllingSet(); // utworzenie połączenia do sterowanego pojazdu + pVehicles[0] = pVehicle->GetFirstDynamic(0); // pierwszy w kierunku jazdy (Np. Pc1) + pVehicles[1] = pVehicle->GetFirstDynamic(1); // ostatni w kierunku jazdy (końcówki) + /* + switch (mvOccupied->CabNo) + { + case -1: SendCtrlBroadcast("CabActivisation",1); break; + case 1: SendCtrlBroadcast("CabActivisation",2); break; + default: AIControllFlag:=False; //na wszelki wypadek + } + */ + iDirection = 0; + iDirectionOrder = mvOccupied->CabNo; // 1=do przodu (w kierunku sprzęgu 0) + VehicleName = mvOccupied->Name; + // TrainParams=NewTrainParams; + // if (TrainParams) + // asNextStop=TrainParams->NextStop(); + // else + TrainParams = new TTrainParameters("none"); // rozkład jazdy + // OrderCommand=""; + // OrderValue=0; + OrdersClear(); + MaxVelFlag = false; + MinVelFlag = false; // Ra: to nie jest używane + iDriverFailCount = 0; + Need_TryAgain = false; // true, jeśli druga pozycja w elektryku nie załapała + Need_BrakeRelease = true; + deltalog = 0.05; // 1.0; - if (WriteLogFlag) - { - mkdir("physicslog\\"); - LogFile.open(AnsiString("physicslog\\"+VehicleName+".dat").c_str(),std::ios::in | std::ios::out | std::ios::trunc); -#if LOGPRESS==0 - LogFile << AnsiString(" Time [s] Velocity [m/s] Acceleration [m/ss] Coupler.Dist[m] Coupler.Force[N] TractionForce [kN] FrictionForce [kN] BrakeForce [kN] BrakePress [MPa] PipePress [MPa] MotorCurrent [A] MCP SCP BCP LBP DmgFlag Command CVal1 CVal2").c_str() << "\r\n"; + if (WriteLogFlag) + { + mkdir("physicslog\\"); + LogFile.open(AnsiString("physicslog\\" + VehicleName + ".dat").c_str(), + std::ios::in | std::ios::out | std::ios::trunc); +#if LOGPRESS == 0 + LogFile << AnsiString(" Time [s] Velocity [m/s] Acceleration [m/ss] Coupler.Dist[m] " + "Coupler.Force[N] TractionForce [kN] FrictionForce [kN] " + "BrakeForce [kN] BrakePress [MPa] PipePress [MPa] " + "MotorCurrent [A] MCP SCP BCP LBP DmgFlag Command CVal1 CVal2") + .c_str() << "\r\n"; #endif -#if LOGPRESS==1 - LogFile << AnsiString("t\tVel\tAcc\tPP\tVVP\tBP\tBVP\tCVP").c_str() << "\n"; +#if LOGPRESS == 1 + LogFile << AnsiString("t\tVel\tAcc\tPP\tVVP\tBP\tBVP\tCVP").c_str() << "\n"; #endif - LogFile.flush(); - } -/* - if (WriteLogFlag) - { - assignfile(AILogFile,VehicleName+".txt"); - rewrite(AILogFile); - writeln(AILogFile,"AI driver log: started OK"); - close(AILogFile); - } -*/ + LogFile.flush(); + } + /* + if (WriteLogFlag) + { + assignfile(AILogFile,VehicleName+".txt"); + rewrite(AILogFile); + writeln(AILogFile,"AI driver log: started OK"); + close(AILogFile); + } + */ - //VelMargin=2; //Controlling->Vmax*0.015; - fWarningDuration=0.0; //nic do wytrąbienia - WaitingExpireTime=31.0; //tyle ma czekać, zanim się ruszy - WaitingTime=0.0; - fMinProximityDist=30.0; //stawanie między 30 a 60 m przed przeszkodą - fMaxProximityDist=50.0; - iVehicleCount=-2; //wartość neutralna - //Prepare2press=false; //bez dociskania - eStopReason=stopSleep; //na początku śpi - fLength=0.0; - fMass=0.0; //[kg] - eSignNext=NULL; //sygnał zmieniający prędkość, do pokazania na [F2] - fShuntVelocity=40; //domyślna prędkość manewrowa - fStopTime=0.0; //czas postoju przed dalszą jazdą (np. na przystanku) - iDrivigFlags=moveStopPoint; //podjedź do W4 możliwie blisko - iDrivigFlags|=moveStopHere; //nie podjeżdżaj do semafora, jeśli droga nie jest wolna - iDrivigFlags|=moveStartHorn; //podaj sygnał po podaniu wolnej drogi - if (primary) - iDrivigFlags|=movePrimary; //aktywnie prowadzące pojazd - Ready=false; - if (mvOccupied->CategoryFlag&2) - {//samochody: na podst. http://www.prawko-kwartnik.info/hamowanie.html - //fDriverBraking=0.0065; //mnożone przez (v^2+40*v) [km/h] daje prawie drogę hamowania [m] - fDriverBraking=0.03; //coś nie hamują te samochody zbyt dobrze - fDriverDist=5.0; //5m - zachowywany odstęp przed kolizją - fVelPlus=10.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus=2.0; //margines prędkości powodujący załączenie napędu - } - else - {//pociągi i statki - fDriverBraking=0.06; //mnożone przez (v^2+40*v) [km/h] daje prawie drogę hamowania [m] - fDriverDist=50.0; //50m - zachowywany odstęp przed kolizją - fVelPlus=5.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus=5.0; //margines prędkości powodujący załączenie napędu - } - SetDriverPsyche(); //na końcu, bo wymaga ustawienia zmiennych - AccDesired=AccPreferred; - fVelMax=-1; //ustalenie prędkości dla składu - fBrakeTime=0.0; //po jakim czasie przekręcić hamulec - iVehicles=0; //na wszelki wypadek - iSpeedTableSize=16; - sSpeedTable=new TSpeedPos[iSpeedTableSize]; - TableClear(); - iRadioChannel=1; //numer aktualnego kanału radiowego - fActionTime=0.0; - eAction=actSleep; - tsGuardSignal=NULL; //komunikat od kierownika - iGuardRadio=0; //nie przez radio - iStationStart=0; //nic? - //fAccThreshold może podlegać uczeniu się - hamowanie powinno być rejestrowane, a potem analizowane - fAccThreshold=(mvOccupied->TrainType&dt_EZT)?-0.6:-0.2; //próg opóźnienia dla zadziałania hamulca - fLastStopExpDist=-1.0f; - iRouteWanted=3; //powiedzmy, że ma jechać prosto (1=w lewo) - iCoupler=0; //sprzęg; niezerowy gdy ma być podłączanie; samo podłączanie w trybie Connect (wcześniej może być np. Prepare_engine) - fOverhead1=3000.0; //informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!) - fOverhead2=-1.0; //informacja o sposobie jazdy (-1=normalnie, 0=bez prądu, >0=z opuszczonym i ograniczeniem prędkości) - iOverheadZero=0; //suma bitowa jezdy bezprądowej, bity ustawiane przez pojazdy z podniesionymi pantografami - iOverheadDown=0; //suma bitowa opuszczenia pantografów, bity ustawiane przez pojazdy z podniesionymi pantografami - fAccDesiredAv=0.0; //uśrednione przyspieszenie z kolejnych przebłysków świadomości, żeby ograniczyć migotanie - fVoltage=0.0; //uśrednione napięcie sieci: przy spadku poniżej wartości minimalnej opóźnić rozruch o losowy czas + // VelMargin=2; //Controlling->Vmax*0.015; + fWarningDuration = 0.0; // nic do wytrąbienia + WaitingExpireTime = 31.0; // tyle ma czekać, zanim się ruszy + WaitingTime = 0.0; + fMinProximityDist = 30.0; // stawanie między 30 a 60 m przed przeszkodą + fMaxProximityDist = 50.0; + iVehicleCount = -2; // wartość neutralna + // Prepare2press=false; //bez dociskania + eStopReason = stopSleep; // na początku śpi + fLength = 0.0; + fMass = 0.0; //[kg] + eSignNext = NULL; // sygnał zmieniający prędkość, do pokazania na [F2] + fShuntVelocity = 40; // domyślna prędkość manewrowa + fStopTime = 0.0; // czas postoju przed dalszą jazdą (np. na przystanku) + iDrivigFlags = moveStopPoint; // podjedź do W4 możliwie blisko + iDrivigFlags |= moveStopHere; // nie podjeżdżaj do semafora, jeśli droga nie jest wolna + iDrivigFlags |= moveStartHorn; // podaj sygnał po podaniu wolnej drogi + if (primary) + iDrivigFlags |= movePrimary; // aktywnie prowadzące pojazd + Ready = false; + if (mvOccupied->CategoryFlag & 2) + { // samochody: na podst. http://www.prawko-kwartnik.info/hamowanie.html + // fDriverBraking=0.0065; //mnożone przez (v^2+40*v) [km/h] daje prawie drogę hamowania [m] + fDriverBraking = 0.03; // coś nie hamują te samochody zbyt dobrze + fDriverDist = 5.0; // 5m - zachowywany odstęp przed kolizją + fVelPlus = 10.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelMinus = 2.0; // margines prędkości powodujący załączenie napędu + } + else + { // pociągi i statki + fDriverBraking = 0.06; // mnożone przez (v^2+40*v) [km/h] daje prawie drogę hamowania [m] + fDriverDist = 50.0; // 50m - zachowywany odstęp przed kolizją + fVelPlus = 5.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelMinus = 5.0; // margines prędkości powodujący załączenie napędu + } + SetDriverPsyche(); // na końcu, bo wymaga ustawienia zmiennych + AccDesired = AccPreferred; + fVelMax = -1; // ustalenie prędkości dla składu + fBrakeTime = 0.0; // po jakim czasie przekręcić hamulec + iVehicles = 0; // na wszelki wypadek + iSpeedTableSize = 16; + sSpeedTable = new TSpeedPos[iSpeedTableSize]; + TableClear(); + iRadioChannel = 1; // numer aktualnego kanału radiowego + fActionTime = 0.0; + eAction = actSleep; + tsGuardSignal = NULL; // komunikat od kierownika + iGuardRadio = 0; // nie przez radio + iStationStart = 0; // nic? + // fAccThreshold może podlegać uczeniu się - hamowanie powinno być rejestrowane, a potem + // analizowane + fAccThreshold = + (mvOccupied->TrainType & dt_EZT) ? -0.6 : -0.2; // próg opóźnienia dla zadziałania hamulca + fLastStopExpDist = -1.0f; + iRouteWanted = 3; // powiedzmy, że ma jechać prosto (1=w lewo) + iCoupler = 0; // sprzęg; niezerowy gdy ma być podłączanie; samo podłączanie w trybie Connect + // (wcześniej może być np. Prepare_engine) + fOverhead1 = 3000.0; // informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!) + fOverhead2 = -1.0; // informacja o sposobie jazdy (-1=normalnie, 0=bez prądu, >0=z opuszczonym i + // ograniczeniem prędkości) + iOverheadZero = 0; // suma bitowa jezdy bezprądowej, bity ustawiane przez pojazdy z + // podniesionymi pantografami + iOverheadDown = 0; // suma bitowa opuszczenia pantografów, bity ustawiane przez pojazdy z + // podniesionymi pantografami + fAccDesiredAv = 0.0; // uśrednione przyspieszenie z kolejnych przebłysków świadomości, żeby + // ograniczyć migotanie + fVoltage = 0.0; // uśrednione napięcie sieci: przy spadku poniżej wartości minimalnej opóźnić + // rozruch o losowy czas }; void __fastcall TController::CloseLog() { - if (WriteLogFlag) - { - LogFile.close(); - //if WriteLogFlag) - // CloseFile(AILogFile); -/* append(AIlogFile); - writeln(AILogFile,ElapsedTime5:2,": QUIT"); - close(AILogFile); */ - } + if (WriteLogFlag) + { + LogFile.close(); + // if WriteLogFlag) + // CloseFile(AILogFile); + /* append(AIlogFile); + writeln(AILogFile,ElapsedTime5:2,": QUIT"); + close(AILogFile); */ + } }; __fastcall TController::~TController() -{//wykopanie mechanika z roboty - delete tsGuardSignal; - delete TrainParams; - delete[] sSpeedTable; - CloseLog(); +{ // wykopanie mechanika z roboty + delete tsGuardSignal; + delete TrainParams; + delete[] sSpeedTable; + CloseLog(); }; AnsiString __fastcall TController::Order2Str(TOrders Order) -{//zamiana kodu rozkazu na opis - if (Order&Change_direction) return "Change_direction"; //może być nałożona na inną i wtedy ma priorytet - if (Order==Wait_for_orders) return "Wait_for_orders"; - if (Order==Prepare_engine) return "Prepare_engine"; - if (Order==Shunt) return "Shunt"; - if (Order==Connect) return "Connect"; - if (Order==Disconnect) return "Disconnect"; - if (Order==Obey_train) return "Obey_train"; - if (Order==Release_engine) return "Release_engine"; - if (Order==Jump_to_first_order) return "Jump_to_first_order"; -/* Ra: wersja ze switch nie działa prawidłowo (czemu?) - switch (Order) - { - Wait_for_orders: return "Wait_for_orders"; - Prepare_engine: return "Prepare_engine"; - Shunt: return "Shunt"; - Change_direction: return "Change_direction"; - Obey_train: return "Obey_train"; - Release_engine: return "Release_engine"; - Jump_to_first_order: return "Jump_to_first_order"; - } -*/ - return "Undefined!"; +{ // zamiana kodu rozkazu na opis + if (Order & Change_direction) + return "Change_direction"; // może być nałożona na inną i wtedy ma priorytet + if (Order == Wait_for_orders) + return "Wait_for_orders"; + if (Order == Prepare_engine) + return "Prepare_engine"; + if (Order == Shunt) + return "Shunt"; + if (Order == Connect) + return "Connect"; + if (Order == Disconnect) + return "Disconnect"; + if (Order == Obey_train) + return "Obey_train"; + if (Order == Release_engine) + return "Release_engine"; + if (Order == Jump_to_first_order) + return "Jump_to_first_order"; + /* Ra: wersja ze switch nie działa prawidłowo (czemu?) + switch (Order) + { + Wait_for_orders: return "Wait_for_orders"; + Prepare_engine: return "Prepare_engine"; + Shunt: return "Shunt"; + Change_direction: return "Change_direction"; + Obey_train: return "Obey_train"; + Release_engine: return "Release_engine"; + Jump_to_first_order: return "Jump_to_first_order"; + } + */ + return "Undefined!"; } AnsiString __fastcall TController::OrderCurrent() -{//pobranie aktualnego rozkazu celem wyświetlenia - return AnsiString(OrderPos)+". "+Order2Str(OrderList[OrderPos]); +{ // pobranie aktualnego rozkazu celem wyświetlenia + return AnsiString(OrderPos) + ". " + Order2Str(OrderList[OrderPos]); }; void __fastcall TController::OrdersClear() -{//czyszczenie tabeli rozkazów na starcie albo po dojściu do końca - OrderPos=0; - OrderTop=1; //szczyt stosu rozkazów - for (int b=0;b OrdersClear"); + WriteLog("--> OrdersClear"); #endif }; void __fastcall TController::Activation() -{//umieszczenie obsady w odpowiednim członie, wykonywane wyłącznie gdy steruje AI - iDirection=iDirectionOrder; //kierunek (względem sprzęgów pojazdu z AI) właśnie został ustalony (zmieniony) - if (iDirection) - {//jeśli jest ustalony kierunek - TDynamicObject *old=pVehicle,*d=pVehicle; //w tym siedzi AI - TController *drugi; //jakby były dwa, to zamienić miejscami, a nie robić wycieku pamięci poprzez nadpisanie - int brake=mvOccupied->LocalBrakePos; - while (mvControlling->MainCtrlPos) //samo zapętlenie DecSpeed() nie wystarcza :/ - DecSpeed(true); //wymuszenie zerowania nastawnika jazdy - while (mvOccupied->ActiveDir<0) mvOccupied->DirectionForward(); //kierunek na 0 - while (mvOccupied->ActiveDir>0) mvOccupied->DirectionBackward(); - if (TestFlag(d->MoverParameters->Couplers[iDirectionOrder<0?1:0].CouplingFlag,ctrain_controll)) - {mvControlling->MainSwitch(false); //dezaktywacja czuwaka, jeśli przejście do innego członu - mvOccupied->DecLocalBrakeLevel(10); //zwolnienie hamulca w opuszczanym pojeździe -// mvOccupied->BrakeLevelSet((mvOccupied->BrakeHandle==FVel6)?4:-2); //odcięcie na zaworze maszynisty, FVel6 po drugiej stronie nie luzuje - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_NP)); //odcięcie na zaworze maszynisty - } - mvOccupied->ActiveCab=mvOccupied->CabNo; //użytkownik moze zmienić ActiveCab wychodząc - mvOccupied->CabDeactivisation(); //tak jest w Train.cpp - //przejście AI na drugą stronę EN57, ET41 itp. - while (TestFlag(d->MoverParameters->Couplers[iDirection<0?1:0].CouplingFlag,ctrain_controll)) - {//jeśli pojazd z przodu jest ukrotniony, to przechodzimy do niego - d=iDirection*d->DirectionGet()<0?d->Next():d->Prev(); //przechodzimy do następnego członu - if (d) - {drugi=d->Mechanik; //zapamiętanie tego, co ewentualnie tam siedzi, żeby w razie dwóch zamienić miejscami - d->Mechanik=this; //na razie bilokacja - d->MoverParameters->SetInternalCommand("",0,0); //usunięcie ewentualnie zalegającej komendy (Change_direction?) - if (d->DirectionGet()!=pVehicle->DirectionGet()) //jeśli są przeciwne do siebie - iDirection=-iDirection; //to będziemy jechać w drugą stronę względem zasiedzianego pojazdu - pVehicle->Mechanik=drugi; //wsadzamy tego, co ewentualnie był (podwójna trakcja) - pVehicle->MoverParameters->CabNo=0; //wyłączanie kabin po drodze - pVehicle->MoverParameters->ActiveCab=0; //i zaznaczenie, że nie ma tam nikogo - pVehicle=d; //a mechu ma nowy pojazd (no, człon) - } - else break; //jak koniec składu, to mechanik dalej nie idzie - } - if (pVehicle!=old) - {//jeśli zmieniony został pojazd prowadzony - Global::pWorld->CabChange(old,pVehicle); //ewentualna zmiana kabiny użytkownikowi - ControllingSet(); //utworzenie połączenia do sterowanego pojazdu (może się zmienić) - silnikowy dla EZT - } - if (mvControlling->EngineType==DieselEngine) //dla 2Ls150 - przed ustawieniem kierunku - można zmienić tryb pracy - if (mvControlling->ShuntModeAllow) - mvControlling->CurrentSwitch((OrderList[OrderPos]&Shunt)||(fMass>224000.0)); //do tego na wzniesieniu może nie dać rady na liniowym - //Ra: to przełączanie poniżej jest tu bez sensu - mvOccupied->ActiveCab=iDirection; //aktywacja kabiny w prowadzonym pojeżdzie (silnikowy może być odwrotnie?) - //mvOccupied->CabNo=iDirection; - //mvOccupied->ActiveDir=0; //żeby sam ustawił kierunek - mvOccupied->CabActivisation(); //uruchomienie kabin w członach - DirectionForward(true); //nawrotnik do przodu - if (brake) //hamowanie tylko jeśli był wcześniej zahamowany (bo możliwe, że jedzie!) - mvOccupied->IncLocalBrakeLevel(brake); //zahamuj jak wcześniej - CheckVehicles(); //sprawdzenie składu, AI zapali światła - TableClear(); //resetowanie tabelki skanowania torów - } +{ // umieszczenie obsady w odpowiednim członie, wykonywane wyłącznie gdy steruje AI + iDirection = iDirectionOrder; // kierunek (względem sprzęgów pojazdu z AI) właśnie został + // ustalony (zmieniony) + if (iDirection) + { // jeśli jest ustalony kierunek + TDynamicObject *old = pVehicle, *d = pVehicle; // w tym siedzi AI + TController *drugi; // jakby były dwa, to zamienić miejscami, a nie robić wycieku pamięci + // poprzez nadpisanie + int brake = mvOccupied->LocalBrakePos; + while (mvControlling->MainCtrlPos) // samo zapętlenie DecSpeed() nie wystarcza :/ + DecSpeed(true); // wymuszenie zerowania nastawnika jazdy + while (mvOccupied->ActiveDir < 0) + mvOccupied->DirectionForward(); // kierunek na 0 + while (mvOccupied->ActiveDir > 0) + mvOccupied->DirectionBackward(); + if (TestFlag(d->MoverParameters->Couplers[iDirectionOrder < 0 ? 1 : 0].CouplingFlag, + ctrain_controll)) + { + mvControlling->MainSwitch( + false); // dezaktywacja czuwaka, jeśli przejście do innego członu + mvOccupied->DecLocalBrakeLevel(10); // zwolnienie hamulca w opuszczanym pojeździe + // mvOccupied->BrakeLevelSet((mvOccupied->BrakeHandle==FVel6)?4:-2); //odcięcie na + // zaworze maszynisty, FVel6 po drugiej stronie nie luzuje + mvOccupied->BrakeLevelSet( + mvOccupied->Handle->GetPos(bh_NP)); // odcięcie na zaworze maszynisty + } + mvOccupied->ActiveCab = mvOccupied->CabNo; // użytkownik moze zmienić ActiveCab wychodząc + mvOccupied->CabDeactivisation(); // tak jest w Train.cpp + // przejście AI na drugą stronę EN57, ET41 itp. + while (TestFlag(d->MoverParameters->Couplers[iDirection < 0 ? 1 : 0].CouplingFlag, + ctrain_controll)) + { // jeśli pojazd z przodu jest ukrotniony, to przechodzimy do niego + d = iDirection * d->DirectionGet() < 0 ? d->Next() : + d->Prev(); // przechodzimy do następnego członu + if (d) + { + drugi = d->Mechanik; // zapamiętanie tego, co ewentualnie tam siedzi, żeby w razie + // dwóch zamienić miejscami + d->Mechanik = this; // na razie bilokacja + d->MoverParameters->SetInternalCommand( + "", 0, 0); // usunięcie ewentualnie zalegającej komendy (Change_direction?) + if (d->DirectionGet() != pVehicle->DirectionGet()) // jeśli są przeciwne do siebie + iDirection = -iDirection; // to będziemy jechać w drugą stronę względem + // zasiedzianego pojazdu + pVehicle->Mechanik = drugi; // wsadzamy tego, co ewentualnie był (podwójna trakcja) + pVehicle->MoverParameters->CabNo = 0; // wyłączanie kabin po drodze + pVehicle->MoverParameters->ActiveCab = 0; // i zaznaczenie, że nie ma tam nikogo + pVehicle = d; // a mechu ma nowy pojazd (no, człon) + } + else + break; // jak koniec składu, to mechanik dalej nie idzie + } + if (pVehicle != old) + { // jeśli zmieniony został pojazd prowadzony + Global::pWorld->CabChange(old, pVehicle); // ewentualna zmiana kabiny użytkownikowi + ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) - + // silnikowy dla EZT + } + if (mvControlling->EngineType == + DieselEngine) // dla 2Ls150 - przed ustawieniem kierunku - można zmienić tryb pracy + if (mvControlling->ShuntModeAllow) + mvControlling->CurrentSwitch( + (OrderList[OrderPos] & Shunt) || + (fMass > 224000.0)); // do tego na wzniesieniu może nie dać rady na liniowym + // Ra: to przełączanie poniżej jest tu bez sensu + mvOccupied->ActiveCab = + iDirection; // aktywacja kabiny w prowadzonym pojeżdzie (silnikowy może być odwrotnie?) + // mvOccupied->CabNo=iDirection; + // mvOccupied->ActiveDir=0; //żeby sam ustawił kierunek + mvOccupied->CabActivisation(); // uruchomienie kabin w członach + DirectionForward(true); // nawrotnik do przodu + if (brake) // hamowanie tylko jeśli był wcześniej zahamowany (bo możliwe, że jedzie!) + mvOccupied->IncLocalBrakeLevel(brake); // zahamuj jak wcześniej + CheckVehicles(); // sprawdzenie składu, AI zapali światła + TableClear(); // resetowanie tabelki skanowania torów + } }; void __fastcall TController::AutoRewident() -{//autorewident: nastawianie hamulców w składzie - int r=0,g=0,p=0; //ilości wagonów poszczególnych typów - TDynamicObject* d=pVehicles[0]; //pojazd na czele składu - //1. Zebranie informacji o składzie pociągu — przejście wzdłuż składu i odczyt parametrów: - // · ilość wagonów -> są zliczane, wszystkich pojazdów jest (iVehicles) - // · długość (jako suma) -> jest w (fLength) - // · masa (jako suma) -> jest w (fMass) - while (d) - {//klasyfikacja pojazdów wg BrakeDelays i mocy (licznik) - if (d->MoverParameters->Power<1) // - lokomotywa - Power>1 - ale może być nieczynna na końcu... - if (TestFlag(d->MoverParameters->BrakeDelays,bdelay_R)) - ++r; // - wagon pospieszny - jest R - else if (TestFlag(d->MoverParameters->BrakeDelays,bdelay_G)) - ++g; // - wagon towarowy - jest G (nie ma R) - else - ++p; // - wagon osobowy - reszta (bez G i bez R) - d=d->Next(); //kolejny pojazd, podłączony od tyłu (licząc od czoła) - } - //2. Określenie typu pociągu i nastawy: - int ustaw; //+16 dla pasażerskiego - if (r+g+p==0) - ustaw=16+bdelay_R; //lokomotywa luzem (może być wieloczłonowa) - else - {//jeśli są wagony - ustaw=(g0 oraz pospiesze<=towarowe+osobowe to P (0) - //inaczej R (2) - } - else - {//inaczej towarowy - nastawianie towarowego - if ((fLength<300.0)&&(fMass<600000.0)) //[kg] - ustaw|=bdelay_P; //jeżeli długość<300 oraz masa<600 to P (0) - else if ((fLength<500.0)&&(fMass<1300000.0)) - ustaw|=bdelay_R; //jeżeli długość<500 oraz masa<1300 to GP (2) - else - ustaw|=bdelay_G; //inaczej G (1) - } - //zasadniczo na sieci PKP kilka lat temu na P/GP jeździły tylko kontenerowce o - //rozkładowej 90 km/h. Pozostałe jeździły 70 km/h i były nastawione na G. - } - d=pVehicles[0]; //pojazd na czele składu - p=0; //będziemy tu liczyć wagony od lokomotywy dla nastawy GP - while (d) - {//3. Nastawianie - switch (ustaw) - { - case bdelay_P: //towarowy P - lokomotywa na G, reszta na P. - d->MoverParameters->BrakeDelaySwitch(d->MoverParameters->Power>1?bdelay_G:bdelay_P); - break; - case bdelay_G: //towarowy G - wszystko na G, jeśli nie ma to P (powinno się wyłączyć hamulec) - d->MoverParameters->BrakeDelaySwitch(TestFlag(d->MoverParameters->BrakeDelays,bdelay_G)?bdelay_G:bdelay_P); - break; - case bdelay_R: //towarowy GP - lokomotywa oraz 5 pierwszych pojazdów przy niej na G, reszta na P - if (d->MoverParameters->Power>1) - {d->MoverParameters->BrakeDelaySwitch(bdelay_G); - p=0; //a jak będzie druga w środku? +{ // autorewident: nastawianie hamulców w składzie + int r = 0, g = 0, p = 0; // ilości wagonów poszczególnych typów + TDynamicObject *d = pVehicles[0]; // pojazd na czele składu + // 1. Zebranie informacji o składzie pociągu — przejście wzdłuż składu i odczyt parametrów: + // · ilość wagonów -> są zliczane, wszystkich pojazdów jest (iVehicles) + // · długość (jako suma) -> jest w (fLength) + // · masa (jako suma) -> jest w (fMass) + while (d) + { // klasyfikacja pojazdów wg BrakeDelays i mocy (licznik) + if (d->MoverParameters->Power < + 1) // - lokomotywa - Power>1 - ale może być nieczynna na końcu... + if (TestFlag(d->MoverParameters->BrakeDelays, bdelay_R)) + ++r; // - wagon pospieszny - jest R + else if (TestFlag(d->MoverParameters->BrakeDelays, bdelay_G)) + ++g; // - wagon towarowy - jest G (nie ma R) + else + ++p; // - wagon osobowy - reszta (bez G i bez R) + d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) } + // 2. Określenie typu pociągu i nastawy: + int ustaw; //+16 dla pasażerskiego + if (r + g + p == 0) + ustaw = 16 + bdelay_R; // lokomotywa luzem (może być wieloczłonowa) else - d->MoverParameters->BrakeDelaySwitch(++p<=5?bdelay_G:bdelay_P); - break; - case 16+bdelay_R: //pasażerski R - na R, jeśli nie ma to P - d->MoverParameters->BrakeDelaySwitch(TestFlag(d->MoverParameters->BrakeDelays,bdelay_R)?bdelay_R:bdelay_P); - break; - case 16+bdelay_P: //pasażerski P - wszystko na P - d->MoverParameters->BrakeDelaySwitch(bdelay_P); - break; - } - d=d->Next(); //kolejny pojazd, podłączony od tyłu (licząc od czoła) - } + { // jeśli są wagony + ustaw = (g < min(4, r + p) ? 16 : 0); + if (ustaw) // jeśli towarowe < Min(4, pospieszne+osobowe) + { // to skład pasażerski - nastawianie pasażerskiego + ustaw += (g && (r < g + p)) ? bdelay_P : bdelay_R; + // jeżeli towarowe>0 oraz pospiesze<=towarowe+osobowe to P (0) + // inaczej R (2) + } + else + { // inaczej towarowy - nastawianie towarowego + if ((fLength < 300.0) && (fMass < 600000.0)) //[kg] + ustaw |= bdelay_P; // jeżeli długość<300 oraz masa<600 to P (0) + else if ((fLength < 500.0) && (fMass < 1300000.0)) + ustaw |= bdelay_R; // jeżeli długość<500 oraz masa<1300 to GP (2) + else + ustaw |= bdelay_G; // inaczej G (1) + } + // zasadniczo na sieci PKP kilka lat temu na P/GP jeździły tylko kontenerowce o + // rozkładowej 90 km/h. Pozostałe jeździły 70 km/h i były nastawione na G. + } + d = pVehicles[0]; // pojazd na czele składu + p = 0; // będziemy tu liczyć wagony od lokomotywy dla nastawy GP + while (d) + { // 3. Nastawianie + switch (ustaw) + { + case bdelay_P: // towarowy P - lokomotywa na G, reszta na P. + d->MoverParameters->BrakeDelaySwitch(d->MoverParameters->Power > 1 ? bdelay_G : + bdelay_P); + break; + case bdelay_G: // towarowy G - wszystko na G, jeśli nie ma to P (powinno się wyłączyć + // hamulec) + d->MoverParameters->BrakeDelaySwitch( + TestFlag(d->MoverParameters->BrakeDelays, bdelay_G) ? bdelay_G : bdelay_P); + break; + case bdelay_R: // towarowy GP - lokomotywa oraz 5 pierwszych pojazdów przy niej na G, reszta + // na P + if (d->MoverParameters->Power > 1) + { + d->MoverParameters->BrakeDelaySwitch(bdelay_G); + p = 0; // a jak będzie druga w środku? + } + else + d->MoverParameters->BrakeDelaySwitch(++p <= 5 ? bdelay_G : bdelay_P); + break; + case 16 + bdelay_R: // pasażerski R - na R, jeśli nie ma to P + d->MoverParameters->BrakeDelaySwitch( + TestFlag(d->MoverParameters->BrakeDelays, bdelay_R) ? bdelay_R : bdelay_P); + break; + case 16 + bdelay_P: // pasażerski P - wszystko na P + d->MoverParameters->BrakeDelaySwitch(bdelay_P); + break; + } + d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) + } }; bool __fastcall TController::CheckVehicles(TOrders user) -{//sprawdzenie stanu posiadanych pojazdów w składzie i zapalenie świateł - TDynamicObject* p; //roboczy wskaźnik na pojazd - iVehicles=0; //ilość pojazdów w składzie - int d=mvOccupied->DirAbsolute; //który sprzęg jest z przodu - if (!d) //jeśli nie ma ustalonego kierunku - d=mvOccupied->CabNo; //to jedziemy wg aktualnej kabiny - iDirection=d; //ustalenie kierunku jazdy (powinno zrobić PrepareEngine?) - d=d>=0?0:1; //kierunek szukania czoła (numer sprzęgu) - pVehicles[0]=p=pVehicle->FirstFind(d); //pojazd na czele składu - //liczenie pojazdów w składzie i ustalenie parametrów - int dir=d=1-d; //a dalej będziemy zliczać od czoła do tyłu - fLength=0.0; //długość składu do badania wyjechania za ograniczenie - fMass=0.0; //całkowita masa do liczenia stycznej składowej grawitacji - fVelMax=-1; //ustalenie prędkości dla składu - bool main=true; //czy jest głównym sterującym - iDrivigFlags|=moveOerlikons; //zakładamy, że są same Oerlikony - //Ra 2014-09: ustawić moveMultiControl, jeśli wszystkie są w ukrotnieniu (i skrajne mają kabinę?) - while (p) - {//sprawdzanie, czy jest głównym sterującym, żeby nie było konfliktu - if (p->Mechanik) //jeśli ma obsadę - if (p->Mechanik!=this) //ale chodzi o inny pojazd, niż aktualnie sprawdzający - if (p->Mechanik->iDrivigFlags&movePrimary) //a tamten ma priorytet - if ((iDrivigFlags&movePrimary)&&(mvOccupied->DirAbsolute)&&(mvOccupied->BrakeCtrlPos>=-1)) //jeśli rządzi i ma kierunek - p->Mechanik->iDrivigFlags&=~movePrimary; //dezaktywuje tamtego - else - main=false; //nici z rządzenia - ++iVehicles; //jest jeden pojazd więcej - pVehicles[1]=p; //zapamiętanie ostatniego - fLength+=p->MoverParameters->Dim.L; //dodanie długości pojazdu - fMass+=p->MoverParameters->TotalMass; //dodanie masy łącznie z ładunkiem - if (fVelMax<0?true:p->MoverParameters->VmaxMoverParameters->Vmax; //ustalenie maksymalnej prędkości dla składu -/* //youBy: bez przesady, to jest proteza, napelniac mozna, a nawet trzeba, ale z umiarem! - //uwzględnić jeszcze wyłączenie hamulca - if ((p->MoverParameters->BrakeSystem!=Pneumatic)&&(p->MoverParameters->BrakeSystem!=ElectroPneumatic)) - iDrivigFlags&=~moveOerlikons; //no jednak nie - else if (p->MoverParameters->BrakeSubsystem!=Oerlikon) - iDrivigFlags&=~moveOerlikons; //wtedy też nie */ - p=p->Neightbour(dir); //pojazd podłączony od wskazanej strony - } - if (main) iDrivigFlags|=movePrimary; //nie znaleziono innego, można się porządzić -/* //tabelka z listą pojazdów jest na razie nie potrzebna - delete[] pVehicles; - pVehicles=new TDynamicObject*[iVehicles]; -*/ - ControllingSet(); //ustalenie członu do sterowania (może być inny niż zasiedziany) - int pantmask=1; - if (iDrivigFlags&movePrimary) - {//jeśli jest aktywnie prowadzącym pojazd, może zrobić własny porządek - p=pVehicles[0]; - while (p) - { - if (TrainParams) - if (p->asDestination=="none") - p->DestinationSet(TrainParams->Relation2); //relacja docelowa, jeśli nie było - if (AIControllFlag) //jeśli prowadzi komputer - p->RaLightsSet(0,0); //gasimy światła - if (p->MoverParameters->EnginePowerSource.SourceType==CurrentCollector) - {//jeśli pojazd posiada pantograf, to przydzielamy mu maskę, którą będzie informował o jeździe bezprądowej - p->iOverheadMask=pantmask; - pantmask<<1; //przesunięcie bitów, max. 32 pojazdy z pantografami w składzie - } - d=p->DirectionSet(d?1:-1); //zwraca położenie następnego (1=zgodny,0=odwrócony - względem czoła składu) - p->fScanDist=300.0; //odległość skanowania w poszukiwaniu innych pojazdów - p->ctOwner=this; //dominator oznacza swoje terytorium - p=p->Next(); //pojazd podłączony od tyłu (licząc od czoła) - } - if (AIControllFlag) - {//jeśli prowadzi komputer - if (OrderCurrentGet()==Obey_train) //jeśli jazda pociągowa - {Lights(1+4+16,2+32+64); //światła pociągowe (Pc1) i końcówki (Pc5) -#if LOGPRESS==0 - AutoRewident(); //nastawianie hamulca do jazdy pociągowej +{ // sprawdzenie stanu posiadanych pojazdów w składzie i zapalenie świateł + TDynamicObject *p; // roboczy wskaźnik na pojazd + iVehicles = 0; // ilość pojazdów w składzie + int d = mvOccupied->DirAbsolute; // który sprzęg jest z przodu + if (!d) // jeśli nie ma ustalonego kierunku + d = mvOccupied->CabNo; // to jedziemy wg aktualnej kabiny + iDirection = d; // ustalenie kierunku jazdy (powinno zrobić PrepareEngine?) + d = d >= 0 ? 0 : 1; // kierunek szukania czoła (numer sprzęgu) + pVehicles[0] = p = pVehicle->FirstFind(d); // pojazd na czele składu + // liczenie pojazdów w składzie i ustalenie parametrów + int dir = d = 1 - d; // a dalej będziemy zliczać od czoła do tyłu + fLength = 0.0; // długość składu do badania wyjechania za ograniczenie + fMass = 0.0; // całkowita masa do liczenia stycznej składowej grawitacji + fVelMax = -1; // ustalenie prędkości dla składu + bool main = true; // czy jest głównym sterującym + iDrivigFlags |= moveOerlikons; // zakładamy, że są same Oerlikony + // Ra 2014-09: ustawić moveMultiControl, jeśli wszystkie są w ukrotnieniu (i skrajne mają + // kabinę?) + while (p) + { // sprawdzanie, czy jest głównym sterującym, żeby nie było konfliktu + if (p->Mechanik) // jeśli ma obsadę + if (p->Mechanik != this) // ale chodzi o inny pojazd, niż aktualnie sprawdzający + if (p->Mechanik->iDrivigFlags & movePrimary) // a tamten ma priorytet + if ((iDrivigFlags & movePrimary) && (mvOccupied->DirAbsolute) && + (mvOccupied->BrakeCtrlPos >= -1)) // jeśli rządzi i ma kierunek + p->Mechanik->iDrivigFlags &= ~movePrimary; // dezaktywuje tamtego + else + main = false; // nici z rządzenia + ++iVehicles; // jest jeden pojazd więcej + pVehicles[1] = p; // zapamiętanie ostatniego + fLength += p->MoverParameters->Dim.L; // dodanie długości pojazdu + fMass += p->MoverParameters->TotalMass; // dodanie masy łącznie z ładunkiem + if (fVelMax < 0 ? true : p->MoverParameters->Vmax < fVelMax) + fVelMax = p->MoverParameters->Vmax; // ustalenie maksymalnej prędkości dla składu + /* //youBy: bez przesady, to jest proteza, napelniac mozna, a nawet trzeba, ale z umiarem! + //uwzględnić jeszcze wyłączenie hamulca + if + ((p->MoverParameters->BrakeSystem!=Pneumatic)&&(p->MoverParameters->BrakeSystem!=ElectroPneumatic)) + iDrivigFlags&=~moveOerlikons; //no jednak nie + else if (p->MoverParameters->BrakeSubsystem!=Oerlikon) + iDrivigFlags&=~moveOerlikons; //wtedy też nie */ + p = p->Neightbour(dir); // pojazd podłączony od wskazanej strony + } + if (main) + iDrivigFlags |= movePrimary; // nie znaleziono innego, można się porządzić + /* //tabelka z listą pojazdów jest na razie nie potrzebna + delete[] pVehicles; + pVehicles=new TDynamicObject*[iVehicles]; + */ + ControllingSet(); // ustalenie członu do sterowania (może być inny niż zasiedziany) + int pantmask = 1; + if (iDrivigFlags & movePrimary) + { // jeśli jest aktywnie prowadzącym pojazd, może zrobić własny porządek + p = pVehicles[0]; + while (p) + { + if (TrainParams) + if (p->asDestination == "none") + p->DestinationSet(TrainParams->Relation2); // relacja docelowa, jeśli nie było + if (AIControllFlag) // jeśli prowadzi komputer + p->RaLightsSet(0, 0); // gasimy światła + if (p->MoverParameters->EnginePowerSource.SourceType == CurrentCollector) + { // jeśli pojazd posiada pantograf, to przydzielamy mu maskę, którą będzie informował o + // jeździe bezprądowej + p->iOverheadMask = pantmask; + pantmask << 1; // przesunięcie bitów, max. 32 pojazdy z pantografami w składzie + } + d = p->DirectionSet(d ? 1 : -1); // zwraca położenie następnego (1=zgodny,0=odwrócony - + // względem czoła składu) + p->fScanDist = 300.0; // odległość skanowania w poszukiwaniu innych pojazdów + p->ctOwner = this; // dominator oznacza swoje terytorium + p = p->Next(); // pojazd podłączony od tyłu (licząc od czoła) + } + if (AIControllFlag) + { // jeśli prowadzi komputer + if (OrderCurrentGet() == Obey_train) // jeśli jazda pociągowa + { + Lights(1 + 4 + 16, 2 + 32 + 64); //światła pociągowe (Pc1) i końcówki (Pc5) +#if LOGPRESS == 0 + AutoRewident(); // nastawianie hamulca do jazdy pociągowej #endif - } - else if (OrderCurrentGet()&(Shunt|Connect)) - {Lights(16,(pVehicles[1]->MoverParameters->CabNo)?1:0); //światła manewrowe (Tb1) na pojeździe z napędem - if (OrderCurrentGet()&Connect) //jeśli łączenie, skanować dalej - pVehicles[0]->fScanDist=5000.0; //odległość skanowania w poszukiwaniu innych pojazdów - } - else if (OrderCurrentGet()==Disconnect) - if (mvOccupied->ActiveDir>0) //jak ma kierunek do przodu - Lights(16,0); //światła manewrowe (Tb1) tylko z przodu, aby nie pozostawić odczepionego ze światłem - else //jak dociska - Lights(0,16); //światła manewrowe (Tb1) tylko z przodu, aby nie pozostawić odczepionego ze światłem - } - else //Ra 2014-02: lepiej tu niż w pętli obsługującej komendy, bo tam się zmieni informacja o składzie - switch (user) //gdy człowiek i gdy nastąpiło połącznie albo rozłączenie - { - case Change_direction: - while (OrderCurrentGet()&(Change_direction)) - JumpToNextOrder(); //zmianę kierunku też można olać, ale zmienić kierunek skanowania! - break; - case Connect: - while (OrderCurrentGet()&(Change_direction)) - JumpToNextOrder(); //zmianę kierunku też można olać, ale zmienić kierunek skanowania! - if (OrderCurrentGet()&(Connect)) - {//jeśli miało być łączenie, zakładamy, że jest dobrze (sprawdzić?) - iCoupler=0; //koniec z doczepianiem - iDrivigFlags&=~moveConnect; //zdjęcie flagi doczepiania - JumpToNextOrder(); //wykonanie następnej komendy - if (OrderCurrentGet()&(Change_direction)) - JumpToNextOrder(); //zmianę kierunku też można olać, ale zmienić kierunek skanowania! - } - break; - case Disconnect: - while (OrderCurrentGet()&(Change_direction)) - JumpToNextOrder(); //zmianę kierunku też można olać, ale zmienić kierunek skanowania! - if (OrderCurrentGet()&(Disconnect)) - {//wypadało by sprawdzić, czy odczepiono wagony w odpowiednim miejscu (iVehicleCount) - JumpToNextOrder(); //wykonanie następnej komendy - if (OrderCurrentGet()&(Change_direction)) - JumpToNextOrder(); //zmianę kierunku też można olać, ale zmienić kierunek skanowania! - } - } - //Ra 2014-09: tymczasowo prymitywne ustawienie warunku pod kątem SN61 - if ((mvOccupied->TrainType==dt_EZT)||(iVehicles==1)) - iDrivigFlags|=movePushPull; //zmiana czoła przez zmianę kabiny - else - iDrivigFlags&=~movePushPull; //zmiana czoła przez manewry - } //blok wykonywany, gdy aktywnie prowadzi - return true; + } + else if (OrderCurrentGet() & (Shunt | Connect)) + { + Lights(16, (pVehicles[1]->MoverParameters->CabNo) ? + 1 : + 0); //światła manewrowe (Tb1) na pojeździe z napędem + if (OrderCurrentGet() & Connect) // jeśli łączenie, skanować dalej + pVehicles[0]->fScanDist = + 5000.0; // odległość skanowania w poszukiwaniu innych pojazdów + } + else if (OrderCurrentGet() == Disconnect) + if (mvOccupied->ActiveDir > 0) // jak ma kierunek do przodu + Lights(16, 0); //światła manewrowe (Tb1) tylko z przodu, aby nie pozostawić + //odczepionego ze światłem + else // jak dociska + Lights(0, 16); //światła manewrowe (Tb1) tylko z przodu, aby nie pozostawić + //odczepionego ze światłem + } + else // Ra 2014-02: lepiej tu niż w pętli obsługującej komendy, bo tam się zmieni informacja + // o składzie + switch (user) // gdy człowiek i gdy nastąpiło połącznie albo rozłączenie + { + case Change_direction: + while (OrderCurrentGet() & (Change_direction)) + JumpToNextOrder(); // zmianę kierunku też można olać, ale zmienić kierunek + // skanowania! + break; + case Connect: + while (OrderCurrentGet() & (Change_direction)) + JumpToNextOrder(); // zmianę kierunku też można olać, ale zmienić kierunek + // skanowania! + if (OrderCurrentGet() & (Connect)) + { // jeśli miało być łączenie, zakładamy, że jest dobrze (sprawdzić?) + iCoupler = 0; // koniec z doczepianiem + iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania + JumpToNextOrder(); // wykonanie następnej komendy + if (OrderCurrentGet() & (Change_direction)) + JumpToNextOrder(); // zmianę kierunku też można olać, ale zmienić kierunek + // skanowania! + } + break; + case Disconnect: + while (OrderCurrentGet() & (Change_direction)) + JumpToNextOrder(); // zmianę kierunku też można olać, ale zmienić kierunek + // skanowania! + if (OrderCurrentGet() & (Disconnect)) + { // wypadało by sprawdzić, czy odczepiono wagony w odpowiednim miejscu + // (iVehicleCount) + JumpToNextOrder(); // wykonanie następnej komendy + if (OrderCurrentGet() & (Change_direction)) + JumpToNextOrder(); // zmianę kierunku też można olać, ale zmienić kierunek + // skanowania! + } + } + // Ra 2014-09: tymczasowo prymitywne ustawienie warunku pod kątem SN61 + if ((mvOccupied->TrainType == dt_EZT) || (iVehicles == 1)) + iDrivigFlags |= movePushPull; // zmiana czoła przez zmianę kabiny + else + iDrivigFlags &= ~movePushPull; // zmiana czoła przez manewry + } // blok wykonywany, gdy aktywnie prowadzi + return true; } -void __fastcall TController::Lights(int head,int rear) -{//zapalenie świateł w skłądzie - pVehicles[0]->RaLightsSet(head,-1); //zapalenie przednich w pierwszym - pVehicles[1]->RaLightsSet(-1,rear); //zapalenie końcówek w ostatnim +void __fastcall TController::Lights(int head, int rear) +{ // zapalenie świateł w skłądzie + pVehicles[0]->RaLightsSet(head, -1); // zapalenie przednich w pierwszym + pVehicles[1]->RaLightsSet(-1, rear); // zapalenie końcówek w ostatnim } void __fastcall TController::DirectionInitial() -{//ustawienie kierunku po wczytaniu trainset (może jechać na wstecznym - mvOccupied->CabActivisation(); //załączenie rozrządu (wirtualne kabiny) - if (mvOccupied->Vel>0.0) - {//jeśli na starcie jedzie - iDirection=iDirectionOrder=(mvOccupied->V>0?1:-1); //początkowa prędkość wymusza kierunek jazdy - DirectionForward(mvOccupied->V*mvOccupied->CabNo>=0.0); //a dalej ustawienie nawrotnika - } - CheckVehicles(); //sprawdzenie świateł oraz skrajnych pojazdów do skanowania +{ // ustawienie kierunku po wczytaniu trainset (może jechać na wstecznym + mvOccupied->CabActivisation(); // załączenie rozrządu (wirtualne kabiny) + if (mvOccupied->Vel > 0.0) + { // jeśli na starcie jedzie + iDirection = iDirectionOrder = + (mvOccupied->V > 0 ? 1 : -1); // początkowa prędkość wymusza kierunek jazdy + DirectionForward(mvOccupied->V * mvOccupied->CabNo >= 0.0); // a dalej ustawienie nawrotnika + } + CheckVehicles(); // sprawdzenie świateł oraz skrajnych pojazdów do skanowania }; -int __fastcall TController::OrderDirectionChange(int newdir,TMoverParameters *Vehicle) -{//zmiana kierunku jazdy, niezależnie od kabiny - int testd=newdir; - if (Vehicle->Vel<0.5) - {//jeśli prawie stoi, można zmienić kierunek, musi być wykonane dwukrotnie, bo za pierwszym razem daje na zero - switch (newdir*Vehicle->CabNo) - {//DirectionBackward() i DirectionForward() to zmiany względem kabiny - case -1: //if (!Vehicle->DirectionBackward()) testd=0; break; - DirectionForward(false); break; - case 1: //if (!Vehicle->DirectionForward()) testd=0; break; - DirectionForward(true); break; - } - if (testd==0) - VelforDriver=-1; //kierunek został zmieniony na żądany, można jechać - } - else //jeśli jedzie - VelforDriver=0; //ma się zatrzymać w celu zmiany kierunku - if ((Vehicle->ActiveDir==0)&&(VelforDriverVel)) //Ra: to jest chyba bez sensu - IncBrake(); //niech hamuje - if (Vehicle->ActiveDir==testd*Vehicle->CabNo) - VelforDriver=-1; //można jechać, bo kierunek jest zgodny z żądanym - if (Vehicle->TrainType==dt_EZT) - if (Vehicle->ActiveDir>0) - //if () //tylko jeśli jazda pociągowa (tego nie wiemy w momencie odpalania silnika) - Vehicle->DirectionForward(); //Ra: z przekazaniem do silnikowego - return (int)VelforDriver; //zwraca prędkość mechanika +int __fastcall TController::OrderDirectionChange(int newdir, TMoverParameters *Vehicle) +{ // zmiana kierunku jazdy, niezależnie od kabiny + int testd = newdir; + if (Vehicle->Vel < 0.5) + { // jeśli prawie stoi, można zmienić kierunek, musi być wykonane dwukrotnie, bo za pierwszym + // razem daje na zero + switch (newdir * Vehicle->CabNo) + { // DirectionBackward() i DirectionForward() to zmiany względem kabiny + case -1: // if (!Vehicle->DirectionBackward()) testd=0; break; + DirectionForward(false); + break; + case 1: // if (!Vehicle->DirectionForward()) testd=0; break; + DirectionForward(true); + break; + } + if (testd == 0) + VelforDriver = -1; // kierunek został zmieniony na żądany, można jechać + } + else // jeśli jedzie + VelforDriver = 0; // ma się zatrzymać w celu zmiany kierunku + if ((Vehicle->ActiveDir == 0) && (VelforDriver < Vehicle->Vel)) // Ra: to jest chyba bez sensu + IncBrake(); // niech hamuje + if (Vehicle->ActiveDir == testd * Vehicle->CabNo) + VelforDriver = -1; // można jechać, bo kierunek jest zgodny z żądanym + if (Vehicle->TrainType == dt_EZT) + if (Vehicle->ActiveDir > 0) + // if () //tylko jeśli jazda pociągowa (tego nie wiemy w momencie odpalania silnika) + Vehicle->DirectionForward(); // Ra: z przekazaniem do silnikowego + return (int)VelforDriver; // zwraca prędkość mechanika } void __fastcall TController::WaitingSet(double Seconds) -{//ustawienie odczekania po zatrzymaniu (ustawienie w trakcie jazdy zatrzyma) - fStopTime=-Seconds; //ujemna wartość oznacza oczekiwanie (potem >=0.0) +{ // ustawienie odczekania po zatrzymaniu (ustawienie w trakcie jazdy zatrzyma) + fStopTime = -Seconds; // ujemna wartość oznacza oczekiwanie (potem >=0.0) } -void __fastcall TController::SetVelocity(double NewVel,double NewVelNext,TStopReason r) -{//ustawienie nowej prędkości - WaitingTime=-WaitingExpireTime; //przypisujemy -WaitingExpireTime, a potem porównujemy z zerem - MaxVelFlag=False; //Ra: to nie jest używane - MinVelFlag=False; //Ra: to nie jest używane -/* nie używane - if ((NewVel>NewVelNext) //jeśli oczekiwana większa niż następna - || (NewVelVel)) //albo aktualna jest mniejsza niż aktualna - fProximityDist=-800.0; //droga hamowania do zmiany prędkości - else - fProximityDist=-300.0; //Ra: ujemne wartości są ignorowane -*/ - if (NewVel==0.0) //jeśli ma stanąć - {if (r!=stopNone) //a jest powód podany - eStopReason=r; //to zapamiętać nowy powód - } - else - { - eStopReason=stopNone; //podana prędkość, to nie ma powodów do stania - //to całe poniżej to warunki zatrąbienia przed ruszeniem - if (OrderList[OrderPos]?OrderList[OrderPos]&(Obey_train|Shunt|Connect|Prepare_engine):true) //jeśli jedzie w dowolnym trybie - if ((mvOccupied->Vel<1.0)) //jesli stoi (na razie, bo chyba powinien też, gdy hamuje przed semaforem) - if (iDrivigFlags&moveStartHorn) //jezeli trąbienie włączone - if (!(iDrivigFlags&(moveStartHornDone|moveConnect))) //jeśli nie zatrąbione i nie jest to moment podłączania składu - if (mvOccupied->CategoryFlag&1) //tylko pociągi trąbią (unimogi tylko na torach, więc trzeba raczej sprawdzać tor) - if ((NewVel>=1.0)||(NewVel<0.0)) //o ile prędkość jest znacząca - {//fWarningDuration=0.3; //czas trąbienia - //if (AIControllFlag) //jak siedzi krasnoludek, to włączy trąbienie - // mvOccupied->WarningSignal=pVehicle->iHornWarning; //wysokość tonu (2=wysoki) - //iDrivigFlags|=moveStartHornDone; //nie trąbić aż do ruszenia - iDrivigFlags|=moveStartHornNow; //zatrąb po odhamowaniu - } - } - VelSignal=NewVel; //prędkość zezwolona na aktualnym odcinku - VelNext=NewVelNext; //prędkość przy następnym obiekcie +void __fastcall TController::SetVelocity(double NewVel, double NewVelNext, TStopReason r) +{ // ustawienie nowej prędkości + WaitingTime = -WaitingExpireTime; // przypisujemy -WaitingExpireTime, a potem porównujemy z + // zerem + MaxVelFlag = False; // Ra: to nie jest używane + MinVelFlag = False; // Ra: to nie jest używane + /* nie używane + if ((NewVel>NewVelNext) //jeśli oczekiwana większa niż następna + || (NewVelVel)) //albo aktualna jest mniejsza niż aktualna + fProximityDist=-800.0; //droga hamowania do zmiany prędkości + else + fProximityDist=-300.0; //Ra: ujemne wartości są ignorowane + */ + if (NewVel == 0.0) // jeśli ma stanąć + { + if (r != stopNone) // a jest powód podany + eStopReason = r; // to zapamiętać nowy powód + } + else + { + eStopReason = stopNone; // podana prędkość, to nie ma powodów do stania + // to całe poniżej to warunki zatrąbienia przed ruszeniem + if (OrderList[OrderPos] ? + OrderList[OrderPos] & (Obey_train | Shunt | Connect | Prepare_engine) : + true) // jeśli jedzie w dowolnym trybie + if ((mvOccupied->Vel < + 1.0)) // jesli stoi (na razie, bo chyba powinien też, gdy hamuje przed semaforem) + if (iDrivigFlags & moveStartHorn) // jezeli trąbienie włączone + if (!(iDrivigFlags & (moveStartHornDone | moveConnect))) // jeśli nie zatrąbione + // i nie jest to moment + // podłączania składu + if (mvOccupied->CategoryFlag & 1) // tylko pociągi trąbią (unimogi tylko na + // torach, więc trzeba raczej sprawdzać + // tor) + if ((NewVel >= 1.0) || (NewVel < 0.0)) // o ile prędkość jest znacząca + { // fWarningDuration=0.3; //czas trąbienia + // if (AIControllFlag) //jak siedzi krasnoludek, to włączy trąbienie + // mvOccupied->WarningSignal=pVehicle->iHornWarning; //wysokość tonu + // (2=wysoki) + // iDrivigFlags|=moveStartHornDone; //nie trąbić aż do ruszenia + iDrivigFlags |= moveStartHornNow; // zatrąb po odhamowaniu + } + } + VelSignal = NewVel; // prędkość zezwolona na aktualnym odcinku + VelNext = NewVelNext; // prędkość przy następnym obiekcie } /* //funkcja do niczego nie potrzebna (ew. do przesunięcia pojazdu o odległość NewDist) @@ -1422,2789 +1776,3357 @@ bool __fastcall TController::SetProximityVelocity(double NewDist,double NewVelNe void __fastcall TController::SetDriverPsyche() { - //double maxdist=0.5; //skalowanie dystansu od innego pojazdu, zmienic to!!! - if ((Psyche==Aggressive)&&(OrderList[OrderPos]==Obey_train)) - { - ReactionTime=HardReactionTime; //w zaleznosci od charakteru maszynisty - //if (pOccupied) - if (mvOccupied->CategoryFlag&2) - {WaitingExpireTime=1; //tyle ma czekać samochód, zanim się ruszy - AccPreferred=3.0; //[m/ss] agresywny - } - else - {WaitingExpireTime=61; //tyle ma czekać, zanim się ruszy - AccPreferred=HardAcceleration; //agresywny - } - } - else - { - ReactionTime=EasyReactionTime; //spokojny - if (mvOccupied->CategoryFlag&2) - {WaitingExpireTime=3; //tyle ma czekać samochód, zanim się ruszy - AccPreferred=2.0; //[m/ss] - } - else - {WaitingExpireTime=65; //tyle ma czekać, zanim się ruszy - AccPreferred=EasyAcceleration; - } - } - if (mvControlling&&mvOccupied) - {//with Controlling do - if (mvControlling->MainCtrlPos<3) - ReactionTime=mvControlling->InitialCtrlDelay+ReactionTime; - if (mvOccupied->BrakeCtrlPos>1) - ReactionTime=0.5*ReactionTime; -/* - if (mvOccupied->Vel>0.1) //o ile jedziemy - {//sprawdzenie jazdy na widoczność - TCoupling *c=pVehicles[0]->MoverParameters->Couplers+(pVehicles[0]->DirectionGet()>0?0:1); //sprzęg z przodu składu - if (c->Connected) //a mamy coś z przodu - if (c->CouplingFlag==0) //jeśli to coś jest podłączone sprzęgiem wirtualnym - {//wyliczanie optymalnego przyspieszenia do jazdy na widoczność (Ra: na pewno tutaj?) - double k=c->Connected->Vel; //prędkość pojazdu z przodu (zakładając, że jedzie w tę samą stronę!!!) - if (k<=mvOccupied->Vel) //porównanie modułów prędkości [km/h] - {if (pVehicles[0]->fTrackBlockfTrackBlock-0.5*fabs(mvOccupied->V)-fMaxProximityDist); //bezpieczna odległość za poprzednim - //a=(v2*v2-v1*v1)/(25.92*(d-0.5*v1)) - //(v2*v2-v1*v1)/2 to różnica energii kinetycznych na jednostkę masy - //jeśli v2=50km/h,v1=60km/h,d=200m => k=(192.9-277.8)/(25.92*(200-0.5*16.7)=-0.0171 [m/s^2] - //jeśli v2=50km/h,v1=60km/h,d=100m => k=(192.9-277.8)/(25.92*(100-0.5*16.7)=-0.0357 [m/s^2] - //jeśli v2=50km/h,v1=60km/h,d=50m => k=(192.9-277.8)/(25.92*( 50-0.5*16.7)=-0.0786 [m/s^2] - //jeśli v2=50km/h,v1=60km/h,d=25m => k=(192.9-277.8)/(25.92*( 25-0.5*16.7)=-0.1967 [m/s^2] - if (d>0) //bo jak ujemne, to zacznie przyspieszać, aby się zderzyć - k=(k*k-mvOccupied->Vel*mvOccupied->Vel)/(25.92*d); //energia kinetyczna dzielona przez masę i drogę daje przyspieszenie - else - k=0.0; //może lepiej nie przyspieszać -AccPreferred; //hamowanie - //WriteLog(pVehicle->asName+" "+AnsiString(k)); - } - if (dCategoryFlag & 2) + { + WaitingExpireTime = 1; // tyle ma czekać samochód, zanim się ruszy + AccPreferred = 3.0; //[m/ss] agresywny + } + else + { + WaitingExpireTime = 61; // tyle ma czekać, zanim się ruszy + AccPreferred = HardAcceleration; // agresywny + } + } + else + { + ReactionTime = EasyReactionTime; // spokojny + if (mvOccupied->CategoryFlag & 2) + { + WaitingExpireTime = 3; // tyle ma czekać samochód, zanim się ruszy + AccPreferred = 2.0; //[m/ss] + } + else + { + WaitingExpireTime = 65; // tyle ma czekać, zanim się ruszy + AccPreferred = EasyAcceleration; + } + } + if (mvControlling && mvOccupied) + { // with Controlling do + if (mvControlling->MainCtrlPos < 3) + ReactionTime = mvControlling->InitialCtrlDelay + ReactionTime; + if (mvOccupied->BrakeCtrlPos > 1) + ReactionTime = 0.5 * ReactionTime; + /* + if (mvOccupied->Vel>0.1) //o ile jedziemy + {//sprawdzenie jazdy na widoczność + TCoupling + *c=pVehicles[0]->MoverParameters->Couplers+(pVehicles[0]->DirectionGet()>0?0:1); //sprzęg + z przodu składu + if (c->Connected) //a mamy coś z przodu + if (c->CouplingFlag==0) //jeśli to coś jest podłączone sprzęgiem wirtualnym + {//wyliczanie optymalnego przyspieszenia do jazdy na widoczność (Ra: na pewno tutaj?) + double k=c->Connected->Vel; //prędkość pojazdu z przodu (zakładając, że jedzie w tę + samą stronę!!!) + if (k<=mvOccupied->Vel) //porównanie modułów prędkości [km/h] + {if (pVehicles[0]->fTrackBlockfTrackBlock-0.5*fabs(mvOccupied->V)-fMaxProximityDist); + //bezpieczna odległość za poprzednim + //a=(v2*v2-v1*v1)/(25.92*(d-0.5*v1)) + //(v2*v2-v1*v1)/2 to różnica energii kinetycznych na jednostkę masy + //jeśli v2=50km/h,v1=60km/h,d=200m => k=(192.9-277.8)/(25.92*(200-0.5*16.7)=-0.0171 + [m/s^2] + //jeśli v2=50km/h,v1=60km/h,d=100m => k=(192.9-277.8)/(25.92*(100-0.5*16.7)=-0.0357 + [m/s^2] + //jeśli v2=50km/h,v1=60km/h,d=50m => k=(192.9-277.8)/(25.92*( 50-0.5*16.7)=-0.0786 + [m/s^2] + //jeśli v2=50km/h,v1=60km/h,d=25m => k=(192.9-277.8)/(25.92*( 25-0.5*16.7)=-0.1967 + [m/s^2] + if (d>0) //bo jak ujemne, to zacznie przyspieszać, aby się zderzyć + k=(k*k-mvOccupied->Vel*mvOccupied->Vel)/(25.92*d); //energia kinetyczna dzielona + przez masę i drogę daje przyspieszenie + else + k=0.0; //może lepiej nie przyspieszać -AccPreferred; //hamowanie + //WriteLog(pVehicle->asName+" "+AnsiString(k)); + } + if (dEnginePowerSource.SourceType==CurrentCollector)/*||(mvOccupied->TrainType==dt_EZT)*/)) - { - if (mvControlling->GetTrainsetVoltage()) //sprawdzanie, czy zasilanie jest może w innym członie - { - voltfront=true; - voltrear=true; - } - } -// begin -// if Couplers[0].Connected<>nil) -// begin -// if Couplers[0].Connected^.PantFrontVolt or Couplers[0].Connected^.PantRearVolt) -// voltfront:=true -// else -// voltfront:=false; -// end -// else -// voltfront:=false; -// if Couplers[1].Connected<>nil) -// begin -// if Couplers[1].Connected^.PantFrontVolt or Couplers[1].Connected^.PantRearVolt) -// voltrear:=true -// else -// voltrear:=false; -// end -// else -// voltrear:=false; -// end - else - //if EnginePowerSource.SourceType<>CurrentCollector) - if (mvOccupied->TrainType!=dt_EZT) - voltfront=true; //Ra 2014-06: to jest wirtualny prąd dla spalinowych??? - if (AIControllFlag) //jeśli prowadzi komputer - {//część wykonawcza dla sterowania przez komputer - mvOccupied->BatterySwitch(true); - if (mvControlling->EnginePowerSource.SourceType==CurrentCollector) - {//jeśli silnikowy jest pantografującym - if (mvControlling->PantPress>4.3) - {//jeżeli jest wystarczające ciśnienie w pantografach - if ((!mvControlling->bPantKurek3)||(mvControlling->PantPress<=mvControlling->ScndPipePress)) //kurek przełączony albo główna już pompuje - mvControlling->PantCompFlag=false; //sprężarkę pantografów można już wyłączyć - mvControlling->PantFront(true); - mvControlling->PantRear(true); - } - else if (mvControlling->PantPress<4.2) //żeby nie załączał zaraz po przekroczeniu 4.0 - {//załączenie małej sprężarki - mvControlling->bPantKurek3=false; //odłączenie zbiornika głównego, bo z nim nie da rady napompować - mvControlling->PantCompFlag=true; //załączenie sprężarki pantografów - } - } - //if (mvOccupied->TrainType==dt_EZT) - //{//Ra 2014-12: po co to tutaj? - // mvControlling->PantFront(true); - // mvControlling->PantRear(true); - //} - //if (mvControlling->EngineType==DieselElectric) - // mvControlling->Battery=true; //Ra: to musi być tak? - } - if (mvControlling->PantFrontVolt||mvControlling->PantRearVolt||voltfront||voltrear) - {//najpierw ustalamy kierunek, jeśli nie został ustalony - if (!iDirection) //jeśli nie ma ustalonego kierunku - if (mvOccupied->V==0) - {//ustalenie kierunku, gdy stoi - iDirection=mvOccupied->CabNo; //wg wybranej kabiny - if (!iDirection) //jeśli nie ma ustalonego kierunku - if ((mvControlling->PantFrontVolt!=0.0)||(mvControlling->PantRearVolt!=0.0)||voltfront||voltrear) - {if (mvOccupied->Couplers[1].CouplingFlag==ctrain_virtual) //jeśli z tyłu nie ma nic - iDirection=-1; //jazda w kierunku sprzęgu 1 - if (mvOccupied->Couplers[0].CouplingFlag==ctrain_virtual) //jeśli z przodu nie ma nic - iDirection=1; //jazda w kierunku sprzęgu 0 - } - } - else //ustalenie kierunku, gdy jedzie - if ((mvControlling->PantFrontVolt!=0.0)||(mvControlling->PantRearVolt!=0.0)||voltfront||voltrear) - if (mvOccupied->V<0) //jedzie do tyłu - iDirection=-1; //jazda w kierunku sprzęgu 1 - else //jak nie do tyłu, to do przodu - iDirection=1; //jazda w kierunku sprzęgu 0 - if (AIControllFlag) //jeśli prowadzi komputer - {//część wykonawcza dla sterowania przez komputer - if (mvControlling->ConvOvldFlag) - {//wywalił bezpiecznik nadmiarowy przetwornicy - while (DecSpeed(true)); //zerowanie napędu - mvControlling->ConvOvldFlag=false; //reset nadmiarowego - } - else if (!mvControlling->Mains) - { - //if TrainType=dt_SN61) - // begin - // OK:=(OrderDirectionChange(ChangeDir,Controlling)=-1); - // OK:=IncMainCtrl(1); - // end; - while (DecSpeed(true)); //zerowanie napędu - OK=mvControlling->MainSwitch(true); - if (mvControlling->EngineType==DieselEngine) - {//Ra 2014-06: dla SN61 trzeba wrzucić pierwszą pozycję - nie wiem, czy tutaj... kiedyś działało... - if (!mvControlling->MainCtrlPos) - {if (mvControlling->RList[0].R==0.0) //gdy na pozycji 0 dawka paliwa jest zerowa, to zgaśnie - mvControlling->IncMainCtrl(1); //dlatego trzeba zwiększyć pozycję - if (!mvControlling->ScndCtrlPos) //jeśli bieg nie został ustawiony - if (!mvControlling->MotorParam[0].AutoSwitch) //gdy biegi ręczne - if (mvControlling->MotorParam[0].mIsat==0.0) //bl,mIsat,fi,mfi - mvControlling->IncScndCtrl(1); //pierwszy bieg - } +{ // odpalanie silnika + bool OK; + bool voltfront, voltrear; + voltfront = false; + voltrear = false; + LastReactionTime = 0.0; + ReactionTime = PrepareTime; + iDrivigFlags |= moveActive; // może skanować sygnały i reagować na komendy + // with Controlling do + if (((mvControlling->EnginePowerSource.SourceType == + CurrentCollector) /*||(mvOccupied->TrainType==dt_EZT)*/)) + { + if (mvControlling + ->GetTrainsetVoltage()) // sprawdzanie, czy zasilanie jest może w innym członie + { + voltfront = true; + voltrear = true; + } + } + // begin + // if Couplers[0].Connected<>nil) + // begin + // if Couplers[0].Connected^.PantFrontVolt or Couplers[0].Connected^.PantRearVolt) + // voltfront:=true + // else + // voltfront:=false; + // end + // else + // voltfront:=false; + // if Couplers[1].Connected<>nil) + // begin + // if Couplers[1].Connected^.PantFrontVolt or Couplers[1].Connected^.PantRearVolt) + // voltrear:=true + // else + // voltrear:=false; + // end + // else + // voltrear:=false; + // end + else + // if EnginePowerSource.SourceType<>CurrentCollector) + if (mvOccupied->TrainType != dt_EZT) + voltfront = true; // Ra 2014-06: to jest wirtualny prąd dla spalinowych??? + if (AIControllFlag) // jeśli prowadzi komputer + { // część wykonawcza dla sterowania przez komputer + mvOccupied->BatterySwitch(true); + if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) + { // jeśli silnikowy jest pantografującym + if (mvControlling->PantPress > 4.3) + { // jeżeli jest wystarczające ciśnienie w pantografach + if ((!mvControlling->bPantKurek3) || + (mvControlling->PantPress <= + mvControlling->ScndPipePress)) // kurek przełączony albo główna już pompuje + mvControlling->PantCompFlag = false; // sprężarkę pantografów można już wyłączyć + mvControlling->PantFront(true); + mvControlling->PantRear(true); + } + else if (mvControlling->PantPress < 4.2) //żeby nie załączał zaraz po przekroczeniu 4.0 + { // załączenie małej sprężarki + mvControlling->bPantKurek3 = + false; // odłączenie zbiornika głównego, bo z nim nie da rady napompować + mvControlling->PantCompFlag = true; // załączenie sprężarki pantografów + } + } + // if (mvOccupied->TrainType==dt_EZT) + //{//Ra 2014-12: po co to tutaj? + // mvControlling->PantFront(true); + // mvControlling->PantRear(true); + //} + // if (mvControlling->EngineType==DieselElectric) + // mvControlling->Battery=true; //Ra: to musi być tak? + } + if (mvControlling->PantFrontVolt || mvControlling->PantRearVolt || voltfront || voltrear) + { // najpierw ustalamy kierunek, jeśli nie został ustalony + if (!iDirection) // jeśli nie ma ustalonego kierunku + if (mvOccupied->V == 0) + { // ustalenie kierunku, gdy stoi + iDirection = mvOccupied->CabNo; // wg wybranej kabiny + if (!iDirection) // jeśli nie ma ustalonego kierunku + if ((mvControlling->PantFrontVolt != 0.0) || + (mvControlling->PantRearVolt != 0.0) || voltfront || voltrear) + { + if (mvOccupied->Couplers[1].CouplingFlag == + ctrain_virtual) // jeśli z tyłu nie ma nic + iDirection = -1; // jazda w kierunku sprzęgu 1 + if (mvOccupied->Couplers[0].CouplingFlag == + ctrain_virtual) // jeśli z przodu nie ma nic + iDirection = 1; // jazda w kierunku sprzęgu 0 + } + } + else // ustalenie kierunku, gdy jedzie + if ((mvControlling->PantFrontVolt != 0.0) || (mvControlling->PantRearVolt != 0.0) || + voltfront || voltrear) + if (mvOccupied->V < 0) // jedzie do tyłu + iDirection = -1; // jazda w kierunku sprzęgu 1 + else // jak nie do tyłu, to do przodu + iDirection = 1; // jazda w kierunku sprzęgu 0 + if (AIControllFlag) // jeśli prowadzi komputer + { // część wykonawcza dla sterowania przez komputer + if (mvControlling->ConvOvldFlag) + { // wywalił bezpiecznik nadmiarowy przetwornicy + while (DecSpeed(true)) + ; // zerowanie napędu + mvControlling->ConvOvldFlag = false; // reset nadmiarowego + } + else if (!mvControlling->Mains) + { + // if TrainType=dt_SN61) + // begin + // OK:=(OrderDirectionChange(ChangeDir,Controlling)=-1); + // OK:=IncMainCtrl(1); + // end; + while (DecSpeed(true)) + ; // zerowanie napędu + OK = mvControlling->MainSwitch(true); + if (mvControlling->EngineType == DieselEngine) + { // Ra 2014-06: dla SN61 trzeba wrzucić pierwszą pozycję - nie wiem, czy tutaj... + // kiedyś działało... + if (!mvControlling->MainCtrlPos) + { + if (mvControlling->RList[0].R == + 0.0) // gdy na pozycji 0 dawka paliwa jest zerowa, to zgaśnie + mvControlling->IncMainCtrl(1); // dlatego trzeba zwiększyć pozycję + if (!mvControlling->ScndCtrlPos) // jeśli bieg nie został ustawiony + if (!mvControlling->MotorParam[0].AutoSwitch) // gdy biegi ręczne + if (mvControlling->MotorParam[0].mIsat == 0.0) // bl,mIsat,fi,mfi + mvControlling->IncScndCtrl(1); // pierwszy bieg + } + } + } + else + { // Ra: iDirection określa, w którą stronę jedzie skład względem sprzęgów pojazdu z AI + OK = (OrderDirectionChange(iDirection, mvOccupied) == -1); + // w EN57 sprężarka w ra jest zasilana z silnikowego + mvControlling->CompressorSwitch(true); + mvControlling->ConverterSwitch(true); + mvControlling->CompressorSwitch(true); + } + } + else + OK = mvControlling->Mains; + } + else + OK = false; + OK = OK && (mvOccupied->ActiveDir != 0) && (mvControlling->CompressorAllow); + if (OK) + { + if (eStopReason == stopSleep) // jeśli dotychczas spał + eStopReason == stopNone; // teraz nie ma powodu do stania + iEngineActive = 1; + return true; + } + else + { + iEngineActive = 0; + return false; } - } - else - {//Ra: iDirection określa, w którą stronę jedzie skład względem sprzęgów pojazdu z AI - OK=(OrderDirectionChange(iDirection,mvOccupied)==-1); - //w EN57 sprężarka w ra jest zasilana z silnikowego - mvControlling->CompressorSwitch(true); - mvControlling->ConverterSwitch(true); - mvControlling->CompressorSwitch(true); - } - } - else OK=mvControlling->Mains; - } - else - OK=false; - OK=OK&&(mvOccupied->ActiveDir!=0)&&(mvControlling->CompressorAllow); - if (OK) - { - if (eStopReason==stopSleep) //jeśli dotychczas spał - eStopReason==stopNone; //teraz nie ma powodu do stania - iEngineActive=1; - return true; - } - else - { - iEngineActive=0; - return false; - } }; bool __fastcall TController::ReleaseEngine() -{//wyłączanie silnika (test wyłączenia, a część wykonawcza tylko jeśli steruje komputer) - bool OK=false; - LastReactionTime=0.0; - ReactionTime=PrepareTime; - if (AIControllFlag) - {//jeśli steruje komputer - if (mvOccupied->DoorOpenCtrl==1) - {//zamykanie drzwi - if (mvOccupied->DoorLeftOpened) mvOccupied->DoorLeft(false); - if (mvOccupied->DoorRightOpened) mvOccupied->DoorRight(false); - } - if (mvOccupied->ActiveDir==0) - if (mvControlling->Mains) - { - mvControlling->CompressorSwitch(false); - mvControlling->ConverterSwitch(false); - if (mvControlling->EnginePowerSource.SourceType==CurrentCollector) - { - mvControlling->PantFront(false); - mvControlling->PantRear(false); +{ // wyłączanie silnika (test wyłączenia, a część wykonawcza tylko jeśli steruje komputer) + bool OK = false; + LastReactionTime = 0.0; + ReactionTime = PrepareTime; + if (AIControllFlag) + { // jeśli steruje komputer + if (mvOccupied->DoorOpenCtrl == 1) + { // zamykanie drzwi + if (mvOccupied->DoorLeftOpened) + mvOccupied->DoorLeft(false); + if (mvOccupied->DoorRightOpened) + mvOccupied->DoorRight(false); + } + if (mvOccupied->ActiveDir == 0) + if (mvControlling->Mains) + { + mvControlling->CompressorSwitch(false); + mvControlling->ConverterSwitch(false); + if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) + { + mvControlling->PantFront(false); + mvControlling->PantRear(false); + } + OK = mvControlling->MainSwitch(false); + } + else + OK = true; } - OK=mvControlling->MainSwitch(false); - } - else - OK=true; - } - else - if (mvOccupied->ActiveDir==0) - OK=mvControlling->Mains; //tylko to testujemy dla pojazdu człowieka - if (AIControllFlag) - if (!mvOccupied->DecBrakeLevel()) //tu moze zmieniać na -2, ale to bez znaczenia - if (!mvOccupied->IncLocalBrakeLevel(1)) - { - while (DecSpeed(true)); //zerowanie nastawników - while (mvOccupied->ActiveDir>0) - mvOccupied->DirectionBackward(); - while (mvOccupied->ActiveDir<0) - mvOccupied->DirectionForward(); - } - OK=OK&&(mvOccupied->Vel<0.01); - if (OK) - {//jeśli się zatrzymał - iEngineActive=0; - eStopReason=stopSleep; //stoimy z powodu wyłączenia - eAction=actSleep; //śpi (wygaszony) - if (AIControllFlag) - {Lights(0,0); //gasimy światła - mvOccupied->BatterySwitch(false); - } - OrderNext(Wait_for_orders); //żeby nie próbował coś robić dalej - TableClear(); //zapominamy ograniczenia - iDrivigFlags&=~moveActive; //ma nie skanować sygnałów i nie reagować na komendy - } - return OK; + else if (mvOccupied->ActiveDir == 0) + OK = mvControlling->Mains; // tylko to testujemy dla pojazdu człowieka + if (AIControllFlag) + if (!mvOccupied->DecBrakeLevel()) // tu moze zmieniać na -2, ale to bez znaczenia + if (!mvOccupied->IncLocalBrakeLevel(1)) + { + while (DecSpeed(true)) + ; // zerowanie nastawników + while (mvOccupied->ActiveDir > 0) + mvOccupied->DirectionBackward(); + while (mvOccupied->ActiveDir < 0) + mvOccupied->DirectionForward(); + } + OK = OK && (mvOccupied->Vel < 0.01); + if (OK) + { // jeśli się zatrzymał + iEngineActive = 0; + eStopReason = stopSleep; // stoimy z powodu wyłączenia + eAction = actSleep; //śpi (wygaszony) + if (AIControllFlag) + { + Lights(0, 0); // gasimy światła + mvOccupied->BatterySwitch(false); + } + OrderNext(Wait_for_orders); //żeby nie próbował coś robić dalej + TableClear(); // zapominamy ograniczenia + iDrivigFlags &= ~moveActive; // ma nie skanować sygnałów i nie reagować na komendy + } + return OK; } bool __fastcall TController::IncBrake() -{//zwiększenie hamowania - bool OK=false; - switch (mvOccupied->BrakeSystem) - { - case Individual: - OK=mvOccupied->IncLocalBrakeLevel(1+floor(0.5+fabs(AccDesired))); - break; - case Pneumatic: - if ((mvOccupied->Couplers[0].Connected==NULL)&&(mvOccupied->Couplers[1].Connected==NULL)) - OK=mvOccupied->IncLocalBrakeLevel(1+floor(0.5+fabs(AccDesired))); //hamowanie lokalnym bo luzem jedzie - else - {if (mvOccupied->BrakeCtrlPos+1==mvOccupied->BrakeCtrlPosNo) +{ // zwiększenie hamowania + bool OK = false; + switch (mvOccupied->BrakeSystem) { - if (AccDesired<-1.5) //hamowanie nagle - OK=mvOccupied->IncBrakeLevel(); - else - OK=false; + case Individual: + OK = mvOccupied->IncLocalBrakeLevel(1 + floor(0.5 + fabs(AccDesired))); + break; + case Pneumatic: + if ((mvOccupied->Couplers[0].Connected == NULL) && + (mvOccupied->Couplers[1].Connected == NULL)) + OK = mvOccupied->IncLocalBrakeLevel( + 1 + floor(0.5 + fabs(AccDesired))); // hamowanie lokalnym bo luzem jedzie + else + { + if (mvOccupied->BrakeCtrlPos + 1 == mvOccupied->BrakeCtrlPosNo) + { + if (AccDesired < -1.5) // hamowanie nagle + OK = mvOccupied->IncBrakeLevel(); + else + OK = false; + } + else + { + /* + if (AccDesired>-0.2) and ((Vel<20) or (Vel-VelNext<10))) + begin + if BrakeCtrlPos>0) + OK:=IncBrakeLevel + else; + OK:=IncLocalBrakeLevel(1); //finezyjne hamowanie lokalnym + end + else + */ + // dodane dla towarowego + if (mvOccupied->BrakeDelayFlag == bdelay_G ? + -AccDesired * 6.6 > Min0R(2, mvOccupied->BrakeCtrlPos) : + true) + { + OK = mvOccupied->IncBrakeLevel(); + } + else + OK = false; + } + } + if (mvOccupied->BrakeCtrlPos > 0) + mvOccupied->BrakeReleaser(0); + break; + case ElectroPneumatic: + if (mvOccupied->fBrakeCtrlPos != mvOccupied->Handle->GetPos(bh_EPB)) + { + mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPB)); + if (mvOccupied->Handle->GetPos(bh_EPR) - mvOccupied->Handle->GetPos(bh_EPN) < 0.1) + mvOccupied->SwitchEPBrake(1); // to nie chce działać + OK = true; + } + else + OK = false; + // if (mvOccupied->BrakeCtrlPosBrakeCtrlPosNo) + // if + // (mvOccupied->BrakePressureTable[mvOccupied->BrakeCtrlPos+1+2].BrakeType==ElectroPneumatic) + // //+2 to indeks Pascala + // OK=mvOccupied->IncBrakeLevel(); + // else + // OK=false; } - else - { -/* - if (AccDesired>-0.2) and ((Vel<20) or (Vel-VelNext<10))) - begin - if BrakeCtrlPos>0) - OK:=IncBrakeLevel - else; - OK:=IncLocalBrakeLevel(1); //finezyjne hamowanie lokalnym - end - else -*/ -//dodane dla towarowego - if (mvOccupied->BrakeDelayFlag==bdelay_G?-AccDesired*6.6>Min0R(2,mvOccupied->BrakeCtrlPos):true) - { - OK=mvOccupied->IncBrakeLevel(); - } - else - OK=false; - } - } - if (mvOccupied->BrakeCtrlPos>0) mvOccupied->BrakeReleaser(0); - break; - case ElectroPneumatic: - if(mvOccupied->fBrakeCtrlPos!=mvOccupied->Handle->GetPos(bh_EPB)) - { - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPB)); - if (mvOccupied->Handle->GetPos(bh_EPR)-mvOccupied->Handle->GetPos(bh_EPN)<0.1) - mvOccupied->SwitchEPBrake(1); //to nie chce działać - OK=true; - } - else OK=false; -// if (mvOccupied->BrakeCtrlPosBrakeCtrlPosNo) -// if (mvOccupied->BrakePressureTable[mvOccupied->BrakeCtrlPos+1+2].BrakeType==ElectroPneumatic) //+2 to indeks Pascala -// OK=mvOccupied->IncBrakeLevel(); -// else -// OK=false; - } - return OK; + return OK; } bool __fastcall TController::DecBrake() -{//zmniejszenie siły hamowania - bool OK=false; - switch (mvOccupied->BrakeSystem) - { - case Individual: - OK=mvOccupied->DecLocalBrakeLevel(1+floor(0.5+fabs(AccDesired))); - break; - case Pneumatic: - if (mvOccupied->BrakeCtrlPos>0) - OK=mvOccupied->DecBrakeLevel(); - if (!OK) - OK=mvOccupied->DecLocalBrakeLevel(2); - if (mvOccupied->PipePress<3.0) - Need_BrakeRelease=true; - break; - case ElectroPneumatic: - if(mvOccupied->fBrakeCtrlPos!=mvOccupied->Handle->GetPos(bh_EPR)) - { - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPR)); - if (mvOccupied->Handle->GetPos(bh_EPR)-mvOccupied->Handle->GetPos(bh_EPN)<0.1) - mvOccupied->SwitchEPBrake(1); - OK=true; - } - else OK=false; - if (!OK) - OK=mvOccupied->DecLocalBrakeLevel(2); - break; - } - return OK; +{ // zmniejszenie siły hamowania + bool OK = false; + switch (mvOccupied->BrakeSystem) + { + case Individual: + OK = mvOccupied->DecLocalBrakeLevel(1 + floor(0.5 + fabs(AccDesired))); + break; + case Pneumatic: + if (mvOccupied->BrakeCtrlPos > 0) + OK = mvOccupied->DecBrakeLevel(); + if (!OK) + OK = mvOccupied->DecLocalBrakeLevel(2); + if (mvOccupied->PipePress < 3.0) + Need_BrakeRelease = true; + break; + case ElectroPneumatic: + if (mvOccupied->fBrakeCtrlPos != mvOccupied->Handle->GetPos(bh_EPR)) + { + mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPR)); + if (mvOccupied->Handle->GetPos(bh_EPR) - mvOccupied->Handle->GetPos(bh_EPN) < 0.1) + mvOccupied->SwitchEPBrake(1); + OK = true; + } + else + OK = false; + if (!OK) + OK = mvOccupied->DecLocalBrakeLevel(2); + break; + } + return OK; }; bool __fastcall TController::IncSpeed() -{//zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać - if (tsGuardSignal) //jeśli jest dźwięk kierownika - if (tsGuardSignal->GetStatus()&DSBSTATUS_PLAYING) //jeśli gada, to nie jedziemy - return false; - bool OK=true; - if (iDrivigFlags&moveDoorOpened) - Doors(false); //zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime) - if (fActionTime<0.0) //gdy jest nakaz poczekać z jazdą, to nie ruszać - return false; - if (mvControlling->SlippingWheels) - return false; //jak poślizg, to nie przyspieszamy - switch (mvOccupied->EngineType) - { - case None: //McZapkie-041003: wagon sterowniczy - if (mvControlling->MainCtrlPosNo>0) //jeśli ma czym kręcić - iDrivigFlags|=moveIncSpeed; //ustawienie flagi jazdy - return false; - case ElectricSeriesMotor: - if (mvControlling->EnginePowerSource.SourceType==CurrentCollector) //jeśli pantografujący - {if (fOverhead2>=0.0) //a jazda bezprądowa ustawiana eventami (albo opuszczenie) - return false; //to nici z ruszania - if (iOverheadZero) //jazda bezprądowa z poziomu toru ustawia bity - return false; //to nici z ruszania - } - if (!mvControlling->FuseFlag) //&&mvControlling->StLinFlag) //yBARC - if ((mvControlling->MainCtrlPos==0)||(mvControlling->StLinFlag)) //youBy polecił dodać 2012-09-08 v367 - //na pozycji 0 przejdzie, a na pozostałych będzie czekać, aż się załączą liniowe (zgaśnie DelayCtrlFlag) - if (Ready||(iDrivigFlags&movePress)) - if (fabs(mvControlling->Im)<(fReady<0.4?mvControlling->Imin:mvControlling->IminLo)) - {//Ra: wywalał nadmiarowy, bo Im może być ujemne; jak nie odhamowany, to nie przesadzać z prądem - if ((mvOccupied->Vel<=30)||(mvControlling->Imax>mvControlling->ImaxLo) - || (fVoltage+fVoltageEnginePowerSource.CollectorParameters.MinV+mvControlling->EnginePowerSource.CollectorParameters.MaxV)) - {//bocznik na szeregowej przy ciezkich bruttach albo przy wysokim rozruchu pod górę albo przy niskim napięciu - if (mvControlling->MainCtrlPos?mvControlling->RList[mvControlling->MainCtrlPos].R>0.0:true) //oporowa - { - OK=(mvControlling->DelayCtrlFlag?true:mvControlling->IncMainCtrl(1)); //kręcimy nastawnik jazdy - if ((OK)&&(mvControlling->MainCtrlPos==1)) //czekaj na 1 pozycji, zanim się nie włączą liniowe - iDrivigFlags|=moveIncSpeed; - else - iDrivigFlags&=~moveIncSpeed; //usunięcie flagi czekania - } - else //jeśli bezoporowa (z wyjątekiem 0) - OK=false; //to dać bocznik - } - else - {//przekroczone 30km/h, można wejść na jazdę równoległą - if (mvControlling->ScndCtrlPos) //jeśli ustawiony bocznik - if (mvControlling->MainCtrlPosMainCtrlPosNo-1) //a nie jest ostatnia pozycja - mvControlling->DecScndCtrl(2); //to bocznik na zero po chamsku (ktoś miał to poprawić...) - OK=mvControlling->IncMainCtrl(1); - } - if ((mvControlling->MainCtrlPos>2)&&(mvControlling->Im==0)) //brak prądu na dalszych pozycjach - Need_TryAgain=true; //nie załączona lokomotywa albo wywalił nadmiarowy - else if (!OK) //nie da się wrzucić kolejnej pozycji - OK=mvControlling->IncScndCtrl(1); //to dać bocznik - } - mvControlling->AutoRelayCheck(); //sprawdzenie logiki sterowania - break; - case Dumb: - case DieselElectric: - if (!mvControlling->FuseFlag) - if (Ready||(iDrivigFlags&movePress)) //{(BrakePress<=0.01*MaxBrakePress)} +{ // zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać + if (tsGuardSignal) // jeśli jest dźwięk kierownika + if (tsGuardSignal->GetStatus() & DSBSTATUS_PLAYING) // jeśli gada, to nie jedziemy + return false; + bool OK = true; + if (iDrivigFlags & moveDoorOpened) + Doors(false); // zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime) + if (fActionTime < 0.0) // gdy jest nakaz poczekać z jazdą, to nie ruszać + return false; + if (mvControlling->SlippingWheels) + return false; // jak poślizg, to nie przyspieszamy + switch (mvOccupied->EngineType) { - OK=mvControlling->IncMainCtrl(1); - if (!OK) - OK=mvControlling->IncScndCtrl(1); + case None: // McZapkie-041003: wagon sterowniczy + if (mvControlling->MainCtrlPosNo > 0) // jeśli ma czym kręcić + iDrivigFlags |= moveIncSpeed; // ustawienie flagi jazdy + return false; + case ElectricSeriesMotor: + if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) // jeśli pantografujący + { + if (fOverhead2 >= 0.0) // a jazda bezprądowa ustawiana eventami (albo opuszczenie) + return false; // to nici z ruszania + if (iOverheadZero) // jazda bezprądowa z poziomu toru ustawia bity + return false; // to nici z ruszania + } + if (!mvControlling->FuseFlag) //&&mvControlling->StLinFlag) //yBARC + if ((mvControlling->MainCtrlPos == 0) || + (mvControlling->StLinFlag)) // youBy polecił dodać 2012-09-08 v367 + // na pozycji 0 przejdzie, a na pozostałych będzie czekać, aż się załączą liniowe + // (zgaśnie DelayCtrlFlag) + if (Ready || (iDrivigFlags & movePress)) + if (fabs(mvControlling->Im) < + (fReady < 0.4 ? mvControlling->Imin : mvControlling->IminLo)) + { // Ra: wywalał nadmiarowy, bo Im może być ujemne; jak nie odhamowany, to nie + // przesadzać z prądem + if ((mvOccupied->Vel <= 30) || + (mvControlling->Imax > mvControlling->ImaxLo) || + (fVoltage + fVoltage < + mvControlling->EnginePowerSource.CollectorParameters.MinV + + mvControlling->EnginePowerSource.CollectorParameters.MaxV)) + { // bocznik na szeregowej przy ciezkich bruttach albo przy wysokim rozruchu + // pod górę albo przy niskim napięciu + if (mvControlling->MainCtrlPos ? + mvControlling->RList[mvControlling->MainCtrlPos].R > 0.0 : + true) // oporowa + { + OK = (mvControlling->DelayCtrlFlag ? + true : + mvControlling->IncMainCtrl(1)); // kręcimy nastawnik jazdy + if ((OK) && + (mvControlling->MainCtrlPos == + 1)) // czekaj na 1 pozycji, zanim się nie włączą liniowe + iDrivigFlags |= moveIncSpeed; + else + iDrivigFlags &= ~moveIncSpeed; // usunięcie flagi czekania + } + else // jeśli bezoporowa (z wyjątekiem 0) + OK = false; // to dać bocznik + } + else + { // przekroczone 30km/h, można wejść na jazdę równoległą + if (mvControlling->ScndCtrlPos) // jeśli ustawiony bocznik + if (mvControlling->MainCtrlPos < + mvControlling->MainCtrlPosNo - 1) // a nie jest ostatnia pozycja + mvControlling->DecScndCtrl(2); // to bocznik na zero po chamsku + // (ktoś miał to poprawić...) + OK = mvControlling->IncMainCtrl(1); + } + if ((mvControlling->MainCtrlPos > 2) && + (mvControlling->Im == 0)) // brak prądu na dalszych pozycjach + Need_TryAgain = true; // nie załączona lokomotywa albo wywalił + // nadmiarowy + else if (!OK) // nie da się wrzucić kolejnej pozycji + OK = mvControlling->IncScndCtrl(1); // to dać bocznik + } + mvControlling->AutoRelayCheck(); // sprawdzenie logiki sterowania + break; + case Dumb: + case DieselElectric: + if (!mvControlling->FuseFlag) + if (Ready || (iDrivigFlags & movePress)) //{(BrakePress<=0.01*MaxBrakePress)} + { + OK = mvControlling->IncMainCtrl(1); + if (!OK) + OK = mvControlling->IncScndCtrl(1); + } + break; + case WheelsDriven: + if (!mvControlling->CabNo) + mvControlling->CabActivisation(); + if (sin(mvControlling->eAngle) > 0) + mvControlling->IncMainCtrl(3 + 3 * floor(0.5 + fabs(AccDesired))); + else + mvControlling->DecMainCtrl(3 + 3 * floor(0.5 + fabs(AccDesired))); + break; + case DieselEngine: + if (mvControlling->ShuntModeAllow) + { // dla 2Ls150 można zmienić tryb pracy, jeśli jest w liniowym i nie daje rady (wymaga + // zerowania kierunku) + // mvControlling->ShuntMode=(OrderList[OrderPos]&Shunt)||(fMass>224000.0); + } + if ((mvControlling->Vel > mvControlling->dizel_minVelfullengage) && + (mvControlling->RList[mvControlling->MainCtrlPos].Mn > 0)) + OK = mvControlling->IncMainCtrl(1); + if (mvControlling->RList[mvControlling->MainCtrlPos].Mn == 0) + OK = mvControlling->IncMainCtrl(1); + if (!mvControlling->Mains) + { + mvControlling->MainSwitch(true); + mvControlling->ConverterSwitch(true); + mvControlling->CompressorSwitch(true); + } + break; } - break; - case WheelsDriven: - if (!mvControlling->CabNo) - mvControlling->CabActivisation(); - if (sin(mvControlling->eAngle)>0) - mvControlling->IncMainCtrl(3+3*floor(0.5+fabs(AccDesired))); - else - mvControlling->DecMainCtrl(3+3*floor(0.5+fabs(AccDesired))); - break; - case DieselEngine: - if (mvControlling->ShuntModeAllow) - {//dla 2Ls150 można zmienić tryb pracy, jeśli jest w liniowym i nie daje rady (wymaga zerowania kierunku) - //mvControlling->ShuntMode=(OrderList[OrderPos]&Shunt)||(fMass>224000.0); - } - if ((mvControlling->Vel>mvControlling->dizel_minVelfullengage)&&(mvControlling->RList[mvControlling->MainCtrlPos].Mn>0)) - OK=mvControlling->IncMainCtrl(1); - if (mvControlling->RList[mvControlling->MainCtrlPos].Mn==0) - OK=mvControlling->IncMainCtrl(1); - if (!mvControlling->Mains) - { - mvControlling->MainSwitch(true); - mvControlling->ConverterSwitch(true); - mvControlling->CompressorSwitch(true); - } - break; - } - return OK; + return OK; } bool __fastcall TController::DecSpeed(bool force) -{//zmniejszenie prędkości (ale nie hamowanie) - bool OK=false; //domyślnie false, aby wyszło z pętli while - switch (mvOccupied->EngineType) - { - case None: //McZapkie-041003: wagon sterowniczy - iDrivigFlags&=~moveIncSpeed; //usunięcie flagi jazdy - if (force) //przy aktywacji kabiny jest potrzeba natychmiastowego wyzerowania - if (mvControlling->MainCtrlPosNo>0) //McZapkie-041003: wagon sterowniczy, np. EZT - mvControlling->DecMainCtrl(1+(mvControlling->MainCtrlPos>2?1:0)); - mvControlling->AutoRelayCheck(); //sprawdzenie logiki sterowania - return false; - case ElectricSeriesMotor: - OK=mvControlling->DecScndCtrl(2); //najpierw bocznik na zero - if (!OK) - OK=mvControlling->DecMainCtrl(1+(mvControlling->MainCtrlPos>2?1:0)); - mvControlling->AutoRelayCheck(); //sprawdzenie logiki sterowania - break; - case Dumb: - case DieselElectric: - OK=mvControlling->DecScndCtrl(2); - if (!OK) - OK=mvControlling->DecMainCtrl(2+(mvControlling->MainCtrlPos/2)); - break; - case WheelsDriven: - if (!mvControlling->CabNo) - mvControlling->CabActivisation(); - if (sin(mvControlling->eAngle)<0) - mvControlling->IncMainCtrl(3+3*floor(0.5+fabs(AccDesired))); - else - mvControlling->DecMainCtrl(3+3*floor(0.5+fabs(AccDesired))); - break; - case DieselEngine: - if ((mvControlling->Vel>mvControlling->dizel_minVelfullengage)) - { - if (mvControlling->RList[mvControlling->MainCtrlPos].Mn>0) - OK=mvControlling->DecMainCtrl(1); - } - else - while ((mvControlling->RList[mvControlling->MainCtrlPos].Mn>0)&&(mvControlling->MainCtrlPos>1)) - OK=mvControlling->DecMainCtrl(1); - if (force) //przy aktywacji kabiny jest potrzeba natychmiastowego wyzerowania - OK=mvControlling->DecMainCtrl(1+(mvControlling->MainCtrlPos>2?1:0)); - break; - } - return OK; +{ // zmniejszenie prędkości (ale nie hamowanie) + bool OK = false; // domyślnie false, aby wyszło z pętli while + switch (mvOccupied->EngineType) + { + case None: // McZapkie-041003: wagon sterowniczy + iDrivigFlags &= ~moveIncSpeed; // usunięcie flagi jazdy + if (force) // przy aktywacji kabiny jest potrzeba natychmiastowego wyzerowania + if (mvControlling->MainCtrlPosNo > 0) // McZapkie-041003: wagon sterowniczy, np. EZT + mvControlling->DecMainCtrl(1 + (mvControlling->MainCtrlPos > 2 ? 1 : 0)); + mvControlling->AutoRelayCheck(); // sprawdzenie logiki sterowania + return false; + case ElectricSeriesMotor: + OK = mvControlling->DecScndCtrl(2); // najpierw bocznik na zero + if (!OK) + OK = mvControlling->DecMainCtrl(1 + (mvControlling->MainCtrlPos > 2 ? 1 : 0)); + mvControlling->AutoRelayCheck(); // sprawdzenie logiki sterowania + break; + case Dumb: + case DieselElectric: + OK = mvControlling->DecScndCtrl(2); + if (!OK) + OK = mvControlling->DecMainCtrl(2 + (mvControlling->MainCtrlPos / 2)); + break; + case WheelsDriven: + if (!mvControlling->CabNo) + mvControlling->CabActivisation(); + if (sin(mvControlling->eAngle) < 0) + mvControlling->IncMainCtrl(3 + 3 * floor(0.5 + fabs(AccDesired))); + else + mvControlling->DecMainCtrl(3 + 3 * floor(0.5 + fabs(AccDesired))); + break; + case DieselEngine: + if ((mvControlling->Vel > mvControlling->dizel_minVelfullengage)) + { + if (mvControlling->RList[mvControlling->MainCtrlPos].Mn > 0) + OK = mvControlling->DecMainCtrl(1); + } + else + while ((mvControlling->RList[mvControlling->MainCtrlPos].Mn > 0) && + (mvControlling->MainCtrlPos > 1)) + OK = mvControlling->DecMainCtrl(1); + if (force) // przy aktywacji kabiny jest potrzeba natychmiastowego wyzerowania + OK = mvControlling->DecMainCtrl(1 + (mvControlling->MainCtrlPos > 2 ? 1 : 0)); + break; + } + return OK; }; void __fastcall TController::SpeedSet() -{//Ra: regulacja prędkości, wykonywana w każdym przebłysku świadomości AI - //ma dokręcać do bezoporowych i zdejmować pozycje w przypadku przekroczenia prądu - switch (mvOccupied->EngineType) - { - case None: //McZapkie-041003: wagon sterowniczy - if (fActionTime>=-1.0) - mvOccupied->DepartureSignal=false; //trochę niech pobuczy, zanim pojedzie - if (mvControlling->MainCtrlPosNo>0) - {//jeśli ma czym kręcić - //TODO: sprawdzanie innego czlonu //if (!FuseFlagCheck()) - if ((AccDesiredVel>VelDesired)) //jeśli nie ma przyspieszać - mvControlling->DecMainCtrl(2); //na zero - else - if (fActionTime>=0.0) - {//jak już można coś poruszać, przetok rozłączać od razu - if (iDrivigFlags&moveIncSpeed) - {//jak ma jechać - if (fReady<0.4) //0.05*Controlling->MaxBrakePress) - {//jak jest odhamowany - if (mvOccupied->ActiveDir>0) mvOccupied->DirectionForward(); //żeby EN57 jechały na drugiej nastawie - { - if (mvControlling->MainCtrlPos&&!mvControlling->StLinFlag) //jak niby jedzie, ale ma rozłączone liniowe - mvControlling->DecMainCtrl(2); //to na zero i czekać na przewalenie kułakowego - else - switch (mvControlling->MainCtrlPos) - {//ruch nastawnika uzależniony jest od aktualnie ustawionej pozycji - case 0: - if (mvControlling->MainCtrlActualPos) //jeśli kułakowy nie jest wyzerowany - break; //to czekać na wyzerowanie - mvControlling->IncMainCtrl(1); //przetok; bez "break", bo nie ma czekania na 1. pozycji - case 1: - if (VelDesired>=20) mvControlling->IncMainCtrl(1); //szeregowa - case 2: - if (VelDesired>=50) mvControlling->IncMainCtrl(1); //równoległa - case 3: - if (VelDesired>=80) mvControlling->IncMainCtrl(1); //bocznik 1 - case 4: - if (VelDesired>=90) mvControlling->IncMainCtrl(1); //bocznik 2 - case 5: - if (VelDesired>=100) mvControlling->IncMainCtrl(1); //bocznik 3 - } - if (mvControlling->MainCtrlPos) //jak załączył pozycję - {fActionTime=-5.0; //niech trochę potrzyma - mvControlling->AutoRelayCheck(); //sprawdzenie logiki sterowania - } +{ // Ra: regulacja prędkości, wykonywana w każdym przebłysku świadomości AI + // ma dokręcać do bezoporowych i zdejmować pozycje w przypadku przekroczenia prądu + switch (mvOccupied->EngineType) + { + case None: // McZapkie-041003: wagon sterowniczy + if (fActionTime >= -1.0) + mvOccupied->DepartureSignal = false; // trochę niech pobuczy, zanim pojedzie + if (mvControlling->MainCtrlPosNo > 0) + { // jeśli ma czym kręcić + // TODO: sprawdzanie innego czlonu //if (!FuseFlagCheck()) + if ((AccDesired < fAccGravity - 0.05) || + (mvOccupied->Vel > VelDesired)) // jeśli nie ma przyspieszać + mvControlling->DecMainCtrl(2); // na zero + else if (fActionTime >= 0.0) + { // jak już można coś poruszać, przetok rozłączać od razu + if (iDrivigFlags & moveIncSpeed) + { // jak ma jechać + if (fReady < 0.4) // 0.05*Controlling->MaxBrakePress) + { // jak jest odhamowany + if (mvOccupied->ActiveDir > 0) + mvOccupied->DirectionForward(); //żeby EN57 jechały na drugiej nastawie + { + if (mvControlling->MainCtrlPos && + !mvControlling + ->StLinFlag) // jak niby jedzie, ale ma rozłączone liniowe + mvControlling->DecMainCtrl( + 2); // to na zero i czekać na przewalenie kułakowego + else + switch (mvControlling->MainCtrlPos) + { // ruch nastawnika uzależniony jest od aktualnie ustawionej + // pozycji + case 0: + if (mvControlling->MainCtrlActualPos) // jeśli kułakowy nie jest + // wyzerowany + break; // to czekać na wyzerowanie + mvControlling->IncMainCtrl(1); // przetok; bez "break", bo nie + // ma czekania na 1. pozycji + case 1: + if (VelDesired >= 20) + mvControlling->IncMainCtrl(1); // szeregowa + case 2: + if (VelDesired >= 50) + mvControlling->IncMainCtrl(1); // równoległa + case 3: + if (VelDesired >= 80) + mvControlling->IncMainCtrl(1); // bocznik 1 + case 4: + if (VelDesired >= 90) + mvControlling->IncMainCtrl(1); // bocznik 2 + case 5: + if (VelDesired >= 100) + mvControlling->IncMainCtrl(1); // bocznik 3 + } + if (mvControlling->MainCtrlPos) // jak załączył pozycję + { + fActionTime = -5.0; // niech trochę potrzyma + mvControlling->AutoRelayCheck(); // sprawdzenie logiki sterowania + } + } + } + } + else + { + while (mvControlling->MainCtrlPos) + mvControlling->DecMainCtrl(1); // na zero + fActionTime = -5.0; // niech trochę potrzyma + mvControlling->AutoRelayCheck(); // sprawdzenie logiki sterowania + } + } } - } - } - else - {while (mvControlling->MainCtrlPos) - mvControlling->DecMainCtrl(1); //na zero - fActionTime=-5.0; //niech trochę potrzyma - mvControlling->AutoRelayCheck(); //sprawdzenie logiki sterowania - } + break; + case ElectricSeriesMotor: + if ((!mvControlling->StLinFlag) && (!mvControlling->DelayCtrlFlag) && + (!iDrivigFlags & moveIncSpeed)) // styczniki liniowe rozłączone yBARC + // if (iDrivigFlags&moveIncSpeed) {} //jeśli czeka na załączenie liniowych + // else + while (DecSpeed()) + ; // zerowanie napędu + else if (Ready || (iDrivigFlags & movePress)) // o ile może jechać + if (fAccGravity < -0.10) // i jedzie pod górę większą niż 10 promil + { // procedura wjeżdżania na ekstremalne wzniesienia + if (fabs(mvControlling->Im) > + 0.85 * mvControlling->Imax) // a prąd jest większy niż 85% nadmiarowego + // if (mvControlling->Imin*mvControlling->Voltage/(fMass*fAccGravity)<-2.8) //a + // na niskim się za szybko nie pojedzie + if (mvControlling->Imax * mvControlling->Voltage / (fMass * fAccGravity) < + -2.8) // a na niskim się za szybko nie pojedzie + { // włączenie wysokiego rozruchu; + // (I*U)[A*V=W=kg*m*m/sss]/(m[kg]*a[m/ss])=v[m/s]; 2.8m/ss=10km/h + if (mvControlling->RList[mvControlling->MainCtrlPos].Bn > 1) + { // jeśli jedzie na równoległym, to zbijamy do szeregowego, aby włączyć + // wysoki rozruch + if (mvControlling->ScndCtrlPos > 0) // jeżeli jest bocznik + mvControlling->DecScndCtrl( + 2); // wyłączyć bocznik, bo może blokować skręcenie NJ + do // skręcanie do bezoporowej na szeregowym + mvControlling->DecMainCtrl(1); // kręcimy nastawnik jazdy o 1 wstecz + while (mvControlling->MainCtrlPos ? + mvControlling->RList[mvControlling->MainCtrlPos].Bn > 1 : + false); // oporowa zapętla + } + if (mvControlling->Imax < mvControlling->ImaxHi) // jeśli da się na wysokim + mvControlling->CurrentSwitch( + true); // rozruch wysoki (za to może się ślizgać) + if (ReactionTime > 0.1) + ReactionTime = 0.1; // orientuj się szybciej + } // if (Im>Imin) + if (fabs(mvControlling->Im) > 0.75 * mvControlling->ImaxHi) // jeśli prąd jest duży + mvControlling->SandDoseOn(); // piaskujemy tory, coby się nie ślizgać + if ((fabs(mvControlling->Im) > 0.96 * mvControlling->Imax) || + mvControlling->SlippingWheels) // jeśli prąd jest duży (można 690 na 750) + if (mvControlling->ScndCtrlPos > 0) // jeżeli jest bocznik + mvControlling->DecScndCtrl(2); // zmniejszyć bocznik + else + mvControlling->DecMainCtrl(1); // kręcimy nastawnik jazdy o 1 wstecz + } + else // gdy nie jedzie ambitnie pod górę + { // sprawdzenie, czy rozruch wysoki jest potrzebny + if (mvControlling->Imax > mvControlling->ImaxLo) + if (mvOccupied->Vel >= 30.0) // jak się rozpędził + if (fAccGravity > -0.02) // a i pochylenie mnijsze niż 2‰ + mvControlling->CurrentSwitch(false); // rozruch wysoki wyłącz + // dokręcanie do bezoporowej, bo IncSpeed() może nie być wywoływane + // if (mvOccupied->Vel-0.1) //nie ma hamować + // if (Controlling->RList[MainCtrlPos].R>0.0) + // if (Im<1.3*Imin) //lekkie przekroczenie miimalnego prądu jest dopuszczalne + // IncMainCtrl(1); //zwieksz nastawnik skoro możesz - tak aby się ustawic na + // bezoporowej + } + break; + case Dumb: + case DieselElectric: + break; + // WheelsDriven : + // begin + // OK:=False; + // end; + case DieselEngine: + // Ra 2014-06: "automatyczna" skrzynia biegów... + if (!mvControlling->MotorParam[mvControlling->ScndCtrlPos].AutoSwitch) // gdy biegi ręczne + if ((mvControlling->ShuntMode ? mvControlling->AnPos : 1.0) * mvControlling->Vel > + 0.6 * mvControlling->MotorParam[mvControlling->ScndCtrlPos].mfi) + // if (mvControlling->enrot>0.95*mvControlling->dizel_nMmax) //youBy: jeśli obroty > + // 0,95 nmax, wrzuć wyższy bieg - Ra: to nie działa + { // jak prędkość większa niż 0.6 maksymalnej na danym biegu, wrzucić wyższy + mvControlling->DecMainCtrl(2); + if (mvControlling->IncScndCtrl(1)) + if (mvControlling->MotorParam[mvControlling->ScndCtrlPos].mIsat == + 0.0) // jeśli bieg jałowy + mvControlling->IncScndCtrl(1); // to kolejny + } + else if ((mvControlling->ShuntMode ? mvControlling->AnPos : 1.0) * mvControlling->Vel < + mvControlling->MotorParam[mvControlling->ScndCtrlPos].fi) + { // jak prędkość mniejsza niż minimalna na danym biegu, wrzucić niższy + mvControlling->DecMainCtrl(2); + mvControlling->DecScndCtrl(1); + if (mvControlling->MotorParam[mvControlling->ScndCtrlPos].mIsat == + 0.0) // jeśli bieg jałowy + if (mvControlling->ScndCtrlPos) // a jeszcze zera nie osiągnięto + mvControlling->DecScndCtrl(1); // to kolejny wcześniejszy + else + mvControlling->IncScndCtrl(1); // a jak zeszło na zero, to powrót + } + break; } - } - break; - case ElectricSeriesMotor: - if ((!mvControlling->StLinFlag)&&(!mvControlling->DelayCtrlFlag)&&(!iDrivigFlags&moveIncSpeed)) //styczniki liniowe rozłączone yBARC -// if (iDrivigFlags&moveIncSpeed) {} //jeśli czeka na załączenie liniowych -// else - while (DecSpeed()); //zerowanie napędu - else - if (Ready||(iDrivigFlags&movePress)) //o ile może jechać - if (fAccGravity<-0.10) //i jedzie pod górę większą niż 10 promil - {//procedura wjeżdżania na ekstremalne wzniesienia - if (fabs(mvControlling->Im)>0.85*mvControlling->Imax) //a prąd jest większy niż 85% nadmiarowego - //if (mvControlling->Imin*mvControlling->Voltage/(fMass*fAccGravity)<-2.8) //a na niskim się za szybko nie pojedzie - if (mvControlling->Imax*mvControlling->Voltage/(fMass*fAccGravity)<-2.8) //a na niskim się za szybko nie pojedzie - {//włączenie wysokiego rozruchu; (I*U)[A*V=W=kg*m*m/sss]/(m[kg]*a[m/ss])=v[m/s]; 2.8m/ss=10km/h - if (mvControlling->RList[mvControlling->MainCtrlPos].Bn>1) - {//jeśli jedzie na równoległym, to zbijamy do szeregowego, aby włączyć wysoki rozruch - if (mvControlling->ScndCtrlPos>0) //jeżeli jest bocznik - mvControlling->DecScndCtrl(2); //wyłączyć bocznik, bo może blokować skręcenie NJ - do //skręcanie do bezoporowej na szeregowym - mvControlling->DecMainCtrl(1); //kręcimy nastawnik jazdy o 1 wstecz - while (mvControlling->MainCtrlPos?mvControlling->RList[mvControlling->MainCtrlPos].Bn>1:false); //oporowa zapętla - } - if (mvControlling->ImaxImaxHi) //jeśli da się na wysokim - mvControlling->CurrentSwitch(true); //rozruch wysoki (za to może się ślizgać) - if (ReactionTime>0.1) - ReactionTime=0.1; //orientuj się szybciej - } //if (Im>Imin) - if (fabs(mvControlling->Im)>0.75*mvControlling->ImaxHi) //jeśli prąd jest duży - mvControlling->SandDoseOn(); //piaskujemy tory, coby się nie ślizgać - if ((fabs(mvControlling->Im)>0.96*mvControlling->Imax)||mvControlling->SlippingWheels) //jeśli prąd jest duży (można 690 na 750) - if (mvControlling->ScndCtrlPos>0) //jeżeli jest bocznik - mvControlling->DecScndCtrl(2); //zmniejszyć bocznik - else - mvControlling->DecMainCtrl(1); //kręcimy nastawnik jazdy o 1 wstecz - } - else //gdy nie jedzie ambitnie pod górę - {//sprawdzenie, czy rozruch wysoki jest potrzebny - if (mvControlling->Imax>mvControlling->ImaxLo) - if (mvOccupied->Vel>=30.0) //jak się rozpędził - if (fAccGravity>-0.02) //a i pochylenie mnijsze niż 2‰ - mvControlling->CurrentSwitch(false); //rozruch wysoki wyłącz - //dokręcanie do bezoporowej, bo IncSpeed() może nie być wywoływane - //if (mvOccupied->Vel-0.1) //nie ma hamować - // if (Controlling->RList[MainCtrlPos].R>0.0) - // if (Im<1.3*Imin) //lekkie przekroczenie miimalnego prądu jest dopuszczalne - // IncMainCtrl(1); //zwieksz nastawnik skoro możesz - tak aby się ustawic na bezoporowej - } - break; - case Dumb: - case DieselElectric: - break; - //WheelsDriven : - // begin - // OK:=False; - // end; - case DieselEngine: - //Ra 2014-06: "automatyczna" skrzynia biegów... - if (!mvControlling->MotorParam[mvControlling->ScndCtrlPos].AutoSwitch) //gdy biegi ręczne - if ((mvControlling->ShuntMode?mvControlling->AnPos:1.0)*mvControlling->Vel>0.6*mvControlling->MotorParam[mvControlling->ScndCtrlPos].mfi) - //if (mvControlling->enrot>0.95*mvControlling->dizel_nMmax) //youBy: jeśli obroty > 0,95 nmax, wrzuć wyższy bieg - Ra: to nie działa - {//jak prędkość większa niż 0.6 maksymalnej na danym biegu, wrzucić wyższy - mvControlling->DecMainCtrl(2); - if (mvControlling->IncScndCtrl(1)) - if (mvControlling->MotorParam[mvControlling->ScndCtrlPos].mIsat==0.0) //jeśli bieg jałowy - mvControlling->IncScndCtrl(1); //to kolejny - } - else if ((mvControlling->ShuntMode?mvControlling->AnPos:1.0)*mvControlling->VelMotorParam[mvControlling->ScndCtrlPos].fi) - {//jak prędkość mniejsza niż minimalna na danym biegu, wrzucić niższy - mvControlling->DecMainCtrl(2); - mvControlling->DecScndCtrl(1); - if (mvControlling->MotorParam[mvControlling->ScndCtrlPos].mIsat==0.0) //jeśli bieg jałowy - if (mvControlling->ScndCtrlPos) //a jeszcze zera nie osiągnięto - mvControlling->DecScndCtrl(1); //to kolejny wcześniejszy - else - mvControlling->IncScndCtrl(1); //a jak zeszło na zero, to powrót - } - break; - } }; void __fastcall TController::Doors(bool what) -{//otwieranie/zamykanie drzwi w składzie albo (tylko AI) EZT - if (what) - {//otwarcie - } - else - {//zamykanie - if (mvOccupied->DoorOpenCtrl==1) - {//jeśli drzwi sterowane z kabiny - if (AIControllFlag) - if (mvOccupied->DoorLeftOpened||mvOccupied->DoorRightOpened) - {//AI zamyka drzwi przed odjazdem - if (mvOccupied->DoorClosureWarning) - mvOccupied->DepartureSignal=true; //załącenie bzyczka - mvOccupied->DoorLeft(false); //zamykanie drzwi - mvOccupied->DoorRight(false); - //Ra: trzeba by ustawić jakiś czas oczekiwania na zamknięcie się drzwi - fActionTime=-1.5-0.1*random(10); //czekanie sekundę, może trochę dłużej - iDrivigFlags&=~moveDoorOpened; //nie wykonywać drugi raz +{ // otwieranie/zamykanie drzwi w składzie albo (tylko AI) EZT + if (what) + { // otwarcie + } + else + { // zamykanie + if (mvOccupied->DoorOpenCtrl == 1) + { // jeśli drzwi sterowane z kabiny + if (AIControllFlag) + if (mvOccupied->DoorLeftOpened || mvOccupied->DoorRightOpened) + { // AI zamyka drzwi przed odjazdem + if (mvOccupied->DoorClosureWarning) + mvOccupied->DepartureSignal = true; // załącenie bzyczka + mvOccupied->DoorLeft(false); // zamykanie drzwi + mvOccupied->DoorRight(false); + // Ra: trzeba by ustawić jakiś czas oczekiwania na zamknięcie się drzwi + fActionTime = -1.5 - 0.1 * random(10); // czekanie sekundę, może trochę dłużej + iDrivigFlags &= ~moveDoorOpened; // nie wykonywać drugi raz + } + } + else + { // jeśli nie, to zamykanie w składzie wagonowym + TDynamicObject *p = pVehicles[0]; // pojazd na czole składu + while (p) + { // zamykanie drzwi w pojazdach - flaga zezwolenia była by lepsza + p->MoverParameters->DoorLeft(false); // w lokomotywie można by nie zamykać... + p->MoverParameters->DoorRight(false); + p = p->Next(); // pojazd podłączony z tyłu (patrząc od czoła) + } + // WaitingSet(5); //10 sekund tu to za długo, opóźnia odjazd o pół minuty + fActionTime = -1.5 - 0.1 * random(10); // czekanie sekundę, może trochę dłużej + iDrivigFlags &= ~moveDoorOpened; // zostały zamknięte - nie wykonywać drugi raz + } } - } - else - {//jeśli nie, to zamykanie w składzie wagonowym - TDynamicObject *p=pVehicles[0]; //pojazd na czole składu - while (p) - {//zamykanie drzwi w pojazdach - flaga zezwolenia była by lepsza - p->MoverParameters->DoorLeft(false); //w lokomotywie można by nie zamykać... - p->MoverParameters->DoorRight(false); - p=p->Next(); //pojazd podłączony z tyłu (patrząc od czoła) - } - //WaitingSet(5); //10 sekund tu to za długo, opóźnia odjazd o pół minuty - fActionTime=-1.5-0.1*random(10); //czekanie sekundę, może trochę dłużej - iDrivigFlags&=~moveDoorOpened; //zostały zamknięte - nie wykonywać drugi raz - } - } }; void __fastcall TController::RecognizeCommand() -{//odczytuje i wykonuje komendę przekazaną lokomotywie - TCommand *c=&mvOccupied->CommandIn; - PutCommand(c->Command,c->Value1,c->Value2,c->Location,stopComm); - c->Command=""; //usunięcie obsłużonej komendy +{ // odczytuje i wykonuje komendę przekazaną lokomotywie + TCommand *c = &mvOccupied->CommandIn; + PutCommand(c->Command, c->Value1, c->Value2, c->Location, stopComm); + c->Command = ""; // usunięcie obsłużonej komendy } - -void __fastcall TController::PutCommand(AnsiString NewCommand,double NewValue1,double NewValue2,const TLocation &NewLocation,TStopReason reason) -{//wysłanie komendy przez event PutValues, jak pojazd ma obsadę, to wysyła tutaj, a nie do pojazdu bezpośrednio - vector3 sl; - sl.x=-NewLocation.X; //zamiana na współrzędne scenerii - sl.z= NewLocation.Y; - sl.y= NewLocation.Z; - if (!PutCommand(NewCommand,NewValue1,NewValue2,&sl,reason)) - mvOccupied->PutCommand(NewCommand,NewValue1,NewValue2,NewLocation); +void __fastcall TController::PutCommand(AnsiString NewCommand, double NewValue1, double NewValue2, + const TLocation &NewLocation, TStopReason reason) +{ // wysłanie komendy przez event PutValues, jak pojazd ma obsadę, to wysyła tutaj, a nie do pojazdu + // bezpośrednio + vector3 sl; + sl.x = -NewLocation.X; // zamiana na współrzędne scenerii + sl.z = NewLocation.Y; + sl.y = NewLocation.Z; + if (!PutCommand(NewCommand, NewValue1, NewValue2, &sl, reason)) + mvOccupied->PutCommand(NewCommand, NewValue1, NewValue2, NewLocation); } - -bool __fastcall TController::PutCommand(AnsiString NewCommand,double NewValue1,double NewValue2,const vector3 *NewLocation,TStopReason reason) -{//analiza komendy - if (NewCommand=="CabSignal") - {//SHP wyzwalane jest przez człon z obsadą, ale obsługiwane przez silnikowy - //nie jest to najlepiej zrobione, ale bez symulacji obwodów lepiej nie będzie - //Ra 2014-04: jednak przeniosłem do rozrządczego - mvOccupied->PutCommand(NewCommand,NewValue1,NewValue2,mvOccupied->Loc); - mvOccupied->RunInternalCommand(); //rozpoznaj komende bo lokomotywa jej nie rozpoznaje - return true; //załatwione - } - if (NewCommand=="Overhead") - {//informacja o stanie sieci trakcyjnej - fOverhead1=NewValue1; //informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!) - fOverhead2=NewValue2; //informacja o sposobie jazdy (-1=normalnie, 0=bez prądu, >0=z opuszczonym i ograniczeniem prędkości) - return true; //załatwione - } - else if (NewCommand=="Emergency_brake") //wymuszenie zatrzymania, niezależnie kto prowadzi - {//Ra: no nadal nie jest zbyt pięknie - SetVelocity(0,0,reason); - mvOccupied->PutCommand("Emergency_brake",1.0,1.0,mvOccupied->Loc); - return true; //załatwione - } - else if (NewCommand.Pos("Timetable:")==1) - {//przypisanie nowego rozkładu jazdy, również prowadzonemu przez użytkownika - NewCommand.Delete(1,10); //zostanie nazwa pliku z rozkładem +bool __fastcall TController::PutCommand(AnsiString NewCommand, double NewValue1, double NewValue2, + const vector3 *NewLocation, TStopReason reason) +{ // analiza komendy + if (NewCommand == "CabSignal") + { // SHP wyzwalane jest przez człon z obsadą, ale obsługiwane przez silnikowy + // nie jest to najlepiej zrobione, ale bez symulacji obwodów lepiej nie będzie + // Ra 2014-04: jednak przeniosłem do rozrządczego + mvOccupied->PutCommand(NewCommand, NewValue1, NewValue2, mvOccupied->Loc); + mvOccupied->RunInternalCommand(); // rozpoznaj komende bo lokomotywa jej nie rozpoznaje + return true; // załatwione + } + if (NewCommand == "Overhead") + { // informacja o stanie sieci trakcyjnej + fOverhead1 = + NewValue1; // informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!) + fOverhead2 = NewValue2; // informacja o sposobie jazdy (-1=normalnie, 0=bez prądu, >0=z + // opuszczonym i ograniczeniem prędkości) + return true; // załatwione + } + else if (NewCommand == "Emergency_brake") // wymuszenie zatrzymania, niezależnie kto prowadzi + { // Ra: no nadal nie jest zbyt pięknie + SetVelocity(0, 0, reason); + mvOccupied->PutCommand("Emergency_brake", 1.0, 1.0, mvOccupied->Loc); + return true; // załatwione + } + else if (NewCommand.Pos("Timetable:") == 1) + { // przypisanie nowego rozkładu jazdy, również prowadzonemu przez użytkownika + NewCommand.Delete(1, 10); // zostanie nazwa pliku z rozkładem #if LOGSTOPS - WriteLog("New timetable for "+pVehicle->asName+": "+NewCommand); //informacja + WriteLog("New timetable for " + pVehicle->asName + ": " + NewCommand); // informacja #endif - if (!TrainParams) - TrainParams=new TTrainParameters(NewCommand); //rozkład jazdy - else - TrainParams->NewName(NewCommand); //czyści tabelkę przystanków - delete tsGuardSignal; tsGuardSignal=NULL; //wywalenie kierownika - if (NewCommand!="none") - {if (!TrainParams->LoadTTfile(Global::asCurrentSceneryPath,floor(NewValue2+0.5),NewValue1)) //pierwszy parametr to przesunięcie rozkładu w czasie - { - if (ConversionError==-8) - ErrorLog("Missed timetable: "+NewCommand); - WriteLog("Cannot load timetable file "+NewCommand+"\r\nError "+ConversionError+" in position "+TrainParams->StationCount); - NewCommand=""; //puste, dla wymiennej tekstury - } - else - {//inicjacja pierwszego przystanku i pobranie jego nazwy - TrainParams->UpdateMTable(GlobalTime->hh,GlobalTime->mm,TrainParams->NextStationName); - TrainParams->StationIndexInc(); //przejście do następnej - iStationStart=TrainParams->StationIndex; - asNextStop=TrainParams->NextStop(); - iDrivigFlags|=movePrimary; //skoro dostał rozkład, to jest teraz głównym - NewCommand=Global::asCurrentSceneryPath+NewCommand+".wav"; //na razie jeden - if (FileExists(NewCommand)) - {//wczytanie dźwięku odjazdu podawanego bezpośrenido - tsGuardSignal=new TTextSound(); - tsGuardSignal->Init(NewCommand.c_str(),30,pVehicle->GetPosition().x,pVehicle->GetPosition().y,pVehicle->GetPosition().z,false); - //rsGuardSignal->Stop(); - iGuardRadio=0; //nie przez radio + if (!TrainParams) + TrainParams = new TTrainParameters(NewCommand); // rozkład jazdy + else + TrainParams->NewName(NewCommand); // czyści tabelkę przystanków + delete tsGuardSignal; + tsGuardSignal = NULL; // wywalenie kierownika + if (NewCommand != "none") + { + if (!TrainParams->LoadTTfile( + Global::asCurrentSceneryPath, floor(NewValue2 + 0.5), + NewValue1)) // pierwszy parametr to przesunięcie rozkładu w czasie + { + if (ConversionError == -8) + ErrorLog("Missed timetable: " + NewCommand); + WriteLog("Cannot load timetable file " + NewCommand + "\r\nError " + + ConversionError + " in position " + TrainParams->StationCount); + NewCommand = ""; // puste, dla wymiennej tekstury + } + else + { // inicjacja pierwszego przystanku i pobranie jego nazwy + TrainParams->UpdateMTable(GlobalTime->hh, GlobalTime->mm, + TrainParams->NextStationName); + TrainParams->StationIndexInc(); // przejście do następnej + iStationStart = TrainParams->StationIndex; + asNextStop = TrainParams->NextStop(); + iDrivigFlags |= movePrimary; // skoro dostał rozkład, to jest teraz głównym + NewCommand = Global::asCurrentSceneryPath + NewCommand + ".wav"; // na razie jeden + if (FileExists(NewCommand)) + { // wczytanie dźwięku odjazdu podawanego bezpośrenido + tsGuardSignal = new TTextSound(); + tsGuardSignal->Init(NewCommand.c_str(), 30, pVehicle->GetPosition().x, + pVehicle->GetPosition().y, pVehicle->GetPosition().z, + false); + // rsGuardSignal->Stop(); + iGuardRadio = 0; // nie przez radio + } + else + { + NewCommand.Insert("radio", NewCommand.Length() - 3); // wstawienie przed kropką + if (FileExists(NewCommand)) + { // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie) + tsGuardSignal = new TTextSound(); + tsGuardSignal->Init(NewCommand.c_str(), -1, pVehicle->GetPosition().x, + pVehicle->GetPosition().y, pVehicle->GetPosition().z, + false); + iGuardRadio = iRadioChannel; + } + } + NewCommand = TrainParams->Relation2; // relacja docelowa z rozkładu + } + // jeszcze poustawiać tekstury na wyświetlaczach + TDynamicObject *p = pVehicles[0]; + while (p) + { + p->DestinationSet(NewCommand); // relacja docelowa + p = p->Next(); // pojazd podłączony od tyłu (licząc od czoła) + } + } + if (NewLocation) // jeśli podane współrzędne eventu/komórki ustawiającej rozkład (trainset + // nie podaje) + { + vector3 v = *NewLocation - pVehicle->GetPosition(); // wektor do punktu sterującego + vector3 d = pVehicle->VectorFront(); // wektor wskazujący przód + iDirectionOrder = ((v.x * d.x + v.z * d.z) * NewValue1 > 0) ? + 1 : + -1; // do przodu, gdy iloczyn skalarny i prędkość dodatnie + /* + if (NewValue1!=0.0) //jeśli ma jechać + if (iDirectionOrder==0) //a kierunek nie był określony (normalnie określany przez + reardriver/headdriver) + iDirectionOrder=NewValue1>0?1:-1; //ustalenie kierunku jazdy względem sprzęgów + else + if (NewValue1<0) //dla ujemnej prędkości + iDirectionOrder=-iDirectionOrder; //ma jechać w drugą stronę + */ + if (AIControllFlag) // jeśli prowadzi komputer + Activation(); // umieszczenie obsługi we właściwym członie, ustawienie nawrotnika w + // przód + } + /* + else + if (!iDirectionOrder) + {//jeśli nie ma kierunku, trzeba ustalić + if (mvOccupied->V!=0.0) + iDirectionOrder=mvOccupied->V>0?1:-1; + else + iDirectionOrder=mvOccupied->ActiveCab; + if (!iDirectionOrder) iDirectionOrder=1; + } + */ + // jeśli wysyłane z Trainset, to wszystko jest już odpowiednio ustawione + // if (!NewLocation) //jeśli wysyłane z Trainset + // if (mvOccupied->CabNo*mvOccupied->V*NewValue1<0) //jeśli zadana prędkość niezgodna z + // aktualnym kierunkiem jazdy + // DirectionForward(false); //jedziemy do tyłu (nawrotnik do tyłu) + // CheckVehicles(); //sprawdzenie składu, AI zapali światła + TableClear(); // wyczyszczenie tabelki prędkości, bo na nowo trzeba określić kierunek i + // sprawdzić przystanki + OrdersInit( + fabs(NewValue1)); // ustalenie tabelki komend wg rozkładu oraz prędkości początkowej + // if (NewValue1!=0.0) if (!AIControllFlag) DirectionForward(NewValue1>0.0); //ustawienie + // nawrotnika użytkownikowi (propaguje się do członów) + // if (NewValue1>0) + // TrainNumber=floor(NewValue1); //i co potem ??? + return true; // załatwione } - else - {NewCommand.Insert("radio",NewCommand.Length()-3); //wstawienie przed kropką - if (FileExists(NewCommand)) - {//wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie) - tsGuardSignal=new TTextSound(); - tsGuardSignal->Init(NewCommand.c_str(),-1,pVehicle->GetPosition().x,pVehicle->GetPosition().y,pVehicle->GetPosition().z,false); - iGuardRadio=iRadioChannel; - } + if (NewCommand == "SetVelocity") + { + if (NewLocation) + vCommandLocation = *NewLocation; + if ((NewValue1 != 0.0) && (OrderList[OrderPos] != Obey_train)) + { // o ile jazda + if (!iEngineActive) + OrderNext(Prepare_engine); // trzeba odpalić silnik najpierw, światła ustawi + // JumpToNextOrder() + // if (OrderList[OrderPos]!=Obey_train) //jeśli nie pociągowa + OrderNext(Obey_train); // to uruchomić jazdę pociągową (od razu albo po odpaleniu + // silnika + OrderCheck(); // jeśli jazda pociągowa teraz, to wykonać niezbędne operacje + } + if (NewValue1 != 0.0) // jeśli jechać + iDrivigFlags &= ~moveStopHere; // podjeżanie do semaforów zezwolone + else + iDrivigFlags |= moveStopHere; // stać do momentu podania komendy jazdy + SetVelocity(NewValue1, NewValue2, reason); // bylo: nic nie rob bo SetVelocity zewnetrznie + // jest wywolywane przez dynobj.cpp } - NewCommand=TrainParams->Relation2; //relacja docelowa z rozkładu - } - //jeszcze poustawiać tekstury na wyświetlaczach - TDynamicObject *p=pVehicles[0]; - while (p) - { - p->DestinationSet(NewCommand); //relacja docelowa - p=p->Next(); //pojazd podłączony od tyłu (licząc od czoła) - } - } - if (NewLocation) //jeśli podane współrzędne eventu/komórki ustawiającej rozkład (trainset nie podaje) - {vector3 v=*NewLocation-pVehicle->GetPosition(); //wektor do punktu sterującego - vector3 d=pVehicle->VectorFront(); //wektor wskazujący przód - iDirectionOrder=((v.x*d.x+v.z*d.z)*NewValue1>0)?1:-1; //do przodu, gdy iloczyn skalarny i prędkość dodatnie -/* - if (NewValue1!=0.0) //jeśli ma jechać - if (iDirectionOrder==0) //a kierunek nie był określony (normalnie określany przez reardriver/headdriver) - iDirectionOrder=NewValue1>0?1:-1; //ustalenie kierunku jazdy względem sprzęgów - else - if (NewValue1<0) //dla ujemnej prędkości - iDirectionOrder=-iDirectionOrder; //ma jechać w drugą stronę -*/ - if (AIControllFlag) //jeśli prowadzi komputer - Activation(); //umieszczenie obsługi we właściwym członie, ustawienie nawrotnika w przód - } -/* - else - if (!iDirectionOrder) - {//jeśli nie ma kierunku, trzeba ustalić - if (mvOccupied->V!=0.0) - iDirectionOrder=mvOccupied->V>0?1:-1; - else - iDirectionOrder=mvOccupied->ActiveCab; - if (!iDirectionOrder) iDirectionOrder=1; - } -*/ - //jeśli wysyłane z Trainset, to wszystko jest już odpowiednio ustawione - //if (!NewLocation) //jeśli wysyłane z Trainset - // if (mvOccupied->CabNo*mvOccupied->V*NewValue1<0) //jeśli zadana prędkość niezgodna z aktualnym kierunkiem jazdy - // DirectionForward(false); //jedziemy do tyłu (nawrotnik do tyłu) - //CheckVehicles(); //sprawdzenie składu, AI zapali światła - TableClear(); //wyczyszczenie tabelki prędkości, bo na nowo trzeba określić kierunek i sprawdzić przystanki - OrdersInit(fabs(NewValue1)); //ustalenie tabelki komend wg rozkładu oraz prędkości początkowej - //if (NewValue1!=0.0) if (!AIControllFlag) DirectionForward(NewValue1>0.0); //ustawienie nawrotnika użytkownikowi (propaguje się do członów) - //if (NewValue1>0) - // TrainNumber=floor(NewValue1); //i co potem ??? - return true; //załatwione - } - if (NewCommand=="SetVelocity") - { - if (NewLocation) - vCommandLocation=*NewLocation; - if ((NewValue1!=0.0)&&(OrderList[OrderPos]!=Obey_train)) - {//o ile jazda - if (!iEngineActive) - OrderNext(Prepare_engine); //trzeba odpalić silnik najpierw, światła ustawi JumpToNextOrder() - //if (OrderList[OrderPos]!=Obey_train) //jeśli nie pociągowa - OrderNext(Obey_train); //to uruchomić jazdę pociągową (od razu albo po odpaleniu silnika - OrderCheck(); //jeśli jazda pociągowa teraz, to wykonać niezbędne operacje - } - if (NewValue1!=0.0) //jeśli jechać - iDrivigFlags&=~moveStopHere; //podjeżanie do semaforów zezwolone - else - iDrivigFlags|=moveStopHere; //stać do momentu podania komendy jazdy - SetVelocity(NewValue1,NewValue2,reason); //bylo: nic nie rob bo SetVelocity zewnetrznie jest wywolywane przez dynobj.cpp - } - else if (NewCommand=="SetProximityVelocity") - { -/* - if (SetProximityVelocity(NewValue1,NewValue2)) - if (NewLocation) - vCommandLocation=*NewLocation; -*/ - } - else if (NewCommand=="ShuntVelocity") - {//uruchomienie jazdy manewrowej bądź zmiana prędkości - if (NewLocation) - vCommandLocation=*NewLocation; - //if (OrderList[OrderPos]=Obey_train) and (NewValue1<>0)) - if (!iEngineActive) - OrderNext(Prepare_engine); //trzeba odpalić silnik najpierw - OrderNext(Shunt); //zamieniamy w aktualnej pozycji, albo dodajey za odpaleniem silnika - if (NewValue1!=0.0) - { - //if (iVehicleCount>=0) WriteLog("Skasowano ilosć wagonów w ShuntVelocity!"); - iVehicleCount=-2; //wartość neutralna - CheckVehicles(); //zabrać to do OrderCheck() - } - //dla prędkości ujemnej przestawić nawrotnik do tyłu? ale -1=brak ograniczenia !!!! - //if (iDrivigFlags&movePress) WriteLog("Skasowano docisk w ShuntVelocity!"); - iDrivigFlags&=~movePress; //bez dociskania - SetVelocity(NewValue1,NewValue2,reason); - if (NewValue1!=0.0) - iDrivigFlags&=~moveStopHere; //podjeżanie do semaforów zezwolone - else - iDrivigFlags|=moveStopHere; //ma stać w miejscu - if (fabs(NewValue1)>2.0) //o ile wartość jest sensowna (-1 nie jest konkretną wartością) - fShuntVelocity=fabs(NewValue1); //zapamiętanie obowiązującej prędkości dla manewrów - } - else if (NewCommand=="Wait_for_orders") - {//oczekiwanie; NewValue1 - czas oczekiwania, -1 = na inną komendę - if (NewValue1>0.0?NewValue1>fStopTime:false) - fStopTime=NewValue1; //Ra: włączenie czekania bez zmiany komendy - else - OrderList[OrderPos]=Wait_for_orders; //czekanie na komendę (albo dać OrderPos=0) - } - else if (NewCommand=="Prepare_engine") - {//włączenie albo wyłączenie silnika (w szerokim sensie) - OrdersClear(); //czyszczenie tabelki rozkazów, aby nic dalej nie robił - if (NewValue1==0.0) - OrderNext(Release_engine); //wyłączyć silnik (przygotować pojazd do jazdy) - else if (NewValue1>0.0) - OrderNext(Prepare_engine); //odpalić silnik (wyłączyć wszystko, co się da) - //po załączeniu przejdzie do kolejnej komendy, po wyłączeniu na Wait_for_orders - } - else if (NewCommand=="Change_direction") - { - TOrders o=OrderList[OrderPos]; //co robił przed zmianą kierunku - if (!iEngineActive) - OrderNext(Prepare_engine); //trzeba odpalić silnik najpierw - if (NewValue1==0.0) - iDirectionOrder=-iDirection; //zmiana na przeciwny niż obecny - else - if (NewLocation) //jeśli podane współrzędne eventu/komórki ustawiającej rozkład (trainset nie podaje) - {vector3 v=*NewLocation-pVehicle->GetPosition(); //wektor do punktu sterującego - vector3 d=pVehicle->VectorFront(); //wektor wskazujący przód - iDirectionOrder=((v.x*d.x+v.z*d.z)*NewValue1>0)?1:-1; //do przodu, gdy iloczyn skalarny i prędkość dodatnie - //iDirectionOrder=1; else if (NewValue1<0.0) iDirectionOrder=-1; - } - if (iDirectionOrder!=iDirection) - OrderNext(Change_direction); //zadanie komendy do wykonania - if (o>=Shunt) //jeśli jazda manewrowa albo pociągowa - OrderNext(o); //to samo robić po zmianie - else if (!o) //jeśli wcześniej było czekanie - OrderNext(Shunt); //to dalej jazda manewrowa - if (mvOccupied->Vel>=1.0) //jeśli jedzie - iDrivigFlags&=~moveStartHorn; //to bez trąbienia po ruszeniu z zatrzymania - //Change_direction wykona się samo i następnie przejdzie do kolejnej komendy - } - else if (NewCommand=="Obey_train") - { - if (!iEngineActive) - OrderNext(Prepare_engine); //trzeba odpalić silnik najpierw - OrderNext(Obey_train); - //if (NewValue1>0) TrainNumber=floor(NewValue1); //i co potem ??? - OrderCheck(); //jeśli jazda pociągowa teraz, to wykonać niezbędne operacje - } - else if (NewCommand=="Shunt") - {//NewValue1 - ilość wagonów (-1=wszystkie); NewValue2: 0=odczep, 1..63=dołącz, -1=bez zmian - //-3,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1), zmienić kierunek i czekać w trybie pociągowym - //-2,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1), zmienić kierunek i czekać - //-2, y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i czekać - //-1,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i jechać w powrotną stronę - //-1, y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i jechać dalej - //-1, 0 - tryb manewrowy bez zmian (odczepianie z pozostawieniem wagonów nie ma sensu) - // 0, 0 - odczepienie lokomotywy - // 1,-y - podłączyć się do składu (sprzęgiem y>=1), a następnie odczepić i zabrać (x) wagonów - // 1, 0 - odczepienie lokomotywy z jednym wagonem - iDrivigFlags&=~moveStopHere; //podjeżanie do semaforów zezwolone - if (!iEngineActive) - OrderNext(Prepare_engine); //trzeba odpalić silnik najpierw - if (NewValue2!=0) //jeśli podany jest sprzęg - {iCoupler=floor(fabs(NewValue2)); //jakim sprzęgiem - OrderNext(Connect); //najpierw połącz pojazdy - if (NewValue1>=0.0) //jeśli ilość wagonów inna niż wszystkie - {//to po podpięciu należy się odczepić - iDirectionOrder=-iDirection; //zmiana na ciągnięcie - OrderPush(Change_direction); //najpierw zmień kierunek, bo odczepiamy z tyłu - OrderPush(Disconnect); //a odczep już po zmianie kierunku - } - else if (NewValue2<0.0) //jeśli wszystkie, a sprzęg ujemny, to tylko zmiana kierunku po podczepieniu - {//np. Shunt -1 -3 - iDirectionOrder=-iDirection; //jak się podczepi, to jazda w przeciwną stronę - OrderNext(Change_direction); - } - WaitingTime=0.0; //nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie - } - else //if (NewValue2==0.0) //zerowy sprzęg - if (NewValue1>=0.0) //jeśli ilość wagonów inna niż wszystkie - {//będzie odczepianie, ale jeśli wagony są z przodu, to trzeba najpierw zmienić kierunek - if ((mvOccupied->Couplers[mvOccupied->DirAbsolute>0?1:0].CouplingFlag==0)? //z tyłu nic - (mvOccupied->Couplers[mvOccupied->DirAbsolute>0?0:1].CouplingFlag>0):false) //a z przodu skład - {iDirectionOrder=-iDirection; //zmiana na ciągnięcie - OrderNext(Change_direction); //najpierw zmień kierunek (zastąpi Disconnect) - OrderPush(Disconnect); //a odczep już po zmianie kierunku + else if (NewCommand == "SetProximityVelocity") + { + /* + if (SetProximityVelocity(NewValue1,NewValue2)) + if (NewLocation) + vCommandLocation=*NewLocation; + */ } - else - if (mvOccupied->Couplers[mvOccupied->DirAbsolute>0?1:0].CouplingFlag>0) //z tyłu coś - OrderNext(Disconnect); //jak ciągnie, to tylko odczep (NewValue1) wagonów - WaitingTime=0.0; //nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie - } - if (NewValue1==-1.0) - {iDrivigFlags&=~moveStopHere; //ma jechać - WaitingTime=0.0; //nie ma co dalej czekać, można zatrąbić i jechać - } - if (NewValue1<-1.5) //jeśli -2/-3, czyli czekanie z ruszeniem na sygnał - iDrivigFlags|=moveStopHere; //nie podjeżdżać do semafora, jeśli droga nie jest wolna (nie dotyczy Connect) - if (NewValue1<-2.5) //jeśli - OrderNext(Obey_train); //to potem jazda pociągowa - else - OrderNext(Shunt); //to potem manewruj dalej - CheckVehicles(); //sprawdzić światła - //if ((iVehicleCount>=0)&&(NewValue1<0)) WriteLog("Skasowano ilosć wagonów w Shunt!"); - if (NewValue1!=iVehicleCount) - iVehicleCount=floor(NewValue1); //i co potem ? - trzeba zaprogramowac odczepianie -/* - if (NewValue1!=-1.0) - if (NewValue2!=0.0) + else if (NewCommand == "ShuntVelocity") + { // uruchomienie jazdy manewrowej bądź zmiana prędkości + if (NewLocation) + vCommandLocation = *NewLocation; + // if (OrderList[OrderPos]=Obey_train) and (NewValue1<>0)) + if (!iEngineActive) + OrderNext(Prepare_engine); // trzeba odpalić silnik najpierw + OrderNext(Shunt); // zamieniamy w aktualnej pozycji, albo dodajey za odpaleniem silnika + if (NewValue1 != 0.0) + { + // if (iVehicleCount>=0) WriteLog("Skasowano ilosć wagonów w ShuntVelocity!"); + iVehicleCount = -2; // wartość neutralna + CheckVehicles(); // zabrać to do OrderCheck() + } + // dla prędkości ujemnej przestawić nawrotnik do tyłu? ale -1=brak ograniczenia !!!! + // if (iDrivigFlags&movePress) WriteLog("Skasowano docisk w ShuntVelocity!"); + iDrivigFlags &= ~movePress; // bez dociskania + SetVelocity(NewValue1, NewValue2, reason); + if (NewValue1 != 0.0) + iDrivigFlags &= ~moveStopHere; // podjeżanie do semaforów zezwolone + else + iDrivigFlags |= moveStopHere; // ma stać w miejscu + if (fabs(NewValue1) > 2.0) // o ile wartość jest sensowna (-1 nie jest konkretną wartością) + fShuntVelocity = fabs(NewValue1); // zapamiętanie obowiązującej prędkości dla manewrów + } + else if (NewCommand == "Wait_for_orders") + { // oczekiwanie; NewValue1 - czas oczekiwania, -1 = na inną komendę + if (NewValue1 > 0.0 ? NewValue1 > fStopTime : false) + fStopTime = NewValue1; // Ra: włączenie czekania bez zmiany komendy + else + OrderList[OrderPos] = Wait_for_orders; // czekanie na komendę (albo dać OrderPos=0) + } + else if (NewCommand == "Prepare_engine") + { // włączenie albo wyłączenie silnika (w szerokim sensie) + OrdersClear(); // czyszczenie tabelki rozkazów, aby nic dalej nie robił + if (NewValue1 == 0.0) + OrderNext(Release_engine); // wyłączyć silnik (przygotować pojazd do jazdy) + else if (NewValue1 > 0.0) + OrderNext(Prepare_engine); // odpalić silnik (wyłączyć wszystko, co się da) + // po załączeniu przejdzie do kolejnej komendy, po wyłączeniu na Wait_for_orders + } + else if (NewCommand == "Change_direction") + { + TOrders o = OrderList[OrderPos]; // co robił przed zmianą kierunku + if (!iEngineActive) + OrderNext(Prepare_engine); // trzeba odpalić silnik najpierw + if (NewValue1 == 0.0) + iDirectionOrder = -iDirection; // zmiana na przeciwny niż obecny + else if (NewLocation) // jeśli podane współrzędne eventu/komórki ustawiającej rozkład + // (trainset nie podaje) + { + vector3 v = *NewLocation - pVehicle->GetPosition(); // wektor do punktu sterującego + vector3 d = pVehicle->VectorFront(); // wektor wskazujący przód + iDirectionOrder = ((v.x * d.x + v.z * d.z) * NewValue1 > 0) ? + 1 : + -1; // do przodu, gdy iloczyn skalarny i prędkość dodatnie + // iDirectionOrder=1; else if (NewValue1<0.0) iDirectionOrder=-1; + } + if (iDirectionOrder != iDirection) + OrderNext(Change_direction); // zadanie komendy do wykonania + if (o >= Shunt) // jeśli jazda manewrowa albo pociągowa + OrderNext(o); // to samo robić po zmianie + else if (!o) // jeśli wcześniej było czekanie + OrderNext(Shunt); // to dalej jazda manewrowa + if (mvOccupied->Vel >= 1.0) // jeśli jedzie + iDrivigFlags &= ~moveStartHorn; // to bez trąbienia po ruszeniu z zatrzymania + // Change_direction wykona się samo i następnie przejdzie do kolejnej komendy + } + else if (NewCommand == "Obey_train") + { + if (!iEngineActive) + OrderNext(Prepare_engine); // trzeba odpalić silnik najpierw + OrderNext(Obey_train); + // if (NewValue1>0) TrainNumber=floor(NewValue1); //i co potem ??? + OrderCheck(); // jeśli jazda pociągowa teraz, to wykonać niezbędne operacje + } + else if (NewCommand == "Shunt") + { // NewValue1 - ilość wagonów (-1=wszystkie); NewValue2: 0=odczep, 1..63=dołącz, -1=bez zmian + //-3,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1), zmienić kierunek i czekać w + //trybie pociągowym + //-2,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1), zmienić kierunek i czekać + //-2, y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i czekać + //-1,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i jechać w powrotną stronę + //-1, y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i jechać dalej + //-1, 0 - tryb manewrowy bez zmian (odczepianie z pozostawieniem wagonów nie ma sensu) + // 0, 0 - odczepienie lokomotywy + // 1,-y - podłączyć się do składu (sprzęgiem y>=1), a następnie odczepić i zabrać (x) + // wagonów + // 1, 0 - odczepienie lokomotywy z jednym wagonem + iDrivigFlags &= ~moveStopHere; // podjeżanie do semaforów zezwolone + if (!iEngineActive) + OrderNext(Prepare_engine); // trzeba odpalić silnik najpierw + if (NewValue2 != 0) // jeśli podany jest sprzęg + { + iCoupler = floor(fabs(NewValue2)); // jakim sprzęgiem + OrderNext(Connect); // najpierw połącz pojazdy + if (NewValue1 >= 0.0) // jeśli ilość wagonów inna niż wszystkie + { // to po podpięciu należy się odczepić + iDirectionOrder = -iDirection; // zmiana na ciągnięcie + OrderPush(Change_direction); // najpierw zmień kierunek, bo odczepiamy z tyłu + OrderPush(Disconnect); // a odczep już po zmianie kierunku + } + else if (NewValue2 < 0.0) // jeśli wszystkie, a sprzęg ujemny, to tylko zmiana kierunku + // po podczepieniu + { // np. Shunt -1 -3 + iDirectionOrder = -iDirection; // jak się podczepi, to jazda w przeciwną stronę + OrderNext(Change_direction); + } + WaitingTime = + 0.0; // nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie + } + else // if (NewValue2==0.0) //zerowy sprzęg + if (NewValue1 >= 0.0) // jeśli ilość wagonów inna niż wszystkie + { // będzie odczepianie, ale jeśli wagony są z przodu, to trzeba najpierw zmienić kierunek + if ((mvOccupied->Couplers[mvOccupied->DirAbsolute > 0 ? 1 : 0].CouplingFlag == + 0) ? // z tyłu nic + (mvOccupied->Couplers[mvOccupied->DirAbsolute > 0 ? 0 : 1].CouplingFlag > 0) : + false) // a z przodu skład + { + iDirectionOrder = -iDirection; // zmiana na ciągnięcie + OrderNext(Change_direction); // najpierw zmień kierunek (zastąpi Disconnect) + OrderPush(Disconnect); // a odczep już po zmianie kierunku + } + else if (mvOccupied->Couplers[mvOccupied->DirAbsolute > 0 ? 1 : 0].CouplingFlag > + 0) // z tyłu coś + OrderNext(Disconnect); // jak ciągnie, to tylko odczep (NewValue1) wagonów + WaitingTime = + 0.0; // nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie + } + if (NewValue1 == -1.0) + { + iDrivigFlags &= ~moveStopHere; // ma jechać + WaitingTime = 0.0; // nie ma co dalej czekać, można zatrąbić i jechać + } + if (NewValue1 < -1.5) // jeśli -2/-3, czyli czekanie z ruszeniem na sygnał + iDrivigFlags |= moveStopHere; // nie podjeżdżać do semafora, jeśli droga nie jest wolna + // (nie dotyczy Connect) + if (NewValue1 < -2.5) // jeśli + OrderNext(Obey_train); // to potem jazda pociągowa + else + OrderNext(Shunt); // to potem manewruj dalej + CheckVehicles(); // sprawdzić światła + // if ((iVehicleCount>=0)&&(NewValue1<0)) WriteLog("Skasowano ilosć wagonów w Shunt!"); + if (NewValue1 != iVehicleCount) + iVehicleCount = floor(NewValue1); // i co potem ? - trzeba zaprogramowac odczepianie + /* + if (NewValue1!=-1.0) + if (NewValue2!=0.0) - if (VelDesired==0) - SetVelocity(20,0); //to niech jedzie -*/ - } - else if (NewCommand=="Jump_to_first_order") - JumpToFirstOrder(); - else if (NewCommand=="Jump_to_order") - { - if (NewValue1==-1.0) - JumpToNextOrder(); - else - if ((NewValue1>=0)&&(NewValue1= 0) && (NewValue1 < maxorders)) + { + OrderPos = floor(NewValue1); + if (!OrderPos) + OrderPos = 1; // zgodność wstecz: dopiero pierwsza uruchamia #if LOGORDERS - WriteLog("--> Jump_to_order"); - OrdersDump(); + WriteLog("--> Jump_to_order"); + OrdersDump(); #endif - } -/* - if (WriteLogFlag) - { - append(AIlogFile); - writeln(AILogFile,ElapsedTime:5:2," - new order: ",Order2Str( OrderList[OrderPos])," @ ",OrderPos); - close(AILogFile); - } -*/ - } -/* //ta komenda jest teraz skanowana, więc wysyłanie jej eventem nie ma sensu - else if (NewCommand=="OutsideStation") //wskaznik W5 - { - if (OrderList[OrderPos]==Obey_train) - SetVelocity(NewValue1,NewValue2,stopOut); //koniec stacji - predkosc szlakowa - else //manewry - zawracaj - { - iDirectionOrder=-iDirection; //zmiana na przeciwny niż obecny - OrderNext(Change_direction); //zmiana kierunku - OrderNext(Shunt); //a dalej manewry - iDrivigFlags&=~moveStartHorn; //bez trąbienia po zatrzymaniu - } - } -*/ - else if (NewCommand=="Warning_signal") - { - if (AIControllFlag) //poniższa komenda nie jest wykonywana przez użytkownika - if (NewValue1>0) - { - fWarningDuration=NewValue1; //czas trąbienia - mvOccupied->WarningSignal=(NewValue2>1)?2:1; //wysokość tonu - } - } - else if (NewCommand=="Radio_channel") - {//wybór kanału radiowego (którego powinien używać AI, ręczny maszynista musi go ustawić sam) - if (NewValue1>=0) //wartości ujemne są zarezerwowane, -1 = nie zmieniać kanału - {iRadioChannel=NewValue1; - if (iGuardRadio) - iGuardRadio=iRadioChannel; //kierownikowi też zmienić - } - //NewValue2 może zawierać dodatkowo oczekiwany kod odpowiedzi, np. dla W29 "nawiązać łączność radiową z dyżurnym ruchu odcinkowym" - } - else return false; //nierozpoznana - wysłać bezpośrednio do pojazdu - return true; //komenda została przetworzona + } + /* + if (WriteLogFlag) + { + append(AIlogFile); + writeln(AILogFile,ElapsedTime:5:2," - new order: ",Order2Str( OrderList[OrderPos])," @ + ",OrderPos); + close(AILogFile); + } + */ + } + /* //ta komenda jest teraz skanowana, więc wysyłanie jej eventem nie ma sensu + else if (NewCommand=="OutsideStation") //wskaznik W5 + { + if (OrderList[OrderPos]==Obey_train) + SetVelocity(NewValue1,NewValue2,stopOut); //koniec stacji - predkosc szlakowa + else //manewry - zawracaj + { + iDirectionOrder=-iDirection; //zmiana na przeciwny niż obecny + OrderNext(Change_direction); //zmiana kierunku + OrderNext(Shunt); //a dalej manewry + iDrivigFlags&=~moveStartHorn; //bez trąbienia po zatrzymaniu + } + } + */ + else if (NewCommand == "Warning_signal") + { + if (AIControllFlag) // poniższa komenda nie jest wykonywana przez użytkownika + if (NewValue1 > 0) + { + fWarningDuration = NewValue1; // czas trąbienia + mvOccupied->WarningSignal = (NewValue2 > 1) ? 2 : 1; // wysokość tonu + } + } + else if (NewCommand == "Radio_channel") + { // wybór kanału radiowego (którego powinien używać AI, ręczny maszynista musi go ustawić sam) + if (NewValue1 >= 0) // wartości ujemne są zarezerwowane, -1 = nie zmieniać kanału + { + iRadioChannel = NewValue1; + if (iGuardRadio) + iGuardRadio = iRadioChannel; // kierownikowi też zmienić + } + // NewValue2 może zawierać dodatkowo oczekiwany kod odpowiedzi, np. dla W29 "nawiązać + // łączność radiową z dyżurnym ruchu odcinkowym" + } + else + return false; // nierozpoznana - wysłać bezpośrednio do pojazdu + return true; // komenda została przetworzona }; void __fastcall TController::PhysicsLog() -{//zapis logu - na razie tylko wypisanie parametrów - if (LogFile.is_open()) - { -#if LOGPRESS==0 - LogFile << ElapsedTime<<" "<WheelDiameter*mvOccupied->nrot)<<" "; - LogFile << mvControlling->AccS<<" "<Couplers[1].Dist<<" "<Couplers[1].CForce<<" "; - LogFile << mvOccupied->Ft<<" "<Ff<<" "<Fb<<" "<BrakePress<<" "; - LogFile << mvOccupied->PipePress<<" "<Im<<" "<MainCtrlPos)<<" "; - LogFile << int(mvControlling->ScndCtrlPos)<<" "<BrakeCtrlPos)<<" "<LocalBrakePos)<<" "; - LogFile << int(mvControlling->ActiveDir)<<" "<CommandIn.Command.c_str()<<" "<CommandIn.Value1<<" "; - LogFile << mvOccupied->CommandIn.Value2<<" "<SecuritySystem.Status)<<" "<SlippingWheels)<<"\r\n"; +{ // zapis logu - na razie tylko wypisanie parametrów + if (LogFile.is_open()) + { +#if LOGPRESS == 0 + LogFile << ElapsedTime << " " << fabs(11.31 * mvOccupied->WheelDiameter * mvOccupied->nrot) + << " "; + LogFile << mvControlling->AccS << " " << mvOccupied->Couplers[1].Dist << " " + << mvOccupied->Couplers[1].CForce << " "; + LogFile << mvOccupied->Ft << " " << mvOccupied->Ff << " " << mvOccupied->Fb << " " + << mvOccupied->BrakePress << " "; + LogFile << mvOccupied->PipePress << " " << mvControlling->Im << " " + << int(mvControlling->MainCtrlPos) << " "; + LogFile << int(mvControlling->ScndCtrlPos) << " " << int(mvOccupied->BrakeCtrlPos) + << " " << int(mvOccupied->LocalBrakePos) << " "; + LogFile << int(mvControlling->ActiveDir) << " " << mvOccupied->CommandIn.Command.c_str() + << " " << mvOccupied->CommandIn.Value1 << " "; + LogFile << mvOccupied->CommandIn.Value2 << " " << int(mvControlling->SecuritySystem.Status) + << " " << int(mvControlling->SlippingWheels) << "\r\n"; #endif -#if LOGPRESS==1 - LogFile << ElapsedTime<<"\t"<WheelDiameter*mvOccupied->nrot)<<"\t"; - LogFile << Controlling->AccS<<"\t"; - LogFile << mvOccupied->PipePress<<"\t"<CntrlPipePress<<"\t"<BrakePress<<"\t"; - LogFile << mvOccupied->Volume<<"\t"<Hamulec->GetCRP()<<"\n"; +#if LOGPRESS == 1 + LogFile << ElapsedTime << "\t" << fabs(11.31 * mvOccupied->WheelDiameter * mvOccupied->nrot) + << "\t"; + LogFile << Controlling->AccS << "\t"; + LogFile << mvOccupied->PipePress << "\t" << mvOccupied->CntrlPipePress << "\t" + << mvOccupied->BrakePress << "\t"; + LogFile << mvOccupied->Volume << "\t" << mvOccupied->Hamulec->GetCRP() << "\n"; #endif - LogFile.flush(); - } + LogFile.flush(); + } }; bool __fastcall TController::UpdateSituation(double dt) -{//uruchamiać przynajmniej raz na sekundę - if ((iDrivigFlags&movePrimary)==0) return true; //pasywny nic nie robi - double AbsAccS; - //double VelReduced; //o ile km/h może przekroczyć dozwoloną prędkość bez hamowania - bool UpdateOK=false; - if (AIControllFlag) - {//yb: zeby EP nie musial sie bawic z ciesnieniem w PG -// if (mvOccupied->BrakeSystem==ElectroPneumatic) -// mvOccupied->PipePress=0.5; //yB: w SPKS są poprawnie zrobione pozycje - if (mvControlling->SlippingWheels) - { - mvControlling->SandDoseOn(); //piasku! - //Controlling->SlippingWheels=false; //a to tu nie ma sensu, flaga używana w dalszej części - } - } - //ABu-160305 testowanie gotowości do jazdy - //Ra: przeniesione z DynObj, skład użytkownika też jest testowany, żeby mu przekazać, że ma odhamować - Ready=true; //wstępnie gotowy - fReady=0.0; //założenie, że odhamowany - fAccGravity=0.0; //przyspieszenie wynikające z pochylenia - double dy; //składowa styczna grawitacji, w przedziale <0,1> - TDynamicObject *p=pVehicles[0]; //pojazd na czole składu - while (p) - {//sprawdzenie odhamowania wszystkich połączonych pojazdów - if (Ready) //bo jak coś nie odhamowane, to dalej nie ma co sprawdzać - //if (p->MoverParameters->BrakePress>=0.03*p->MoverParameters->MaxBrakePress) - if (p->MoverParameters->BrakePress>=0.4) //wg UIC określone sztywno na 0.04 - {Ready=false; //nie gotowy - //Ra: odluźnianie przeładowanych lokomotyw, ciągniętych na zimno - prowizorka... - if (AIControllFlag) //skład jak dotąd był wyluzowany - {if (mvOccupied->BrakeCtrlPos==0) //jest pozycja jazdy - if ((p->MoverParameters->PipePress-5.0)>-0.1) //jeśli ciśnienie jak dla jazdy - if (p->MoverParameters->Hamulec->GetCRP()>p->MoverParameters->PipePress+0.12) //za dużo w zbiorniku - p->MoverParameters->BrakeReleaser(1); //indywidualne luzowanko - if (p->MoverParameters->Power>0.01) //jeśli ma silnik - if (p->MoverParameters->FuseFlag) //wywalony nadmiarowy - Need_TryAgain=true; //reset jak przy wywaleniu nadmiarowego - } - } - if (fReadyMoverParameters->BrakePress) - fReady=p->MoverParameters->BrakePress; //szukanie najbardziej zahamowanego - if ((dy=p->VectorFront().y)!=0.0) //istotne tylko dla pojazdów na pochyleniu - fAccGravity-=p->DirectionGet()*p->MoverParameters->TotalMassxg*dy; //ciężar razy składowa styczna grawitacji - p=p->Next(); //pojazd podłączony z tyłu (patrząc od czoła) - } - if (iDirection) - fAccGravity/=iDirection*fMass; //siłę generują pojazdy na pochyleniu ale działa ona całość składu, więc a=F/m - if (!Ready) //v367: jeśli wg powyższych warunków skład nie jest odhamowany - if (fAccGravity<-0.05) //jeśli ma pod górę na tyle, by się stoczyć - //if (mvOccupied->BrakePress<0.08) //to wystarczy, że zadziałają liniowe (nie ma ich jeszcze!!!) - if (fReady<0.8) //delikatniejszy warunek, obejmuje wszystkie wagony - Ready=true; //żeby uznać za odhamowany - HelpMeFlag=false; - //Winger 020304 - if (AIControllFlag) - { - if (mvControlling->EnginePowerSource.SourceType==CurrentCollector) - { - if (mvOccupied->ScndPipePress>4.3) //gdy główna sprężarka bezpiecznie nabije ciśnienie - mvControlling->bPantKurek3=true; //to można przestawić kurek na zasilanie pantografów z głównej pneumatyki - fVoltage=0.5*(fVoltage+fabs(mvControlling->RunningTraction.TractionVoltage)); //uśrednione napięcie sieci: przy spadku poniżej wartości minimalnej opóźnić rozruch o losowy czas - if (fVoltageEnginePowerSource.CollectorParameters.MinV) //gdy rozłączenie WS z powodu niskiego napięcia - if (fActionTime>=0) //jeśli czas oczekiwania nie został ustawiony - fActionTime=-2-random(10); //losowy czas oczekiwania przed ponownym załączeniem jazdy - } - if (mvOccupied->Vel>0.0) - {//jeżeli jedzie - if (iDrivigFlags&moveDoorOpened) //jeśli drzwi otwarte - if (mvOccupied->Vel>1.0) //nie zamykać drzwi przy drganiach, bo zatrzymanie na W4 akceptuje niewielkie prędkości - Doors(false); - //przy prowadzeniu samochodu trzeba każdą oś odsuwać oddzielnie, inaczej kicha wychodzi - if (mvOccupied->CategoryFlag&2) //jeśli samochód - //if (fabs(mvOccupied->OffsetTrackH)Dim.W) //Ra: szerokość drogi tu powinna być? - if (!mvOccupied->ChangeOffsetH(-0.01*mvOccupied->Vel*dt)) //ruch w poprzek drogi - mvOccupied->ChangeOffsetH(0.01*mvOccupied->Vel*dt); //Ra: co to miało być, to nie wiem - if (mvControlling->EnginePowerSource.SourceType==CurrentCollector) - { - if ((fOverhead2>=0.0)||iOverheadZero) - {//jeśli jazda bezprądowa albo z opuszczonym pantografem - while (DecSpeed(true)); //zerowanie napędu - } - if ((fOverhead2>0.0)||iOverheadDown) - {//jazda z opuszczonymi pantografami - mvControlling->PantFront(false); - mvControlling->PantRear(false); - } - else - {//jeśli nie trzeba opuszczać pantografów - if (iDirection>=0) //jak jedzie w kierunku sprzęgu 0 - mvControlling->PantRear(true); //jazda na tylnym - else - mvControlling->PantFront(true); - } - if (mvOccupied->Vel>10) //opuszczenie przedniego po rozpędzeniu się - { - if (mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo>1) //o ile jest więcej niż jeden - if (iDirection>=0) //jak jedzie w kierunku sprzęgu 0 - {//poczekać na podniesienie tylnego - if (mvControlling->PantRearVolt!=0.0) //czy jest napięcie zasilające na tylnym? - mvControlling->PantFront(false); //opuszcza od sprzęgu 0 - } - else - {//poczekać na podniesienie przedniego - if (mvControlling->PantFrontVolt!=0.0) //czy jest napięcie zasilające na przednim? - mvControlling->PantRear(false); //opuszcza od sprzęgu 1 - } - } - } - } - if (iDrivigFlags&moveStartHornNow) //czy ma zatrąbić przed ruszeniem? - if (Ready) //gotów do jazdy - if (iEngineActive) //jeszcze się odpalić musi - if (fStopTime>=0) //i nie musi czekać - {//uruchomienie trąbienia - fWarningDuration=0.3; //czas trąbienia - //if (AIControllFlag) //jak siedzi krasnoludek, to włączy trąbienie - mvOccupied->WarningSignal=pVehicle->iHornWarning; //wysokość tonu (2=wysoki) - iDrivigFlags|=moveStartHornDone; //nie trąbić aż do ruszenia - iDrivigFlags&=~moveStartHornNow; //trąbienie zostało zorganizowane - } - } - ElapsedTime+=dt; - WaitingTime+=dt; - fBrakeTime-=dt; //wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca - fStopTime+=dt; //zliczanie czasu postoju, nie ruszy dopóki ujemne - fActionTime+=dt; //czas używany przy regulacji prędkości i zamykaniu drzwi - if (WriteLogFlag) - { - if (LastUpdatedTime>deltalog) - {//zapis do pliku DAT - PhysicsLog(); - if (fabs(mvOccupied->V)>0.1) //Ra: [m/s] - deltalog=0.05;//0.2; - else deltalog=0.05;//1.0; - LastUpdatedTime=0.0; - } - else - LastUpdatedTime=LastUpdatedTime+dt; - } - //Ra: skanowanie również dla prowadzonego ręcznie, aby podpowiedzieć prędkość - if ((LastReactionTime>Min0R(ReactionTime,2.0))) - { - //Ra: nie wiem czemu ReactionTime potrafi dostać 12 sekund, to jest przegięcie, bo przeżyna STÓJ - //yB: otóż jest to jedna trzecia czasu napełniania na towarowym; może się przydać przy wdrażaniu hamowania, żeby nie ruszało kranem jak głupie - //Ra: ale nie może się budzić co pół minuty, bo przeżyna semafory - //Ra: trzeba by tak: - // 1. Ustalić istotną odległość zainteresowania (np. 3×droga hamowania z V.max). - fBrakeDist=fDriverBraking*mvOccupied->Vel*(40.0+mvOccupied->Vel); //przybliżona droga hamowania - //dla hamowania -0.2 [m/ss] droga wynosi 0.389*Vel*Vel [km/h], czyli 600m dla 40km/h, 3.8km dla 100km/h i 9.8km dla 160km/h - //dla hamowania -0.4 [m/ss] droga wynosi 0.096*Vel*Vel [km/h], czyli 150m dla 40km/h, 1.0km dla 100km/h i 2.5km dla 160km/h - //ogólnie droga hamowania przy stałym opóźnieniu to Vel*Vel/(3.6*3.6*a) [m] - //fBrakeDist powinno być wyznaczane dla danego składu za pomocą sieci neuronowych, w zależności od prędkości i siły (ciśnienia) hamowania - //następnie w drugą stronę, z drogi hamowania i chwilowej prędkości powinno być wyznaczane zalecane ciśnienie - if (fMass>1000000.0) fBrakeDist*=2.0; //korekta dla ciężkich, bo przeżynają - da to coś? - if (mvOccupied->BrakeDelayFlag==bdelay_G) fBrakeDist=fBrakeDist+2*mvOccupied->Vel; //dla nastawienia G koniecznie należy wydłużyć drogę na czas reakcji - //double scanmax=(mvOccupied->Vel>0.0)?3*fDriverDist+fBrakeDist:10.0*fDriverDist; - double scanmax=(mvOccupied->Vel>5.0)?400+fBrakeDist:50.0*fDriverDist; //1000m dla stojących pociągów; Ra 2015-01: przy dłuższej drodze skanowania AI jeździ spokojniej - // 2. Sprawdzić, czy tabelka pokrywa założony odcinek (nie musi, jeśli jest STOP). - // 3. Sprawdzić, czy trajektoria ruchu przechodzi przez zwrotnice - jeśli tak, to sprawdzić, czy stan się nie zmienił. - // 4. Ewentualnie uzupełnić tabelkę informacjami o sygnałach i ograniczeniach, jeśli się "zużyła". - TableCheck(scanmax); //wypełnianie tabelki i aktualizacja odległości - // 5. Sprawdzić stany sygnalizacji zapisanej w tabelce, wyznaczyć prędkości. - // 6. Z tabelki wyznaczyć krytyczną odległość i prędkość (najmniejsze przyspieszenie). - // 7. Jeśli jest inny pojazd z przodu, ewentualnie skorygować odległość i prędkość. - // 8. Ustalić częstotliwość świadomości AI (zatrzymanie precyzyjne - częściej, brak atrakcji - rzadziej). - if (AIControllFlag) - {//tu bedzie logika sterowania - if (mvOccupied->CommandIn.Command!="") - if (!mvOccupied->RunInternalCommand()) //rozpoznaj komende bo lokomotywa jej nie rozpoznaje - RecognizeCommand(); //samo czyta komendę wstawioną do pojazdu? - if (mvOccupied->SecuritySystem.Status>1) //jak zadziałało CA/SHP - if (!mvOccupied->SecuritySystemReset()) //to skasuj - //if ((TestFlag(mvOccupied->SecuritySystem.Status,s_ebrake))&&(mvOccupied->BrakeCtrlPos==0)&&(AccDesired>0.0)) - if ((TestFlag(mvOccupied->SecuritySystem.Status,s_SHPebrake)||TestFlag(mvOccupied->SecuritySystem.Status,s_CAebrake))&&(mvOccupied->BrakeCtrlPos==0)&&(AccDesired>0.0)) - mvOccupied->BrakeLevelSet(0); //!!! hm, może po prostu normalnie sterować hamulcem? - } - switch (OrderList[OrderPos]) - {//ustalenie prędkości przy doczepianiu i odczepianiu, dystansów w pozostałych przypadkach - case Connect: //podłączanie do składu - if (iDrivigFlags&moveConnect) - {//jeśli stanął już blisko, unikając zderzenia i można próbować podłączyć - fMinProximityDist=-0.01; fMaxProximityDist=0.0; //[m] dojechać maksymalnie - fVelPlus=0.5; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus=0.5; //margines prędkości powodujący załączenie napędu - if (AIControllFlag) - {//to robi tylko AI, wersję dla człowieka trzeba dopiero zrobić - //sprzęgi sprawdzamy w pierwszej kolejności, bo jak połączony, to koniec - bool ok; //true gdy się podłączy (uzyskany sprzęg będzie zgodny z żądanym) - if (pVehicles[0]->DirectionGet()>0) //jeśli sprzęg 0 - {//sprzęg 0 - próba podczepienia - if (pVehicles[0]->MoverParameters->Couplers[0].Connected) //jeśli jest coś wykryte (a chyba jest, nie?) - if (pVehicles[0]->MoverParameters->Attach(0,2,pVehicles[0]->MoverParameters->Couplers[0].Connected,iCoupler)) - { - //pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); - //pVehicles[0]->dsbCouplerAttach->Play(0,0,0); - } - //WriteLog("CoupleDist[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CoupleDist)+", Connected[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag)); - ok=(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag==iCoupler); //udało się? (mogło częściowo) - } - else //if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1 - {//sprzęg 1 - próba podczepienia - if (pVehicles[0]->MoverParameters->Couplers[1].Connected) //jeśli jest coś wykryte (a chyba jest, nie?) - if (pVehicles[0]->MoverParameters->Attach(1,2,pVehicles[0]->MoverParameters->Couplers[1].Connected,iCoupler)) - { - //pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); - //pVehicles[0]->dsbCouplerAttach->Play(0,0,0); - } - //WriteLog("CoupleDist[1]="+AnsiString(Controlling->Couplers[1].CoupleDist)+", Connected[0]="+AnsiString(Controlling->Couplers[1].CouplingFlag)); - ok=(pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag==iCoupler); //udało się? (mogło częściowo) - } - if (ok) - {//jeżeli został podłączony - iCoupler=0; //dalsza jazda manewrowa już bez łączenia - iDrivigFlags&=~moveConnect; //zdjęcie flagi doczepiania - SetVelocity(0,0,stopJoin); //wyłączyć przyspieszanie - CheckVehicles(); //sprawdzić światła nowego składu - JumpToNextOrder(); //wykonanie następnej komendy - } - else - SetVelocity(2.0,0.0); //jazda w ustawionym kierunku z prędkością 2 (18s) - } //if (AIControllFlag) //koniec zblokowania, bo była zmienna lokalna -/* //Ra 2014-02: lepiej tam, bo jak tam się odźwieży skład, to tu pVehicles[0] będzie czymś innym - else - {//jeśli człowiek ma podłączyć, to czekamy na zmianę stanu sprzęgów na końcach dotychczasowego składu - bool ok; //true gdy się podłączy (uzyskany sprzęg będzie zgodny z żądanym) - if (pVehicles[0]->DirectionGet()>0) //jeśli sprzęg 0 - ok=(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag>0); //==iCoupler); //udało się? (mogło częściowo) - else //if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1 - ok=(pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag>0); //==iCoupler); //udało się? (mogło częściowo) - if (ok) - {//jeżeli został podłączony - iDrivigFlags&=~moveConnect; //zdjęcie flagi doczepiania - JumpToNextOrder(); //wykonanie następnej komendy - } - } -*/ - } - else - {//jak daleko, to jazda jak dla Shunt na kolizję - fMinProximityDist=0.0; fMaxProximityDist=5.0; //[m] w takim przedziale odległości powinien stanąć - fVelPlus=2.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus=1.0; //margines prędkości powodujący załączenie napędu - //VelReduced=5; //[km/h] - //if (mvOccupied->Vel<0.5) //jeśli już prawie stanął - if (pVehicles[0]->fTrackBlock<=20.0) //przy zderzeniu fTrackBlock nie jest miarodajne - iDrivigFlags|=moveConnect; //początek podczepiania, z wyłączeniem sprawdzania fTrackBlock - } - break; - case Disconnect: //20.07.03 - manewrowanie wagonami - fMinProximityDist=1.0; fMaxProximityDist=10.0; //[m] - fVelPlus=1.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus=0.5; //margines prędkości powodujący załączenie napędu +{ // uruchamiać przynajmniej raz na sekundę + if ((iDrivigFlags & movePrimary) == 0) + return true; // pasywny nic nie robi + double AbsAccS; + // double VelReduced; //o ile km/h może przekroczyć dozwoloną prędkość bez hamowania + bool UpdateOK = false; if (AIControllFlag) - {if (iVehicleCount>=0) //jeśli była podana ilość wagonów - { - if (iDrivigFlags&movePress) //jeśli dociskanie w celu odczepienia - {//3. faza odczepiania. - SetVelocity(2,0); //jazda w ustawionym kierunku z prędkością 2 - if ((mvControlling->MainCtrlPos>0)||(mvOccupied->BrakeSystem==ElectroPneumatic)) //jeśli jazda - { - //WriteLog("Odczepianie w kierunku "+AnsiString(mvOccupied->DirAbsolute)); - TDynamicObject *p=pVehicle; //pojazd do odczepienia, w (pVehicle) siedzi AI - int d; //numer sprzęgu, który sprawdzamy albo odczepiamy - int n=iVehicleCount; //ile wagonów ma zostać - do - {//szukanie pojazdu do odczepienia - d=p->DirectionGet()>0?0:1; //numer sprzęgu od strony czoła składu - //if (p->MoverParameters->Couplers[d].CouplerType==Articulated) //jeśli sprzęg typu wózek (za mało) - if (p->MoverParameters->Couplers[d].CouplingFlag&ctrain_depot) //jeżeli sprzęg zablokowany - //if (p->GetTrack()->) //a nie stoi na torze warsztatowym (ustalić po czym poznać taki tor) - ++n; //to liczymy człony jako jeden - p->MoverParameters->BrakeReleaser(1); //wyluzuj pojazd, aby dało się dopychać - p->MoverParameters->BrakeLevelSet(0); //hamulec na zero, aby nie hamował - if (n) - {//jeśli jeszcze nie koniec - p=p->Prev(); //kolejny w stronę czoła składu (licząc od tyłu), bo dociskamy - if (!p) iVehicleCount=-2,n=0; //nie ma co dalej sprawdzać, doczepianie zakończone - } - } while (n--); - if (p?p->MoverParameters->Couplers[d].CouplingFlag==0:true) - iVehicleCount=-2; //odczepiono, co było do odczepienia - else - if (!p->Dettach(d)) //zwraca maskę bitową połączenia; usuwa własność pojazdów - {//tylko jeśli odepnie - //WriteLog("Odczepiony od strony "); - iVehicleCount=-2; - } //a jak nie, to dociskać dalej - } - if (iVehicleCount>=0) //zmieni się po odczepieniu - if (!mvOccupied->DecLocalBrakeLevel(1)) - {//dociśnij sklad - //WriteLog("Dociskanie"); - //mvOccupied->BrakeReleaser(); //wyluzuj lokomotywę - //Ready=true; //zamiast sprawdzenia odhamowania całego składu - IncSpeed(); //dla (Ready)==false nie ruszy + { // yb: zeby EP nie musial sie bawic z ciesnieniem w PG + // if (mvOccupied->BrakeSystem==ElectroPneumatic) + // mvOccupied->PipePress=0.5; //yB: w SPKS są poprawnie zrobione pozycje + if (mvControlling->SlippingWheels) + { + mvControlling->SandDoseOn(); // piasku! + // Controlling->SlippingWheels=false; //a to tu nie ma sensu, flaga używana w dalszej + // części } - } - if ((mvOccupied->Vel==0.0)&&!(iDrivigFlags&movePress)) - {//2. faza odczepiania: zmień kierunek na przeciwny i dociśnij - //za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach powino zostać wyłączone) - //WriteLog("Zahamowanie składu"); - //while ((mvOccupied->BrakeCtrlPos>3)&&mvOccupied->DecBrakeLevel()); - //while ((mvOccupied->BrakeCtrlPos<3)&&mvOccupied->IncBrakeLevel()); - mvOccupied->BrakeLevelSet(mvOccupied->BrakeSystem==ElectroPneumatic?1:3); - double p=mvOccupied->BrakePressureActual.PipePressureVal; //tu może być 0 albo -1 nawet - if (p<3.9) p=3.9; //TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia sensu 0 oraz -1 w tym miejscu - if (mvOccupied->BrakeSystem==ElectroPneumatic?mvOccupied->BrakePress>2:mvOccupied->PipePressBrakeSystem==ElectroPneumatic) - mvOccupied->BrakeLevelSet(0); //wyłączenie EP, gdy wystarczy (może nie być potrzebne, bo na początku jest) - //WriteLog("Luzowanie lokomotywy i zmiana kierunku"); - mvOccupied->BrakeReleaser(1); //wyluzuj lokomotywę; a ST45? - mvOccupied->DecLocalBrakeLevel(10); //zwolnienie hamulca - iDrivigFlags|=movePress; //następnie będzie dociskanie - DirectionForward(mvOccupied->ActiveDir<0); //zmiana kierunku jazdy na przeciwny (dociskanie) - CheckVehicles(); //od razu zmienić światła (zgasić) - bez tego się nie odczepi - fStopTime=0.0; //nie ma na co czekać z odczepianiem - } - } - } //odczepiania - else //to poniżej jeśli ilość wagonów ujemna - if (iDrivigFlags&movePress) - {//4. faza odczepiania: zwolnij i zmień kierunek - SetVelocity(0,0,stopJoin); //wyłączyć przyspieszanie - if (!DecSpeed()) //jeśli już bardziej wyłączyć się nie da - {//ponowna zmiana kierunku - //WriteLog("Ponowna zmiana kierunku"); - DirectionForward(mvOccupied->ActiveDir<0); //zmiana kierunku jazdy na właściwy - iDrivigFlags&=~movePress; //koniec dociskania - JumpToNextOrder(); //zmieni światła - TableClear(); //skanowanie od nowa - iDrivigFlags&=~moveStartHorn; //bez trąbienia przed ruszeniem - SetVelocity(fShuntVelocity,fShuntVelocity); //ustawienie prędkości jazdy - } - } } - break; - case Shunt: - //na jaką odleglość i z jaką predkością ma podjechać - fMinProximityDist=2.0; fMaxProximityDist=4.0; //[m] - fVelPlus=2.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus=3.0; //margines prędkości powodujący załączenie napędu - if (fVelMinus>0.1*fShuntVelocity) - fVelMinus=0.1*fShuntVelocity; //były problemy z jazdą np. 3km/h podczas ładowania wagonów - break; - case Obey_train: - //na jaka odleglosc i z jaka predkoscia ma podjechac do przeszkody - if (mvOccupied->CategoryFlag&1) //jeśli pociąg + // ABu-160305 testowanie gotowości do jazdy + // Ra: przeniesione z DynObj, skład użytkownika też jest testowany, żeby mu przekazać, że ma + // odhamować + Ready = true; // wstępnie gotowy + fReady = 0.0; // założenie, że odhamowany + fAccGravity = 0.0; // przyspieszenie wynikające z pochylenia + double dy; // składowa styczna grawitacji, w przedziale <0,1> + TDynamicObject *p = pVehicles[0]; // pojazd na czole składu + while (p) + { // sprawdzenie odhamowania wszystkich połączonych pojazdów + if (Ready) // bo jak coś nie odhamowane, to dalej nie ma co sprawdzać + // if (p->MoverParameters->BrakePress>=0.03*p->MoverParameters->MaxBrakePress) + if (p->MoverParameters->BrakePress >= 0.4) // wg UIC określone sztywno na 0.04 + { + Ready = false; // nie gotowy + // Ra: odluźnianie przeładowanych lokomotyw, ciągniętych na zimno - prowizorka... + if (AIControllFlag) // skład jak dotąd był wyluzowany + { + if (mvOccupied->BrakeCtrlPos == 0) // jest pozycja jazdy + if ((p->MoverParameters->PipePress - 5.0) > + -0.1) // jeśli ciśnienie jak dla jazdy + if (p->MoverParameters->Hamulec->GetCRP() > + p->MoverParameters->PipePress + 0.12) // za dużo w zbiorniku + p->MoverParameters->BrakeReleaser(1); // indywidualne luzowanko + if (p->MoverParameters->Power > 0.01) // jeśli ma silnik + if (p->MoverParameters->FuseFlag) // wywalony nadmiarowy + Need_TryAgain = true; // reset jak przy wywaleniu nadmiarowego + } + } + if (fReady < p->MoverParameters->BrakePress) + fReady = p->MoverParameters->BrakePress; // szukanie najbardziej zahamowanego + if ((dy = p->VectorFront().y) != 0.0) // istotne tylko dla pojazdów na pochyleniu + fAccGravity -= p->DirectionGet() * p->MoverParameters->TotalMassxg * + dy; // ciężar razy składowa styczna grawitacji + p = p->Next(); // pojazd podłączony z tyłu (patrząc od czoła) + } + if (iDirection) + fAccGravity /= + iDirection * + fMass; // siłę generują pojazdy na pochyleniu ale działa ona całość składu, więc a=F/m + if (!Ready) // v367: jeśli wg powyższych warunków skład nie jest odhamowany + if (fAccGravity < -0.05) // jeśli ma pod górę na tyle, by się stoczyć + // if (mvOccupied->BrakePress<0.08) //to wystarczy, że zadziałają liniowe (nie ma ich + // jeszcze!!!) + if (fReady < 0.8) // delikatniejszy warunek, obejmuje wszystkie wagony + Ready = true; //żeby uznać za odhamowany + HelpMeFlag = false; + // Winger 020304 + if (AIControllFlag) { - fMinProximityDist=10.0; - fMaxProximityDist=(mvOccupied->Vel>0.0)?20.0:50.0; //[m] jak stanie za daleko, to niech nie dociąga paru metrów - if (iDrivigFlags&moveLate) - {fVelMinus=1.0; //jeśli spóźniony, to gna - fVelPlus=5.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - } - else - {//gdy nie musi się sprężać - fVelMinus=int(0.05*VelDesired); //margines prędkości powodujący załączenie napędu - if (fVelMinus>5.0) fVelMinus=5.0; - else if (fVelMinus<1.0) fVelMinus=1.0; //żeby nie ruszał przy 0.1 - fVelPlus=int(0.5+0.05*VelDesired); //normalnie dopuszczalne przekroczenie to 5% prędkości - if (fVelPlus>5.0) fVelPlus=5.0; //ale nie więcej niż 5km/h - } + if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) + { + if (mvOccupied->ScndPipePress > 4.3) // gdy główna sprężarka bezpiecznie nabije + // ciśnienie + mvControlling->bPantKurek3 = + true; // to można przestawić kurek na zasilanie pantografów z głównej pneumatyki + fVoltage = + 0.5 * (fVoltage + + fabs(mvControlling->RunningTraction.TractionVoltage)); // uśrednione napięcie + // sieci: przy spadku + // poniżej wartości + // minimalnej opóźnić + // rozruch o losowy + // czas + if (fVoltage < mvControlling->EnginePowerSource.CollectorParameters + .MinV) // gdy rozłączenie WS z powodu niskiego napięcia + if (fActionTime >= 0) // jeśli czas oczekiwania nie został ustawiony + fActionTime = + -2 - random(10); // losowy czas oczekiwania przed ponownym załączeniem jazdy + } + if (mvOccupied->Vel > 0.0) + { // jeżeli jedzie + if (iDrivigFlags & moveDoorOpened) // jeśli drzwi otwarte + if (mvOccupied->Vel > 1.0) // nie zamykać drzwi przy drganiach, bo zatrzymanie na W4 + // akceptuje niewielkie prędkości + Doors(false); + // przy prowadzeniu samochodu trzeba każdą oś odsuwać oddzielnie, inaczej kicha wychodzi + if (mvOccupied->CategoryFlag & 2) // jeśli samochód + // if (fabs(mvOccupied->OffsetTrackH)Dim.W) //Ra: szerokość drogi tu + // powinna być? + if (!mvOccupied->ChangeOffsetH(-0.01 * mvOccupied->Vel * dt)) // ruch w poprzek + // drogi + mvOccupied->ChangeOffsetH(0.01 * mvOccupied->Vel * + dt); // Ra: co to miało być, to nie wiem + if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) + { + if ((fOverhead2 >= 0.0) || iOverheadZero) + { // jeśli jazda bezprądowa albo z opuszczonym pantografem + while (DecSpeed(true)) + ; // zerowanie napędu + } + if ((fOverhead2 > 0.0) || iOverheadDown) + { // jazda z opuszczonymi pantografami + mvControlling->PantFront(false); + mvControlling->PantRear(false); + } + else + { // jeśli nie trzeba opuszczać pantografów + if (iDirection >= 0) // jak jedzie w kierunku sprzęgu 0 + mvControlling->PantRear(true); // jazda na tylnym + else + mvControlling->PantFront(true); + } + if (mvOccupied->Vel > 10) // opuszczenie przedniego po rozpędzeniu się + { + if (mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > + 1) // o ile jest więcej niż jeden + if (iDirection >= 0) // jak jedzie w kierunku sprzęgu 0 + { // poczekać na podniesienie tylnego + if (mvControlling->PantRearVolt != + 0.0) // czy jest napięcie zasilające na tylnym? + mvControlling->PantFront(false); // opuszcza od sprzęgu 0 + } + else + { // poczekać na podniesienie przedniego + if (mvControlling->PantFrontVolt != + 0.0) // czy jest napięcie zasilające na przednim? + mvControlling->PantRear(false); // opuszcza od sprzęgu 1 + } + } + } + } + if (iDrivigFlags & moveStartHornNow) // czy ma zatrąbić przed ruszeniem? + if (Ready) // gotów do jazdy + if (iEngineActive) // jeszcze się odpalić musi + if (fStopTime >= 0) // i nie musi czekać + { // uruchomienie trąbienia + fWarningDuration = 0.3; // czas trąbienia + // if (AIControllFlag) //jak siedzi krasnoludek, to włączy trąbienie + mvOccupied->WarningSignal = + pVehicle->iHornWarning; // wysokość tonu (2=wysoki) + iDrivigFlags |= moveStartHornDone; // nie trąbić aż do ruszenia + iDrivigFlags &= ~moveStartHornNow; // trąbienie zostało zorganizowane + } } - else //samochod (sokista też) + ElapsedTime += dt; + WaitingTime += dt; + fBrakeTime -= + dt; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca + fStopTime += dt; // zliczanie czasu postoju, nie ruszy dopóki ujemne + fActionTime += dt; // czas używany przy regulacji prędkości i zamykaniu drzwi + if (WriteLogFlag) { - fMinProximityDist=7.0; fMaxProximityDist=10.0; //[m] - fVelPlus=10.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus=2.0; //margines prędkości powodujący załączenie napędu + if (LastUpdatedTime > deltalog) + { // zapis do pliku DAT + PhysicsLog(); + if (fabs(mvOccupied->V) > 0.1) // Ra: [m/s] + deltalog = 0.05; // 0.2; + else + deltalog = 0.05; // 1.0; + LastUpdatedTime = 0.0; + } + else + LastUpdatedTime = LastUpdatedTime + dt; } - //VelReduced=4; //[km/h] - break; - default: - fMinProximityDist=0.01; fMaxProximityDist=2.0; //[m] - fVelPlus=2.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus=5.0; //margines prędkości powodujący załączenie napędu - } //switch - switch (OrderList[OrderPos]) - {//co robi maszynista - case Prepare_engine: //odpala silnik - //if (AIControllFlag) - if (PrepareEngine()) //dla użytkownika tylko sprawdza, czy uruchomił - {//gotowy do drogi? - SetDriverPsyche(); - //OrderList[OrderPos]:=Shunt; //Ra: to nie może tak być, bo scenerie robią Jump_to_first_order i przechodzi w manewrowy - JumpToNextOrder(); //w następnym jest Shunt albo Obey_train, moze też być Change_direction, Connect albo Disconnect - //if OrderList[OrderPos]<>Wait_for_Orders) - // if BrakeSystem=Pneumatic) //napelnianie uderzeniowe na wstepie - // if BrakeSubsystem=Oerlikon) - // if (BrakeCtrlPos=0)) - // DecBrakeLevel; - } - break; - case Release_engine: - if (ReleaseEngine()) //zdana maszyna? - JumpToNextOrder(); - break; - case Jump_to_first_order: - if (OrderPos>1) - OrderPos=1; //w zerowym zawsze jest czekanie - else - ++OrderPos; + // Ra: skanowanie również dla prowadzonego ręcznie, aby podpowiedzieć prędkość + if ((LastReactionTime > Min0R(ReactionTime, 2.0))) + { + // Ra: nie wiem czemu ReactionTime potrafi dostać 12 sekund, to jest przegięcie, bo przeżyna + // STÓJ + // yB: otóż jest to jedna trzecia czasu napełniania na towarowym; może się przydać przy + // wdrażaniu hamowania, żeby nie ruszało kranem jak głupie + // Ra: ale nie może się budzić co pół minuty, bo przeżyna semafory + // Ra: trzeba by tak: + // 1. Ustalić istotną odległość zainteresowania (np. 3×droga hamowania z V.max). + fBrakeDist = fDriverBraking * mvOccupied->Vel * + (40.0 + mvOccupied->Vel); // przybliżona droga hamowania + // dla hamowania -0.2 [m/ss] droga wynosi 0.389*Vel*Vel [km/h], czyli 600m dla 40km/h, 3.8km + // dla 100km/h i 9.8km dla 160km/h + // dla hamowania -0.4 [m/ss] droga wynosi 0.096*Vel*Vel [km/h], czyli 150m dla 40km/h, 1.0km + // dla 100km/h i 2.5km dla 160km/h + // ogólnie droga hamowania przy stałym opóźnieniu to Vel*Vel/(3.6*3.6*a) [m] + // fBrakeDist powinno być wyznaczane dla danego składu za pomocą sieci neuronowych, w + // zależności od prędkości i siły (ciśnienia) hamowania + // następnie w drugą stronę, z drogi hamowania i chwilowej prędkości powinno być wyznaczane + // zalecane ciśnienie + if (fMass > 1000000.0) + fBrakeDist *= 2.0; // korekta dla ciężkich, bo przeżynają - da to coś? + if (mvOccupied->BrakeDelayFlag == bdelay_G) + fBrakeDist = + fBrakeDist + + 2 * + mvOccupied + ->Vel; // dla nastawienia G koniecznie należy wydłużyć drogę na czas reakcji + // double scanmax=(mvOccupied->Vel>0.0)?3*fDriverDist+fBrakeDist:10.0*fDriverDist; + double scanmax = (mvOccupied->Vel > 5.0) ? + 400 + fBrakeDist : + 50.0 * fDriverDist; // 1000m dla stojących pociągów; Ra 2015-01: przy + // dłuższej drodze skanowania AI jeździ spokojniej + // 2. Sprawdzić, czy tabelka pokrywa założony odcinek (nie musi, jeśli jest STOP). + // 3. Sprawdzić, czy trajektoria ruchu przechodzi przez zwrotnice - jeśli tak, to sprawdzić, + // czy stan się nie zmienił. + // 4. Ewentualnie uzupełnić tabelkę informacjami o sygnałach i ograniczeniach, jeśli się + // "zużyła". + TableCheck(scanmax); // wypełnianie tabelki i aktualizacja odległości + // 5. Sprawdzić stany sygnalizacji zapisanej w tabelce, wyznaczyć prędkości. + // 6. Z tabelki wyznaczyć krytyczną odległość i prędkość (najmniejsze przyspieszenie). + // 7. Jeśli jest inny pojazd z przodu, ewentualnie skorygować odległość i prędkość. + // 8. Ustalić częstotliwość świadomości AI (zatrzymanie precyzyjne - częściej, brak atrakcji + // - rzadziej). + if (AIControllFlag) + { // tu bedzie logika sterowania + if (mvOccupied->CommandIn.Command != "") + if (!mvOccupied->RunInternalCommand()) // rozpoznaj komende bo lokomotywa jej nie + // rozpoznaje + RecognizeCommand(); // samo czyta komendę wstawioną do pojazdu? + if (mvOccupied->SecuritySystem.Status > 1) // jak zadziałało CA/SHP + if (!mvOccupied->SecuritySystemReset()) // to skasuj + // if + // ((TestFlag(mvOccupied->SecuritySystem.Status,s_ebrake))&&(mvOccupied->BrakeCtrlPos==0)&&(AccDesired>0.0)) + if ((TestFlag(mvOccupied->SecuritySystem.Status, s_SHPebrake) || + TestFlag(mvOccupied->SecuritySystem.Status, s_CAebrake)) && + (mvOccupied->BrakeCtrlPos == 0) && (AccDesired > 0.0)) + mvOccupied->BrakeLevelSet( + 0); //!!! hm, może po prostu normalnie sterować hamulcem? + } + switch (OrderList[OrderPos]) + { // ustalenie prędkości przy doczepianiu i odczepianiu, dystansów w pozostałych przypadkach + case Connect: // podłączanie do składu + if (iDrivigFlags & moveConnect) + { // jeśli stanął już blisko, unikając zderzenia i można próbować podłączyć + fMinProximityDist = -0.01; + fMaxProximityDist = 0.0; //[m] dojechać maksymalnie + fVelPlus = 0.5; // dopuszczalne przekroczenie prędkości na ograniczeniu bez + // hamowania + fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu + if (AIControllFlag) + { // to robi tylko AI, wersję dla człowieka trzeba dopiero zrobić + // sprzęgi sprawdzamy w pierwszej kolejności, bo jak połączony, to koniec + bool ok; // true gdy się podłączy (uzyskany sprzęg będzie zgodny z żądanym) + if (pVehicles[0]->DirectionGet() > 0) // jeśli sprzęg 0 + { // sprzęg 0 - próba podczepienia + if (pVehicles[0]->MoverParameters->Couplers[0].Connected) // jeśli jest coś + // wykryte (a + // chyba jest, + // nie?) + if (pVehicles[0]->MoverParameters->Attach( + 0, 2, pVehicles[0]->MoverParameters->Couplers[0].Connected, + iCoupler)) + { + // pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); + // pVehicles[0]->dsbCouplerAttach->Play(0,0,0); + } + // WriteLog("CoupleDist[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CoupleDist)+", + // Connected[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag)); + ok = (pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag == + iCoupler); // udało się? (mogło częściowo) + } + else // if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1 + { // sprzęg 1 - próba podczepienia + if (pVehicles[0]->MoverParameters->Couplers[1].Connected) // jeśli jest coś + // wykryte (a + // chyba jest, + // nie?) + if (pVehicles[0]->MoverParameters->Attach( + 1, 2, pVehicles[0]->MoverParameters->Couplers[1].Connected, + iCoupler)) + { + // pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); + // pVehicles[0]->dsbCouplerAttach->Play(0,0,0); + } + // WriteLog("CoupleDist[1]="+AnsiString(Controlling->Couplers[1].CoupleDist)+", + // Connected[0]="+AnsiString(Controlling->Couplers[1].CouplingFlag)); + ok = (pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag == + iCoupler); // udało się? (mogło częściowo) + } + if (ok) + { // jeżeli został podłączony + iCoupler = 0; // dalsza jazda manewrowa już bez łączenia + iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania + SetVelocity(0, 0, stopJoin); // wyłączyć przyspieszanie + CheckVehicles(); // sprawdzić światła nowego składu + JumpToNextOrder(); // wykonanie następnej komendy + } + else + SetVelocity(2.0, 0.0); // jazda w ustawionym kierunku z prędkością 2 (18s) + } // if (AIControllFlag) //koniec zblokowania, bo była zmienna lokalna + /* //Ra 2014-02: lepiej tam, bo jak tam się odźwieży skład, to tu pVehicles[0] + będzie czymś innym + else + {//jeśli człowiek ma podłączyć, to czekamy na zmianę stanu sprzęgów na końcach + dotychczasowego składu + bool ok; //true gdy się podłączy (uzyskany sprzęg będzie zgodny z żądanym) + if (pVehicles[0]->DirectionGet()>0) //jeśli sprzęg 0 + ok=(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag>0); + //==iCoupler); //udało się? (mogło częściowo) + else //if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1 + ok=(pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag>0); + //==iCoupler); //udało się? (mogło częściowo) + if (ok) + {//jeżeli został podłączony + iDrivigFlags&=~moveConnect; //zdjęcie flagi doczepiania + JumpToNextOrder(); //wykonanie następnej komendy + } + } + */ + } + else + { // jak daleko, to jazda jak dla Shunt na kolizję + fMinProximityDist = 0.0; + fMaxProximityDist = 5.0; //[m] w takim przedziale odległości powinien stanąć + fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez + // hamowania + fVelMinus = 1.0; // margines prędkości powodujący załączenie napędu + // VelReduced=5; //[km/h] + // if (mvOccupied->Vel<0.5) //jeśli już prawie stanął + if (pVehicles[0]->fTrackBlock <= + 20.0) // przy zderzeniu fTrackBlock nie jest miarodajne + iDrivigFlags |= + moveConnect; // początek podczepiania, z wyłączeniem sprawdzania fTrackBlock + } + break; + case Disconnect: // 20.07.03 - manewrowanie wagonami + fMinProximityDist = 1.0; + fMaxProximityDist = 10.0; //[m] + fVelPlus = 1.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu + if (AIControllFlag) + { + if (iVehicleCount >= 0) // jeśli była podana ilość wagonów + { + if (iDrivigFlags & movePress) // jeśli dociskanie w celu odczepienia + { // 3. faza odczepiania. + SetVelocity(2, 0); // jazda w ustawionym kierunku z prędkością 2 + if ((mvControlling->MainCtrlPos > 0) || + (mvOccupied->BrakeSystem == ElectroPneumatic)) // jeśli jazda + { + // WriteLog("Odczepianie w kierunku + // "+AnsiString(mvOccupied->DirAbsolute)); + TDynamicObject *p = + pVehicle; // pojazd do odczepienia, w (pVehicle) siedzi AI + int d; // numer sprzęgu, który sprawdzamy albo odczepiamy + int n = iVehicleCount; // ile wagonów ma zostać + do + { // szukanie pojazdu do odczepienia + d = p->DirectionGet() > 0 ? + 0 : + 1; // numer sprzęgu od strony czoła składu + // if (p->MoverParameters->Couplers[d].CouplerType==Articulated) + // //jeśli sprzęg typu wózek (za mało) + if (p->MoverParameters->Couplers[d].CouplingFlag & + ctrain_depot) // jeżeli sprzęg zablokowany + // if (p->GetTrack()->) //a nie stoi na torze warsztatowym + // (ustalić po czym poznać taki tor) + ++n; // to liczymy człony jako jeden + p->MoverParameters->BrakeReleaser( + 1); // wyluzuj pojazd, aby dało się dopychać + p->MoverParameters->BrakeLevelSet( + 0); // hamulec na zero, aby nie hamował + if (n) + { // jeśli jeszcze nie koniec + p = p->Prev(); // kolejny w stronę czoła składu (licząc od + // tyłu), bo dociskamy + if (!p) + iVehicleCount = -2, + n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone + } + } while (n--); + if (p ? p->MoverParameters->Couplers[d].CouplingFlag == 0 : true) + iVehicleCount = -2; // odczepiono, co było do odczepienia + else if (!p->Dettach(d)) // zwraca maskę bitową połączenia; usuwa + // własność pojazdów + { // tylko jeśli odepnie + // WriteLog("Odczepiony od strony "); + iVehicleCount = -2; + } // a jak nie, to dociskać dalej + } + if (iVehicleCount >= 0) // zmieni się po odczepieniu + if (!mvOccupied->DecLocalBrakeLevel(1)) + { // dociśnij sklad + // WriteLog("Dociskanie"); + // mvOccupied->BrakeReleaser(); //wyluzuj lokomotywę + // Ready=true; //zamiast sprawdzenia odhamowania całego składu + IncSpeed(); // dla (Ready)==false nie ruszy + } + } + if ((mvOccupied->Vel == 0.0) && !(iDrivigFlags & movePress)) + { // 2. faza odczepiania: zmień kierunek na przeciwny i dociśnij + // za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach + // powino zostać wyłączone) + // WriteLog("Zahamowanie składu"); + // while ((mvOccupied->BrakeCtrlPos>3)&&mvOccupied->DecBrakeLevel()); + // while ((mvOccupied->BrakeCtrlPos<3)&&mvOccupied->IncBrakeLevel()); + mvOccupied->BrakeLevelSet(mvOccupied->BrakeSystem == ElectroPneumatic ? 1 : + 3); + double p = mvOccupied->BrakePressureActual + .PipePressureVal; // tu może być 0 albo -1 nawet + if (p < 3.9) + p = 3.9; // TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia + // sensu 0 oraz -1 w tym miejscu + if (mvOccupied->BrakeSystem == ElectroPneumatic ? + mvOccupied->BrakePress > 2 : + mvOccupied->PipePress < p + 0.1) + { // jeśli w miarę został zahamowany (ciśnienie mniejsze niż podane na + // pozycji 3, zwyle 0.37) + if (mvOccupied->BrakeSystem == ElectroPneumatic) + mvOccupied->BrakeLevelSet(0); // wyłączenie EP, gdy wystarczy (może + // nie być potrzebne, bo na początku + // jest) + // WriteLog("Luzowanie lokomotywy i zmiana kierunku"); + mvOccupied->BrakeReleaser(1); // wyluzuj lokomotywę; a ST45? + mvOccupied->DecLocalBrakeLevel(10); // zwolnienie hamulca + iDrivigFlags |= movePress; // następnie będzie dociskanie + DirectionForward(mvOccupied->ActiveDir < + 0); // zmiana kierunku jazdy na przeciwny (dociskanie) + CheckVehicles(); // od razu zmienić światła (zgasić) - bez tego się nie + // odczepi + fStopTime = 0.0; // nie ma na co czekać z odczepianiem + } + } + } // odczepiania + else // to poniżej jeśli ilość wagonów ujemna + if (iDrivigFlags & movePress) + { // 4. faza odczepiania: zwolnij i zmień kierunek + SetVelocity(0, 0, stopJoin); // wyłączyć przyspieszanie + if (!DecSpeed()) // jeśli już bardziej wyłączyć się nie da + { // ponowna zmiana kierunku + // WriteLog("Ponowna zmiana kierunku"); + DirectionForward(mvOccupied->ActiveDir < + 0); // zmiana kierunku jazdy na właściwy + iDrivigFlags &= ~movePress; // koniec dociskania + JumpToNextOrder(); // zmieni światła + TableClear(); // skanowanie od nowa + iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed ruszeniem + SetVelocity(fShuntVelocity, fShuntVelocity); // ustawienie prędkości jazdy + } + } + } + break; + case Shunt: + // na jaką odleglość i z jaką predkością ma podjechać + fMinProximityDist = 2.0; + fMaxProximityDist = 4.0; //[m] + fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelMinus = 3.0; // margines prędkości powodujący załączenie napędu + if (fVelMinus > 0.1 * fShuntVelocity) + fVelMinus = + 0.1 * + fShuntVelocity; // były problemy z jazdą np. 3km/h podczas ładowania wagonów + break; + case Obey_train: + // na jaka odleglosc i z jaka predkoscia ma podjechac do przeszkody + if (mvOccupied->CategoryFlag & 1) // jeśli pociąg + { + fMinProximityDist = 10.0; + fMaxProximityDist = + (mvOccupied->Vel > 0.0) ? + 20.0 : + 50.0; //[m] jak stanie za daleko, to niech nie dociąga paru metrów + if (iDrivigFlags & moveLate) + { + fVelMinus = 1.0; // jeśli spóźniony, to gna + fVelPlus = + 5.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + } + else + { // gdy nie musi się sprężać + fVelMinus = + int(0.05 * VelDesired); // margines prędkości powodujący załączenie napędu + if (fVelMinus > 5.0) + fVelMinus = 5.0; + else if (fVelMinus < 1.0) + fVelMinus = 1.0; //żeby nie ruszał przy 0.1 + fVelPlus = int( + 0.5 + + 0.05 * VelDesired); // normalnie dopuszczalne przekroczenie to 5% prędkości + if (fVelPlus > 5.0) + fVelPlus = 5.0; // ale nie więcej niż 5km/h + } + } + else // samochod (sokista też) + { + fMinProximityDist = 7.0; + fMaxProximityDist = 10.0; //[m] + fVelPlus = + 10.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelMinus = 2.0; // margines prędkości powodujący załączenie napędu + } + // VelReduced=4; //[km/h] + break; + default: + fMinProximityDist = 0.01; + fMaxProximityDist = 2.0; //[m] + fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelMinus = 5.0; // margines prędkości powodujący załączenie napędu + } // switch + switch (OrderList[OrderPos]) + { // co robi maszynista + case Prepare_engine: // odpala silnik + // if (AIControllFlag) + if (PrepareEngine()) // dla użytkownika tylko sprawdza, czy uruchomił + { // gotowy do drogi? + SetDriverPsyche(); + // OrderList[OrderPos]:=Shunt; //Ra: to nie może tak być, bo scenerie robią + // Jump_to_first_order i przechodzi w manewrowy + JumpToNextOrder(); // w następnym jest Shunt albo Obey_train, moze też być + // Change_direction, Connect albo Disconnect + // if OrderList[OrderPos]<>Wait_for_Orders) + // if BrakeSystem=Pneumatic) //napelnianie uderzeniowe na wstepie + // if BrakeSubsystem=Oerlikon) + // if (BrakeCtrlPos=0)) + // DecBrakeLevel; + } + break; + case Release_engine: + if (ReleaseEngine()) // zdana maszyna? + JumpToNextOrder(); + break; + case Jump_to_first_order: + if (OrderPos > 1) + OrderPos = 1; // w zerowym zawsze jest czekanie + else + ++OrderPos; #if LOGORDERS - WriteLog("--> Jump_to_first_order"); - OrdersDump(); + WriteLog("--> Jump_to_first_order"); + OrdersDump(); #endif - break; - case Wait_for_orders: //jeśli czeka, też ma skanować, żeby odpalić się od semafora -/* - if ((mvOccupied->ActiveDir!=0)) - {//jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy - VelDesired=fVelMax; //wstępnie prędkość maksymalna dla pojazdu(-ów), będzie następnie ograniczana - SetDriverPsyche(); //ustawia AccPreferred (potrzebne tu?) - //Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci - AccDesired=AccPreferred; //AccPreferred wynika z osobowości mechanika - VelNext=VelDesired; //maksymalna prędkość wynikająca z innych czynników niż trajektoria ruchu - ActualProximityDist=scanmax; //funkcja Update() może pozostawić wartości bez zmian - //hm, kiedyś semafory wysyłały SetVelocity albo ShuntVelocity i ustawły tak VelSignal - a teraz jak to zrobić? - TCommandType comm=TableUpdate(mvOccupied->Vel,VelDesired,ActualProximityDist,VelNext,AccDesired); //szukanie optymalnych wartości - } -*/ - //break; - case Shunt: - case Obey_train: - case Connect: - case Disconnect: - case Change_direction: //tryby wymagające jazdy - case Change_direction|Shunt: //zmiana kierunku podczas manewrów - case Change_direction|Connect: //zmiana kierunku podczas podłączania - if (OrderList[OrderPos]!=Obey_train) //spokojne manewry + break; + case Wait_for_orders: // jeśli czeka, też ma skanować, żeby odpalić się od semafora + /* + if ((mvOccupied->ActiveDir!=0)) + {//jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy + VelDesired=fVelMax; //wstępnie prędkość maksymalna dla pojazdu(-ów), będzie następnie + ograniczana + SetDriverPsyche(); //ustawia AccPreferred (potrzebne tu?) + //Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci + AccDesired=AccPreferred; //AccPreferred wynika z osobowości mechanika + VelNext=VelDesired; //maksymalna prędkość wynikająca z innych czynników niż + trajektoria ruchu + ActualProximityDist=scanmax; //funkcja Update() może pozostawić wartości bez zmian + //hm, kiedyś semafory wysyłały SetVelocity albo ShuntVelocity i ustawły tak VelSignal + - a teraz jak to zrobić? + TCommandType + comm=TableUpdate(mvOccupied->Vel,VelDesired,ActualProximityDist,VelNext,AccDesired); + //szukanie optymalnych wartości + } + */ + // break; + case Shunt: + case Obey_train: + case Connect: + case Disconnect: + case Change_direction: // tryby wymagające jazdy + case Change_direction | Shunt: // zmiana kierunku podczas manewrów + case Change_direction | Connect: // zmiana kierunku podczas podłączania + if (OrderList[OrderPos] != Obey_train) // spokojne manewry + { + VelSignal = Min0R(VelSignal, 40); // jeśli manewry, to ograniczamy prędkość + if (AIControllFlag) + { // to poniżej tylko dla AI + if (iVehicleCount >= 0) // jeśli jest co odczepić + if (!(iDrivigFlags & movePress)) + if (mvOccupied->Vel > 0.0) + if (!iCoupler) // jeśli nie ma wcześniej potrzeby podczepienia + { + SetVelocity(0, 0, stopJoin); // 1. faza odczepiania: zatrzymanie + // WriteLog("Zatrzymanie w celu odczepienia"); + } + } + } + else + SetDriverPsyche(); // Ra: było w PrepareEngine(), potrzebne tu? + // no albo przypisujemy -WaitingExpireTime, albo porównujemy z WaitingExpireTime + // if + // ((VelSignal==0.0)&&(WaitingTime>WaitingExpireTime)&&(mvOccupied->RunningTrack.Velmax!=0.0)) + if (OrderList[OrderPos] & + (Shunt | Obey_train | Connect)) // odjechać sam może tylko jeśli jest w trybie jazdy + { // automatyczne ruszanie po odstaniu albo spod SBL + if ((VelSignal == 0.0) && (WaitingTime > 0.0) && + (mvOccupied->RunningTrack.Velmax != 0.0)) + { // jeśli stoi, a upłynął czas oczekiwania i tor ma niezerową prędkość + /* + if (WriteLogFlag) + { + append(AIlogFile); + writeln(AILogFile,ElapsedTime:5:2,": ",Name," V=0 waiting time expired! + (",WaitingTime:4:1,")"); + close(AILogFile); + } + */ + if ((OrderList[OrderPos] & (Obey_train | Shunt)) ? + (iDrivigFlags & moveStopHere) : + false) + WaitingTime = -WaitingExpireTime; // zakaz ruszania z miejsca bez otrzymania + // wolnej drogi + else if (mvOccupied->CategoryFlag & 1) + { // jeśli pociąg + if (AIControllFlag) + { + PrepareEngine(); // zmieni ustawiony kierunek + SetVelocity(20, 20); // jak się nastał, to niech jedzie 20km/h + WaitingTime = 0.0; + fWarningDuration = 1.5; // a zatrąbić trochę + mvOccupied->WarningSignal = 1; + } + else + SetVelocity(20, 20); // użytkownikowi zezwalamy jechać + } + else + { // samochód ma stać, aż dostanie odjazd, chyba że stoi przez kolizję + if (eStopReason == stopBlock) + if (pVehicles[0]->fTrackBlock > fDriverDist) + if (AIControllFlag) + { + PrepareEngine(); // zmieni ustawiony kierunek + SetVelocity(-1, -1); // jak się nastał, to niech jedzie + WaitingTime = 0.0; + } + else + SetVelocity(-1, + -1); // użytkownikowi pozwalamy jechać (samochodem?) + } + } + else if ((VelSignal == 0.0) && (VelNext > 0.0) && (mvOccupied->Vel < 1.0)) + if (iCoupler ? true : (iDrivigFlags & moveStopHere) == 0) // Ra: tu jest coś nie + // tak, bo bez tego + // warunku ruszało w + // manewrowym !!!! + SetVelocity(VelNext, VelNext, stopSem); // omijanie SBL + } // koniec samoistnego odjeżdżania + if (AIControllFlag) + if ((HelpMeFlag) || (mvControlling->DamageFlag > 0)) + { + HelpMeFlag = false; + /* + if (WriteLogFlag) + with Controlling do + { + append(AIlogFile); + writeln(AILogFile,ElapsedTime:5:2,": ",Name," HelpMe! + (",DamageFlag,")"); + close(AILogFile); + } + */ + } + if (AIControllFlag) + if (OrderList[OrderPos] & + Change_direction) // może być zmieszane z jeszcze jakąś komendą + { // sprobuj zmienic kierunek + SetVelocity(0, 0, stopDir); // najpierw trzeba się zatrzymać + if (mvOccupied->Vel < 0.1) + { // jeśli się zatrzymał, to zmieniamy kierunek jazdy, a nawet kabinę/człon + Activation(); // ustawienie zadanego wcześniej kierunku i ewentualne + // przemieszczenie AI + PrepareEngine(); + JumpToNextOrder(); // następnie robimy, co jest do zrobienia (Shunt albo + // Obey_train) + if (OrderList[OrderPos] & (Shunt | Connect)) // jeśli dalej mamy manewry + if ((iDrivigFlags & moveStopHere) == 0) // o ile nie stać w miejscu + { // jechać od razu w przeciwną stronę i nie trąbić z tego tytułu + iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed ruszeniem + SetVelocity(fShuntVelocity, fShuntVelocity); // to od razu jedziemy + } + // iDrivigFlags|=moveStartHorn; //a później już można trąbić + /* + if (WriteLogFlag) + { + append(AIlogFile); + writeln(AILogFile,ElapsedTime:5:2,": ",Name," Direction changed!"); + close(AILogFile); + } + */ + } + // else + // VelSignal:=0.0; //na wszelki wypadek niech zahamuje + } // Change_direction (tylko dla AI) + // ustalanie zadanej predkosci + if (AIControllFlag) // jeśli prowadzi AI + if (!iEngineActive) // jeśli silnik nie odpalony, to próbować naprawić + if (OrderList[OrderPos] & (Change_direction | Connect | Disconnect | Shunt | + Obey_train)) // jeśli coś ma robić + PrepareEngine(); // to niech odpala do skutku + if (iDrivigFlags & moveActive) // jeśli może skanować sygnały i reagować na komendy + { // jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy + // Ra: tu by jeszcze trzeba było wstawić uzależnienie (VelDesired) od odległości od + // przeszkody + // no chyba żeby to uwzgldnić już w (ActualProximityDist) + VelDesired = fVelMax; // wstępnie prędkość maksymalna dla pojazdu(-ów), będzie + // następnie ograniczana + if (TrainParams) // jeśli ma rozkład + if (TrainParams->TTVmax > 0.0) // i ograniczenie w rozkładzie + VelDesired = Min0R(VelDesired, + TrainParams->TTVmax); // to nie przekraczać rozkladowej + SetDriverPsyche(); // ustawia AccPreferred (potrzebne tu?) + // Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci + AccDesired = AccPreferred; // AccPreferred wynika z osobowości mechanika + VelNext = VelDesired; // maksymalna prędkość wynikająca z innych czynników niż + // trajektoria ruchu + ActualProximityDist = scanmax; // funkcja Update() może pozostawić wartości bez + // zmian + // hm, kiedyś semafory wysyłały SetVelocity albo ShuntVelocity i ustawły tak + // VelSignal - a teraz jak to zrobić? + TCommandType comm = TableUpdate(VelDesired, ActualProximityDist, VelNext, + AccDesired); // szukanie optymalnych wartości + // if (VelSignal!=VelDesired) //jeżeli prędkość zalecana jest inna (ale tryb też + // może być inny) + switch (comm) + { // ustawienie VelSignal - trochę proteza = do przemyślenia + case cm_Ready: // W4 zezwolił na jazdę + TableCheck( + scanmax); // ewentualne doskanowanie trasy za W4, który zezwolił na jazdę + TableUpdate(VelDesired, ActualProximityDist, VelNext, + AccDesired); // aktualizacja po skanowaniu + // if (comm!=cm_SetVelocity) //jeśli dalej jest kolejny W4, to ma zwrócić + // cm_SetVelocity + if (VelNext == 0.0) + break; // ale jak coś z przodu zamyka, to ma stać + if (iDrivigFlags & moveStopCloser) + VelSignal = VelDesired; // niech jedzie, jak W4 puściło - nie, ma czekać na + // sygnał z sygnalizatora! + case cm_SetVelocity: // od wersji 357 semafor nie budzi wyłączonej lokomotywy + if (!(OrderList[OrderPos] & + ~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders + if (fabs(VelSignal) >= + 1.0) // 0.1 nie wysyła się do samochodow, bo potem nie ruszą + PutCommand("SetVelocity", VelSignal, VelNext, + NULL); // komenda robi dodatkowe operacje + break; + case cm_ShuntVelocity: // od wersji 357 Tm nie budzi wyłączonej lokomotywy + if (!(OrderList[OrderPos] & + ~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders + PutCommand("ShuntVelocity", VelSignal, VelNext, NULL); + else if (iCoupler) // jeśli jedzie w celu połączenia + SetVelocity(VelSignal, VelNext); + break; + case cm_Command: // komenda z komórki + if (!(OrderList[OrderPos] & + ~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders + if (mvOccupied->Vel < 0.1) // dopiero jak stanie + // iDrivigFlags|=moveStopHere moveStopCloser) //chyba że stanął za daleko + // (SU46 w WK staje za daleko) + { + PutCommand(eSignNext->CommandGet(), eSignNext->ValueGet(1), + eSignNext->ValueGet(2), NULL); + eSignNext->StopCommandSent(); // się wykonało już + } + break; + } + if (VelNext == 0.0) + if (!(OrderList[OrderPos] & + ~(Shunt | Connect))) // jedzie w Shunt albo Connect, albo Wait_for_orders + { // jeżeli wolnej drogi nie ma, a jest w trybie manewrowym albo oczekiwania + // if + // ((OrderList[OrderPos]&Connect)?pVehicles[0]->fTrackBlock>ActualProximityDist:true) + // //pomiar odległości nie działa dobrze? + // w trybie Connect skanować do tyłu tylko jeśli przed kolejnym sygnałem nie + // ma taboru do podłączenia + // Ra 2F1H: z tym (fTrackBlock) to nie jest najlepszy pomysł, bo lepiej by + // było porównać z odległością od sygnalizatora z przodu + if ((OrderList[OrderPos] | Connect) ? pVehicles[0]->fTrackBlock > 2000 : + true) + if ((comm = BackwardScan()) != cm_Unknown) // jeśli w drugą można jechać + { // należy sprawdzać odległość od znalezionego sygnalizatora, + // aby w przypadku prędkości 0.1 wyciągnąć najpierw skład za + // sygnalizator + // i dopiero wtedy zmienić kierunek jazdy, oczekując podania + // prędkości >0.5 + if (comm == cm_Command) // jeśli komenda Shunt + iDrivigFlags |= + moveStopHere; // to ją odbierz bez przemieszczania się (np. + // odczep wagony po dopchnięciu do końca toru) + iDirectionOrder = -iDirection; // zmiana kierunku jazdy + OrderList[OrderPos] = TOrders(OrderList[OrderPos] | + Change_direction); // zmiana kierunku + // bez psucia + // kolejnych komend + } + } + double vel = mvOccupied->Vel; // prędkość w kierunku jazdy + if (iDirection * mvOccupied->V < 0) + vel = -vel; // ujemna, gdy jedzie w przeciwną stronę, niż powinien + if (VelDesired < 0.0) + VelDesired = fVelMax; // bo VelDesired<0 oznacza prędkość maksymalną + // Ra: jazda na widoczność + if (pVehicles[0]->fTrackBlock < 1000.0) // przy 300m stał z zapamiętaną kolizją + { // Ra 2F3F: przy jeździe pociągowej nie powinien dojeżdżać do poprzedzającego + // składu + if ((mvOccupied->CategoryFlag & 1) ? + ((OrderCurrentGet() & (Connect | Obey_train)) == Obey_train) : + false) // jeśli jesteśmy pociągiem a jazda pociągowa i nie ściąganie ze + // szlaku + { + pVehicles[0]->ABuScanObjects(pVehicles[0]->DirectionGet(), + 1000.0); // skanowanie sprawdzające + // Ra 2F3F: i jest problem, jak droga za semaforem kieruje na jakiś pojazd + // (np. w Skwarkach na ET22) + if (pVehicles[0]->fTrackBlock < 1000.0) // i jeśli nadal coś jest + if (VelNext != 0.0) // a następny sygnał zezwala na jazdę + if (pVehicles[0]->fTrackBlock < + ActualProximityDist) // i jest bliżej (tu by trzeba było wstawić + // odległość do semafora, z pominięciem SBL + VelDesired = 0.0; // to stoimy + } + else + pVehicles[0]->ABuScanObjects(pVehicles[0]->DirectionGet(), + 300.0); // skanowanie sprawdzające + } + // if (mvOccupied->Vel>=0.1) //o ile jedziemy; jak stoimy to też trzeba jakoś + // zatrzymywać + if ((iDrivigFlags & moveConnect) == 0) // przy końcówce podłączania nie hamować + { // sprawdzenie jazdy na widoczność + TCoupling *c = + pVehicles[0]->MoverParameters->Couplers + + (pVehicles[0]->DirectionGet() > 0 ? 0 : 1); // sprzęg z przodu składu + if (c->Connected) // a mamy coś z przodu + if (c->CouplingFlag == + 0) // jeśli to coś jest podłączone sprzęgiem wirtualnym + { // wyliczanie optymalnego przyspieszenia do jazdy na widoczność + double k = c->Connected->Vel; // prędkość pojazdu z przodu (zakładając, + // że jedzie w tę samą stronę!!!) + if (k < vel + 10) // porównanie modułów prędkości [km/h] + { // zatroszczyć się trzeba, jeśli tamten nie jedzie znacząco szybciej + double d = + pVehicles[0]->fTrackBlock - 0.5 * vel - + fMaxProximityDist; // odległość bezpieczna zależy od prędkości + if (d < 0) // jeśli odległość jest zbyt mała + { // AccPreferred=-0.9; //hamowanie maksymalne, bo jest za blisko + if (k < 10.0) // k - prędkość tego z przodu + { // jeśli tamten porusza się z niewielką prędkością albo stoi + if (OrderCurrentGet() & Connect) + { // jeśli spinanie, to jechać dalej + AccPreferred = 0.2; // nie hamuj + VelNext = VelDesired = 2.0; // i pakuj się na tamtego + } + else // a normalnie to hamować + { + AccPreferred = -1.0; // to hamuj maksymalnie + VelNext = VelDesired = 0.0; // i nie pakuj się na + // tamtego + } + } + else // jeśli oba jadą, to przyhamuj lekko i ogranicz prędkość + { + if (k < vel) // jak tamten jedzie wolniej + if (d < fBrakeDist) // a jest w drodze hamowania + { + if (AccPreferred > fAccThreshold) + AccPreferred = + fAccThreshold; // to przyhamuj troszkę + VelNext = VelDesired = int(k); // to chyba już sobie + // dohamuje według + // uznania + } + } + ReactionTime = 0.1; // orientuj się, bo jest goraco + } + else + { // jeśli odległość jest większa, ustalić maksymalne możliwe + // przyspieszenie (hamowanie) + k = (k * k - vel * vel) / (25.92 * d); // energia kinetyczna + // dzielona przez masę i + // drogę daje + // przyspieszenie + if (k > 0.0) + k *= 1.5; // jedź szybciej, jeśli możesz + // double ak=(c->Connected->V>0?1.0:-1.0)*c->Connected->AccS; + // //przyspieszenie tamtego + if (d < fBrakeDist) // a jest w drodze hamowania + if (k < AccPreferred) + { // jeśli nie ma innych powodów do wolniejszej jazdy + AccPreferred = k; + if (VelNext > c->Connected->Vel) + { + VelNext = + c->Connected + ->Vel; // ograniczenie do prędkości tamtego + ActualProximityDist = + d; // i odległość od tamtego jest istotniejsza + } + ReactionTime = 0.2; // zwiększ czujność + } +#if LOGVELOCITY + WriteLog("Collision: AccPreferred=" + AnsiString(k)); +#endif + } + } + } + } + // sprawdzamy możliwe ograniczenia prędkości + if (OrderCurrentGet() & (Shunt | Obey_train)) // w Connect nie, bo moveStopHere + // odnosi się do stanu po połączeniu + if (iDrivigFlags & moveStopHere) // jeśli ma czekać na wolną drogę + if (vel == 0.0) // a stoi + if (VelNext == 0.0) // a wyjazdu nie ma + VelDesired = 0.0; // to ma stać + if (fStopTime < 0) // czas postoju przed dalszą jazdą (np. na przystanku) + VelDesired = 0.0; // jak ma czekać, to nie ma jazdy + // else if (VelSignal<0) + // VelDesired=fVelMax; //ile fabryka dala (Ra: uwzględione wagony) + else if (VelSignal >= 0) // VelSignal>0 jest ograniczeniem prędkości (z semafora) + VelDesired = Min0R(VelDesired, VelSignal); + if (mvOccupied->RunningTrack.Velmax >= + 0) // ograniczenie prędkości z trajektorii ruchu + VelDesired = + Min0R(VelDesired, + mvOccupied->RunningTrack.Velmax); // uwaga na ograniczenia szlakowej! + if (VelforDriver >= 0) // tu jest zero przy zmianie kierunku jazdy + VelDesired = Min0R(VelDesired, VelforDriver); // Ra: tu może być 40, jeśli + // mechanik nie ma znajomości + // szlaaku, albo kierowca jeździ + // 70 + if (TrainParams) + if (TrainParams->CheckTrainLatency() < 5.0) + if (TrainParams->TTVmax > 0.0) + VelDesired = Min0R( + VelDesired, + TrainParams + ->TTVmax); // jesli nie spozniony to nie przekraczać rozkladowej + if (VelDesired > 0.0) + if (VelNext > 0.0) + { // jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w + // składzie + if (iDrivigFlags & moveGuardSignal) + { // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas + // stania + iDrivigFlags &= ~moveGuardSignal; // tylko raz nadać + tsGuardSignal->Stop(); + // w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy + // bezpośrednim + // albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w + // pobliżu, a drugi radiowy, słyszalny w innych lokomotywach + // na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić + // obsługę kanałów radiowych itd. + if (!iGuardRadio) // jeśli nie przez radio + tsGuardSignal->Play( + 1.0, 0, !FreeFlyModeFlag, + pVehicle->GetPosition()); // dla true jest głośniej + else + // if (iGuardRadio==iRadioChannel) //zgodność kanału + // if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu + // (albo może mieć radio przenośne) - kierownik mógłby powtarzać + // przy braku reakcji + if (SquareMagnitude(pVehicle->GetPosition() - + Global::pCameraPosition) < + 2000 * 2000) // w odległości mniejszej niż 2km + tsGuardSignal->Play( + 1.0, 0, true, + pVehicle->GetPosition()); // dźwięk niby przez radio + } + if (iDrivigFlags & moveDoorOpened) // jeśli drzwi otwarte + if (!mvOccupied + ->DoorOpenCtrl) // jeśli drzwi niesterowane przez maszynistę + Doors(false); // a EZT zamknie dopiero po odegraniu komunikatu + // kierownika + } + if (mvOccupied->V == 0.0) + AbsAccS = fAccGravity; // Ra 2014-03: jesli skład stoi, to działa na niego + // składowa styczna grawitacji + else + AbsAccS = iDirection * mvOccupied->AccS; // przyspieszenie chwilowe, liczone + // jako różnica skierowanej prędkości w + // czasie +// if (mvOccupied->V<0.0) AbsAccS=-AbsAccS; //Ra 2014-03: to trzeba przemyśleć +// if (vel<0) //jeżeli się stacza w tył; 2014-03: to jest bez sensu, bo vel>=0 +// AbsAccS=-AbsAccS; //to przyspieszenie też działa wtedy w nieodpowiednią stronę +// AbsAccS+=fAccGravity; //wypadkowe przyspieszenie (czy to ma sens?) +#if LOGVELOCITY + // WriteLog("VelDesired="+AnsiString(VelDesired)+", + // VelSignal="+AnsiString(VelSignal)); + WriteLog("Vel=" + AnsiString(vel) + ", AbsAccS=" + AnsiString(AbsAccS) + + ", AccGrav=" + AnsiString(fAccGravity)); +#endif + // ustalanie zadanego przyspieszenia + //(ActualProximityDist) - odległość do miejsca zmniejszenia prędkości + //(AccPreferred) - wynika z psychyki oraz uwzglęnia już ewentualne zderzenie z + //pojazdem z przodu, ujemne gdy należy hamować + //(AccDesired) - uwzględnia sygnały na drodze ruchu, ujemne gdy należy hamować + //(fAccGravity) - chwilowe przspieszenie grawitacyjne, ujemne działa przeciwnie do + //zadanego kierunku jazdy + //(AbsAccS) - chwilowe przyspieszenie pojazu (uwzględnia grawitację), ujemne działa + //przeciwnie do zadanego kierunku jazdy + //(AccDesired) porównujemy z (fAccGravity) albo (AbsAccS) + // if ((VelNext>=0.0)&&(ActualProximityDist>=0)&&(mvOccupied->Vel>=VelNext)) //gdy + // zbliza sie i jest za szybko do NOWEGO + if ((VelNext >= 0.0) && (ActualProximityDist <= scanmax) && (vel >= VelNext)) + { // gdy zbliża się i jest za szybki do nowej prędkości, albo stoi na zatrzymaniu + if (vel > 0.0) + { // jeśli jedzie + if ((vel < VelNext) ? + (ActualProximityDist > fMaxProximityDist * (1 + 0.1 * vel)) : + false) // dojedz do semafora/przeszkody + { // jeśli jedzie wolniej niż można i jest wystarczająco daleko, to można + // przyspieszyć + if (AccPreferred > 0.0) // jeśli nie ma zawalidrogi + AccDesired = AccPreferred; + // VelDesired:=Min0R(VelDesired,VelReduced+VelNext); + } + else if (ActualProximityDist > fMinProximityDist) + { // jedzie szybciej, niż trzeba na końcu ActualProximityDist, ale jeszcze + // jest daleko + if (vel < + VelNext + 40.0) // dwustopniowe hamowanie - niski przy małej różnicy + { // jeśli jedzie wolniej niż VelNext+35km/h //Ra: 40, żeby nie + // kombinował na zwrotnicach + if (VelNext == 0.0) + { // jeśli ma się zatrzymać, musi być to robione precyzyjnie i + // skutecznie + if (ActualProximityDist < + fMaxProximityDist) // jak minął już maksymalny dystans + { // po prostu hamuj (niski stopień) //ma stanąć, a jest w + // drodze hamowania albo ma jechać + AccDesired = fAccThreshold; // hamowanie tak, aby stanąć + VelDesired = 0.0; // Min0R(VelDesired,VelNext); + } + else if (ActualProximityDist > fBrakeDist) + { // jeśli ma stanąć, a mieści się w drodze hamowania + if (vel < 10.0) // jeśli prędkość jest łatwa do zatrzymania + { // tu jest trochę problem, bo do punktu zatrzymania dobija + // na raty + // AccDesired=AccDesired<0.0?0.0:0.1*AccPreferred; + AccDesired = AccPreferred; // proteza trochę; jak tu + // wychodzi 0.05, to loki + // mają problem utrzymać + // takie przyspieszenie + } + else if (vel <= 30.0) // trzymaj 30 km/h + AccDesired = Min0R(0.5 * AccDesired, + AccPreferred); // jak jest tu 0.5, to + // samochody się + // dobijają do siebie + else + AccDesired = 0.0; + } + else // 25.92 (=3.6*3.6*2) - przelicznik z km/h na m/s + if (vel < + VelNext + fVelPlus) // jeśli niewielkie przekroczenie + // AccDesired=0.0; + AccDesired = Min0R(0.0, AccPreferred); // proteza trochę: to + // niech nie hamuje, + // chyba że coś z + // przodu + else + AccDesired = -(vel * vel) / + (25.92 * (ActualProximityDist + + 0.1)); //-fMinProximityDist));//-0.1; + ////mniejsze opóźnienie przy + //małej różnicy + ReactionTime = 0.1; // i orientuj się szybciej, jak masz stanąć + } + else if (vel < VelNext + fVelPlus) // jeśli niewielkie + // przekroczenie, ale ma jechać + AccDesired = + Min0R(0.0, AccPreferred); // to olej (zacznij luzować) + else + { // jeśli większe przekroczenie niż fVelPlus [km/h], ale ma jechać + // Ra 2F1I: jak było (VelNext+fVelPlus) tu, to hamował zbyt + // późno przed 40, a potem zbyt mocno i zwalniał do 30 + AccDesired = (VelNext * VelNext - vel * vel) / + (25.92 * ActualProximityDist + + 0.1); // mniejsze opóźnienie przy małej różnicy + if (ActualProximityDist < fMaxProximityDist) + ReactionTime = 0.1; // i orientuj się szybciej, jeśli w + // krytycznym przedziale + } + } + else // przy dużej różnicy wysoki stopień (1,25 potrzebnego opoznienia) + AccDesired = (VelNext * VelNext - vel * vel) / + (20.73 * ActualProximityDist + + 0.1); // najpierw hamuje mocniej, potem zluzuje + if (AccPreferred < AccDesired) + AccDesired = AccPreferred; //(1+abs(AccDesired)) + // ReactionTime=0.5*mvOccupied->BrakeDelay[2+2*mvOccupied->BrakeDelayFlag]; + // //aby szybkosc hamowania zalezala od przyspieszenia i opoznienia + // hamulcow + // fBrakeTime=0.5*mvOccupied->BrakeDelay[2+2*mvOccupied->BrakeDelayFlag]; + // //aby szybkosc hamowania zalezala od przyspieszenia i opoznienia + // hamulcow + } + else + { // jest bliżej niż fMinProximityDist + VelDesired = + Min0R(VelDesired, VelNext); // utrzymuj predkosc bo juz blisko + if (vel < + VelNext + fVelPlus) // jeśli niewielkie przekroczenie, ale ma jechać + AccDesired = Min0R(0.0, AccPreferred); // to olej (zacznij luzować) + ReactionTime = 0.1; // i orientuj się szybciej + } + } + else // zatrzymany (vel==0.0) + // if (iDrivigFlags&moveStopHere) //to nie dotyczy podczepiania + // if ((VelNext>0.0)||(ActualProximityDist>fMaxProximityDist*1.2)) + if (VelNext > 0.0) + AccDesired = AccPreferred; // można jechać + else // jeśli daleko jechać nie można + if (ActualProximityDist > + fMaxProximityDist) // ale ma kawałek do sygnalizatora + { // if ((iDrivigFlags&moveStopHere)?false:AccPreferred>0) + if (AccPreferred > 0) + AccDesired = AccPreferred; // dociagnij do semafora; + else + VelDesired = 0.0; //,AccDesired=-fabs(fAccGravity); //stoj (hamuj z siłą + //równą składowej stycznej grawitacji) + } + else + VelDesired = 0.0; // VelNext=0 i stoi bliżej niż fMaxProximityDist + } + else // gdy jedzie wolniej niż potrzeba, albo nie ma przeszkód na drodze + AccDesired = (VelDesired != 0.0 ? AccPreferred : -0.01); // normalna jazda + // koniec predkosci nastepnej + if ((VelDesired >= 0.0) && + (vel > VelDesired)) // jesli jedzie za szybko do AKTUALNEGO + if (VelDesired == 0.0) // jesli stoj, to hamuj, ale i tak juz za pozno :) + AccDesired = -0.9; // hamuj solidnie + else if ((vel < VelDesired + fVelPlus)) // o 5 km/h to olej + { + if ((AccDesired > 0.0)) + AccDesired = 0.0; + } + else + AccDesired = fAccThreshold; // hamuj tak średnio + // koniec predkosci aktualnej + if (fAccThreshold > -0.3) // bez sensu, ale dla towarowych korzystnie + { // Ra 2014-03: to nie uwzględnia odległości i zaczyna hamować, jak tylko zobaczy + // W4 + if ((AccDesired > 0.0) && + (VelNext >= 0.0)) // wybieg bądź lekkie hamowanie, warunki byly zamienione + if (vel > VelNext + 100.0) // lepiej zaczac hamowac + AccDesired = fAccThreshold; + else if (vel > VelNext + 70.0) + AccDesired = 0.0; // nie spiesz się, bo będzie hamowanie + // koniec wybiegu i hamowania + } + if (AIControllFlag) + { // część wykonawcza tylko dla AI, dla człowieka jedynie napisy + if (mvControlling->ConvOvldFlag || + !mvControlling->Mains) // WS może wywalić z powodu błędu w drutach + { // wywalił bezpiecznik nadmiarowy przetwornicy + // while (DecSpeed()); //zerowanie napędu + // Controlling->ConvOvldFlag=false; //reset nadmiarowego + PrepareEngine(); // próba ponownego załączenia + } + // włączanie bezpiecznika + if ((mvControlling->EngineType == ElectricSeriesMotor) || + (mvControlling->TrainType & dt_EZT) || + (mvControlling->EngineType == DieselElectric)) + if (mvControlling->FuseFlag || Need_TryAgain) + { + Need_TryAgain = + false; // true, jeśli druga pozycja w elektryku nie załapała + // if (!Controlling->DecScndCtrl(1)) //kręcenie po mału + // if (!Controlling->DecMainCtrl(1)) //nastawnik jazdy na 0 + mvControlling->DecScndCtrl(2); // nastawnik bocznikowania na 0 + mvControlling->DecMainCtrl(2); // nastawnik jazdy na 0 + mvControlling->MainSwitch( + true); // Ra: dodałem, bo EN57 stawały po wywaleniu + if (!mvControlling->FuseOn()) + HelpMeFlag = true; + else + { + ++iDriverFailCount; + if (iDriverFailCount > maxdriverfails) + Psyche = Easyman; + if (iDriverFailCount > maxdriverfails * 2) + SetDriverPsyche(); + } + } + if (mvOccupied->BrakeSystem == Pneumatic) // napełnianie uderzeniowe + if (mvOccupied->BrakeHandle == FV4a) + { + if (mvOccupied->BrakeCtrlPos == -2) + mvOccupied->BrakeLevelSet(0); + // if + // ((mvOccupied->BrakeCtrlPos<0)&&(mvOccupied->PipeBrakePress<0.01))//{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)}) + // mvOccupied->IncBrakeLevel(); + if ((mvOccupied->PipePress < 3.0) && (AccDesired > -0.03)) + mvOccupied->BrakeReleaser(1); + if ((mvOccupied->BrakeCtrlPos == 0) && (AbsAccS < 0.0) && + (AccDesired > -0.03)) + // if FuzzyLogicAI(CntrlPipePress-PipePress,0.01,1)) + // if + // ((mvOccupied->BrakePress>0.5)&&(mvOccupied->LocalBrakePos<0.5))//{((Volume/BrakeVVolume/10)<0.485)}) + if ((mvOccupied->EqvtPipePress < 4.95) && + (fReady > 0.35)) //{((Volume/BrakeVVolume/10)<0.485)}) + { + if (iDrivigFlags & + moveOerlikons) // a reszta składu jest na to gotowa + mvOccupied->BrakeLevelSet(-1); // napełnianie w Oerlikonie + } + else if (Need_BrakeRelease) + { + Need_BrakeRelease = false; + mvOccupied->BrakeReleaser(1); + // DecBrakeLevel(); //z tym by jeszcze miało jakiś sens + } + // if + // ((mvOccupied->BrakeCtrlPos<0)&&(mvOccupied->BrakePress<0.3))//{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)}) + if ((mvOccupied->BrakeCtrlPos < 0) && + (mvOccupied->EqvtPipePress > + (fReady < 0.25 ? + 5.1 : + 5.2))) //{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)}) + mvOccupied->IncBrakeLevel(); + } +#if LOGVELOCITY + WriteLog("Dist=" + FloatToStrF(ActualProximityDist, ffFixed, 7, 1) + + ", VelDesired=" + FloatToStrF(VelDesired, ffFixed, 7, 1) + + ", AccDesired=" + FloatToStrF(AccDesired, ffFixed, 7, 3) + + ", VelSignal=" + AnsiString(VelSignal) + ", VelNext=" + + AnsiString(VelNext)); +#endif + if (AccDesired > 0.1) + if (vel < 10.0) // Ra 2F1H: jeśli prędkość jest mała, a można przyspieszać, + // to nie ograniczać przyspieszenia do 0.5m/ss + AccDesired = 0.9; // przy małych prędkościach może być trudno utrzymać + // małe przyspieszenie + // Ra 2F1I: wyłączyć kiedyś to uśrednianie i przeanalizować skanowanie, czemu + // migocze + if (AccDesired > -0.15) // hamowania lepeiej nie uśredniać + AccDesired = fAccDesiredAv = + 0.2 * AccDesired + + 0.8 * fAccDesiredAv; // uśrednione, żeby ograniczyć migotanie + if (VelDesired == 0.0) + if (AccDesired >= -0.01) + AccDesired = -0.01; // Ra 2F1J: jeszcze jedna prowizoryczna łatka + if (AccDesired >= 0.0) + if (iDrivigFlags & movePress) + mvOccupied->BrakeReleaser(1); // wyluzuj lokomotywę - może być więcej! + else if (OrderList[OrderPos] != + Disconnect) // przy odłączaniu nie zwalniamy tu hamulca + if ((AccDesired > 0.0) || + (fAccGravity * fAccGravity < + 0.001)) // luzuj tylko na plaskim lub przy ruszaniu + { + while (DecBrake()) + ; // jeśli przyspieszamy, to nie hamujemy + if (mvOccupied->BrakePress > 0.4) + mvOccupied->BrakeReleaser( + 1); // wyluzuj lokomotywę, to szybciej ruszymy + } + // margines dla prędkości jest doliczany tylko jeśli oczekiwana prędkość jest + // większa od 5km/h + if (!(iDrivigFlags & movePress)) + { // jeśli nie dociskanie + if (AccDesired < -0.1) + while (DecSpeed()) + ; // jeśli hamujemy, to nie przyspieszamy + else if (((fAccGravity < -0.01) ? AccDesired < 0.0 : + AbsAccS > AccDesired) || + (vel > VelDesired)) // jak za bardzo przyspiesza albo prędkość + // przekroczona + DecSpeed(); // pojedyncze cofnięcie pozycji, bo na zero to przesada + } + // yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej + // zwiekszanie predkosci + // Ra 2F1H: jest konflikt histerezy pomiędzy nastawioną pozycją a uzyskiwanym + // przyspieszeniem - utrzymanie pozycji powoduje przekroczenie przyspieszenia + if (AbsAccS < + AccDesired) // jeśli przyspieszenie pojazdu jest mniejsze niż żądane oraz + if (vel < VelDesired - fVelMinus) // jeśli prędkość w kierunku czoła jest + // mniejsza od dozwolonej o margines + if ((ActualProximityDist > fMaxProximityDist) ? true : (vel < VelNext)) + IncSpeed(); // to można przyspieszyć + // if ((AbsAccS0) and + // (EngineType=ElectricSeriesMotor) + // and (RList[MainCtrlPos].R>0.0) and (not DelayCtrlFlag)) + // if (ImTrainType & + dt_EZT) // właściwie, to warunek powinien być na działający EP + { // Ra: to dobrze hamuje EP w EZT + if ((AccDesired <= fAccThreshold) ? // jeśli hamować - u góry ustawia się + // hamowanie na fAccThreshold + ((AbsAccS > AccDesired) || (mvOccupied->BrakeCtrlPos < 0)) : + false) // hamować bardziej, gdy aktualne opóźnienie hamowania + // mniejsze niż (AccDesired) + IncBrake(); + else if (OrderList[OrderPos] != + Disconnect) // przy odłączaniu nie zwalniamy tu hamulca + if (AbsAccS < + AccDesired - + 0.05) // jeśli opóźnienie większe od wymaganego (z histerezą) + { // luzowanie, gdy za dużo + if (mvOccupied->BrakeCtrlPos >= 0) + DecBrake(); // tutaj zmniejszało o 1 przy odczepianiu + } + else if (mvOccupied->Handle->TimeEP) + { + if (mvOccupied->Handle->GetPos(bh_EPR) - + mvOccupied->Handle->GetPos(bh_EPN) < + 0.1) + mvOccupied->SwitchEPBrake(0); + else + mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPN)); + } + // else if (mvOccupied->BrakeCtrlPos<0) IncBrake(); //ustawienie + // jazdy (pozycja 0) + // else if (mvOccupied->BrakeCtrlPos>0) DecBrake(); + } + else + { // a stara wersja w miarę dobrze działa na składy wagonowe + // if (mvOccupied->Handle->Time) + // mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_MB)); + // //najwyzej sobie przestawi + if (((fAccGravity < -0.05) && (vel < 0)) || + ((AccDesired < fAccGravity - 0.1) && + (AbsAccS > + AccDesired + 0.05))) // u góry ustawia się hamowanie na fAccThreshold + // if not MinVelFlag) + if (fBrakeTime < 0 ? true : (AccDesired < fAccGravity - 0.3) || + (mvOccupied->BrakeCtrlPos <= 0)) + if (!IncBrake()) // jeśli upłynął czas reakcji hamulca, chyba że + // nagłe albo luzował + MinVelFlag = true; + else + { + MinVelFlag = false; + fBrakeTime = + 3 + + 0.5 * + (mvOccupied + ->BrakeDelay[2 + 2 * mvOccupied->BrakeDelayFlag] - + 3); + // Ra: ten czas należy zmniejszyć, jeśli czas dojazdu do + // zatrzymania jest mniejszy + fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1 + } + if ((AccDesired < fAccGravity - 0.05) && (AbsAccS < AccDesired - 0.2)) + // if ((AccDesired<0.0)&&(AbsAccSBrakeDelay[1 + 2 * mvOccupied->BrakeDelayFlag]) / 3.0; + fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1 + } + } + // Mietek-end1 + SpeedSet(); // ciągla regulacja prędkości +#if LOGVELOCITY + WriteLog("BrakePos=" + AnsiString(mvOccupied->BrakeCtrlPos) + ", MainCtrl=" + + AnsiString(mvControlling->MainCtrlPos)); +#endif + + /* //Ra: mamy teraz wskażnik na człon silnikowy, gorzej jak są dwa w + ukrotnieniu... + //zapobieganie poslizgowi w czlonie silnikowym; Ra: Couplers[1] powinno + być + if (Controlling->Couplers[0].Connected!=NULL) + if (TestFlag(Controlling->Couplers[0].CouplingFlag,ctrain_controll)) + if (Controlling->Couplers[0].Connected->SlippingWheels) + if (Controlling->ScndCtrlPos>0?!Controlling->DecScndCtrl(1):true) + { + if (!Controlling->DecMainCtrl(1)) + if (mvOccupied->BrakeCtrlPos==mvOccupied->BrakeCtrlPosNo) + mvOccupied->DecBrakeLevel(); + ++iDriverFailCount; + } + */ + // zapobieganie poslizgowi u nas + if (mvControlling->SlippingWheels) + { + if (!mvControlling->DecScndCtrl(2)) // bocznik na zero + mvControlling->DecMainCtrl(1); + if (mvOccupied->BrakeCtrlPos == + mvOccupied->BrakeCtrlPosNo) // jeśli ostatnia pozycja hamowania + mvOccupied->DecBrakeLevel(); // to cofnij hamulec + else + mvControlling->AntiSlippingButton(); + ++iDriverFailCount; + mvControlling->SlippingWheels = false; // flaga już wykorzystana + } + if (iDriverFailCount > maxdriverfails) + { + Psyche = Easyman; + if (iDriverFailCount > maxdriverfails * 2) + SetDriverPsyche(); + } + } // if (AIControllFlag) + else + { // tu mozna dać komunikaty tekstowe albo słowne: przyspiesz, hamuj (lekko, + // średnio, mocno) + } + } // kierunek różny od zera + else + { // tutaj, gdy pojazd jest wyłączony + if (!AIControllFlag) // jeśli sterowanie jest w gestii użytkownika + if (mvOccupied->Battery) // czy użytkownik załączył baterię? + if (mvOccupied->ActiveDir) // czy ustawił kierunek + { // jeśli tak, to uruchomienie skanowania + CheckVehicles(); // sprawdzić skład + TableClear(); // resetowanie tabelki skanowania + PrepareEngine(); // uruchomienie + } + } + if (AIControllFlag) + { // odhamowywanie składu po zatrzymaniu i zabezpieczanie lokomotywy + if ((OrderList[OrderPos] & (Disconnect | Connect)) == + 0) // przy (p)odłączaniu nie zwalniamy tu hamulca + if ((mvOccupied->V == 0.0) && ((VelDesired == 0.0) || (AccDesired == 0.0))) + if ((mvOccupied->BrakeCtrlPos < 1) || !mvOccupied->DecBrakeLevel()) + mvOccupied->IncLocalBrakeLevel(1); // dodatkowy na pozycję 1 + } + break; // rzeczy robione przy jezdzie + } // switch (OrderList[OrderPos]) + // kasowanie licznika czasu + LastReactionTime = 0.0; + UpdateOK = true; + } // if ((LastReactionTime>Min0R(ReactionTime,2.0))) + else + LastReactionTime += dt; + + if ((fLastStopExpDist > 0.0) && (mvOccupied->DistCounter > fLastStopExpDist)) { - VelSignal=Min0R(VelSignal,40); //jeśli manewry, to ograniczamy prędkość - if (AIControllFlag) - {//to poniżej tylko dla AI - if (iVehicleCount>=0) //jeśli jest co odczepić - if (!(iDrivigFlags&movePress)) - if (mvOccupied->Vel>0.0) - if (!iCoupler) //jeśli nie ma wcześniej potrzeby podczepienia - {SetVelocity(0,0,stopJoin); //1. faza odczepiania: zatrzymanie - //WriteLog("Zatrzymanie w celu odczepienia"); - } - } + iStationStart = TrainParams->StationIndex; // zaktualizować wyświetlanie rozkładu + fLastStopExpDist = -1.0f; // usunąć licznik } - else - SetDriverPsyche(); //Ra: było w PrepareEngine(), potrzebne tu? - //no albo przypisujemy -WaitingExpireTime, albo porównujemy z WaitingExpireTime - //if ((VelSignal==0.0)&&(WaitingTime>WaitingExpireTime)&&(mvOccupied->RunningTrack.Velmax!=0.0)) - if (OrderList[OrderPos]&(Shunt|Obey_train|Connect)) //odjechać sam może tylko jeśli jest w trybie jazdy - {//automatyczne ruszanie po odstaniu albo spod SBL - if ((VelSignal==0.0)&&(WaitingTime>0.0)&&(mvOccupied->RunningTrack.Velmax!=0.0)) - {//jeśli stoi, a upłynął czas oczekiwania i tor ma niezerową prędkość -/* - if (WriteLogFlag) - { - append(AIlogFile); - writeln(AILogFile,ElapsedTime:5:2,": ",Name," V=0 waiting time expired! (",WaitingTime:4:1,")"); - close(AILogFile); - } -*/ - if ((OrderList[OrderPos]&(Obey_train|Shunt))?(iDrivigFlags&moveStopHere):false) - WaitingTime=-WaitingExpireTime; //zakaz ruszania z miejsca bez otrzymania wolnej drogi - else if (mvOccupied->CategoryFlag&1) - {//jeśli pociąg - if (AIControllFlag) - {PrepareEngine(); //zmieni ustawiony kierunek - SetVelocity(20,20); //jak się nastał, to niech jedzie 20km/h - WaitingTime=0.0; - fWarningDuration=1.5; //a zatrąbić trochę - mvOccupied->WarningSignal=1; - } - else - SetVelocity(20,20); //użytkownikowi zezwalamy jechać - } - else - {//samochód ma stać, aż dostanie odjazd, chyba że stoi przez kolizję - if (eStopReason==stopBlock) - if (pVehicles[0]->fTrackBlock>fDriverDist) - if (AIControllFlag) - {PrepareEngine(); //zmieni ustawiony kierunek - SetVelocity(-1,-1); //jak się nastał, to niech jedzie - WaitingTime=0.0; - } - else - SetVelocity(-1,-1); //użytkownikowi pozwalamy jechać (samochodem?) - } - } - else if ((VelSignal==0.0)&&(VelNext>0.0)&&(mvOccupied->Vel<1.0)) - if (iCoupler?true:(iDrivigFlags&moveStopHere)==0) //Ra: tu jest coś nie tak, bo bez tego warunku ruszało w manewrowym !!!! - SetVelocity(VelNext,VelNext,stopSem); //omijanie SBL - } //koniec samoistnego odjeżdżania + if (AIControllFlag) - if ((HelpMeFlag)||(mvControlling->DamageFlag>0)) - { - HelpMeFlag=false; -/* - if (WriteLogFlag) - with Controlling do + { + if (fWarningDuration > 0.0) // jeśli pozostało coś do wytrąbienia + { // trąbienie trwa nadal + fWarningDuration = fWarningDuration - dt; + if (fWarningDuration < 0.05) + mvOccupied->WarningSignal = 0; // a tu się kończy + if (ReactionTime > fWarningDuration) + ReactionTime = + fWarningDuration; // wcześniejszy przebłysk świadomości, by zakończyć trąbienie + } + if (mvOccupied->Vel >= + 3.0) // jesli jedzie, można odblokować trąbienie, bo się wtedy nie włączy { - append(AIlogFile); - writeln(AILogFile,ElapsedTime:5:2,": ",Name," HelpMe! (",DamageFlag,")"); - close(AILogFile); + iDrivigFlags &= ~moveStartHornDone; // zatrąbi dopiero jak następnym razem stanie + iDrivigFlags |= moveStartHorn; // i trąbić przed następnym ruszeniem } -*/ - } - if (AIControllFlag) - if (OrderList[OrderPos]&Change_direction) //może być zmieszane z jeszcze jakąś komendą - {//sprobuj zmienic kierunek - SetVelocity(0,0,stopDir); //najpierw trzeba się zatrzymać - if (mvOccupied->Vel<0.1) - {//jeśli się zatrzymał, to zmieniamy kierunek jazdy, a nawet kabinę/człon - Activation(); //ustawienie zadanego wcześniej kierunku i ewentualne przemieszczenie AI - PrepareEngine(); - JumpToNextOrder(); //następnie robimy, co jest do zrobienia (Shunt albo Obey_train) - if (OrderList[OrderPos]&(Shunt|Connect)) //jeśli dalej mamy manewry - if ((iDrivigFlags&moveStopHere)==0) //o ile nie stać w miejscu - {//jechać od razu w przeciwną stronę i nie trąbić z tego tytułu - iDrivigFlags&=~moveStartHorn; //bez trąbienia przed ruszeniem - SetVelocity(fShuntVelocity,fShuntVelocity); //to od razu jedziemy - } - //iDrivigFlags|=moveStartHorn; //a później już można trąbić -/* - if (WriteLogFlag) - { - append(AIlogFile); - writeln(AILogFile,ElapsedTime:5:2,": ",Name," Direction changed!"); - close(AILogFile); - } -*/ - } - //else - // VelSignal:=0.0; //na wszelki wypadek niech zahamuje - } //Change_direction (tylko dla AI) - //ustalanie zadanej predkosci - if (AIControllFlag) //jeśli prowadzi AI - if (!iEngineActive) //jeśli silnik nie odpalony, to próbować naprawić - if (OrderList[OrderPos]&(Change_direction|Connect|Disconnect|Shunt|Obey_train)) //jeśli coś ma robić - PrepareEngine(); //to niech odpala do skutku - if (iDrivigFlags&moveActive) //jeśli może skanować sygnały i reagować na komendy - {//jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy - //Ra: tu by jeszcze trzeba było wstawić uzależnienie (VelDesired) od odległości od przeszkody - // no chyba żeby to uwzgldnić już w (ActualProximityDist) - VelDesired=fVelMax; //wstępnie prędkość maksymalna dla pojazdu(-ów), będzie następnie ograniczana - if (TrainParams) //jeśli ma rozkład - if (TrainParams->TTVmax>0.0) //i ograniczenie w rozkładzie - VelDesired=Min0R(VelDesired,TrainParams->TTVmax); //to nie przekraczać rozkladowej - SetDriverPsyche(); //ustawia AccPreferred (potrzebne tu?) - //Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci - AccDesired=AccPreferred; //AccPreferred wynika z osobowości mechanika - VelNext=VelDesired; //maksymalna prędkość wynikająca z innych czynników niż trajektoria ruchu - ActualProximityDist=scanmax; //funkcja Update() może pozostawić wartości bez zmian - //hm, kiedyś semafory wysyłały SetVelocity albo ShuntVelocity i ustawły tak VelSignal - a teraz jak to zrobić? - TCommandType comm=TableUpdate(VelDesired,ActualProximityDist,VelNext,AccDesired); //szukanie optymalnych wartości - //if (VelSignal!=VelDesired) //jeżeli prędkość zalecana jest inna (ale tryb też może być inny) - switch (comm) - {//ustawienie VelSignal - trochę proteza = do przemyślenia - case cm_Ready: //W4 zezwolił na jazdę - TableCheck(scanmax); //ewentualne doskanowanie trasy za W4, który zezwolił na jazdę - TableUpdate(VelDesired,ActualProximityDist,VelNext,AccDesired); //aktualizacja po skanowaniu - //if (comm!=cm_SetVelocity) //jeśli dalej jest kolejny W4, to ma zwrócić cm_SetVelocity - if (VelNext==0.0) break; //ale jak coś z przodu zamyka, to ma stać - if (iDrivigFlags&moveStopCloser) - VelSignal=VelDesired; //niech jedzie, jak W4 puściło - nie, ma czekać na sygnał z sygnalizatora! - case cm_SetVelocity: //od wersji 357 semafor nie budzi wyłączonej lokomotywy - if (!(OrderList[OrderPos]&~(Obey_train|Shunt))) //jedzie w dowolnym trybie albo Wait_for_orders - if (fabs(VelSignal)>=1.0) //0.1 nie wysyła się do samochodow, bo potem nie ruszą - PutCommand("SetVelocity",VelSignal,VelNext,NULL); //komenda robi dodatkowe operacje - break; - case cm_ShuntVelocity: //od wersji 357 Tm nie budzi wyłączonej lokomotywy - if (!(OrderList[OrderPos]&~(Obey_train|Shunt))) //jedzie w dowolnym trybie albo Wait_for_orders - PutCommand("ShuntVelocity",VelSignal,VelNext,NULL); - else if (iCoupler) //jeśli jedzie w celu połączenia - SetVelocity(VelSignal,VelNext); - break; - case cm_Command: //komenda z komórki - if (!(OrderList[OrderPos]&~(Obey_train|Shunt))) //jedzie w dowolnym trybie albo Wait_for_orders - if (mvOccupied->Vel<0.1) //dopiero jak stanie - //iDrivigFlags|=moveStopHere moveStopCloser) //chyba że stanął za daleko (SU46 w WK staje za daleko) - {PutCommand(eSignNext->CommandGet(),eSignNext->ValueGet(1),eSignNext->ValueGet(2),NULL); - eSignNext->StopCommandSent(); //się wykonało już - } - break; - } - if (VelNext==0.0) - if (!(OrderList[OrderPos]&~(Shunt|Connect))) //jedzie w Shunt albo Connect, albo Wait_for_orders - {//jeżeli wolnej drogi nie ma, a jest w trybie manewrowym albo oczekiwania - //if ((OrderList[OrderPos]&Connect)?pVehicles[0]->fTrackBlock>ActualProximityDist:true) //pomiar odległości nie działa dobrze? - //w trybie Connect skanować do tyłu tylko jeśli przed kolejnym sygnałem nie ma taboru do podłączenia - //Ra 2F1H: z tym (fTrackBlock) to nie jest najlepszy pomysł, bo lepiej by było porównać z odległością od sygnalizatora z przodu - if ((OrderList[OrderPos]|Connect)?pVehicles[0]->fTrackBlock>2000:true) - if ((comm=BackwardScan())!=cm_Unknown) //jeśli w drugą można jechać - {//należy sprawdzać odległość od znalezionego sygnalizatora, - //aby w przypadku prędkości 0.1 wyciągnąć najpierw skład za sygnalizator - //i dopiero wtedy zmienić kierunek jazdy, oczekując podania prędkości >0.5 - if (comm==cm_Command) //jeśli komenda Shunt - iDrivigFlags|=moveStopHere; //to ją odbierz bez przemieszczania się (np. odczep wagony po dopchnięciu do końca toru) - iDirectionOrder=-iDirection; //zmiana kierunku jazdy - OrderList[OrderPos]=TOrders(OrderList[OrderPos]|Change_direction); //zmiana kierunku bez psucia kolejnych komend - } - } - double vel=mvOccupied->Vel; //prędkość w kierunku jazdy - if (iDirection*mvOccupied->V<0) vel=-vel; //ujemna, gdy jedzie w przeciwną stronę, niż powinien - if (VelDesired<0.0) VelDesired=fVelMax; //bo VelDesired<0 oznacza prędkość maksymalną - //Ra: jazda na widoczność - if (pVehicles[0]->fTrackBlock<1000.0) //przy 300m stał z zapamiętaną kolizją - {//Ra 2F3F: przy jeździe pociągowej nie powinien dojeżdżać do poprzedzającego składu - if ((mvOccupied->CategoryFlag&1)?((OrderCurrentGet()&(Connect|Obey_train))==Obey_train):false) //jeśli jesteśmy pociągiem a jazda pociągowa i nie ściąganie ze szlaku - {pVehicles[0]->ABuScanObjects(pVehicles[0]->DirectionGet(),1000.0); //skanowanie sprawdzające - //Ra 2F3F: i jest problem, jak droga za semaforem kieruje na jakiś pojazd (np. w Skwarkach na ET22) - if (pVehicles[0]->fTrackBlock<1000.0) //i jeśli nadal coś jest - if (VelNext!=0.0) //a następny sygnał zezwala na jazdę - if (pVehicles[0]->fTrackBlockABuScanObjects(pVehicles[0]->DirectionGet(),300.0); //skanowanie sprawdzające - } - //if (mvOccupied->Vel>=0.1) //o ile jedziemy; jak stoimy to też trzeba jakoś zatrzymywać - if ((iDrivigFlags&moveConnect)==0) //przy końcówce podłączania nie hamować - {//sprawdzenie jazdy na widoczność - TCoupling *c=pVehicles[0]->MoverParameters->Couplers+(pVehicles[0]->DirectionGet()>0?0:1); //sprzęg z przodu składu - if (c->Connected) //a mamy coś z przodu - if (c->CouplingFlag==0) //jeśli to coś jest podłączone sprzęgiem wirtualnym - {//wyliczanie optymalnego przyspieszenia do jazdy na widoczność - double k=c->Connected->Vel; //prędkość pojazdu z przodu (zakładając, że jedzie w tę samą stronę!!!) - if (kfTrackBlock-0.5*vel-fMaxProximityDist; //odległość bezpieczna zależy od prędkości - if (d<0) //jeśli odległość jest zbyt mała - {//AccPreferred=-0.9; //hamowanie maksymalne, bo jest za blisko - if (k<10.0) //k - prędkość tego z przodu - {//jeśli tamten porusza się z niewielką prędkością albo stoi - if (OrderCurrentGet()&Connect) - {//jeśli spinanie, to jechać dalej - AccPreferred=0.2; //nie hamuj - VelNext=VelDesired=2.0; //i pakuj się na tamtego - } - else //a normalnie to hamować - {AccPreferred=-1.0; //to hamuj maksymalnie - VelNext=VelDesired=0.0; //i nie pakuj się na tamtego - } - } - else //jeśli oba jadą, to przyhamuj lekko i ogranicz prędkość - {if (kfAccThreshold) AccPreferred=fAccThreshold; //to przyhamuj troszkę - VelNext=VelDesired=int(k); //to chyba już sobie dohamuje według uznania - } - } - ReactionTime=0.1; //orientuj się, bo jest goraco - } - else - {//jeśli odległość jest większa, ustalić maksymalne możliwe przyspieszenie (hamowanie) - k=(k*k-vel*vel)/(25.92*d); //energia kinetyczna dzielona przez masę i drogę daje przyspieszenie - if (k>0.0) k*=1.5; //jedź szybciej, jeśli możesz - //double ak=(c->Connected->V>0?1.0:-1.0)*c->Connected->AccS; //przyspieszenie tamtego - if (dc->Connected->Vel) - {VelNext=c->Connected->Vel; //ograniczenie do prędkości tamtego - ActualProximityDist=d; //i odległość od tamtego jest istotniejsza - } - ReactionTime=0.2; //zwiększ czujność - } -#if LOGVELOCITY - WriteLog("Collision: AccPreferred="+AnsiString(k)); -#endif - } - } - } - } - //sprawdzamy możliwe ograniczenia prędkości - if (OrderCurrentGet()&(Shunt|Obey_train)) //w Connect nie, bo moveStopHere odnosi się do stanu po połączeniu - if (iDrivigFlags&moveStopHere) //jeśli ma czekać na wolną drogę - if (vel==0.0) //a stoi - if (VelNext==0.0) //a wyjazdu nie ma - VelDesired=0.0; //to ma stać - if (fStopTime<0) //czas postoju przed dalszą jazdą (np. na przystanku) - VelDesired=0.0; //jak ma czekać, to nie ma jazdy - //else if (VelSignal<0) - //VelDesired=fVelMax; //ile fabryka dala (Ra: uwzględione wagony) - else - if (VelSignal>=0) //VelSignal>0 jest ograniczeniem prędkości (z semafora) - VelDesired=Min0R(VelDesired,VelSignal); - if (mvOccupied->RunningTrack.Velmax>=0) //ograniczenie prędkości z trajektorii ruchu - VelDesired=Min0R(VelDesired,mvOccupied->RunningTrack.Velmax); //uwaga na ograniczenia szlakowej! - if (VelforDriver>=0) //tu jest zero przy zmianie kierunku jazdy - VelDesired=Min0R(VelDesired,VelforDriver); //Ra: tu może być 40, jeśli mechanik nie ma znajomości szlaaku, albo kierowca jeździ 70 - if (TrainParams) - if (TrainParams->CheckTrainLatency()<5.0) - if (TrainParams->TTVmax>0.0) - VelDesired=Min0R(VelDesired,TrainParams->TTVmax); //jesli nie spozniony to nie przekraczać rozkladowej - if (VelDesired>0.0) - if (VelNext>0.0) - {//jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w składzie - if (iDrivigFlags&moveGuardSignal) - {//komunikat od kierownika tu, bo musi być wolna droga i odczekany czas stania - iDrivigFlags&=~moveGuardSignal; //tylko raz nadać - tsGuardSignal->Stop(); - //w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy bezpośrednim - //albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w pobliżu, a drugi radiowy, słyszalny w innych lokomotywach - //na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić obsługę kanałów radiowych itd. - if (!iGuardRadio) //jeśli nie przez radio - tsGuardSignal->Play(1.0,0,!FreeFlyModeFlag,pVehicle->GetPosition()); //dla true jest głośniej - else - //if (iGuardRadio==iRadioChannel) //zgodność kanału - //if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu (albo może mieć radio przenośne) - kierownik mógłby powtarzać przy braku reakcji - if (SquareMagnitude(pVehicle->GetPosition()-Global::pCameraPosition)<2000*2000) //w odległości mniejszej niż 2km - tsGuardSignal->Play(1.0,0,true,pVehicle->GetPosition()); //dźwięk niby przez radio - } - if (iDrivigFlags&moveDoorOpened) //jeśli drzwi otwarte - if (!mvOccupied->DoorOpenCtrl) //jeśli drzwi niesterowane przez maszynistę - Doors(false); //a EZT zamknie dopiero po odegraniu komunikatu kierownika - } - if (mvOccupied->V==0.0) AbsAccS=fAccGravity; //Ra 2014-03: jesli skład stoi, to działa na niego składowa styczna grawitacji - else AbsAccS=iDirection*mvOccupied->AccS; //przyspieszenie chwilowe, liczone jako różnica skierowanej prędkości w czasie - //if (mvOccupied->V<0.0) AbsAccS=-AbsAccS; //Ra 2014-03: to trzeba przemyśleć - //if (vel<0) //jeżeli się stacza w tył; 2014-03: to jest bez sensu, bo vel>=0 - // AbsAccS=-AbsAccS; //to przyspieszenie też działa wtedy w nieodpowiednią stronę - //AbsAccS+=fAccGravity; //wypadkowe przyspieszenie (czy to ma sens?) -#if LOGVELOCITY - //WriteLog("VelDesired="+AnsiString(VelDesired)+", VelSignal="+AnsiString(VelSignal)); - WriteLog("Vel="+AnsiString(vel)+", AbsAccS="+AnsiString(AbsAccS)+", AccGrav="+AnsiString(fAccGravity)); -#endif - //ustalanie zadanego przyspieszenia - //(ActualProximityDist) - odległość do miejsca zmniejszenia prędkości - //(AccPreferred) - wynika z psychyki oraz uwzglęnia już ewentualne zderzenie z pojazdem z przodu, ujemne gdy należy hamować - //(AccDesired) - uwzględnia sygnały na drodze ruchu, ujemne gdy należy hamować - //(fAccGravity) - chwilowe przspieszenie grawitacyjne, ujemne działa przeciwnie do zadanego kierunku jazdy - //(AbsAccS) - chwilowe przyspieszenie pojazu (uwzględnia grawitację), ujemne działa przeciwnie do zadanego kierunku jazdy - //(AccDesired) porównujemy z (fAccGravity) albo (AbsAccS) - //if ((VelNext>=0.0)&&(ActualProximityDist>=0)&&(mvOccupied->Vel>=VelNext)) //gdy zbliza sie i jest za szybko do NOWEGO - if ((VelNext>=0.0)&&(ActualProximityDist<=scanmax)&&(vel>=VelNext)) - {//gdy zbliża się i jest za szybki do nowej prędkości, albo stoi na zatrzymaniu - if (vel>0.0) - {//jeśli jedzie - if ((velfMaxProximityDist*(1+0.1*vel)):false) //dojedz do semafora/przeszkody - {//jeśli jedzie wolniej niż można i jest wystarczająco daleko, to można przyspieszyć - if (AccPreferred>0.0) //jeśli nie ma zawalidrogi - AccDesired=AccPreferred; - //VelDesired:=Min0R(VelDesired,VelReduced+VelNext); - } - else if (ActualProximityDist>fMinProximityDist) - {//jedzie szybciej, niż trzeba na końcu ActualProximityDist, ale jeszcze jest daleko - if (velfBrakeDist) - {//jeśli ma stanąć, a mieści się w drodze hamowania - if (vel<10.0) //jeśli prędkość jest łatwa do zatrzymania - {//tu jest trochę problem, bo do punktu zatrzymania dobija na raty - //AccDesired=AccDesired<0.0?0.0:0.1*AccPreferred; - AccDesired=AccPreferred; //proteza trochę; jak tu wychodzi 0.05, to loki mają problem utrzymać takie przyspieszenie - } - else if (vel<=30.0) //trzymaj 30 km/h - AccDesired=Min0R(0.5*AccDesired,AccPreferred); //jak jest tu 0.5, to samochody się dobijają do siebie - else - AccDesired=0.0; - } - else //25.92 (=3.6*3.6*2) - przelicznik z km/h na m/s - if (velBrakeDelay[2+2*mvOccupied->BrakeDelayFlag]; //aby szybkosc hamowania zalezala od przyspieszenia i opoznienia hamulcow - //fBrakeTime=0.5*mvOccupied->BrakeDelay[2+2*mvOccupied->BrakeDelayFlag]; //aby szybkosc hamowania zalezala od przyspieszenia i opoznienia hamulcow - } - else - {//jest bliżej niż fMinProximityDist - VelDesired=Min0R(VelDesired,VelNext); //utrzymuj predkosc bo juz blisko - if (vel0.0)||(ActualProximityDist>fMaxProximityDist*1.2)) - if (VelNext>0.0) - AccDesired=AccPreferred; //można jechać - else //jeśli daleko jechać nie można - if (ActualProximityDist>fMaxProximityDist) //ale ma kawałek do sygnalizatora - {//if ((iDrivigFlags&moveStopHere)?false:AccPreferred>0) - if (AccPreferred>0) - AccDesired=AccPreferred; //dociagnij do semafora; - else - VelDesired=0.0;//,AccDesired=-fabs(fAccGravity); //stoj (hamuj z siłą równą składowej stycznej grawitacji) - } - else - VelDesired=0.0; //VelNext=0 i stoi bliżej niż fMaxProximityDist - } - else //gdy jedzie wolniej niż potrzeba, albo nie ma przeszkód na drodze - AccDesired=(VelDesired!=0.0?AccPreferred:-0.01); //normalna jazda - //koniec predkosci nastepnej - if ((VelDesired>=0.0)&&(vel>VelDesired)) //jesli jedzie za szybko do AKTUALNEGO - if (VelDesired==0.0) //jesli stoj, to hamuj, ale i tak juz za pozno :) - AccDesired=-0.9; //hamuj solidnie - else - if ((vel0.0)) - AccDesired=0.0; - } - else - AccDesired=fAccThreshold; //hamuj tak średnio - //koniec predkosci aktualnej - if (fAccThreshold>-0.3) //bez sensu, ale dla towarowych korzystnie - {//Ra 2014-03: to nie uwzględnia odległości i zaczyna hamować, jak tylko zobaczy W4 - if ((AccDesired>0.0)&&(VelNext>=0.0)) //wybieg bądź lekkie hamowanie, warunki byly zamienione - if (vel>VelNext+100.0) //lepiej zaczac hamowac - AccDesired=fAccThreshold; - else - if (vel>VelNext+70.0) - AccDesired=0.0; //nie spiesz się, bo będzie hamowanie - //koniec wybiegu i hamowania - } - if (AIControllFlag) - {//część wykonawcza tylko dla AI, dla człowieka jedynie napisy - if (mvControlling->ConvOvldFlag||!mvControlling->Mains) //WS może wywalić z powodu błędu w drutach - {//wywalił bezpiecznik nadmiarowy przetwornicy - //while (DecSpeed()); //zerowanie napędu - //Controlling->ConvOvldFlag=false; //reset nadmiarowego - PrepareEngine(); //próba ponownego załączenia - } - //włączanie bezpiecznika - if ((mvControlling->EngineType==ElectricSeriesMotor)||(mvControlling->TrainType&dt_EZT)||(mvControlling->EngineType==DieselElectric)) - if (mvControlling->FuseFlag||Need_TryAgain) - {Need_TryAgain=false; //true, jeśli druga pozycja w elektryku nie załapała - //if (!Controlling->DecScndCtrl(1)) //kręcenie po mału - // if (!Controlling->DecMainCtrl(1)) //nastawnik jazdy na 0 - mvControlling->DecScndCtrl(2); //nastawnik bocznikowania na 0 - mvControlling->DecMainCtrl(2); //nastawnik jazdy na 0 - mvControlling->MainSwitch(true); //Ra: dodałem, bo EN57 stawały po wywaleniu - if (!mvControlling->FuseOn()) - HelpMeFlag=true; - else - { - ++iDriverFailCount; - if (iDriverFailCount>maxdriverfails) - Psyche=Easyman; - if (iDriverFailCount>maxdriverfails*2) - SetDriverPsyche(); - } - } - if (mvOccupied->BrakeSystem==Pneumatic) //napełnianie uderzeniowe - if (mvOccupied->BrakeHandle==FV4a) - { - if (mvOccupied->BrakeCtrlPos==-2) - mvOccupied->BrakeLevelSet(0); -// if ((mvOccupied->BrakeCtrlPos<0)&&(mvOccupied->PipeBrakePress<0.01))//{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)}) -// mvOccupied->IncBrakeLevel(); - if ((mvOccupied->PipePress<3.0)&&(AccDesired>-0.03)) mvOccupied->BrakeReleaser(1); - if ((mvOccupied->BrakeCtrlPos==0)&&(AbsAccS<0.0)&&(AccDesired>-0.03)) - //if FuzzyLogicAI(CntrlPipePress-PipePress,0.01,1)) -// if ((mvOccupied->BrakePress>0.5)&&(mvOccupied->LocalBrakePos<0.5))//{((Volume/BrakeVVolume/10)<0.485)}) - if ((mvOccupied->EqvtPipePress<4.95)&&(fReady>0.35))//{((Volume/BrakeVVolume/10)<0.485)}) - {if (iDrivigFlags&moveOerlikons) //a reszta składu jest na to gotowa - mvOccupied->BrakeLevelSet(-1); //napełnianie w Oerlikonie - } - else - if (Need_BrakeRelease) - { - Need_BrakeRelease=false; - mvOccupied->BrakeReleaser(1); - //DecBrakeLevel(); //z tym by jeszcze miało jakiś sens - } -// if ((mvOccupied->BrakeCtrlPos<0)&&(mvOccupied->BrakePress<0.3))//{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)}) - if ((mvOccupied->BrakeCtrlPos<0)&&(mvOccupied->EqvtPipePress>(fReady<0.25?5.1:5.2)))//{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)}) - mvOccupied->IncBrakeLevel(); - } -#if LOGVELOCITY - WriteLog("Dist="+FloatToStrF(ActualProximityDist,ffFixed,7,1)+", VelDesired="+FloatToStrF(VelDesired,ffFixed,7,1)+", AccDesired="+FloatToStrF(AccDesired,ffFixed,7,3)+", VelSignal="+AnsiString(VelSignal)+", VelNext="+AnsiString(VelNext)); -#endif - if (AccDesired>0.1) - if (vel<10.0) //Ra 2F1H: jeśli prędkość jest mała, a można przyspieszać, to nie ograniczać przyspieszenia do 0.5m/ss - AccDesired=0.9; //przy małych prędkościach może być trudno utrzymać małe przyspieszenie - //Ra 2F1I: wyłączyć kiedyś to uśrednianie i przeanalizować skanowanie, czemu migocze - if (AccDesired>-0.15) //hamowania lepeiej nie uśredniać - AccDesired=fAccDesiredAv=0.2*AccDesired+0.8*fAccDesiredAv; //uśrednione, żeby ograniczyć migotanie - if (VelDesired==0.0) if (AccDesired>=-0.01) AccDesired=-0.01; //Ra 2F1J: jeszcze jedna prowizoryczna łatka - if (AccDesired>=0.0) - if (iDrivigFlags&movePress) - mvOccupied->BrakeReleaser(1); //wyluzuj lokomotywę - może być więcej! - else - if (OrderList[OrderPos]!=Disconnect) //przy odłączaniu nie zwalniamy tu hamulca - if ((AccDesired>0.0)||(fAccGravity*fAccGravity<0.001)) //luzuj tylko na plaskim lub przy ruszaniu - {while (DecBrake()); //jeśli przyspieszamy, to nie hamujemy - if (mvOccupied->BrakePress>0.4) - mvOccupied->BrakeReleaser(1); //wyluzuj lokomotywę, to szybciej ruszymy - } - //margines dla prędkości jest doliczany tylko jeśli oczekiwana prędkość jest większa od 5km/h - if (!(iDrivigFlags&movePress)) - {//jeśli nie dociskanie - if (AccDesired<-0.1) - while (DecSpeed()); //jeśli hamujemy, to nie przyspieszamy - else if (((fAccGravity<-0.01)?AccDesired<0.0:AbsAccS>AccDesired)||(vel>VelDesired)) //jak za bardzo przyspiesza albo prędkość przekroczona - DecSpeed(); //pojedyncze cofnięcie pozycji, bo na zero to przesada - } - //yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej - //zwiekszanie predkosci - //Ra 2F1H: jest konflikt histerezy pomiędzy nastawioną pozycją a uzyskiwanym przyspieszeniem - utrzymanie pozycji powoduje przekroczenie przyspieszenia - if (AbsAccSfMaxProximityDist)?true:(vel0) and (EngineType=ElectricSeriesMotor) - // and (RList[MainCtrlPos].R>0.0) and (not DelayCtrlFlag)) - // if (ImTrainType&dt_EZT) //właściwie, to warunek powinien być na działający EP - {//Ra: to dobrze hamuje EP w EZT - if ((AccDesired<=fAccThreshold)? //jeśli hamować - u góry ustawia się hamowanie na fAccThreshold - ((AbsAccS>AccDesired)||(mvOccupied->BrakeCtrlPos<0)):false) //hamować bardziej, gdy aktualne opóźnienie hamowania mniejsze niż (AccDesired) - IncBrake(); - else - if (OrderList[OrderPos]!=Disconnect) //przy odłączaniu nie zwalniamy tu hamulca - if (AbsAccSBrakeCtrlPos>=0) - DecBrake(); //tutaj zmniejszało o 1 przy odczepianiu - } - else if (mvOccupied->Handle->TimeEP) - { - if (mvOccupied->Handle->GetPos(bh_EPR)-mvOccupied->Handle->GetPos(bh_EPN)<0.1) - mvOccupied->SwitchEPBrake(0); - else - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPN)); - } -// else if (mvOccupied->BrakeCtrlPos<0) IncBrake(); //ustawienie jazdy (pozycja 0) -// else if (mvOccupied->BrakeCtrlPos>0) DecBrake(); - } - else - {//a stara wersja w miarę dobrze działa na składy wagonowe -// if (mvOccupied->Handle->Time) -// mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_MB)); //najwyzej sobie przestawi - if (((fAccGravity<-0.05)&&(vel<0))||((AccDesiredAccDesired+0.05))) //u góry ustawia się hamowanie na fAccThreshold - //if not MinVelFlag) - if (fBrakeTime<0?true:(AccDesiredBrakeCtrlPos<=0)) - if (!IncBrake()) //jeśli upłynął czas reakcji hamulca, chyba że nagłe albo luzował - MinVelFlag=true; - else - {MinVelFlag=false; - fBrakeTime=3+0.5*(mvOccupied->BrakeDelay[2+2*mvOccupied->BrakeDelayFlag]-3); - //Ra: ten czas należy zmniejszyć, jeśli czas dojazdu do zatrzymania jest mniejszy - fBrakeTime*=0.5; //Ra: tymczasowo, bo przeżyna S1 - } - if ((AccDesiredBrakeDelay[1+2*mvOccupied->BrakeDelayFlag])/3.0; - fBrakeTime*=0.5; //Ra: tymczasowo, bo przeżyna S1 - } - } - //Mietek-end1 - SpeedSet(); //ciągla regulacja prędkości -#if LOGVELOCITY - WriteLog("BrakePos="+AnsiString(mvOccupied->BrakeCtrlPos)+", MainCtrl="+AnsiString(mvControlling->MainCtrlPos)); -#endif - -/* //Ra: mamy teraz wskażnik na człon silnikowy, gorzej jak są dwa w ukrotnieniu... - //zapobieganie poslizgowi w czlonie silnikowym; Ra: Couplers[1] powinno być - if (Controlling->Couplers[0].Connected!=NULL) - if (TestFlag(Controlling->Couplers[0].CouplingFlag,ctrain_controll)) - if (Controlling->Couplers[0].Connected->SlippingWheels) - if (Controlling->ScndCtrlPos>0?!Controlling->DecScndCtrl(1):true) - { - if (!Controlling->DecMainCtrl(1)) - if (mvOccupied->BrakeCtrlPos==mvOccupied->BrakeCtrlPosNo) - mvOccupied->DecBrakeLevel(); - ++iDriverFailCount; - } -*/ - //zapobieganie poslizgowi u nas - if (mvControlling->SlippingWheels) - { - if (!mvControlling->DecScndCtrl(2)) //bocznik na zero - mvControlling->DecMainCtrl(1); - if (mvOccupied->BrakeCtrlPos==mvOccupied->BrakeCtrlPosNo) //jeśli ostatnia pozycja hamowania - mvOccupied->DecBrakeLevel(); //to cofnij hamulec - else - mvControlling->AntiSlippingButton(); - ++iDriverFailCount; - mvControlling->SlippingWheels=false; //flaga już wykorzystana - } - if (iDriverFailCount>maxdriverfails) - { - Psyche=Easyman; - if (iDriverFailCount>maxdriverfails*2) - SetDriverPsyche(); - } - } //if (AIControllFlag) - else - {//tu mozna dać komunikaty tekstowe albo słowne: przyspiesz, hamuj (lekko, średnio, mocno) - } - } //kierunek różny od zera - else - {//tutaj, gdy pojazd jest wyłączony - if (!AIControllFlag) //jeśli sterowanie jest w gestii użytkownika - if (mvOccupied->Battery) //czy użytkownik załączył baterię? - if (mvOccupied->ActiveDir) //czy ustawił kierunek - {//jeśli tak, to uruchomienie skanowania - CheckVehicles(); //sprawdzić skład - TableClear(); //resetowanie tabelki skanowania - PrepareEngine(); //uruchomienie - } + return UpdateOK; } - if (AIControllFlag) - {//odhamowywanie składu po zatrzymaniu i zabezpieczanie lokomotywy - if ((OrderList[OrderPos]&(Disconnect|Connect))==0) //przy (p)odłączaniu nie zwalniamy tu hamulca - if ((mvOccupied->V==0.0)&&((VelDesired==0.0)||(AccDesired==0.0))) - if ((mvOccupied->BrakeCtrlPos<1)||!mvOccupied->DecBrakeLevel()) - mvOccupied->IncLocalBrakeLevel(1); //dodatkowy na pozycję 1 - } - break; //rzeczy robione przy jezdzie - } //switch (OrderList[OrderPos]) - //kasowanie licznika czasu - LastReactionTime=0.0; - UpdateOK=true; - } //if ((LastReactionTime>Min0R(ReactionTime,2.0))) - else - LastReactionTime+=dt; - - if((fLastStopExpDist>0.0)&&(mvOccupied->DistCounter>fLastStopExpDist)) - { - iStationStart=TrainParams->StationIndex; //zaktualizować wyświetlanie rozkładu - fLastStopExpDist=-1.0f; //usunąć licznik - } - - if (AIControllFlag) - { - if (fWarningDuration>0.0) //jeśli pozostało coś do wytrąbienia - {//trąbienie trwa nadal - fWarningDuration=fWarningDuration-dt; - if (fWarningDuration<0.05) - mvOccupied->WarningSignal=0; //a tu się kończy - if (ReactionTime>fWarningDuration) - ReactionTime=fWarningDuration; //wcześniejszy przebłysk świadomości, by zakończyć trąbienie - } - if (mvOccupied->Vel>=3.0) //jesli jedzie, można odblokować trąbienie, bo się wtedy nie włączy - {iDrivigFlags&=~moveStartHornDone; //zatrąbi dopiero jak następnym razem stanie - iDrivigFlags|=moveStartHorn; //i trąbić przed następnym ruszeniem - } - return UpdateOK; - } - else //if (AIControllFlag) - return false; //AI nie obsługuje + else // if (AIControllFlag) + return false; // AI nie obsługuje } void __fastcall TController::JumpToNextOrder() -{//wykonanie kolejnej komendy z tablicy rozkazów - if (OrderList[OrderPos]!=Wait_for_orders) - { - if (OrderList[OrderPos]&Change_direction) //jeśli zmiana kierunku - if (OrderList[OrderPos]!=Change_direction) //ale nałożona na coś - {OrderList[OrderPos]=TOrders(OrderList[OrderPos]&~Change_direction); //usunięcie zmiany kierunku z innej komendy +{ // wykonanie kolejnej komendy z tablicy rozkazów + if (OrderList[OrderPos] != Wait_for_orders) + { + if (OrderList[OrderPos] & Change_direction) // jeśli zmiana kierunku + if (OrderList[OrderPos] != Change_direction) // ale nałożona na coś + { + OrderList[OrderPos] = + TOrders(OrderList[OrderPos] & + ~Change_direction); // usunięcie zmiany kierunku z innej komendy + OrderCheck(); + return; + } + if (OrderPos < maxorders - 1) + ++OrderPos; + else + OrderPos = 0; + } OrderCheck(); - return; - } - if (OrderPos JumpToNextOrder"); - OrdersDump(); //normalnie nie ma po co tego wypisywać + WriteLog("--> JumpToNextOrder"); + OrdersDump(); // normalnie nie ma po co tego wypisywać #endif }; void __fastcall TController::JumpToFirstOrder() -{//taki relikt - OrderPos=1; - if (OrderTop==0) OrderTop=1; - OrderCheck(); +{ // taki relikt + OrderPos = 1; + if (OrderTop == 0) + OrderTop = 1; + OrderCheck(); #if LOGORDERS - WriteLog("--> JumpToFirstOrder"); - OrdersDump(); //normalnie nie ma po co tego wypisywać + WriteLog("--> JumpToFirstOrder"); + OrdersDump(); // normalnie nie ma po co tego wypisywać #endif }; void __fastcall TController::OrderCheck() -{//reakcja na zmianę rozkazu - if (OrderList[OrderPos]&(Shunt|Connect|Obey_train)) - CheckVehicles(); //sprawdzić światła - if (OrderList[OrderPos]&Change_direction) //może być nałożona na inną i wtedy ma priorytet - iDirectionOrder=-iDirection; //trzeba zmienić jawnie, bo się nie domyśli - else if (OrderList[OrderPos]==Obey_train) - iDrivigFlags|=moveStopPoint; //W4 są widziane - else if (OrderList[OrderPos]==Disconnect) - iVehicleCount=iVehicleCount<0?0:iVehicleCount; //odczepianie lokomotywy - else if (OrderList[OrderPos]==Connect) - iDrivigFlags&=~moveStopPoint; //podczas jazdy na połączenie nie zwracać uwagi na W4 - else if (OrderList[OrderPos]==Wait_for_orders) - OrdersClear(); //czyszczenie rozkazów i przeskok do zerowej pozycji +{ // reakcja na zmianę rozkazu + if (OrderList[OrderPos] & (Shunt | Connect | Obey_train)) + CheckVehicles(); // sprawdzić światła + if (OrderList[OrderPos] & Change_direction) // może być nałożona na inną i wtedy ma priorytet + iDirectionOrder = -iDirection; // trzeba zmienić jawnie, bo się nie domyśli + else if (OrderList[OrderPos] == Obey_train) + iDrivigFlags |= moveStopPoint; // W4 są widziane + else if (OrderList[OrderPos] == Disconnect) + iVehicleCount = iVehicleCount < 0 ? 0 : iVehicleCount; // odczepianie lokomotywy + else if (OrderList[OrderPos] == Connect) + iDrivigFlags &= ~moveStopPoint; // podczas jazdy na połączenie nie zwracać uwagi na W4 + else if (OrderList[OrderPos] == Wait_for_orders) + OrdersClear(); // czyszczenie rozkazów i przeskok do zerowej pozycji } void __fastcall TController::OrderNext(TOrders NewOrder) -{//ustawienie rozkazu do wykonania jako następny - if (OrderList[OrderPos]==NewOrder) - return; //jeśli robi to, co trzeba, to koniec - if (!OrderPos) OrderPos=1; //na pozycji zerowej pozostaje czekanie - OrderTop=OrderPos; //ale może jest czymś zajęty na razie - if (NewOrder>=Shunt) //jeśli ma jechać - {//ale może być zajęty chwilowymi operacjami - while (OrderList[OrderTop]?OrderList[OrderTop]= Shunt) // jeśli ma jechać + { // ale może być zajęty chwilowymi operacjami + while (OrderList[OrderTop] ? OrderList[OrderTop] < Shunt : false) // jeśli coś robi + ++OrderTop; // pomijamy wszystkie tymczasowe prace + } + else + { // jeśli ma ustawioną jazdę, to wyłączamy na rzecz operacji + while (OrderList[OrderTop] ? + (OrderList[OrderTop] < Shunt) && (OrderList[OrderTop] != NewOrder) : + false) // jeśli coś robi + ++OrderTop; // pomijamy wszystkie tymczasowe prace + } + OrderList[OrderTop++] = NewOrder; // dodanie rozkazu jako następnego #if LOGORDERS - WriteLog("--> OrderNext"); - OrdersDump(); //normalnie nie ma po co tego wypisywać + WriteLog("--> OrderNext"); + OrdersDump(); // normalnie nie ma po co tego wypisywać #endif } void __fastcall TController::OrderPush(TOrders NewOrder) -{//zapisanie na stosie kolejnego rozkazu do wykonania - if (OrderPos==OrderTop) //jeśli miałby być zapis na aktalnej pozycji - if (OrderList[OrderPos] zapis na kolejnej - if (OrderList[OrderTop]!=NewOrder) //jeśli jest to samo, to nie dodajemy - OrderList[OrderTop++]=NewOrder; //dodanie rozkazu na stos - //if (OrderTop=maxorders) - ErrorLog("Commands overflow: The program will now crash"); +{ // zapisanie na stosie kolejnego rozkazu do wykonania + if (OrderPos == OrderTop) // jeśli miałby być zapis na aktalnej pozycji + if (OrderList[OrderPos] < Shunt) // ale nie jedzie + ++OrderTop; // niektóre operacje muszą zostać najpierw dokończone => zapis na kolejnej + if (OrderList[OrderTop] != NewOrder) // jeśli jest to samo, to nie dodajemy + OrderList[OrderTop++] = NewOrder; // dodanie rozkazu na stos + // if (OrderTop= maxorders) + ErrorLog("Commands overflow: The program will now crash"); #if LOGORDERS - WriteLog("--> OrderPush"); - OrdersDump(); //normalnie nie ma po co tego wypisywać + WriteLog("--> OrderPush"); + OrdersDump(); // normalnie nie ma po co tego wypisywać #endif } void __fastcall TController::OrdersDump() -{//wypisanie kolejnych rozkazów do logu - WriteLog("Orders for "+pVehicle->asName+":"); - for (int b=0;basName + ":"); + for (int b = 0; b < maxorders; ++b) + { + WriteLog(AnsiString(b) + ": " + Order2Str(OrderList[b]) + (OrderPos == b ? " <-" : "")); + if (b) // z wyjątkiem pierwszej pozycji + if (OrderList[b] == Wait_for_orders) // jeśli końcowa komenda + break; // dalej nie trzeba + } }; -TOrders __fastcall TController::OrderCurrentGet() -{ - return OrderList[OrderPos]; -} +TOrders __fastcall TController::OrderCurrentGet() { return OrderList[OrderPos]; } -TOrders __fastcall TController::OrderNextGet() -{ - return OrderList[OrderPos+1]; -} +TOrders __fastcall TController::OrderNextGet() { return OrderList[OrderPos + 1]; } void __fastcall TController::OrdersInit(double fVel) -{//wypełnianie tabelki rozkazów na podstawie rozkładu - //ustawienie kolejności komend, niezależnie kto prowadzi - //Mechanik->OrderPush(Wait_for_orders); //czekanie na lepsze czasy - //OrderPos=OrderTop=0; //wypełniamy od pozycji 0 - OrdersClear(); //usunięcie poprzedniej tabeli - OrderPush(Prepare_engine); //najpierw odpalenie silnika - if (TrainParams->TrainName==AnsiString("none")) - {//brak rozkładu to jazda manewrowa - if (fVel>0.05) //typowo 0.1 oznacza gotowość do jazdy, 0.01 tylko załączenie silnika - OrderPush(Shunt); //jeśli nie ma rozkładu, to manewruje - } - else - {//jeśli z rozkładem, to jedzie na szlak - if ((fVel>0.0)&&(fVel<0.02)) - OrderPush(Shunt); //dla prędkości 0.01 włączamy jazdę manewrową - else if (TrainParams? - (TrainParams->TimeTable[1].StationWare.Pos("@")? //jeśli obrót na pierwszym przystanku - ((iDrivigFlags&movePushPull)? //SZT również! SN61 zależnie od wagonów... - (TrainParams->TimeTable[1].StationName==TrainParams->Relation1):false):false):true) - OrderPush(Shunt); //a teraz start będzie w manewrowym, a tryb pociągowy włączy W4 - else - //jeśli start z pierwszej stacji i jednocześnie jest na niej zmiana kierunku, to EZT ma mieć Shunt - OrderPush(Obey_train); //dla starych scenerii start w trybie pociagowym - if (DebugModeFlag) //normalnie nie ma po co tego wypisywać - WriteLog("/* Timetable: "+TrainParams->ShowRelation()); - TMTableLine *t; - for (int i=0;i<=TrainParams->StationCount;++i) - {t=TrainParams->TimeTable+i; - if (DebugModeFlag) //normalnie nie ma po co tego wypisywać - WriteLog(AnsiString(t->StationName)+" "+AnsiString((int)t->Ah)+":"+AnsiString((int)t->Am)+", "+AnsiString((int)t->Dh)+":"+AnsiString((int)t->Dm)+" "+AnsiString(t->StationWare)); - if (AnsiString(t->StationWare).Pos("@")) - {//zmiana kierunku i dalsza jazda wg rozkładu - if (iDrivigFlags&movePushPull) //SZT również! SN61 zależnie od wagonów... - {//jeśli skład zespolony, wystarczy zmienić kierunek jazdy - OrderPush(Change_direction); //zmiana kierunku +{ // wypełnianie tabelki rozkazów na podstawie rozkładu + // ustawienie kolejności komend, niezależnie kto prowadzi + // Mechanik->OrderPush(Wait_for_orders); //czekanie na lepsze czasy + // OrderPos=OrderTop=0; //wypełniamy od pozycji 0 + OrdersClear(); // usunięcie poprzedniej tabeli + OrderPush(Prepare_engine); // najpierw odpalenie silnika + if (TrainParams->TrainName == AnsiString("none")) + { // brak rozkładu to jazda manewrowa + if (fVel > 0.05) // typowo 0.1 oznacza gotowość do jazdy, 0.01 tylko załączenie silnika + OrderPush(Shunt); // jeśli nie ma rozkładu, to manewruje } else - {//dla zwykłego składu wagonowego odczepiamy lokomotywę - OrderPush(Disconnect); //odczepienie lokomotywy - OrderPush(Shunt); //a dalej manewry - if (i<=TrainParams->StationCount) //130827: to się jednak nie sprawdza - {//"@" na ostatniej robi tylko odpięcie - //OrderPush(Change_direction); //zmiana kierunku - //OrderPush(Shunt); //jazda na drugą stronę składu - //OrderPush(Change_direction); //zmiana kierunku - //OrderPush(Connect); //jazda pod wagony - } + { // jeśli z rozkładem, to jedzie na szlak + if ((fVel > 0.0) && (fVel < 0.02)) + OrderPush(Shunt); // dla prędkości 0.01 włączamy jazdę manewrową + else if (TrainParams ? + (TrainParams->TimeTable[1].StationWare.Pos( + "@") ? // jeśli obrót na pierwszym przystanku + ((iDrivigFlags & + movePushPull) ? // SZT również! SN61 zależnie od wagonów... + (TrainParams->TimeTable[1].StationName == TrainParams->Relation1) : + false) : + false) : + true) + OrderPush(Shunt); // a teraz start będzie w manewrowym, a tryb pociągowy włączy W4 + else + // jeśli start z pierwszej stacji i jednocześnie jest na niej zmiana kierunku, to EZT ma + // mieć Shunt + OrderPush(Obey_train); // dla starych scenerii start w trybie pociagowym + if (DebugModeFlag) // normalnie nie ma po co tego wypisywać + WriteLog("/* Timetable: " + TrainParams->ShowRelation()); + TMTableLine *t; + for (int i = 0; i <= TrainParams->StationCount; ++i) + { + t = TrainParams->TimeTable + i; + if (DebugModeFlag) // normalnie nie ma po co tego wypisywać + WriteLog(AnsiString(t->StationName) + " " + AnsiString((int)t->Ah) + ":" + + AnsiString((int)t->Am) + ", " + AnsiString((int)t->Dh) + ":" + + AnsiString((int)t->Dm) + " " + AnsiString(t->StationWare)); + if (AnsiString(t->StationWare).Pos("@")) + { // zmiana kierunku i dalsza jazda wg rozkładu + if (iDrivigFlags & movePushPull) // SZT również! SN61 zależnie od wagonów... + { // jeśli skład zespolony, wystarczy zmienić kierunek jazdy + OrderPush(Change_direction); // zmiana kierunku + } + else + { // dla zwykłego składu wagonowego odczepiamy lokomotywę + OrderPush(Disconnect); // odczepienie lokomotywy + OrderPush(Shunt); // a dalej manewry + if (i <= TrainParams->StationCount) // 130827: to się jednak nie sprawdza + { //"@" na ostatniej robi tylko odpięcie + // OrderPush(Change_direction); //zmiana kierunku + // OrderPush(Shunt); //jazda na drugą stronę składu + // OrderPush(Change_direction); //zmiana kierunku + // OrderPush(Connect); //jazda pod wagony + } + } + if (i < TrainParams->StationCount) // jak nie ostatnia stacja + OrderPush(Obey_train); // to dalej wg rozkładu + } + } + if (DebugModeFlag) // normalnie nie ma po co tego wypisywać + WriteLog("*/"); + OrderPush(Shunt); // po wykonaniu rozkładu przełączy się na manewry + } + // McZapkie-100302 - to ma byc wyzwalane ze scenerii + if (fVel == 0.0) + SetVelocity(0, 0, stopSleep); // jeśli nie ma prędkości początkowej, to śpi + else + { // jeśli podana niezerowa prędkość + if ((fVel >= 1.0) || + (fVel < 0.02)) // jeśli ma jechać - dla 0.01 ma podjechać manewrowo po podaniu sygnału + iDrivigFlags = (iDrivigFlags & ~moveStopHere) | + moveStopCloser; // to do następnego W4 ma podjechać blisko + else + iDrivigFlags |= moveStopHere; // czekać na sygnał + JumpToFirstOrder(); + if (fVel >= 1.0) // jeśli ma jechać + SetVelocity(fVel, -1); // ma ustawić żądaną prędkość + else + SetVelocity(0, 0, stopSleep); // prędkość w przedziale (0;1) oznacza, że ma stać } - if (iStationCount) //jak nie ostatnia stacja - OrderPush(Obey_train); //to dalej wg rozkładu - } - } - if (DebugModeFlag) //normalnie nie ma po co tego wypisywać - WriteLog("*/"); - OrderPush(Shunt); //po wykonaniu rozkładu przełączy się na manewry - } - //McZapkie-100302 - to ma byc wyzwalane ze scenerii - if (fVel==0.0) - SetVelocity(0,0,stopSleep); //jeśli nie ma prędkości początkowej, to śpi - else - {//jeśli podana niezerowa prędkość - if ((fVel>=1.0)||(fVel<0.02)) //jeśli ma jechać - dla 0.01 ma podjechać manewrowo po podaniu sygnału - iDrivigFlags=(iDrivigFlags&~moveStopHere)|moveStopCloser; //to do następnego W4 ma podjechać blisko - else - iDrivigFlags|=moveStopHere; //czekać na sygnał - JumpToFirstOrder(); - if (fVel>=1.0) //jeśli ma jechać - SetVelocity(fVel,-1); //ma ustawić żądaną prędkość - else - SetVelocity(0,0,stopSleep); //prędkość w przedziale (0;1) oznacza, że ma stać - } #if LOGORDERS - WriteLog("--> OrdersInit"); + WriteLog("--> OrdersInit"); #endif - if (DebugModeFlag) //normalnie nie ma po co tego wypisywać - OrdersDump(); //wypisanie kontrolne tabelki rozkazów - //McZapkie! - zeby w ogole AI ruszyl to musi wykonac powyzsze rozkazy - //Ale mozna by je zapodac ze scenerii + if (DebugModeFlag) // normalnie nie ma po co tego wypisywać + OrdersDump(); // wypisanie kontrolne tabelki rozkazów + // McZapkie! - zeby w ogole AI ruszyl to musi wykonac powyzsze rozkazy + // Ale mozna by je zapodac ze scenerii }; - AnsiString __fastcall TController::StopReasonText() -{//informacja tekstowa o przyczynie zatrzymania - if (eStopReason!=7) //zawalidroga będzie inaczej - return StopReasonTable[eStopReason]; - else - return "Blocked by "+(pVehicles[0]->PrevAny()->GetName()); +{ // informacja tekstowa o przyczynie zatrzymania + if (eStopReason != 7) // zawalidroga będzie inaczej + return StopReasonTable[eStopReason]; + else + return "Blocked by " + (pVehicles[0]->PrevAny()->GetName()); }; //---------------------------------------------------------------------------------------------------------------------- -//McZapkie: skanowanie semaforów -//Ra: stare funkcje skanujące, używane podczas manewrów do szukania sygnalizatora z tyłu +// McZapkie: skanowanie semaforów +// Ra: stare funkcje skanujące, używane podczas manewrów do szukania sygnalizatora z tyłu //- nie reagują na PutValues, bo nie ma takiej potrzeby //- rozpoznają tylko zerową prędkość (jako koniec toru i brak podstaw do dalszego skanowania) //---------------------------------------------------------------------------------------------------------------------- /* //nie używane double __fastcall TController::Distance(vector3 &p1,vector3 &n,vector3 &p2) -{//Ra:obliczenie odległości punktu (p1) od płaszczyzny o wektorze normalnym (n) przechodzącej przez (p2) +{//Ra:obliczenie odległości punktu (p1) od płaszczyzny o wektorze normalnym (n) przechodzącej przez +(p2) return n.x*(p1.x-p2.x)+n.y*(p1.y-p2.y)+n.z*(p1.z-p2.z); //ax1+by1+cz1+d, gdzie d=-(ax2+by2+cz2) }; */ bool __fastcall TController::BackwardTrackBusy(TTrack *Track) -{//najpierw sprawdzamy, czy na danym torze są pojazdy z innego składu - if (Track->iNumDynamics) - {//jeśli tylko z własnego składu, to tor jest wolny - for (int i=0;iiNumDynamics;++i) - if (Track->Dynamics[i]->ctOwner!=this) //jeśli jest jakiś cudzy - return true; //to tor jest zajęty i skanowanie nie obowiązuje - } - return false; //wolny +{ // najpierw sprawdzamy, czy na danym torze są pojazdy z innego składu + if (Track->iNumDynamics) + { // jeśli tylko z własnego składu, to tor jest wolny + for (int i = 0; i < Track->iNumDynamics; ++i) + if (Track->Dynamics[i]->ctOwner != this) // jeśli jest jakiś cudzy + return true; // to tor jest zajęty i skanowanie nie obowiązuje + } + return false; // wolny }; -TEvent* __fastcall TController::CheckTrackEventBackward(double fDirection,TTrack *Track) -{//sprawdzanie eventu w torze, czy jest sygnałowym - skanowanie do tyłu - TEvent* e=(fDirection>0)?Track->evEvent2:Track->evEvent1; - if (e) - if (!e->bEnabled) //jeśli sygnałowy (nie dodawany do kolejki) - if (e->Type==tp_GetValues) //PutValues nie może się zmienić - return e; - return NULL; +TEvent *__fastcall TController::CheckTrackEventBackward(double fDirection, TTrack *Track) +{ // sprawdzanie eventu w torze, czy jest sygnałowym - skanowanie do tyłu + TEvent *e = (fDirection > 0) ? Track->evEvent2 : Track->evEvent1; + if (e) + if (!e->bEnabled) // jeśli sygnałowy (nie dodawany do kolejki) + if (e->Type == tp_GetValues) // PutValues nie może się zmienić + return e; + return NULL; }; -TTrack* __fastcall TController::BackwardTraceRoute(double &fDistance,double &fDirection,TTrack *Track,TEvent*&Event) -{//szukanie sygnalizatora w kierunku przeciwnym jazdy (eventu odczytu komórki pamięci) - TTrack *pTrackChVel=Track; //tor ze zmianą prędkości - TTrack *pTrackFrom; //odcinek poprzedni, do znajdywania końca dróg - double fDistChVel=-1; //odległość do toru ze zmianą prędkości - double fCurrentDistance=pVehicle->RaTranslationGet(); //aktualna pozycja na torze - double s=0; - if (fDirection>0) //jeśli w kierunku Point2 toru - fCurrentDistance=Track->Length()-fCurrentDistance; - if (BackwardTrackBusy(Track)) - {//jak tor zajęty innym składem, to nie ma po co skanować - fDistance=0; //to na tym torze stoimy - return NULL; //stop, skanowanie nie dało sensownych rezultatów - } - if ((Event=CheckTrackEventBackward(fDirection,Track))!=NULL) - {//jeśli jest semafor na tym torze - fDistance=0; //to na tym torze stoimy - return Track; - } - if ((Track->VelocityGet()==0.0)||(Track->iDamageFlag&128)) - {//jak prędkosć 0 albo uszkadza, to nie ma po co skanować - fDistance=0; //to na tym torze stoimy - return NULL; //stop, skanowanie nie dało sensownych rezultatów - } - while (sScannedFlag=true; //do pokazywania przeskanowanych torów - pTrackFrom=Track; //zapamiętanie aktualnego odcinka - s+=fCurrentDistance; //doliczenie kolejnego odcinka do przeskanowanej długości - if (fDirection>0) - {//jeśli szukanie od Point1 w kierunku Point2 - if (Track->iNextDirection) - fDirection=-fDirection; - Track=Track->CurrentNext(); //może być NULL - } - else //if (fDirection<0) - {//jeśli szukanie od Point2 w kierunku Point1 - if (!Track->iPrevDirection) - fDirection=-fDirection; - Track=Track->CurrentPrev(); //może być NULL - } - if (Track==pTrackFrom) Track=NULL; //koniec, tak jak dla torów - if (Track?(Track->VelocityGet()==0.0)||(Track->iDamageFlag&128)||BackwardTrackBusy(Track):true) - {//gdy dalej toru nie ma albo zerowa prędkość, albo uszkadza pojazd - fDistance=s; - return NULL; //zwraca NULL, że skanowanie nie dało sensownych rezultatów - } - fCurrentDistance=Track->Length(); - if ((Event=CheckTrackEventBackward(fDirection,Track))!=NULL) - {//znaleziony tor z eventem - fDistance=s; - return Track; - } - } - Event=NULL; //jak dojdzie tu, to nie ma semafora - if (fDistChVel<0) - {//zwraca ostatni sprawdzony tor - fDistance=s; - return Track; - } - fDistance=fDistChVel; //odległość do zmiany prędkości - return pTrackChVel; //i tor na którym się zmienia +TTrack *__fastcall TController::BackwardTraceRoute(double &fDistance, double &fDirection, + TTrack *Track, TEvent *&Event) +{ // szukanie sygnalizatora w kierunku przeciwnym jazdy (eventu odczytu komórki pamięci) + TTrack *pTrackChVel = Track; // tor ze zmianą prędkości + TTrack *pTrackFrom; // odcinek poprzedni, do znajdywania końca dróg + double fDistChVel = -1; // odległość do toru ze zmianą prędkości + double fCurrentDistance = pVehicle->RaTranslationGet(); // aktualna pozycja na torze + double s = 0; + if (fDirection > 0) // jeśli w kierunku Point2 toru + fCurrentDistance = Track->Length() - fCurrentDistance; + if (BackwardTrackBusy(Track)) + { // jak tor zajęty innym składem, to nie ma po co skanować + fDistance = 0; // to na tym torze stoimy + return NULL; // stop, skanowanie nie dało sensownych rezultatów + } + if ((Event = CheckTrackEventBackward(fDirection, Track)) != NULL) + { // jeśli jest semafor na tym torze + fDistance = 0; // to na tym torze stoimy + return Track; + } + if ((Track->VelocityGet() == 0.0) || (Track->iDamageFlag & 128)) + { // jak prędkosć 0 albo uszkadza, to nie ma po co skanować + fDistance = 0; // to na tym torze stoimy + return NULL; // stop, skanowanie nie dało sensownych rezultatów + } + while (s < fDistance) + { + // Track->ScannedFlag=true; //do pokazywania przeskanowanych torów + pTrackFrom = Track; // zapamiętanie aktualnego odcinka + s += fCurrentDistance; // doliczenie kolejnego odcinka do przeskanowanej długości + if (fDirection > 0) + { // jeśli szukanie od Point1 w kierunku Point2 + if (Track->iNextDirection) + fDirection = -fDirection; + Track = Track->CurrentNext(); // może być NULL + } + else // if (fDirection<0) + { // jeśli szukanie od Point2 w kierunku Point1 + if (!Track->iPrevDirection) + fDirection = -fDirection; + Track = Track->CurrentPrev(); // może być NULL + } + if (Track == pTrackFrom) + Track = NULL; // koniec, tak jak dla torów + if (Track ? + (Track->VelocityGet() == 0.0) || (Track->iDamageFlag & 128) || + BackwardTrackBusy(Track) : + true) + { // gdy dalej toru nie ma albo zerowa prędkość, albo uszkadza pojazd + fDistance = s; + return NULL; // zwraca NULL, że skanowanie nie dało sensownych rezultatów + } + fCurrentDistance = Track->Length(); + if ((Event = CheckTrackEventBackward(fDirection, Track)) != NULL) + { // znaleziony tor z eventem + fDistance = s; + return Track; + } + } + Event = NULL; // jak dojdzie tu, to nie ma semafora + if (fDistChVel < 0) + { // zwraca ostatni sprawdzony tor + fDistance = s; + return Track; + } + fDistance = fDistChVel; // odległość do zmiany prędkości + return pTrackChVel; // i tor na którym się zmienia } - -//sprawdzanie zdarzeń semaforów i ograniczeń szlakowych -void __fastcall TController::SetProximityVelocity(double dist,double vel,const vector3 *pos) -{//Ra:przeslanie do AI prędkości -/* - //!!!! zastąpić prawidłową reakcją AI na SetProximityVelocity !!!! - if (vel==0) - {//jeśli zatrzymanie, to zmniejszamy dystans o 10m - dist-=10.0; - }; - if (dist<0.0) dist=0.0; - if ((vel<0)?true:dist>0.1*(MoverParameters->Vel*MoverParameters->Vel-vel*vel)+50) - {//jeśli jest dalej od umownej drogi hamowania -*/ - PutCommand("SetProximityVelocity",dist,vel,pos); -/* - } - else - {//jeśli jest zagrożenie, że przekroczy - Mechanik->SetVelocity(floor(0.2*sqrt(dist)+vel),vel,stopError); - } - */ +// sprawdzanie zdarzeń semaforów i ograniczeń szlakowych +void __fastcall TController::SetProximityVelocity(double dist, double vel, const vector3 *pos) +{ // Ra:przeslanie do AI prędkości + /* + //!!!! zastąpić prawidłową reakcją AI na SetProximityVelocity !!!! + if (vel==0) + {//jeśli zatrzymanie, to zmniejszamy dystans o 10m + dist-=10.0; + }; + if (dist<0.0) dist=0.0; + if ((vel<0)?true:dist>0.1*(MoverParameters->Vel*MoverParameters->Vel-vel*vel)+50) + {//jeśli jest dalej od umownej drogi hamowania + */ + PutCommand("SetProximityVelocity", dist, vel, pos); + /* + } + else + {//jeśli jest zagrożenie, że przekroczy + Mechanik->SetVelocity(floor(0.2*sqrt(dist)+vel),vel,stopError); + } + */ } TCommandType __fastcall TController::BackwardScan() -{//sprawdzanie zdarzeń semaforów z tyłu pojazdu, zwraca komendę - //dzięki temu będzie można stawać za wskazanym sygnalizatorem, a zwłaszcza jeśli będzie jazda na kozioł - //ograniczenia prędkości nie są wtedy istotne, również koniec toru jest do niczego nie przydatny - //zwraca true, jeśli należy odwrócić kierunek jazdy pojazdu - if ((OrderList[OrderPos]&~(Shunt|Connect))) - return cm_Unknown; //skanowanie sygnałów tylko gdy jedzie w trybie manewrowym albo czeka na rozkazy - vector3 sl; - int startdir=-pVehicles[0]->DirectionGet(); //kierunek jazdy względem sprzęgów pojazdu na czele - if (startdir==0) //jeśli kabina i kierunek nie jest określony - return cm_Unknown; //nie robimy nic - double scandir=startdir*pVehicles[0]->RaDirectionGet(); //szukamy od pierwszej osi w wybranym kierunku - if (scandir!=0.0) //skanowanie toru w poszukiwaniu eventów GetValues (PutValues nie są przydatne) - {//Ra: przy wstecznym skanowaniu prędkość nie ma znaczenia - //scanback=pVehicles[1]->NextDistance(fLength+1000.0); //odległość do następnego pojazdu, 1000 gdy nic nie ma - double scanmax=1000; //1000m do tyłu, żeby widział przeciwny koniec stacji - double scandist=scanmax; //zmodyfikuje na rzeczywiście przeskanowane - TEvent *e=NULL; //event potencjalnie od semafora - //opcjonalnie może być skanowanie od "wskaźnika" z przodu, np. W5, Tm=Ms1, koniec toru - TTrack *scantrack=BackwardTraceRoute(scandist,scandir,pVehicles[0]->RaTrackGet(),e); //wg drugiej osi w kierunku ruchu - vector3 dir=startdir*pVehicles[0]->VectorFront(); //wektor w kierunku jazdy/szukania - if (!scantrack) //jeśli wstecz wykryto koniec toru - return cm_Unknown; //to raczej nic się nie da w takiej sytuacji zrobić - else - {//a jeśli są dalej tory - double vmechmax; //prędkość ustawiona semaforem - if (e) - {//jeśli jest jakiś sygnał na widoku +{ // sprawdzanie zdarzeń semaforów z tyłu pojazdu, zwraca komendę + // dzięki temu będzie można stawać za wskazanym sygnalizatorem, a zwłaszcza jeśli będzie jazda + // na kozioł + // ograniczenia prędkości nie są wtedy istotne, również koniec toru jest do niczego nie + // przydatny + // zwraca true, jeśli należy odwrócić kierunek jazdy pojazdu + if ((OrderList[OrderPos] & ~(Shunt | Connect))) + return cm_Unknown; // skanowanie sygnałów tylko gdy jedzie w trybie manewrowym albo czeka na + // rozkazy + vector3 sl; + int startdir = + -pVehicles[0]->DirectionGet(); // kierunek jazdy względem sprzęgów pojazdu na czele + if (startdir == 0) // jeśli kabina i kierunek nie jest określony + return cm_Unknown; // nie robimy nic + double scandir = + startdir * pVehicles[0]->RaDirectionGet(); // szukamy od pierwszej osi w wybranym kierunku + if (scandir != + 0.0) // skanowanie toru w poszukiwaniu eventów GetValues (PutValues nie są przydatne) + { // Ra: przy wstecznym skanowaniu prędkość nie ma znaczenia + // scanback=pVehicles[1]->NextDistance(fLength+1000.0); //odległość do następnego pojazdu, + // 1000 gdy nic nie ma + double scanmax = 1000; // 1000m do tyłu, żeby widział przeciwny koniec stacji + double scandist = scanmax; // zmodyfikuje na rzeczywiście przeskanowane + TEvent *e = NULL; // event potencjalnie od semafora + // opcjonalnie może być skanowanie od "wskaźnika" z przodu, np. W5, Tm=Ms1, koniec toru + TTrack *scantrack = BackwardTraceRoute(scandist, scandir, pVehicles[0]->RaTrackGet(), + e); // wg drugiej osi w kierunku ruchu + vector3 dir = startdir * pVehicles[0]->VectorFront(); // wektor w kierunku jazdy/szukania + if (!scantrack) // jeśli wstecz wykryto koniec toru + return cm_Unknown; // to raczej nic się nie da w takiej sytuacji zrobić + else + { // a jeśli są dalej tory + double vmechmax; // prędkość ustawiona semaforem + if (e) + { // jeśli jest jakiś sygnał na widoku #if LOGBACKSCAN - AnsiString edir=pVehicle->asName+" - "+AnsiString((scandir>0)?"Event2 ":"Event1 "); + AnsiString edir = + pVehicle->asName + " - " + AnsiString((scandir > 0) ? "Event2 " : "Event1 "); #endif - //najpierw sprawdzamy, czy semafor czy inny znak został przejechany - vector3 pos=pVehicles[1]->RearPosition(); //pozycja tyłu - vector3 sem; //wektor do sygnału - if (e->Type==tp_GetValues) - {//przesłać info o zbliżającym się semaforze + // najpierw sprawdzamy, czy semafor czy inny znak został przejechany + vector3 pos = pVehicles[1]->RearPosition(); // pozycja tyłu + vector3 sem; // wektor do sygnału + if (e->Type == tp_GetValues) + { // przesłać info o zbliżającym się semaforze #if LOGBACKSCAN - edir+="("+(e->Params[8].asGroundNode->asName)+"): "; + edir += "(" + (e->Params[8].asGroundNode->asName) + "): "; #endif - sl=e->PositionGet(); //położenie komórki pamięci - sem=sl-pos; //wektor do komórki pamięci od końca składu - //sem=e->Params[8].asGroundNode->pCenter-pos; //wektor do komórki pamięci - if (dir.x*sem.x+dir.z*sem.z<0) //jeśli został minięty - //if ((mvOccupied->CategoryFlag&1)?(VelNext!=0.0):true) //dla pociągu wymagany sygnał zezwalający - {//iloczyn skalarny jest ujemny, gdy sygnał stoi z tyłu + sl = e->PositionGet(); // położenie komórki pamięci + sem = sl - pos; // wektor do komórki pamięci od końca składu + // sem=e->Params[8].asGroundNode->pCenter-pos; //wektor do komórki pamięci + if (dir.x * sem.x + dir.z * sem.z < 0) // jeśli został minięty + // if ((mvOccupied->CategoryFlag&1)?(VelNext!=0.0):true) //dla pociągu wymagany + // sygnał zezwalający + { // iloczyn skalarny jest ujemny, gdy sygnał stoi z tyłu #if LOGBACKSCAN - WriteLog(edir+"- ignored as not passed yet"); + WriteLog(edir + "- ignored as not passed yet"); #endif - return cm_Unknown; //nic - } - vmechmax=e->ValueGet(1); //prędkość przy tym semaforze - //przeliczamy odległość od semafora - potrzebne by były współrzędne początku składu - //scandist=(pos-e->Params[8].asGroundNode->pCenter).Length()-0.5*mvOccupied->Dim.L-10; //10m luzu - scandist=sem.Length()-2; //2m luzu przy manewrach wystarczy - if (scandist<0) scandist=0; //ujemnych nie ma po co wysyłać - bool move=false; //czy AI w trybie manewerowym ma dociągnąć pod S1 - if (e->Command()==cm_SetVelocity) - if ((vmechmax==0.0)?(OrderCurrentGet()&(Shunt|Connect)):(OrderCurrentGet()&Connect)) //przy podczepianiu ignorować wyjazd? - move=true; //AI w trybie manewerowym ma dociągnąć pod S1 - else - {// - if ((scandist>fMinProximityDist)?(mvOccupied->Vel>0.0)&&(OrderCurrentGet()!=Shunt):false) - {//jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości - //jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył - //Mechanik->PutCommand("SetProximityVelocity",scandist,vmechmax,sl); + return cm_Unknown; // nic + } + vmechmax = e->ValueGet(1); // prędkość przy tym semaforze + // przeliczamy odległość od semafora - potrzebne by były współrzędne początku + // składu + // scandist=(pos-e->Params[8].asGroundNode->pCenter).Length()-0.5*mvOccupied->Dim.L-10; + // //10m luzu + scandist = sem.Length() - 2; // 2m luzu przy manewrach wystarczy + if (scandist < 0) + scandist = 0; // ujemnych nie ma po co wysyłać + bool move = false; // czy AI w trybie manewerowym ma dociągnąć pod S1 + if (e->Command() == cm_SetVelocity) + if ((vmechmax == 0.0) ? (OrderCurrentGet() & (Shunt | Connect)) : + (OrderCurrentGet() & + Connect)) // przy podczepianiu ignorować wyjazd? + move = true; // AI w trybie manewerowym ma dociągnąć pod S1 + else + { // + if ((scandist > fMinProximityDist) ? + (mvOccupied->Vel > 0.0) && (OrderCurrentGet() != Shunt) : + false) + { // jeśli semafor jest daleko, a pojazd jedzie, to informujemy o + // zmianie prędkości +// jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył +// Mechanik->PutCommand("SetProximityVelocity",scandist,vmechmax,sl); #if LOGBACKSCAN - //WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+" "+AnsiString(vmechmax)); - WriteLog(edir); + // WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+" + // "+AnsiString(vmechmax)); + WriteLog(edir); #endif - //SetProximityVelocity(scandist,vmechmax,&sl); - return (vmechmax>0)?cm_SetVelocity:cm_Unknown; - } - else //ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma stać - //if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli stoi lub ma stanąć/stać - {//semafor na tym torze albo lokomtywa stoi, a ma ruszyć, albo ma stanąć, albo nie ruszać - //stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam - //PutCommand("SetVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem); + // SetProximityVelocity(scandist,vmechmax,&sl); + return (vmechmax > 0) ? cm_SetVelocity : cm_Unknown; + } + else // ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma + // stać + // if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli stoi lub ma + // stanąć/stać + { // semafor na tym torze albo lokomtywa stoi, a ma ruszyć, albo ma + // stanąć, albo nie ruszać +// stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam +// PutCommand("SetVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem); #if LOGBACKSCAN - WriteLog(edir+"SetVelocity "+AnsiString(vmechmax)+" "+AnsiString(e->Params[9].asMemCell->Value2())); + WriteLog(edir + "SetVelocity " + AnsiString(vmechmax) + " " + + AnsiString(e->Params[9].asMemCell->Value2())); #endif - return (vmechmax>0)?cm_SetVelocity:cm_Unknown; - } - } - if (OrderCurrentGet()?OrderCurrentGet()&(Shunt|Connect):true) //w Wait_for_orders też widzi tarcze - {//reakcja AI w trybie manewrowym dodatkowo na sygnały manewrowe - if (move?true:e->Command()==cm_ShuntVelocity) - {//jeśli powyżej było SetVelocity 0 0, to dociągamy pod S1 - if ((scandist>fMinProximityDist)?(mvOccupied->Vel>0.0)||(vmechmax==0.0):false) - {//jeśli tarcza jest daleko, to: - //- jesli pojazd jedzie, to informujemy o zmianie prędkości - //- jeśli stoi, to z własnej inicjatywy może podjechać pod zamkniętą tarczę - if (mvOccupied->Vel>0.0) //tylko jeśli jedzie - {//Mechanik->PutCommand("SetProximityVelocity",scandist,vmechmax,sl); + return (vmechmax > 0) ? cm_SetVelocity : cm_Unknown; + } + } + if (OrderCurrentGet() ? OrderCurrentGet() & (Shunt | Connect) : + true) // w Wait_for_orders też widzi tarcze + { // reakcja AI w trybie manewrowym dodatkowo na sygnały manewrowe + if (move ? true : e->Command() == cm_ShuntVelocity) + { // jeśli powyżej było SetVelocity 0 0, to dociągamy pod S1 + if ((scandist > fMinProximityDist) ? + (mvOccupied->Vel > 0.0) || (vmechmax == 0.0) : + false) + { // jeśli tarcza jest daleko, to: + //- jesli pojazd jedzie, to informujemy o zmianie prędkości + //- jeśli stoi, to z własnej inicjatywy może podjechać pod zamkniętą + //tarczę + if (mvOccupied->Vel > 0.0) // tylko jeśli jedzie + { // Mechanik->PutCommand("SetProximityVelocity",scandist,vmechmax,sl); #if LOGBACKSCAN - //WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+" "+AnsiString(vmechmax)); - WriteLog(edir); + // WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+" + // "+AnsiString(vmechmax)); + WriteLog(edir); #endif - //SetProximityVelocity(scandist,vmechmax,&sl); - return (iDrivigFlags&moveTrackEnd)?cm_ChangeDirection:cm_Unknown; //jeśli jedzie na W5 albo koniec toru, to można zmienić kierunek - } - } - else //ustawiamy prędkość tylko wtedy, gdy ma ruszyć, albo stanąć albo ma stać pod tarczą - {//stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam - //if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli jedzie lub ma stanąć/stać - {//nie dostanie komendy jeśli jedzie i ma jechać - //PutCommand("ShuntVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem); + // SetProximityVelocity(scandist,vmechmax,&sl); + return (iDrivigFlags & moveTrackEnd) ? + cm_ChangeDirection : + cm_Unknown; // jeśli jedzie na W5 albo koniec toru, + // to można zmienić kierunek + } + } + else // ustawiamy prędkość tylko wtedy, gdy ma ruszyć, albo stanąć albo + // ma stać pod tarczą + { // stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam + // if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli jedzie + // lub ma stanąć/stać + { // nie dostanie komendy jeśli jedzie i ma jechać +// PutCommand("ShuntVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem); #if LOGBACKSCAN - WriteLog(edir+"ShuntVelocity "+AnsiString(vmechmax)+" "+AnsiString(e->ValueGet(2))); + WriteLog(edir + "ShuntVelocity " + AnsiString(vmechmax) + " " + + AnsiString(e->ValueGet(2))); #endif - return (vmechmax>0)?cm_ShuntVelocity:cm_Unknown; - } - } - if ((vmechmax!=0.0)&&(scandist<100.0)) - {//jeśli Tm w odległości do 100m podaje zezwolenie na jazdę, to od razu ją ignorujemy, aby móc szukać kolejnej - //eSignSkip=e; //wtedy uznajemy ignorowaną przy poszukiwaniu nowej + return (vmechmax > 0) ? cm_ShuntVelocity : cm_Unknown; + } + } + if ((vmechmax != 0.0) && (scandist < 100.0)) + { // jeśli Tm w odległości do 100m podaje zezwolenie na jazdę, to od + // razu ją ignorujemy, aby móc szukać kolejnej +// eSignSkip=e; //wtedy uznajemy ignorowaną przy poszukiwaniu nowej #if LOGBACKSCAN - WriteLog(edir+"- will be ignored due to Ms2"); + WriteLog(edir + "- will be ignored due to Ms2"); #endif - return (vmechmax>0)?cm_ShuntVelocity:cm_Unknown; - } - } //if (move?... - } //if (OrderCurrentGet()==Shunt) - if (!e->bEnabled) //jeśli skanowany - if (e->StopCommand()) //a podłączona komórka ma komendę - return cm_Command; //to też się obrócić - } //if (e->Type==tp_GetValues) - } //if (e) - } //if (scantrack) - } //if (scandir!=0.0) - return cm_Unknown; //nic + return (vmechmax > 0) ? cm_ShuntVelocity : cm_Unknown; + } + } // if (move?... + } // if (OrderCurrentGet()==Shunt) + if (!e->bEnabled) // jeśli skanowany + if (e->StopCommand()) // a podłączona komórka ma komendę + return cm_Command; // to też się obrócić + } // if (e->Type==tp_GetValues) + } // if (e) + } // if (scantrack) + } // if (scandir!=0.0) + return cm_Unknown; // nic }; AnsiString __fastcall TController::NextStop() -{//informacja o następnym zatrzymaniu, wyświetlane pod [F1] - if (asNextStop.Length()<20) return ""; //nie zawiera nazwy stacji, gdy dojechał do końca - //dodać godzinę odjazdu - if (!TrainParams) - return ""; //tu nie powinno nigdy wejść - TMTableLine *t=TrainParams->TimeTable+TrainParams->StationIndex; - if (t->Dh>=0) //jeśli jest godzina odjazdu - return - asNextStop.SubString(20,30) - +AnsiString(" ") - +AnsiString(int(t->Dh)) - +AnsiString(":") - +AnsiString(int(100+t->Dm)).SubString(2,2); //odjazd - else if (t->Ah>=0) //przyjazd - return - asNextStop.SubString(20,30) - +AnsiString(" (") - +AnsiString(int(t->Ah)) - +AnsiString(":") - +AnsiString(int(100+t->Am)).SubString(2,2) - +AnsiString(")"); //przyjazd - return ""; +{ // informacja o następnym zatrzymaniu, wyświetlane pod [F1] + if (asNextStop.Length() < 20) + return ""; // nie zawiera nazwy stacji, gdy dojechał do końca + // dodać godzinę odjazdu + if (!TrainParams) + return ""; // tu nie powinno nigdy wejść + TMTableLine *t = TrainParams->TimeTable + TrainParams->StationIndex; + if (t->Dh >= 0) // jeśli jest godzina odjazdu + return asNextStop.SubString(20, 30) + AnsiString(" ") + AnsiString(int(t->Dh)) + + AnsiString(":") + AnsiString(int(100 + t->Dm)).SubString(2, 2); // odjazd + else if (t->Ah >= 0) // przyjazd + return asNextStop.SubString(20, 30) + AnsiString(" (") + AnsiString(int(t->Ah)) + + AnsiString(":") + AnsiString(int(100 + t->Am)).SubString(2, 2) + + AnsiString(")"); // przyjazd + return ""; }; //-----------koniec skanowania semaforow void __fastcall TController::TakeControl(bool yes) -{//przejęcie kontroli przez AI albo oddanie - if (AIControllFlag==yes) return; //już jest jak ma być - if (yes) //żeby nie wykonywać dwa razy - {//teraz AI prowadzi - AIControllFlag=AIdriver; - pVehicle->Controller=AIdriver; - iDirection=0; //kierunek jazdy trzeba dopiero zgadnąć - //gdy zgaszone światła, flaga podjeżdżania pod semafory pozostaje bez zmiany - if (OrderCurrentGet()) //jeśli coś robi - PrepareEngine(); //niech sprawdzi stan silnika - else //jeśli nic nie robi - if (pVehicle->iLights[mvOccupied->CabNo<0?1:0]&21) //któreś ze świateł zapalone? - {//od wersji 357 oczekujemy podania komend dla AI przez scenerię - OrderNext(Prepare_engine); - if (pVehicle->iLights[mvOccupied->CabNo<0?1:0]&4) //górne światło zapalone - OrderNext(Obey_train); //jazda pociągowa +{ // przejęcie kontroli przez AI albo oddanie + if (AIControllFlag == yes) + return; // już jest jak ma być + if (yes) //żeby nie wykonywać dwa razy + { // teraz AI prowadzi + AIControllFlag = AIdriver; + pVehicle->Controller = AIdriver; + iDirection = 0; // kierunek jazdy trzeba dopiero zgadnąć + // gdy zgaszone światła, flaga podjeżdżania pod semafory pozostaje bez zmiany + if (OrderCurrentGet()) // jeśli coś robi + PrepareEngine(); // niech sprawdzi stan silnika + else // jeśli nic nie robi + if (pVehicle->iLights[mvOccupied->CabNo < 0 ? 1 : 0] & + 21) // któreś ze świateł zapalone? + { // od wersji 357 oczekujemy podania komend dla AI przez scenerię + OrderNext(Prepare_engine); + if (pVehicle->iLights[mvOccupied->CabNo < 0 ? 1 : 0] & 4) // górne światło zapalone + OrderNext(Obey_train); // jazda pociągowa + else + OrderNext(Shunt); // jazda manewrowa + if (mvOccupied->Vel >= 1.0) // jeśli jedzie (dla 0.1 ma stać) + iDrivigFlags &= ~moveStopHere; // to ma nie czekać na sygnał, tylko jechać + else + iDrivigFlags |= moveStopHere; // a jak stoi, to niech czeka + } + /* od wersji 357 oczekujemy podania komend dla AI przez scenerię + if (OrderCurrentGet()) + {if (OrderCurrentGet()iLights[mvOccupied->CabNo<0?1:0]&4) //górne światło + OrderNext(Obey_train); //jazda pociągowa + else + OrderNext(Shunt); //jazda manewrowa + } + } + else //jeśli jest w stanie Wait_for_orders + JumpToFirstOrder(); //uruchomienie? + // czy dac ponizsze? to problematyczne + //SetVelocity(pVehicle->GetVelocity(),-1); //utrzymanie dotychczasowej? + if (pVehicle->GetVelocity()>0.0) + SetVelocity(-1,-1); //AI ustali sobie odpowiednią prędkość + */ + // Activation(); //przeniesie użytkownika w ostatnio wybranym kierunku + CheckVehicles(); // ustawienie świateł + TableClear(); // ponowne utworzenie tabelki, bo człowiek mógł pojechać niezgodnie z + // sygnałami + } else - OrderNext(Shunt); //jazda manewrowa - if (mvOccupied->Vel>=1.0) //jeśli jedzie (dla 0.1 ma stać) - iDrivigFlags&=~moveStopHere; //to ma nie czekać na sygnał, tylko jechać - else - iDrivigFlags|=moveStopHere; //a jak stoi, to niech czeka - } -/* od wersji 357 oczekujemy podania komend dla AI przez scenerię - if (OrderCurrentGet()) - {if (OrderCurrentGet()iLights[mvOccupied->CabNo<0?1:0]&4) //górne światło - OrderNext(Obey_train); //jazda pociągowa - else - OrderNext(Shunt); //jazda manewrowa - } - } - else //jeśli jest w stanie Wait_for_orders - JumpToFirstOrder(); //uruchomienie? - // czy dac ponizsze? to problematyczne - //SetVelocity(pVehicle->GetVelocity(),-1); //utrzymanie dotychczasowej? - if (pVehicle->GetVelocity()>0.0) - SetVelocity(-1,-1); //AI ustali sobie odpowiednią prędkość -*/ - //Activation(); //przeniesie użytkownika w ostatnio wybranym kierunku - CheckVehicles(); //ustawienie świateł - TableClear(); //ponowne utworzenie tabelki, bo człowiek mógł pojechać niezgodnie z sygnałami - } - else - {//a teraz użytkownik - AIControllFlag=Humandriver; - pVehicle->Controller=Humandriver; - } + { // a teraz użytkownik + AIControllFlag = Humandriver; + pVehicle->Controller = Humandriver; + } }; void __fastcall TController::DirectionForward(bool forward) -{//ustawienie jazdy do przodu dla true i do tyłu dla false (zależy od kabiny) - while (mvControlling->MainCtrlPos) //samo zapętlenie DecSpeed() nie wystarcza - DecSpeed(true); //wymuszenie zerowania nastawnika jazdy, inaczej się może zawiesić - if (forward) - while (mvOccupied->ActiveDir<=0) - mvOccupied->DirectionForward(); //do przodu w obecnej kabinie - else - while (mvOccupied->ActiveDir>=0) - mvOccupied->DirectionBackward(); //do tyłu w obecnej kabinie - if (mvOccupied->EngineType==DieselEngine) //specjalnie dla SN61 - if (iDrivigFlags&moveActive) //jeśli był już odpalony - if (mvControlling->RList[mvControlling->MainCtrlPos].Mn==0) - mvControlling->IncMainCtrl(1); //żeby nie zgasł +{ // ustawienie jazdy do przodu dla true i do tyłu dla false (zależy od kabiny) + while (mvControlling->MainCtrlPos) // samo zapętlenie DecSpeed() nie wystarcza + DecSpeed(true); // wymuszenie zerowania nastawnika jazdy, inaczej się może zawiesić + if (forward) + while (mvOccupied->ActiveDir <= 0) + mvOccupied->DirectionForward(); // do przodu w obecnej kabinie + else + while (mvOccupied->ActiveDir >= 0) + mvOccupied->DirectionBackward(); // do tyłu w obecnej kabinie + if (mvOccupied->EngineType == DieselEngine) // specjalnie dla SN61 + if (iDrivigFlags & moveActive) // jeśli był już odpalony + if (mvControlling->RList[mvControlling->MainCtrlPos].Mn == 0) + mvControlling->IncMainCtrl(1); //żeby nie zgasł }; -AnsiString __fastcall TController::Relation() -{//zwraca relację pociągu - return TrainParams->ShowRelation(); -}; +AnsiString __fastcall TController::Relation() { // zwraca relację pociągu return TrainParams->ShowRelation(); }; -AnsiString __fastcall TController::TrainName() -{//zwraca relację pociągu - return TrainParams->TrainName; -}; +AnsiString __fastcall TController::TrainName() { // zwraca relację pociągu return TrainParams->TrainName; }; -int __fastcall TController::StationCount() -{//zwraca ilość stacji (miejsc zatrzymania) - return TrainParams->StationCount; -}; +int __fastcall TController::StationCount() { // zwraca ilość stacji (miejsc zatrzymania) return TrainParams->StationCount; }; -int __fastcall TController::StationIndex() -{//zwraca indeks aktualnej stacji (miejsca zatrzymania) - return TrainParams->StationIndex; -}; +int __fastcall TController::StationIndex() { // zwraca indeks aktualnej stacji (miejsca zatrzymania) return TrainParams->StationIndex; }; -bool __fastcall TController::IsStop() -{//informuje, czy jest zatrzymanie na najbliższej stacji - return TrainParams->IsStop(); -}; +bool __fastcall TController::IsStop() { // informuje, czy jest zatrzymanie na najbliższej stacji return TrainParams->IsStop(); }; void __fastcall TController::MoveTo(TDynamicObject *to) -{//przesunięcie AI do innego pojazdu (przy zmianie kabiny) - //mvOccupied->CabDeactivisation(); //wyłączenie kabiny w opuszczanym - pVehicle->Mechanik=to->Mechanik; //żeby się zamieniły, jak jest jakieś drugie - pVehicle=to; - ControllingSet(); //utworzenie połączenia do sterowanego pojazdu - pVehicle->Mechanik=this; - //iDirection=0; //kierunek jazdy trzeba dopiero zgadnąć +{ // przesunięcie AI do innego pojazdu (przy zmianie kabiny) + // mvOccupied->CabDeactivisation(); //wyłączenie kabiny w opuszczanym + pVehicle->Mechanik = to->Mechanik; //żeby się zamieniły, jak jest jakieś drugie + pVehicle = to; + ControllingSet(); // utworzenie połączenia do sterowanego pojazdu + pVehicle->Mechanik = this; + // iDirection=0; //kierunek jazdy trzeba dopiero zgadnąć }; void __fastcall TController::ControllingSet() -{//znajduje człon do sterowania w EZT będzie to silnikowy - //problematyczne jest sterowanie z członu biernego, dlatego damy AI silnikowy - //dzięki temu będzie wirtualna kabina w silnikowym, działająca w rozrządczym - //w plikach FIZ zostały zgubione ujemne maski sprzęgów, stąd problemy z EZT - mvOccupied=pVehicle->MoverParameters; //domyślny skrót do obiektu parametrów - mvControlling=pVehicle->ControlledFind()->MoverParameters; //poszukiwanie członu sterowanego +{ // znajduje człon do sterowania w EZT będzie to silnikowy + // problematyczne jest sterowanie z członu biernego, dlatego damy AI silnikowy + // dzięki temu będzie wirtualna kabina w silnikowym, działająca w rozrządczym + // w plikach FIZ zostały zgubione ujemne maski sprzęgów, stąd problemy z EZT + mvOccupied = pVehicle->MoverParameters; // domyślny skrót do obiektu parametrów + mvControlling = pVehicle->ControlledFind()->MoverParameters; // poszukiwanie członu sterowanego }; AnsiString __fastcall TController::TableText(int i) -{//pozycja tabelki prędkości - i=(iFirst+i)%iSpeedTableSize; //numer pozycji - if (i!=iLast) //w (iLast) znajduje się kolejny tor do przeskanowania, ale nie jest ona aktywną - return sSpeedTable[i].TableText(); - return ""; //wskaźnik końca +{ // pozycja tabelki prędkości + i = (iFirst + i) % iSpeedTableSize; // numer pozycji + if (i != iLast) // w (iLast) znajduje się kolejny tor do przeskanowania, ale nie jest ona + // aktywną + return sSpeedTable[i].TableText(); + return ""; // wskaźnik końca }; int __fastcall TController::CrossRoute(TTrack *tr) -{//zwraca numer segmentu dla skrzyżowania (tr) - //pożądany numer segmentu jest określany podczas skanowania drogi - //droga powinna być określona sposobem przejazdu przez skrzyżowania albo współrzędnymi miejsca docelowego - for (int i=iFirst;i!=iLast;i=(i+1)%iSpeedTableSize) - {//trzeba przejrzeć tabelę skanowania w poszukiwaniu (tr) - //i jak się znajdzie, to zwrócić zapamiętany numer segmentu i kierunek przejazdu (-6..-1,1..6) - if ((sSpeedTable[i].iFlags&3)==3) //jeśli pozycja istotna (1) oraz odcinek (2) - if (sSpeedTable[i].trTrack==tr) //jeśli pozycja odpowiadająca skrzyżowaniu (tr) - return (sSpeedTable[i].iFlags>>28); //najstarsze 4 bity jako liczba -8..7 - } - return 0; //nic nie znaleziono? +{ // zwraca numer segmentu dla skrzyżowania (tr) + // pożądany numer segmentu jest określany podczas skanowania drogi + // droga powinna być określona sposobem przejazdu przez skrzyżowania albo współrzędnymi miejsca + // docelowego + for (int i = iFirst; i != iLast; i = (i + 1) % iSpeedTableSize) + { // trzeba przejrzeć tabelę skanowania w poszukiwaniu (tr) + // i jak się znajdzie, to zwrócić zapamiętany numer segmentu i kierunek przejazdu + // (-6..-1,1..6) + if ((sSpeedTable[i].iFlags & 3) == 3) // jeśli pozycja istotna (1) oraz odcinek (2) + if (sSpeedTable[i].trTrack == tr) // jeśli pozycja odpowiadająca skrzyżowaniu (tr) + return (sSpeedTable[i].iFlags >> 28); // najstarsze 4 bity jako liczba -8..7 + } + return 0; // nic nie znaleziono? }; void __fastcall TController::RouteSwitch(int d) -{//ustawienie kierunku jazdy z kabiny - d&=3; - if (d) - if (iRouteWanted!=d) - {//nowy kierunek - iRouteWanted=d; //zapamiętanie - if (mvOccupied->CategoryFlag&2) //jeśli samochód - for (int i=iFirst;i!=iLast;i=(i+1)%iSpeedTableSize) - {//szukanie pierwszego skrzyżowania i resetowanie kierunku na nim - if ((sSpeedTable[i].iFlags&3)==3) //jeśli pozycja istotna (1) oraz odcinek (2) - if ((sSpeedTable[i].iFlags&32)==0) //odcinek nie może być miniętym - if (sSpeedTable[i].trTrack->eType==tt_Cross) //jeśli skrzyżowanie - {//obcięcie tabelki skanowania przed skrzyżowaniem, aby ponownie wybrać drogę - iLast=i-1; //ponowne skanowanie skrzyżowania (w zwrotnicach jest iLast=i, ale tam jest prościej) - if (iLast<0) iLast+=iSpeedTableSize; //bo tabelka jest zapętlona - return; - } - } - } +{ // ustawienie kierunku jazdy z kabiny + d &= 3; + if (d) + if (iRouteWanted != d) + { // nowy kierunek + iRouteWanted = d; // zapamiętanie + if (mvOccupied->CategoryFlag & 2) // jeśli samochód + for (int i = iFirst; i != iLast; i = (i + 1) % iSpeedTableSize) + { // szukanie pierwszego skrzyżowania i resetowanie kierunku na nim + if ((sSpeedTable[i].iFlags & 3) == + 3) // jeśli pozycja istotna (1) oraz odcinek (2) + if ((sSpeedTable[i].iFlags & 32) == 0) // odcinek nie może być miniętym + if (sSpeedTable[i].trTrack->eType == tt_Cross) // jeśli skrzyżowanie + { // obcięcie tabelki skanowania przed skrzyżowaniem, aby ponownie + // wybrać drogę + iLast = i - 1; // ponowne skanowanie skrzyżowania (w zwrotnicach + // jest iLast=i, ale tam jest prościej) + if (iLast < 0) + iLast += iSpeedTableSize; // bo tabelka jest zapętlona + return; + } + } + } }; AnsiString __fastcall TController::OwnerName() { - return pVehicle?pVehicle->MoverParameters->Name:AnsiString("none"); + return pVehicle ? pVehicle->MoverParameters->Name : AnsiString("none"); }; - diff --git a/Driver.h b/Driver.h index d3b72c88..a10a392d 100644 --- a/Driver.h +++ b/Driver.h @@ -9,312 +9,340 @@ using namespace Math3D; enum TOrders -{//rozkazy dla AI - Wait_for_orders=0, //czekanie na dostarczenie następnych rozkazów - //operacje tymczasowe - Prepare_engine=1, //włączenie silnika - Release_engine=2, //wyłączenie silnika - Change_direction=4, //zmiana kierunku (bez skanowania sygnalizacji) - Connect=8, //podłączanie wagonów (z częściowym skanowaniem sygnalizacji) - Disconnect=0x10, //odłączanie wagonów (bez skanowania sygnalizacji) - //jazda - Shunt=0x20, //tryb manewrowy - Obey_train=0x40, //tryb pociągowy - Jump_to_first_order=0x60 //zapęlenie do pierwszej pozycji (po co?) +{ // rozkazy dla AI + Wait_for_orders = 0, // czekanie na dostarczenie następnych rozkazów + // operacje tymczasowe + Prepare_engine = 1, // włączenie silnika + Release_engine = 2, // wyłączenie silnika + Change_direction = 4, // zmiana kierunku (bez skanowania sygnalizacji) + Connect = 8, // podłączanie wagonów (z częściowym skanowaniem sygnalizacji) + Disconnect = 0x10, // odłączanie wagonów (bez skanowania sygnalizacji) + // jazda + Shunt = 0x20, // tryb manewrowy + Obey_train = 0x40, // tryb pociągowy + Jump_to_first_order = 0x60 // zapęlenie do pierwszej pozycji (po co?) }; enum TMovementStatus -{//flagi bitowe ruchu (iDrivigFlags) - moveStopCloser=1, //podjechać blisko W4 (nie podjeżdżać na początku ani po zmianie czoła) - moveStopPoint=2, //stawać na W4 (wyłączone podczas zmiany czoła) - moveActive=4, //pojazd jest załączony i skanuje - movePress=8, //dociskanie przy odłączeniu (zamiast zmiennej Prepare2press) - moveConnect=0x10, //jest blisko innego pojazdu i można próbować podłączyć - movePrimary=0x20, //ma priorytet w składzie (master) - moveLate=0x40, //flaga spóźnienia, włączy bardziej - moveStopHere=0x80, //nie podjeżdżać do semafora, jeśli droga nie jest wolna - moveStartHorn=0x100, //podawaj sygnał po podaniu wolnej drogi - moveStartHornNow=0x200, //podaj sygnał po odhamowaniu - moveStartHornDone=0x400, //podano sygnał po podaniu wolnej drogi - moveOerlikons=0x800, //skład wyłącznie z zaworami? Oerlikona - moveIncSpeed=0x1000, //załączenie jazdy (np. dla EZT) - moveTrackEnd=0x2000, //dalsza jazda do przodu trwale ograniczona (W5, koniec toru) - moveSwitchFound=0x4000, //na drodze skanowania do przodu jest rozjazd - moveGuardSignal=0x8000, //sygnał od kierownika (minął czas postoju) - moveVisibility=0x10000, //jazda na widoczność po przejechaniu S1 na SBL - moveDoorOpened=0x20000, //drzwi zostały otwarte - doliczyć czas na zamknięcie - movePushPull=0x40000 //zmiana czoła przez zmianę kabiny - nie odczepiać przy zmianie kierunku +{ // flagi bitowe ruchu (iDrivigFlags) + moveStopCloser = 1, // podjechać blisko W4 (nie podjeżdżać na początku ani po zmianie czoła) + moveStopPoint = 2, // stawać na W4 (wyłączone podczas zmiany czoła) + moveActive = 4, // pojazd jest załączony i skanuje + movePress = 8, // dociskanie przy odłączeniu (zamiast zmiennej Prepare2press) + moveConnect = 0x10, // jest blisko innego pojazdu i można próbować podłączyć + movePrimary = 0x20, // ma priorytet w składzie (master) + moveLate = 0x40, // flaga spóźnienia, włączy bardziej + moveStopHere = 0x80, // nie podjeżdżać do semafora, jeśli droga nie jest wolna + moveStartHorn = 0x100, // podawaj sygnał po podaniu wolnej drogi + moveStartHornNow = 0x200, // podaj sygnał po odhamowaniu + moveStartHornDone = 0x400, // podano sygnał po podaniu wolnej drogi + moveOerlikons = 0x800, // skład wyłącznie z zaworami? Oerlikona + moveIncSpeed = 0x1000, // załączenie jazdy (np. dla EZT) + moveTrackEnd = 0x2000, // dalsza jazda do przodu trwale ograniczona (W5, koniec toru) + moveSwitchFound = 0x4000, // na drodze skanowania do przodu jest rozjazd + moveGuardSignal = 0x8000, // sygnał od kierownika (minął czas postoju) + moveVisibility = 0x10000, // jazda na widoczność po przejechaniu S1 na SBL + moveDoorOpened = 0x20000, // drzwi zostały otwarte - doliczyć czas na zamknięcie + movePushPull = 0x40000 // zmiana czoła przez zmianę kabiny - nie odczepiać przy zmianie kierunku }; enum TStopReason -{//powód zatrzymania, dodawany do SetVelocity 0 - w zasadzie do usunięcia - stopNone, //nie ma powodu - powinien jechać - stopSleep, //nie został odpalony, to nie pojedzie - stopSem, //semafor zamknięty - stopTime, //czekanie na godzinę odjazdu - stopEnd, //brak dalszej części toru - stopDir, //trzeba stanąć, by zmienić kierunek jazdy - stopJoin, //stoi w celu połączenia wagonów - stopBlock, //przeszkoda na drodze ruchu - stopComm, //otrzymano taką komendę (niewiadomego pochodzenia) - stopOut, //komenda wyjazdu poza stację (raczej nie powinna zatrzymywać!) - stopRadio, //komunikat przekazany radiem (Radiostop) - stopExt, //komenda z zewnątrz - stopError //z powodu błędu w obliczeniu drogi hamowania +{ // powód zatrzymania, dodawany do SetVelocity 0 - w zasadzie do usunięcia + stopNone, // nie ma powodu - powinien jechać + stopSleep, // nie został odpalony, to nie pojedzie + stopSem, // semafor zamknięty + stopTime, // czekanie na godzinę odjazdu + stopEnd, // brak dalszej części toru + stopDir, // trzeba stanąć, by zmienić kierunek jazdy + stopJoin, // stoi w celu połączenia wagonów + stopBlock, // przeszkoda na drodze ruchu + stopComm, // otrzymano taką komendę (niewiadomego pochodzenia) + stopOut, // komenda wyjazdu poza stację (raczej nie powinna zatrzymywać!) + stopRadio, // komunikat przekazany radiem (Radiostop) + stopExt, // komenda z zewnątrz + stopError // z powodu błędu w obliczeniu drogi hamowania }; enum TAction -{//przechowanie aktualnego stanu AI od poprzedniego przebłysku świadomości - actUnknown, //stan nieznany (domyślny na początku) - actPantUp, //podnieś pantograf (info dla użytkownika) - actConv, //załącz przetwornicę (info dla użytkownika) - actCompr, //załącz sprężarkę (info dla użytkownika) - actSleep, //śpi (wygaszony) - actDrive, //jazda - actGo, //ruszanie z miejsca - actSlow, //przyhamowanie przed ograniczeniem - sctStop, //hamowanie w celu precyzyjnego zatrzymania - actIdle, //luzowanie składu przed odjazdem - actRelease, //luzowanie składu po zmniejszeniu prędkości - actConnect, //dojazd w celu podczepienia - actWait, //czekanie na przystanku - actReady, //zgłoszona gotowość do odjazdu od kierownika - actEmergency, //hamowanie awaryjne - actGoUphill, //ruszanie pod górę - actTest, //hamowanie kontrolne (podczas jazdy) - actTrial //próba hamulca (na postoju) +{ // przechowanie aktualnego stanu AI od poprzedniego przebłysku świadomości + actUnknown, // stan nieznany (domyślny na początku) + actPantUp, // podnieś pantograf (info dla użytkownika) + actConv, // załącz przetwornicę (info dla użytkownika) + actCompr, // załącz sprężarkę (info dla użytkownika) + actSleep, //śpi (wygaszony) + actDrive, // jazda + actGo, // ruszanie z miejsca + actSlow, // przyhamowanie przed ograniczeniem + sctStop, // hamowanie w celu precyzyjnego zatrzymania + actIdle, // luzowanie składu przed odjazdem + actRelease, // luzowanie składu po zmniejszeniu prędkości + actConnect, // dojazd w celu podczepienia + actWait, // czekanie na przystanku + actReady, // zgłoszona gotowość do odjazdu od kierownika + actEmergency, // hamowanie awaryjne + actGoUphill, // ruszanie pod górę + actTest, // hamowanie kontrolne (podczas jazdy) + actTrial // próba hamulca (na postoju) }; class TSpeedPos -{//pozycja tabeli prędkości dla AI -public: - double fDist; //aktualna odległość (ujemna gdy minięte) - double fVelNext; //prędkość obowiązująca od tego miejsca - //double fAcc; - int iFlags; - //1=istotny,2=tor,4=odwrotnie,8-zwrotnica (może się zmienić),16-stan zwrotnicy,32-minięty,64=koniec,128=łuk - //0x100=event,0x200=manewrowa,0x400=przystanek,0x800=SBL,0x1000=wysłana komenda,0x2000=W5 - //0x10000=zatkanie - vector3 vPos; //współrzędne XYZ do liczenia odległości - struct - { - TTrack *trTrack; //wskaźnik na tor o zmiennej prędkości (zwrotnica, obrotnica) - TEvent *evEvent; //połączenie z eventem albo komórką pamięci - }; - void __fastcall CommandCheck(); -public: - void __fastcall Clear(); - bool __fastcall Update(vector3 *p,vector3 *dir,double &len); - bool __fastcall Set(TEvent *e,double d); - void __fastcall Set(TTrack *t,double d,int f); - AnsiString __fastcall TableText(); +{ // pozycja tabeli prędkości dla AI + public: + double fDist; // aktualna odległość (ujemna gdy minięte) + double fVelNext; // prędkość obowiązująca od tego miejsca + // double fAcc; + int iFlags; + // 1=istotny,2=tor,4=odwrotnie,8-zwrotnica (może się zmienić),16-stan + // zwrotnicy,32-minięty,64=koniec,128=łuk + // 0x100=event,0x200=manewrowa,0x400=przystanek,0x800=SBL,0x1000=wysłana komenda,0x2000=W5 + // 0x10000=zatkanie + vector3 vPos; // współrzędne XYZ do liczenia odległości + struct + { + TTrack *trTrack; // wskaźnik na tor o zmiennej prędkości (zwrotnica, obrotnica) + TEvent *evEvent; // połączenie z eventem albo komórką pamięci + }; + void __fastcall CommandCheck(); + + public: + void __fastcall Clear(); + bool __fastcall Update(vector3 *p, vector3 *dir, double &len); + bool __fastcall Set(TEvent *e, double d); + void __fastcall Set(TTrack *t, double d, int f); + AnsiString __fastcall TableText(); }; //---------------------------------------------------------------------------- -static const bool Aggressive=true; -static const bool Easyman=false; -static const bool AIdriver=true; -static const bool Humandriver=false; -static const int maxorders=32; //ilość rozkazów w tabelce -static const int maxdriverfails=4; //ile błędów może zrobić AI zanim zmieni nastawienie -extern bool WriteLogFlag; //logowanie parametrów fizycznych +static const bool Aggressive = true; +static const bool Easyman = false; +static const bool AIdriver = true; +static const bool Humandriver = false; +static const int maxorders = 32; // ilość rozkazów w tabelce +static const int maxdriverfails = 4; // ile błędów może zrobić AI zanim zmieni nastawienie +extern bool WriteLogFlag; // logowanie parametrów fizycznych //---------------------------------------------------------------------------- class TController { -private: //obsługa tabelki prędkości (musi mieć możliwość odhaczania stacji w rozkładzie) - TSpeedPos *sSpeedTable; //najbliższe zmiany prędkości - int iSpeedTableSize; //wielkość tabelki - int iFirst; //aktualna pozycja w tabeli (modulo iSpeedTableSize) - int iLast; //ostatnia wypełniona pozycja w tabeli 0:przeliczać do punktu, <0:podana wartość -public: - double ActualProximityDist; //odległość brana pod uwagę przy wyliczaniu prędkości i przyspieszenia -private: - vector3 vCommandLocation; //polozenie wskaznika, sygnalizatora lub innego obiektu do ktorego odnosi sie komenda - TOrders OrderList[maxorders]; //lista rozkazów - int OrderPos,OrderTop; //rozkaz aktualny oraz wolne miejsce do wstawiania nowych - std::ofstream LogFile; //zapis parametrow fizycznych - std::ofstream AILogFile; //log AI - bool MaxVelFlag; - bool MinVelFlag; - int iDirection; //kierunek jazdy względem sprzęgów pojazdu, w którym siedzi AI (1=przód,-1=tył) - int iDirectionOrder; //żadany kierunek jazdy (służy do zmiany kierunku) - int iVehicleCount; //ilość pojazdów do odłączenia albo zabrania ze składu (-1=wszystkie) - int iCoupler; //maska sprzęgu, jaką należy użyć przy łączeniu (po osiągnięciu trybu Connect), 0 gdy jazda bez łączenia - int iDriverFailCount; //licznik błędów AI - bool Need_TryAgain; //true, jeśli druga pozycja w elektryku nie załapała - bool Need_BrakeRelease; -public: - double fMinProximityDist; //minimalna oległość do przeszkody, jaką należy zachować - double fOverhead1; //informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!) - double fOverhead2; //informacja o sposobie jazdy (-1=normalnie, 0=bez prądu, >0=z opuszczonym i ograniczeniem prędkości) - int iOverheadZero; //suma bitowa jezdy bezprądowej, bity ustawiane przez pojazdy z podniesionymi pantografami - int iOverheadDown; //suma bitowa opuszczenia pantografów, bity ustawiane przez pojazdy z podniesionymi pantografami - double fVoltage; //uśrednione napięcie sieci: przy spadku poniżej wartości minimalnej opóźnić rozruch o losowy czas -private: - double fMaxProximityDist; //akceptowalna odległość stanięcia przed przeszkodą - TStopReason eStopReason; //powód zatrzymania przy ustawieniu zerowej prędkości - AnsiString VehicleName; - double fVelPlus; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - double fVelMinus; //margines obniżenia prędkości, powodujący załączenie napędu - double fWarningDuration; //ile czasu jeszcze trąbić - double fStopTime; //czas postoju przed dalszą jazdą (np. na przystanku) - double WaitingTime; //zliczany czas oczekiwania do samoistnego ruszenia - double WaitingExpireTime; //maksymlany czas oczekiwania do samoistnego ruszenia - //TEvent* eSignLast; //ostatnio znaleziony sygnał, o ile nie minięty -private: //---//---//---//---// koniec zmiennych, poniżej metody //---//---//---//---// - void __fastcall SetDriverPsyche(); - bool __fastcall PrepareEngine(); - bool __fastcall ReleaseEngine(); - bool __fastcall IncBrake(); - bool __fastcall DecBrake(); - bool __fastcall IncSpeed(); - bool __fastcall DecSpeed(bool force=false); - void __fastcall SpeedSet(); - void __fastcall Doors(bool what); - void __fastcall RecognizeCommand(); //odczytuje komende przekazana lokomotywie - void __fastcall Activation(); //umieszczenie obsady w odpowiednim członie - void __fastcall ControllingSet(); //znajduje człon do sterowania - void __fastcall AutoRewident(); //ustawia hamulce w składzie -public: - Mtable::TTrainParameters* __fastcall Timetable() {return TrainParams;}; - void __fastcall PutCommand(AnsiString NewCommand,double NewValue1,double NewValue2,const _mover::TLocation &NewLocation,TStopReason reason=stopComm); - bool __fastcall PutCommand(AnsiString NewCommand,double NewValue1,double NewValue2,const vector3 *NewLocation,TStopReason reason=stopComm); - bool __fastcall UpdateSituation(double dt); //uruchamiac przynajmniej raz na sekundę - //procedury dotyczace rozkazow dla maszynisty - void __fastcall SetVelocity(double NewVel,double NewVelNext,TStopReason r=stopNone); //uaktualnia informacje o prędkości - bool __fastcall SetProximityVelocity(double NewDist,double NewVelNext); //uaktualnia informacje o prędkości przy nastepnym semaforze -public: - void __fastcall JumpToNextOrder(); - void __fastcall JumpToFirstOrder(); - void __fastcall OrderPush(TOrders NewOrder); - void __fastcall OrderNext(TOrders NewOrder); - TOrders __fastcall OrderCurrentGet(); - TOrders __fastcall OrderNextGet(); - bool __fastcall CheckVehicles(TOrders user=Wait_for_orders); -private: - void __fastcall CloseLog(); - void __fastcall OrderCheck(); -public: - void __fastcall OrdersInit(double fVel); - void __fastcall OrdersClear(); - void __fastcall OrdersDump(); - __fastcall TController - (bool AI, - TDynamicObject *NewControll, - bool InitPsyche, - bool primary=true //czy ma aktywnie prowadzić? - ); - AnsiString __fastcall OrderCurrent(); - void __fastcall WaitingSet(double Seconds); -private: - AnsiString __fastcall Order2Str(TOrders Order); - void __fastcall DirectionForward(bool forward); - int __fastcall OrderDirectionChange(int newdir,TMoverParameters *Vehicle); - void __fastcall Lights(int head,int rear); - double __fastcall Distance(vector3 &p1,vector3 &n,vector3 &p2); -private: //Ra: metody obsługujące skanowanie toru - TEvent* __fastcall CheckTrackEvent(double fDirection,TTrack *Track); - bool __fastcall TableCheckEvent(TEvent *e); - bool __fastcall TableAddNew(); - bool __fastcall TableNotFound(TEvent *e); - void __fastcall TableClear(); - TEvent* __fastcall TableCheckTrackEvent(double fDirection,TTrack *Track); - void __fastcall TableTraceRoute(double fDistance,TDynamicObject *pVehicle=NULL); - void __fastcall TableCheck(double fDistance); - TCommandType __fastcall TableUpdate(double &fVelDes,double &fDist,double &fNext,double &fAcc); - void __fastcall TablePurger(); -private: //Ra: stare funkcje skanujące, używane do szukania sygnalizatora z tyłu - bool __fastcall BackwardTrackBusy(TTrack *Track); - TEvent* __fastcall CheckTrackEventBackward(double fDirection,TTrack *Track); - TTrack* __fastcall BackwardTraceRoute(double &fDistance,double &fDirection,TTrack *Track,TEvent*&Event); - void __fastcall SetProximityVelocity(double dist,double vel,const vector3 *pos); - TCommandType __fastcall BackwardScan(); -public: - void __fastcall PhysicsLog(); - AnsiString __fastcall StopReasonText(); - __fastcall ~TController(); - AnsiString __fastcall NextStop(); - void __fastcall TakeControl(bool yes); - AnsiString __fastcall Relation(); - AnsiString __fastcall TrainName(); - int __fastcall StationCount(); - int __fastcall StationIndex(); - bool __fastcall IsStop(); - bool __fastcall Primary() {return this?bool(iDrivigFlags&movePrimary):false;}; - int inline __fastcall DrivigFlags() {return iDrivigFlags;}; - void __fastcall MoveTo(TDynamicObject *to); - void __fastcall DirectionInitial(); - AnsiString __fastcall TableText(int i); - int __fastcall CrossRoute(TTrack *tr); - void __fastcall RouteSwitch(int d); - AnsiString __fastcall OwnerName(); + private: // obsługa tabelki prędkości (musi mieć możliwość odhaczania stacji w rozkładzie) + TSpeedPos *sSpeedTable; // najbliższe zmiany prędkości + int iSpeedTableSize; // wielkość tabelki + int iFirst; // aktualna pozycja w tabeli (modulo iSpeedTableSize) + int iLast; // ostatnia wypełniona pozycja w tabeli 0:przeliczać do + // punktu, <0:podana wartość + public: + double + ActualProximityDist; // odległość brana pod uwagę przy wyliczaniu prędkości i przyspieszenia + private: + vector3 vCommandLocation; // polozenie wskaznika, sygnalizatora lub innego obiektu do ktorego + // odnosi sie komenda + TOrders OrderList[maxorders]; // lista rozkazów + int OrderPos, OrderTop; // rozkaz aktualny oraz wolne miejsce do wstawiania nowych + std::ofstream LogFile; // zapis parametrow fizycznych + std::ofstream AILogFile; // log AI + bool MaxVelFlag; + bool MinVelFlag; + int iDirection; // kierunek jazdy względem sprzęgów pojazdu, w którym siedzi AI (1=przód,-1=tył) + int iDirectionOrder; //żadany kierunek jazdy (służy do zmiany kierunku) + int iVehicleCount; // ilość pojazdów do odłączenia albo zabrania ze składu (-1=wszystkie) + int iCoupler; // maska sprzęgu, jaką należy użyć przy łączeniu (po osiągnięciu trybu Connect), 0 + // gdy jazda bez łączenia + int iDriverFailCount; // licznik błędów AI + bool Need_TryAgain; // true, jeśli druga pozycja w elektryku nie załapała + bool Need_BrakeRelease; + + public: + double fMinProximityDist; // minimalna oległość do przeszkody, jaką należy zachować + double fOverhead1; // informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!) + double fOverhead2; // informacja o sposobie jazdy (-1=normalnie, 0=bez prądu, >0=z opuszczonym i + // ograniczeniem prędkości) + int iOverheadZero; // suma bitowa jezdy bezprądowej, bity ustawiane przez pojazdy z + // podniesionymi pantografami + int iOverheadDown; // suma bitowa opuszczenia pantografów, bity ustawiane przez pojazdy z + // podniesionymi pantografami + double fVoltage; // uśrednione napięcie sieci: przy spadku poniżej wartości minimalnej opóźnić + // rozruch o losowy czas + private: + double fMaxProximityDist; // akceptowalna odległość stanięcia przed przeszkodą + TStopReason eStopReason; // powód zatrzymania przy ustawieniu zerowej prędkości + AnsiString VehicleName; + double fVelPlus; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + double fVelMinus; // margines obniżenia prędkości, powodujący załączenie napędu + double fWarningDuration; // ile czasu jeszcze trąbić + double fStopTime; // czas postoju przed dalszą jazdą (np. na przystanku) + double WaitingTime; // zliczany czas oczekiwania do samoistnego ruszenia + double WaitingExpireTime; // maksymlany czas oczekiwania do samoistnego ruszenia + // TEvent* eSignLast; //ostatnio znaleziony sygnał, o ile nie minięty + private: //---//---//---//---// koniec zmiennych, poniżej metody //---//---//---//---// + void __fastcall SetDriverPsyche(); + bool __fastcall PrepareEngine(); + bool __fastcall ReleaseEngine(); + bool __fastcall IncBrake(); + bool __fastcall DecBrake(); + bool __fastcall IncSpeed(); + bool __fastcall DecSpeed(bool force = false); + void __fastcall SpeedSet(); + void __fastcall Doors(bool what); + void __fastcall RecognizeCommand(); // odczytuje komende przekazana lokomotywie + void __fastcall Activation(); // umieszczenie obsady w odpowiednim członie + void __fastcall ControllingSet(); // znajduje człon do sterowania + void __fastcall AutoRewident(); // ustawia hamulce w składzie + public: + Mtable::TTrainParameters *__fastcall Timetable() { return TrainParams; }; + void __fastcall PutCommand(AnsiString NewCommand, double NewValue1, double NewValue2, + const _mover::TLocation &NewLocation, TStopReason reason = stopComm); + bool __fastcall PutCommand(AnsiString NewCommand, double NewValue1, double NewValue2, + const vector3 *NewLocation, TStopReason reason = stopComm); + bool __fastcall UpdateSituation(double dt); // uruchamiac przynajmniej raz na sekundę + // procedury dotyczace rozkazow dla maszynisty + void __fastcall SetVelocity(double NewVel, double NewVelNext, + TStopReason r = stopNone); // uaktualnia informacje o prędkości + bool __fastcall SetProximityVelocity( + double NewDist, + double NewVelNext); // uaktualnia informacje o prędkości przy nastepnym semaforze + public: + void __fastcall JumpToNextOrder(); + void __fastcall JumpToFirstOrder(); + void __fastcall OrderPush(TOrders NewOrder); + void __fastcall OrderNext(TOrders NewOrder); + TOrders __fastcall OrderCurrentGet(); + TOrders __fastcall OrderNextGet(); + bool __fastcall CheckVehicles(TOrders user = Wait_for_orders); + + private: + void __fastcall CloseLog(); + void __fastcall OrderCheck(); + + public: + void __fastcall OrdersInit(double fVel); + void __fastcall OrdersClear(); + void __fastcall OrdersDump(); + __fastcall TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, + bool primary = true // czy ma aktywnie prowadzić? + ); + AnsiString __fastcall OrderCurrent(); + void __fastcall WaitingSet(double Seconds); + + private: + AnsiString __fastcall Order2Str(TOrders Order); + void __fastcall DirectionForward(bool forward); + int __fastcall OrderDirectionChange(int newdir, TMoverParameters *Vehicle); + void __fastcall Lights(int head, int rear); + double __fastcall Distance(vector3 &p1, vector3 &n, vector3 &p2); + + private: // Ra: metody obsługujące skanowanie toru + TEvent *__fastcall CheckTrackEvent(double fDirection, TTrack *Track); + bool __fastcall TableCheckEvent(TEvent *e); + bool __fastcall TableAddNew(); + bool __fastcall TableNotFound(TEvent *e); + void __fastcall TableClear(); + TEvent *__fastcall TableCheckTrackEvent(double fDirection, TTrack *Track); + void __fastcall TableTraceRoute(double fDistance, TDynamicObject *pVehicle = NULL); + void __fastcall TableCheck(double fDistance); + TCommandType __fastcall TableUpdate(double &fVelDes, double &fDist, double &fNext, + double &fAcc); + void __fastcall TablePurger(); + + private: // Ra: stare funkcje skanujące, używane do szukania sygnalizatora z tyłu + bool __fastcall BackwardTrackBusy(TTrack *Track); + TEvent *__fastcall CheckTrackEventBackward(double fDirection, TTrack *Track); + TTrack *__fastcall BackwardTraceRoute(double &fDistance, double &fDirection, TTrack *Track, + TEvent *&Event); + void __fastcall SetProximityVelocity(double dist, double vel, const vector3 *pos); + TCommandType __fastcall BackwardScan(); + + public: + void __fastcall PhysicsLog(); + AnsiString __fastcall StopReasonText(); + __fastcall ~TController(); + AnsiString __fastcall NextStop(); + void __fastcall TakeControl(bool yes); + AnsiString __fastcall Relation(); + AnsiString __fastcall TrainName(); + int __fastcall StationCount(); + int __fastcall StationIndex(); + bool __fastcall IsStop(); + bool __fastcall Primary() { return this ? bool(iDrivigFlags & movePrimary) : false; }; + int inline __fastcall DrivigFlags() { return iDrivigFlags; }; + void __fastcall MoveTo(TDynamicObject *to); + void __fastcall DirectionInitial(); + AnsiString __fastcall TableText(int i); + int __fastcall CrossRoute(TTrack *tr); + void __fastcall RouteSwitch(int d); + AnsiString __fastcall OwnerName(); }; #endif diff --git a/DynObj.cpp b/DynObj.cpp index 051d1731..9ccbd1fe 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -5,7 +5,6 @@ */ - #include "system.hpp" #include "classes.hpp" #pragma hdrstop @@ -14,7 +13,7 @@ #include "Timer.h" #include "Usefull.h" -//McZapkie-260202 +// McZapkie-260202 #include "Globals.h" #include "Texture.h" #include "AirCoupler.h" @@ -28,212 +27,226 @@ #include "Traction.h" #pragma package(smart_init) -//Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny -#define vWorldFront vector3(0,0,1) -#define vWorldUp vector3(0,1,0) -#define vWorldLeft CrossProduct(vWorldUp,vWorldFront) +// Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny +#define vWorldFront vector3(0, 0, 1) +#define vWorldUp vector3(0, 1, 0) +#define vWorldLeft CrossProduct(vWorldUp, vWorldFront) -//Ra: bo te poniżej to się powielały w każdym module odobno -//vector3 vWorldFront=vector3(0,0,1); -//vector3 vWorldUp=vector3(0,1,0); -//vector3 vWorldLeft=CrossProduct(vWorldUp,vWorldFront); +// Ra: bo te poniżej to się powielały w każdym module odobno +// vector3 vWorldFront=vector3(0,0,1); +// vector3 vWorldUp=vector3(0,1,0); +// vector3 vWorldLeft=CrossProduct(vWorldUp,vWorldFront); #define M_2PI 6.283185307179586476925286766559; -const float maxrot=(M_PI/3.0); //60° +const float maxrot = (M_PI / 3.0); // 60° //--------------------------------------------------------------------------- void __fastcall TAnimPant::AKP_4E() -{//ustawienie wymiarów dla pantografu AKP-4E - vPos=vector3(0,0,0); //przypisanie domyśnych współczynników do pantografów - fLenL1=1.22; //1.176289 w modelach - fLenU1=1.755; //1.724482197 w modelach - fHoriz=0.535; //0.54555075 przesunięcie ślizgu w długości pojazdu względem osi obrotu dolnego ramienia - fHeight=0.07; //wysokość ślizgu ponad oś obrotu - fWidth=0.635; //połowa szerokości ślizgu, 0.635 dla AKP-1 i AKP-4E - fAngleL0=DegToRad(2.8547285515689267247882521833308); - fAngleL=fAngleL0; //początkowy kąt dolnego ramienia - //fAngleU0=acos((1.22*cos(fAngleL)+0.535)/1.755); //górne ramię - fAngleU0=acos((fLenL1*cos(fAngleL)+fHoriz)/fLenU1); //górne ramię - fAngleU=fAngleU0; //początkowy kąt - //PantWys=1.22*sin(fAngleL)+1.755*sin(fAngleU); //wysokość początkowa - PantWys=fLenL1*sin(fAngleL)+fLenU1*sin(fAngleU)+fHeight; //wysokość początkowa - PantTraction=PantWys; - hvPowerWire=NULL; - fWidthExtra=0.381; //(2.032m-1.027)/2 - //poza obszarem roboczym jest aproksymacja łamaną o 5 odcinkach - fHeightExtra[0]= 0.0; //+0.0762 - fHeightExtra[1]=-0.01; //+0.1524 - fHeightExtra[2]=-0.03; //+0.2286 - fHeightExtra[3]=-0.07; //+0.3048 - fHeightExtra[4]=-0.15; //+0.3810 +{ // ustawienie wymiarów dla pantografu AKP-4E + vPos = vector3(0, 0, 0); // przypisanie domyśnych współczynników do pantografów + fLenL1 = 1.22; // 1.176289 w modelach + fLenU1 = 1.755; // 1.724482197 w modelach + fHoriz = 0.535; // 0.54555075 przesunięcie ślizgu w długości pojazdu względem osi obrotu dolnego + // ramienia + fHeight = 0.07; // wysokość ślizgu ponad oś obrotu + fWidth = 0.635; // połowa szerokości ślizgu, 0.635 dla AKP-1 i AKP-4E + fAngleL0 = DegToRad(2.8547285515689267247882521833308); + fAngleL = fAngleL0; // początkowy kąt dolnego ramienia + // fAngleU0=acos((1.22*cos(fAngleL)+0.535)/1.755); //górne ramię + fAngleU0 = acos((fLenL1 * cos(fAngleL) + fHoriz) / fLenU1); // górne ramię + fAngleU = fAngleU0; // początkowy kąt + // PantWys=1.22*sin(fAngleL)+1.755*sin(fAngleU); //wysokość początkowa + PantWys = fLenL1 * sin(fAngleL) + fLenU1 * sin(fAngleU) + fHeight; // wysokość początkowa + PantTraction = PantWys; + hvPowerWire = NULL; + fWidthExtra = 0.381; //(2.032m-1.027)/2 + // poza obszarem roboczym jest aproksymacja łamaną o 5 odcinkach + fHeightExtra[0] = 0.0; //+0.0762 + fHeightExtra[1] = -0.01; //+0.1524 + fHeightExtra[2] = -0.03; //+0.2286 + fHeightExtra[3] = -0.07; //+0.3048 + fHeightExtra[4] = -0.15; //+0.3810 }; //--------------------------------------------------------------------------- -int __fastcall TAnim::TypeSet(int i,int fl) -{//ustawienie typu animacji i zależnej od niego ilości animowanych submodeli - fMaxDist=-1.0; //normalnie nie pokazywać - switch (i) - {//maska 0x000F: ile używa wskaźników na submodele (0 gdy jeden, wtedy bez tablicy) - //maska 0x00F0: 0-osie,1-drzwi,2-obracane,3-zderzaki,4-wózki,5-pantografy,6-tłoki - //maska 0xFF00: ile używa liczb float dla współczynników i stanu - case 0: iFlags=0x000; break; //0-oś - case 1: iFlags=0x010; break; //1-drzwi - case 2: iFlags=0x020; - fParam=fl?new float[fl]:NULL; - iFlags+=fl<<8; - break; //2-wahacz, dźwignia itp. - case 3: iFlags=0x030; break; //3-zderzak - case 4: iFlags=0x040; break; //4-wózek - case 5: //5-pantograf - 5 submodeli - iFlags=0x055; - fParamPants=new TAnimPant(); - fParamPants->AKP_4E(); - break; - case 6: iFlags=0x068; break; //6-tłok i rozrząd - 8 submodeli - default: iFlags=0; - } - yUpdate=NULL; - return iFlags&15; //ile wskaźników rezerwować dla danego typu animacji +int __fastcall TAnim::TypeSet(int i, int fl) +{ // ustawienie typu animacji i zależnej od niego ilości animowanych submodeli + fMaxDist = -1.0; // normalnie nie pokazywać + switch (i) + { // maska 0x000F: ile używa wskaźników na submodele (0 gdy jeden, wtedy bez tablicy) + // maska 0x00F0: 0-osie,1-drzwi,2-obracane,3-zderzaki,4-wózki,5-pantografy,6-tłoki + // maska 0xFF00: ile używa liczb float dla współczynników i stanu + case 0: + iFlags = 0x000; + break; // 0-oś + case 1: + iFlags = 0x010; + break; // 1-drzwi + case 2: + iFlags = 0x020; + fParam = fl ? new float[fl] : NULL; + iFlags += fl << 8; + break; // 2-wahacz, dźwignia itp. + case 3: + iFlags = 0x030; + break; // 3-zderzak + case 4: + iFlags = 0x040; + break; // 4-wózek + case 5: // 5-pantograf - 5 submodeli + iFlags = 0x055; + fParamPants = new TAnimPant(); + fParamPants->AKP_4E(); + break; + case 6: + iFlags = 0x068; + break; // 6-tłok i rozrząd - 8 submodeli + default: + iFlags = 0; + } + yUpdate = NULL; + return iFlags & 15; // ile wskaźników rezerwować dla danego typu animacji }; __fastcall TAnim::TAnim() -{//potrzebne to w ogóle? - iFlags=-1; //nieznany typ - destruktor nic nie usuwa +{ // potrzebne to w ogóle? + iFlags = -1; // nieznany typ - destruktor nic nie usuwa }; __fastcall TAnim::~TAnim() -{//usuwanie animacji - switch (iFlags&0xF0) - {//usuwanie struktur, zależnie ile zostało stworzonych - case 0x20: //2-wahacz, dźwignia itp. - delete fParam; - break; - case 0x50: //5-pantograf - delete fParamPants; - break; - case 0x60: //6-tłok i rozrząd - break; - } +{ // usuwanie animacji + switch (iFlags & 0xF0) + { // usuwanie struktur, zależnie ile zostało stworzonych + case 0x20: // 2-wahacz, dźwignia itp. + delete fParam; + break; + case 0x50: // 5-pantograf + delete fParamPants; + break; + case 0x60: // 6-tłok i rozrząd + break; + } }; -void __fastcall TAnim::Parovoz() -{//animowanie tłoka i rozrządu parowozu +void __fastcall TAnim::Parovoz(){// animowanie tłoka i rozrządu parowozu }; //--------------------------------------------------------------------------- -TDynamicObject* __fastcall TDynamicObject::FirstFind(int &coupler_nr) -{//szukanie skrajnego połączonego pojazdu w pociagu - //od strony sprzegu (coupler_nr) obiektu (start) - TDynamicObject* temp=this; - for (int i=0;i<300;i++) //ograniczenie do 300 na wypadek zapętlenia składu - { - if (!temp) - return NULL; //Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów - if (temp->MoverParameters->Couplers[coupler_nr].CouplingFlag==0) - return temp; //nic nie ma już dalej podłączone - if (coupler_nr==0) - {//jeżeli szukamy od sprzęgu 0 - if (temp->PrevConnected) //jeśli mamy coś z przodu - { - if (temp->PrevConnectedNo==0) //jeśli pojazd od strony sprzęgu 0 jest odwrócony - coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu - temp=temp->PrevConnected; //ten jest od strony 0 - } - else - return temp; //jeśli jednak z przodu nic nie ma - } - else - { - if (temp->NextConnected) - {if (temp->NextConnectedNo==1) //jeśli pojazd od strony sprzęgu 1 jest odwrócony - coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu - temp=temp->NextConnected; //ten pojazd jest od strony 1 - } - else - return temp; //jeśli jednak z tyłu nic nie ma - } - } - return NULL; //to tylko po wyczerpaniu pętli +TDynamicObject *__fastcall TDynamicObject::FirstFind(int &coupler_nr) +{ // szukanie skrajnego połączonego pojazdu w pociagu + // od strony sprzegu (coupler_nr) obiektu (start) + TDynamicObject *temp = this; + for (int i = 0; i < 300; i++) // ograniczenie do 300 na wypadek zapętlenia składu + { + if (!temp) + return NULL; // Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów + if (temp->MoverParameters->Couplers[coupler_nr].CouplingFlag == 0) + return temp; // nic nie ma już dalej podłączone + if (coupler_nr == 0) + { // jeżeli szukamy od sprzęgu 0 + if (temp->PrevConnected) // jeśli mamy coś z przodu + { + if (temp->PrevConnectedNo == 0) // jeśli pojazd od strony sprzęgu 0 jest odwrócony + coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu + temp = temp->PrevConnected; // ten jest od strony 0 + } + else + return temp; // jeśli jednak z przodu nic nie ma + } + else + { + if (temp->NextConnected) + { + if (temp->NextConnectedNo == 1) // jeśli pojazd od strony sprzęgu 1 jest odwrócony + coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu + temp = temp->NextConnected; // ten pojazd jest od strony 1 + } + else + return temp; // jeśli jednak z tyłu nic nie ma + } + } + return NULL; // to tylko po wyczerpaniu pętli }; //--------------------------------------------------------------------------- float __fastcall TDynamicObject::GetEPP() -{//szukanie skrajnego połączonego pojazdu w pociagu - //od strony sprzegu (coupler_nr) obiektu (start) - TDynamicObject* temp=this; - int coupler_nr=0; - float eq=0,am=0; +{ // szukanie skrajnego połączonego pojazdu w pociagu + // od strony sprzegu (coupler_nr) obiektu (start) + TDynamicObject *temp = this; + int coupler_nr = 0; + float eq = 0, am = 0; - for (int i=0;i<300;i++) //ograniczenie do 300 na wypadek zapętlenia składu - { - if (!temp) - break; //Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów - eq+=temp->MoverParameters->PipePress*temp->MoverParameters->Dim.L; - am+=temp->MoverParameters->Dim.L; - if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag&2)!=2) - break; //nic nie ma już dalej podłączone - if (coupler_nr==0) - {//jeżeli szukamy od sprzęgu 0 - if (temp->PrevConnected) //jeśli mamy coś z przodu - { - if (temp->PrevConnectedNo==0) //jeśli pojazd od strony sprzęgu 0 jest odwrócony - coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu - temp=temp->PrevConnected; //ten jest od strony 0 - } - else - break; //jeśli jednak z przodu nic nie ma - } - else - { - if (temp->NextConnected) - {if (temp->NextConnectedNo==1) //jeśli pojazd od strony sprzęgu 1 jest odwrócony - coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu - temp=temp->NextConnected; //ten pojazd jest od strony 1 - } - else - break; //jeśli jednak z tyłu nic nie ma - } - } + for (int i = 0; i < 300; i++) // ograniczenie do 300 na wypadek zapętlenia składu + { + if (!temp) + break; // Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów + eq += temp->MoverParameters->PipePress * temp->MoverParameters->Dim.L; + am += temp->MoverParameters->Dim.L; + if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag & 2) != 2) + break; // nic nie ma już dalej podłączone + if (coupler_nr == 0) + { // jeżeli szukamy od sprzęgu 0 + if (temp->PrevConnected) // jeśli mamy coś z przodu + { + if (temp->PrevConnectedNo == 0) // jeśli pojazd od strony sprzęgu 0 jest odwrócony + coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu + temp = temp->PrevConnected; // ten jest od strony 0 + } + else + break; // jeśli jednak z przodu nic nie ma + } + else + { + if (temp->NextConnected) + { + if (temp->NextConnectedNo == 1) // jeśli pojazd od strony sprzęgu 1 jest odwrócony + coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu + temp = temp->NextConnected; // ten pojazd jest od strony 1 + } + else + break; // jeśli jednak z tyłu nic nie ma + } + } - temp=this; - coupler_nr=1; - for (int i=0;i<300;i++) //ograniczenie do 300 na wypadek zapętlenia składu - { - if (!temp) - break; //Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów - eq+=temp->MoverParameters->PipePress*temp->MoverParameters->Dim.L; - am+=temp->MoverParameters->Dim.L; - if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag&2)!=2) - break; //nic nie ma już dalej podłączone - if (coupler_nr==0) - {//jeżeli szukamy od sprzęgu 0 - if (temp->PrevConnected) //jeśli mamy coś z przodu - { - if (temp->PrevConnectedNo==0) //jeśli pojazd od strony sprzęgu 0 jest odwrócony - coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu - temp=temp->PrevConnected; //ten jest od strony 0 - } - else - break; //jeśli jednak z przodu nic nie ma - } - else - { - if (temp->NextConnected) - {if (temp->NextConnectedNo==1) //jeśli pojazd od strony sprzęgu 1 jest odwrócony - coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu - temp=temp->NextConnected; //ten pojazd jest od strony 1 - } - else - break; //jeśli jednak z tyłu nic nie ma - } - } - eq-=MoverParameters->PipePress*MoverParameters->Dim.L; - am-=MoverParameters->Dim.L; - return eq/am; + temp = this; + coupler_nr = 1; + for (int i = 0; i < 300; i++) // ograniczenie do 300 na wypadek zapętlenia składu + { + if (!temp) + break; // Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów + eq += temp->MoverParameters->PipePress * temp->MoverParameters->Dim.L; + am += temp->MoverParameters->Dim.L; + if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag & 2) != 2) + break; // nic nie ma już dalej podłączone + if (coupler_nr == 0) + { // jeżeli szukamy od sprzęgu 0 + if (temp->PrevConnected) // jeśli mamy coś z przodu + { + if (temp->PrevConnectedNo == 0) // jeśli pojazd od strony sprzęgu 0 jest odwrócony + coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu + temp = temp->PrevConnected; // ten jest od strony 0 + } + else + break; // jeśli jednak z przodu nic nie ma + } + else + { + if (temp->NextConnected) + { + if (temp->NextConnectedNo == 1) // jeśli pojazd od strony sprzęgu 1 jest odwrócony + coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu + temp = temp->NextConnected; // ten pojazd jest od strony 1 + } + else + break; // jeśli jednak z tyłu nic nie ma + } + } + eq -= MoverParameters->PipePress * MoverParameters->Dim.L; + am -= MoverParameters->Dim.L; + return eq / am; }; - //--------------------------------------------------------------------------- -TDynamicObject* __fastcall TDynamicObject::GetFirstDynamic(int cpl_type) -{//Szukanie skrajnego połączonego pojazdu w pociagu - //od strony sprzegu (cpl_type) obiektu szukajacego - //Ra: wystarczy jedna funkcja do szukania w obu kierunkach - return FirstFind(cpl_type); //używa referencji +TDynamicObject *__fastcall TDynamicObject::GetFirstDynamic(int cpl_type) +{ // Szukanie skrajnego połączonego pojazdu w pociagu + // od strony sprzegu (cpl_type) obiektu szukajacego + // Ra: wystarczy jedna funkcja do szukania w obu kierunkach + return FirstFind(cpl_type); // używa referencji }; /* @@ -268,1631 +281,1931 @@ TDynamicObject* __fastcall TDynamicObject::GetFirstCabDynamic(int cpl_type) }; */ -void TDynamicObject::ABuSetModelShake(vector3 mShake) -{ - modelShake=mShake; -}; +void TDynamicObject::ABuSetModelShake(vector3 mShake) { modelShake = mShake; }; int __fastcall TDynamicObject::GetPneumatic(bool front, bool red) { - int x,y,z; //1=prosty, 2=skośny - if (red) - { - if (front) - { - x=btCPneumatic1.GetStatus(); - y=btCPneumatic1r.GetStatus(); - } - else - { - x=btCPneumatic2.GetStatus(); - y=btCPneumatic2r.GetStatus(); - } - } - else - if (front) - { - x=btPneumatic1.GetStatus(); - y=btPneumatic1r.GetStatus(); - } - else - { - x=btPneumatic2.GetStatus(); - y=btPneumatic2r.GetStatus(); - } - z=0; //brak węży? - if ((x==1)&&(y==1)) z=3; //dwa proste - if ((x==2)&&(y==0)) z=1; //lewy skośny, brak prawego - if ((x==0)&&(y==2)) z=2; //brak lewego, prawy skośny + int x, y, z; // 1=prosty, 2=skośny + if (red) + { + if (front) + { + x = btCPneumatic1.GetStatus(); + y = btCPneumatic1r.GetStatus(); + } + else + { + x = btCPneumatic2.GetStatus(); + y = btCPneumatic2r.GetStatus(); + } + } + else if (front) + { + x = btPneumatic1.GetStatus(); + y = btPneumatic1r.GetStatus(); + } + else + { + x = btPneumatic2.GetStatus(); + y = btPneumatic2r.GetStatus(); + } + z = 0; // brak węży? + if ((x == 1) && (y == 1)) + z = 3; // dwa proste + if ((x == 2) && (y == 0)) + z = 1; // lewy skośny, brak prawego + if ((x == 0) && (y == 2)) + z = 2; // brak lewego, prawy skośny - return z; + return z; } -void __fastcall TDynamicObject::SetPneumatic(bool front,bool red) +void __fastcall TDynamicObject::SetPneumatic(bool front, bool red) { - int x=0,ten,tamten; - ten=GetPneumatic(front,red); //1=lewy skos,2=prawy skos,3=dwa proste - if (front) - if (PrevConnected) //pojazd od strony sprzęgu 0 - tamten=PrevConnected->GetPneumatic((PrevConnectedNo==0?true:false),red); - if (!front) - if (NextConnected) //pojazd od strony sprzęgu 1 - tamten=NextConnected->GetPneumatic((NextConnectedNo==0?true:false),red); - if (ten==tamten) //jeśli układ jest symetryczny - switch (ten) - { - case 1: x=2; break; //mamy lewy skos, dać lewe skosy - case 2: x=3; break; //mamy prawy skos, dać prawe skosy - case 3: //wszystkie cztery na prosto - if (MoverParameters->Couplers[front?0:1].Render) x=1; else x=4; - break; - } - else - { - if (ten==2) x=4; - if (ten==1) x=1; - if (ten==3) if (tamten==1) x=4; else x=1; - } - if (front) - {if (red) cp1=x; else sp1=x;} //który pokazywać z przodu - else - {if (red) cp2=x; else sp2=x;} //który pokazywać z tyłu + int x = 0, ten, tamten; + ten = GetPneumatic(front, red); // 1=lewy skos,2=prawy skos,3=dwa proste + if (front) + if (PrevConnected) // pojazd od strony sprzęgu 0 + tamten = PrevConnected->GetPneumatic((PrevConnectedNo == 0 ? true : false), red); + if (!front) + if (NextConnected) // pojazd od strony sprzęgu 1 + tamten = NextConnected->GetPneumatic((NextConnectedNo == 0 ? true : false), red); + if (ten == tamten) // jeśli układ jest symetryczny + switch (ten) + { + case 1: + x = 2; + break; // mamy lewy skos, dać lewe skosy + case 2: + x = 3; + break; // mamy prawy skos, dać prawe skosy + case 3: // wszystkie cztery na prosto + if (MoverParameters->Couplers[front ? 0 : 1].Render) + x = 1; + else + x = 4; + break; + } + else + { + if (ten == 2) + x = 4; + if (ten == 1) + x = 1; + if (ten == 3) + if (tamten == 1) + x = 4; + else + x = 1; + } + if (front) + { + if (red) + cp1 = x; + else + sp1 = x; + } // który pokazywać z przodu + else + { + if (red) + cp2 = x; + else + sp2 = x; + } // który pokazywać z tyłu } void TDynamicObject::UpdateAxle(TAnim *pAnim) -{//animacja osi - pAnim->smAnimated->SetRotate(float3(1,0,0),*pAnim->dWheelAngle); +{ // animacja osi + pAnim->smAnimated->SetRotate(float3(1, 0, 0), *pAnim->dWheelAngle); }; void TDynamicObject::UpdateBoogie(TAnim *pAnim) -{//animacja wózka - pAnim->smAnimated->SetRotate(float3(1,0,0),*pAnim->dWheelAngle); +{ // animacja wózka + pAnim->smAnimated->SetRotate(float3(1, 0, 0), *pAnim->dWheelAngle); }; void TDynamicObject::UpdateDoorTranslate(TAnim *pAnim) -{//animacja drzwi - przesuw - //WriteLog("Dla drzwi nr:", i); - //WriteLog("Wspolczynnik", DoorSpeedFactor[i]); - //Ra: te współczynniki są bez sensu, bo modyfikują wektor przesunięcia - //w efekcie drzwi otwierane na zewnątrz będą odlatywac dowolnie daleko :) - //ograniczyłem zakres ruchu funkcją max - if (pAnim->smAnimated) - { - if (pAnim->iNumber&1) - pAnim->smAnimated->SetTranslate(vector3(0,0,Max0R(dDoorMoveR*pAnim->fSpeed,dDoorMoveR))); - else - pAnim->smAnimated->SetTranslate(vector3(0,0,Max0R(dDoorMoveL*pAnim->fSpeed,dDoorMoveL))); - } +{ // animacja drzwi - przesuw + // WriteLog("Dla drzwi nr:", i); + // WriteLog("Wspolczynnik", DoorSpeedFactor[i]); + // Ra: te współczynniki są bez sensu, bo modyfikują wektor przesunięcia + // w efekcie drzwi otwierane na zewnątrz będą odlatywac dowolnie daleko :) + // ograniczyłem zakres ruchu funkcją max + if (pAnim->smAnimated) + { + if (pAnim->iNumber & 1) + pAnim->smAnimated->SetTranslate( + vector3(0, 0, Max0R(dDoorMoveR * pAnim->fSpeed, dDoorMoveR))); + else + pAnim->smAnimated->SetTranslate( + vector3(0, 0, Max0R(dDoorMoveL * pAnim->fSpeed, dDoorMoveL))); + } }; void TDynamicObject::UpdateDoorRotate(TAnim *pAnim) -{//animacja drzwi - obrót - if (pAnim->smAnimated) - {//if (MoverParameters->DoorOpenMethod==2) //obrotowe albo dwójłomne (trzeba kombinowac submodelami i ShiftL=90,R=180) - if (pAnim->iNumber&1) - pAnim->smAnimated->SetRotate(float3(1,0,0),dDoorMoveR); - else - pAnim->smAnimated->SetRotate(float3(1,0,0),dDoorMoveL); - } +{ // animacja drzwi - obrót + if (pAnim->smAnimated) + { // if (MoverParameters->DoorOpenMethod==2) //obrotowe albo dwójłomne (trzeba kombinowac + // submodelami i ShiftL=90,R=180) + if (pAnim->iNumber & 1) + pAnim->smAnimated->SetRotate(float3(1, 0, 0), dDoorMoveR); + else + pAnim->smAnimated->SetRotate(float3(1, 0, 0), dDoorMoveL); + } }; void TDynamicObject::UpdateDoorFold(TAnim *pAnim) -{//animacja drzwi - obrót - if (pAnim->smAnimated) - {//if (MoverParameters->DoorOpenMethod==2) //obrotowe albo dwójłomne (trzeba kombinowac submodelami i ShiftL=90,R=180) - if (pAnim->iNumber&1) - {pAnim->smAnimated->SetRotate(float3(0,0,1),dDoorMoveR); - TSubModel *sm=pAnim->smAnimated->ChildGet(); //skrzydło mniejsze - if (sm) - {sm->SetRotate(float3(0,0,1),-dDoorMoveR-dDoorMoveR); //skrzydło większe - sm=sm->ChildGet(); - if (sm) - sm->SetRotate(float3(0,1,0),dDoorMoveR); //podnóżek? - } - } - else - {pAnim->smAnimated->SetRotate(float3(0,0,1),dDoorMoveL); - //SubModel->SetRotate(float3(0,1,0),fValue*360.0); - TSubModel *sm=pAnim->smAnimated->ChildGet(); //skrzydło mniejsze - if (sm) - {sm->SetRotate(float3(0,0,1),-dDoorMoveL-dDoorMoveL); //skrzydło większe - sm=sm->ChildGet(); - if (sm) - sm->SetRotate(float3(0,1,0),dDoorMoveL); //podnóżek? - } - } - } +{ // animacja drzwi - obrót + if (pAnim->smAnimated) + { // if (MoverParameters->DoorOpenMethod==2) //obrotowe albo dwójłomne (trzeba kombinowac + // submodelami i ShiftL=90,R=180) + if (pAnim->iNumber & 1) + { + pAnim->smAnimated->SetRotate(float3(0, 0, 1), dDoorMoveR); + TSubModel *sm = pAnim->smAnimated->ChildGet(); // skrzydło mniejsze + if (sm) + { + sm->SetRotate(float3(0, 0, 1), -dDoorMoveR - dDoorMoveR); // skrzydło większe + sm = sm->ChildGet(); + if (sm) + sm->SetRotate(float3(0, 1, 0), dDoorMoveR); // podnóżek? + } + } + else + { + pAnim->smAnimated->SetRotate(float3(0, 0, 1), dDoorMoveL); + // SubModel->SetRotate(float3(0,1,0),fValue*360.0); + TSubModel *sm = pAnim->smAnimated->ChildGet(); // skrzydło mniejsze + if (sm) + { + sm->SetRotate(float3(0, 0, 1), -dDoorMoveL - dDoorMoveL); // skrzydło większe + sm = sm->ChildGet(); + if (sm) + sm->SetRotate(float3(0, 1, 0), dDoorMoveL); // podnóżek? + } + } + } }; void TDynamicObject::UpdatePant(TAnim *pAnim) -{//animacja pantografu - 4 obracane ramiona, ślizg piąty - float a,b,c; - a=RadToDeg(pAnim->fParamPants->fAngleL-pAnim->fParamPants->fAngleL0); - b=RadToDeg(pAnim->fParamPants->fAngleU-pAnim->fParamPants->fAngleU0); - c=a+b; - if (pAnim->smElement[0]) pAnim->smElement[0]->SetRotate(float3(-1,0,0),a); //dolne ramię - if (pAnim->smElement[1]) pAnim->smElement[1]->SetRotate(float3(1,0,0),a); - if (pAnim->smElement[2]) pAnim->smElement[2]->SetRotate(float3(1,0,0),c); //górne ramię - if (pAnim->smElement[3]) pAnim->smElement[3]->SetRotate(float3(-1,0,0),c); - if (pAnim->smElement[4]) pAnim->smElement[4]->SetRotate(float3(-1,0,0),b); //ślizg +{ // animacja pantografu - 4 obracane ramiona, ślizg piąty + float a, b, c; + a = RadToDeg(pAnim->fParamPants->fAngleL - pAnim->fParamPants->fAngleL0); + b = RadToDeg(pAnim->fParamPants->fAngleU - pAnim->fParamPants->fAngleU0); + c = a + b; + if (pAnim->smElement[0]) + pAnim->smElement[0]->SetRotate(float3(-1, 0, 0), a); // dolne ramię + if (pAnim->smElement[1]) + pAnim->smElement[1]->SetRotate(float3(1, 0, 0), a); + if (pAnim->smElement[2]) + pAnim->smElement[2]->SetRotate(float3(1, 0, 0), c); // górne ramię + if (pAnim->smElement[3]) + pAnim->smElement[3]->SetRotate(float3(-1, 0, 0), c); + if (pAnim->smElement[4]) + pAnim->smElement[4]->SetRotate(float3(-1, 0, 0), b); //ślizg }; void TDynamicObject::UpdateLeverDouble(TAnim *pAnim) -{//animacja gałki zależna od double - pAnim->smAnimated->SetRotate(float3(1,0,0),pAnim->fSpeed**pAnim->fDoubleBase); +{ // animacja gałki zależna od double + pAnim->smAnimated->SetRotate(float3(1, 0, 0), pAnim->fSpeed * *pAnim->fDoubleBase); }; void TDynamicObject::UpdateLeverFloat(TAnim *pAnim) -{//animacja gałki zależna od float - pAnim->smAnimated->SetRotate(float3(1,0,0),pAnim->fSpeed**pAnim->fFloatBase); +{ // animacja gałki zależna od float + pAnim->smAnimated->SetRotate(float3(1, 0, 0), pAnim->fSpeed * *pAnim->fFloatBase); }; void TDynamicObject::UpdateLeverInt(TAnim *pAnim) -{//animacja gałki zależna od int - pAnim->smAnimated->SetRotate(float3(1,0,0),pAnim->fSpeed**pAnim->iIntBase); +{ // animacja gałki zależna od int + pAnim->smAnimated->SetRotate(float3(1, 0, 0), pAnim->fSpeed * *pAnim->iIntBase); }; void TDynamicObject::UpdateLeverEnum(TAnim *pAnim) -{//ustawienie kąta na wartość wskazaną przez int z tablicy fParam - //pAnim->fParam[0]; - dodać lepkość - pAnim->smAnimated->SetRotate(float3(1,0,0),pAnim->fParam[*pAnim->iIntBase]); +{ // ustawienie kąta na wartość wskazaną przez int z tablicy fParam + // pAnim->fParam[0]; - dodać lepkość + pAnim->smAnimated->SetRotate(float3(1, 0, 0), pAnim->fParam[*pAnim->iIntBase]); }; - -//ABu 29.01.05 przeklejone z render i renderalpha: ********************* +// ABu 29.01.05 przeklejone z render i renderalpha: ********************* void __inline TDynamicObject::ABuLittleUpdate(double ObjSqrDist) -{//ABu290105: pozbierane i uporzadkowane powtarzajace sie rzeczy z Render i RenderAlpha - //dodatkowy warunek, if (ObjSqrDist<...) zeby niepotrzebnie nie zmianiec w obiektach, - //ktorych i tak nie widac - //NBMX wrzesien, MC listopad: zuniwersalnione - btnOn=false; //czy przywrócić stan domyślny po renderowaniu +{ // ABu290105: pozbierane i uporzadkowane powtarzajace sie rzeczy z Render i RenderAlpha + // dodatkowy warunek, if (ObjSqrDist<...) zeby niepotrzebnie nie zmianiec w obiektach, + // ktorych i tak nie widac + // NBMX wrzesien, MC listopad: zuniwersalnione + btnOn = false; // czy przywrócić stan domyślny po renderowaniu - if (mdLoad) //tymczasowo ładunek na poziom podłogi - if (vFloor.z>0.0) - mdLoad->GetSMRoot()->SetTranslate(modelShake+vFloor); + if (mdLoad) // tymczasowo ładunek na poziom podłogi + if (vFloor.z > 0.0) + mdLoad->GetSMRoot()->SetTranslate(modelShake + vFloor); - if (ObjSqrDist<160000) //gdy bliżej niż 400m - { - for (int i=0;iGetSMRoot()->SetTranslate(modelShake); - if (mdKabina) - mdKabina->GetSMRoot()->SetTranslate(modelShake); - if (mdLoad) - mdLoad->GetSMRoot()->SetTranslate(modelShake+vFloor); - if (mdLowPolyInt) - mdLowPolyInt->GetSMRoot()->SetTranslate(modelShake); - if (mdPrzedsionek) - mdPrzedsionek->GetSMRoot()->SetTranslate(modelShake); - //ABu: koniec rzucania - //ABu011104: liczenie obrotow wozkow - ABuBogies(); - //Mczapkie-100402: rysowanie lub nie - sprzegow - //ABu-240105: Dodatkowy warunek: if (...).Render, zeby rysowal tylko jeden - //z polaczonych sprzegow - if ((TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_coupler)) - &&(MoverParameters->Couplers[0].Render)) - {btCoupler1.TurnOn(); btnOn=true;} - //else btCoupler1.TurnOff(); - if ((TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_coupler)) - &&(MoverParameters->Couplers[1].Render)) - {btCoupler2.TurnOn(); btnOn=true;} - //else btCoupler2.TurnOff(); - //******************************************************************************** - //przewody powietrzne j.w., ABu: decyzja czy rysowac tylko na podstawie 'render' - juz nie - //przewody powietrzne, yB: decyzja na podstawie polaczen w t3d - if (Global::bnewAirCouplers) - { - SetPneumatic(false,false); //wczytywanie z t3d ulozenia wezykow - SetPneumatic(true,false); //i zapisywanie do zmiennej - SetPneumatic(true,true); //ktore z nich nalezy - SetPneumatic(false,true); //wyswietlic w tej klatce - - if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_pneumatic)) - { - switch (cp1) + if (ObjSqrDist < 160000) // gdy bliżej niż 400m { - case 1: btCPneumatic1.TurnOn(); break; - case 2: btCPneumatic1.TurnxOn(); break; - case 3: btCPneumatic1r.TurnxOn(); break; - case 4: btCPneumatic1r.TurnOn(); break; + for (int i = 0; i < iAnimations; ++i) // wykonanie kolejnych animacji + if (ObjSqrDist < pAnimations[i].fMaxDist) + if (pAnimations[i].yUpdate) // jeśli zdefiniowana funkcja + pAnimations[i].yUpdate(pAnimations + + i); // aktualizacja animacji (położenia submodeli + if (ObjSqrDist < 2500) // gdy bliżej niż 50m + { + // ABu290105: rzucanie pudlem + // te animacje wymagają bananów w modelach! + mdModel->GetSMRoot()->SetTranslate(modelShake); + if (mdKabina) + mdKabina->GetSMRoot()->SetTranslate(modelShake); + if (mdLoad) + mdLoad->GetSMRoot()->SetTranslate(modelShake + vFloor); + if (mdLowPolyInt) + mdLowPolyInt->GetSMRoot()->SetTranslate(modelShake); + if (mdPrzedsionek) + mdPrzedsionek->GetSMRoot()->SetTranslate(modelShake); + // ABu: koniec rzucania + // ABu011104: liczenie obrotow wozkow + ABuBogies(); + // Mczapkie-100402: rysowanie lub nie - sprzegow + // ABu-240105: Dodatkowy warunek: if (...).Render, zeby rysowal tylko jeden + // z polaczonych sprzegow + if ((TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_coupler)) && + (MoverParameters->Couplers[0].Render)) + { + btCoupler1.TurnOn(); + btnOn = true; + } + // else btCoupler1.TurnOff(); + if ((TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_coupler)) && + (MoverParameters->Couplers[1].Render)) + { + btCoupler2.TurnOn(); + btnOn = true; + } + // else btCoupler2.TurnOff(); + //******************************************************************************** + // przewody powietrzne j.w., ABu: decyzja czy rysowac tylko na podstawie 'render' - juz + // nie + // przewody powietrzne, yB: decyzja na podstawie polaczen w t3d + if (Global::bnewAirCouplers) + { + SetPneumatic(false, false); // wczytywanie z t3d ulozenia wezykow + SetPneumatic(true, false); // i zapisywanie do zmiennej + SetPneumatic(true, true); // ktore z nich nalezy + SetPneumatic(false, true); // wyswietlic w tej klatce + + if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_pneumatic)) + { + switch (cp1) + { + case 1: + btCPneumatic1.TurnOn(); + break; + case 2: + btCPneumatic1.TurnxOn(); + break; + case 3: + btCPneumatic1r.TurnxOn(); + break; + case 4: + btCPneumatic1r.TurnOn(); + break; + } + btnOn = true; + } + // else + //{ + // btCPneumatic1.TurnOff(); + // btCPneumatic1r.TurnOff(); + //} + + if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_pneumatic)) + { + switch (cp2) + { + case 1: + btCPneumatic2.TurnOn(); + break; + case 2: + btCPneumatic2.TurnxOn(); + break; + case 3: + btCPneumatic2r.TurnxOn(); + break; + case 4: + btCPneumatic2r.TurnOn(); + break; + } + btnOn = true; + } + // else + //{ + // btCPneumatic2.TurnOff(); + // btCPneumatic2r.TurnOff(); + //} + + // przewody zasilajace, j.w. (yB) + if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_scndpneumatic)) + { + switch (sp1) + { + case 1: + btPneumatic1.TurnOn(); + break; + case 2: + btPneumatic1.TurnxOn(); + break; + case 3: + btPneumatic1r.TurnxOn(); + break; + case 4: + btPneumatic1r.TurnOn(); + break; + } + btnOn = true; + } + // else + //{ + // btPneumatic1.TurnOff(); + // btPneumatic1r.TurnOff(); + //} + + if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_scndpneumatic)) + { + switch (sp2) + { + case 1: + btPneumatic2.TurnOn(); + break; + case 2: + btPneumatic2.TurnxOn(); + break; + case 3: + btPneumatic2r.TurnxOn(); + break; + case 4: + btPneumatic2r.TurnOn(); + break; + } + btnOn = true; + } + // else + //{ + // btPneumatic2.TurnOff(); + // btPneumatic2r.TurnOff(); + //} + } + //*********************************************************************************/ + else // po staremu ABu'oewmu + { + // przewody powietrzne j.w., ABu: decyzja czy rysowac tylko na podstawie 'render' + if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_pneumatic)) + { + if (MoverParameters->Couplers[0].Render) + btCPneumatic1.TurnOn(); + else + btCPneumatic1r.TurnOn(); + btnOn = true; + } + // else + //{ + // btCPneumatic1.TurnOff(); + // btCPneumatic1r.TurnOff(); + //} + + if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_pneumatic)) + { + if (MoverParameters->Couplers[1].Render) + btCPneumatic2.TurnOn(); + else + btCPneumatic2r.TurnOn(); + btnOn = true; + } + // else + //{ + // btCPneumatic2.TurnOff(); + // btCPneumatic2r.TurnOff(); + //} + + // przewody powietrzne j.w., ABu: decyzja czy rysowac tylko na podstawie 'render' + // //yB - zasilajace + if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_scndpneumatic)) + { + if (MoverParameters->Couplers[0].Render) + btPneumatic1.TurnOn(); + else + btPneumatic1r.TurnOn(); + btnOn = true; + } + // else + //{ + // btPneumatic1.TurnOff(); + // btPneumatic1r.TurnOff(); + //} + + if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_scndpneumatic)) + { + if (MoverParameters->Couplers[1].Render) + btPneumatic2.TurnOn(); + else + btPneumatic2r.TurnOn(); + btnOn = true; + } + // else + //{ + // btPneumatic2.TurnOff(); + // btPneumatic2r.TurnOff(); + //} + } + //*************************************************************/// koniec wezykow + // uginanie zderzakow + for (int i = 0; i < 2; i++) + { + double dist = MoverParameters->Couplers[i].Dist / 2.0; + if (smBuforLewy[i]) + if (dist < 0) + smBuforLewy[i]->SetTranslate(vector3(dist, 0, 0)); + if (smBuforPrawy[i]) + if (dist < 0) + smBuforPrawy[i]->SetTranslate(vector3(dist, 0, 0)); + } + } + + // Winger 160204 - podnoszenie pantografow + + // przewody sterowania ukrotnionego + if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_controll)) + { + btCCtrl1.TurnOn(); + btnOn = true; + } + // else btCCtrl1.TurnOff(); + if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_controll)) + { + btCCtrl2.TurnOn(); + btnOn = true; + } + // else btCCtrl2.TurnOff(); + // McZapkie-181103: mostki przejsciowe + if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_passenger)) + { + btCPass1.TurnOn(); + btnOn = true; + } + // else btCPass1.TurnOff(); + if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_passenger)) + { + btCPass2.TurnOn(); + btnOn = true; + } + // else btCPass2.TurnOff(); + if (MoverParameters->Battery) + { // sygnaly konca pociagu + if (btEndSignals1.Active()) + { + if (TestFlag(iLights[0], 2) || TestFlag(iLights[0], 32)) + { + btEndSignals1.TurnOn(); + btnOn = true; + } + // else btEndSignals1.TurnOff(); + } + else + { + if (TestFlag(iLights[0], 2)) + { + btEndSignals11.TurnOn(); + btnOn = true; + } + // else btEndSignals11.TurnOff(); + if (TestFlag(iLights[0], 32)) + { + btEndSignals13.TurnOn(); + btnOn = true; + } + // else btEndSignals13.TurnOff(); + } + if (btEndSignals2.Active()) + { + if (TestFlag(iLights[1], 2) || TestFlag(iLights[1], 32)) + { + btEndSignals2.TurnOn(); + btnOn = true; + } + // else btEndSignals2.TurnOff(); + } + else + { + if (TestFlag(iLights[1], 2)) + { + btEndSignals21.TurnOn(); + btnOn = true; + } + // else btEndSignals21.TurnOff(); + if (TestFlag(iLights[1], 32)) + { + btEndSignals23.TurnOn(); + btnOn = true; + } + // else btEndSignals23.TurnOff(); + } + } + // tablice blaszane: + if (TestFlag(iLights[0], 64)) + { + btEndSignalsTab1.TurnOn(); + btnOn = true; + } + // else btEndSignalsTab1.TurnOff(); + if (TestFlag(iLights[1], 64)) + { + btEndSignalsTab2.TurnOn(); + btnOn = true; + } + // else btEndSignalsTab2.TurnOff(); + // McZapkie-181002: krecenie wahaczem (korzysta z kata obrotu silnika) + if (iAnimType[ANIM_LEVERS]) + for (int i = 0; i < 4; ++i) + if (smWahacze[i]) + smWahacze[i]->SetRotate(float3(1, 0, 0), + fWahaczeAmp * cos(MoverParameters->eAngle)); + if (Mechanik && (Controller != Humandriver)) + { // rysowanie figurki mechanika + if (smMechanik0) // mechanik od strony sprzęgu 0 + if (smMechanik1) // jak jest drugi, to pierwszego jedynie pokazujemy + smMechanik0->iVisible = MoverParameters->ActiveCab > 0; + else + { // jak jest tylko jeden, to do drugiej kabiny go obracamy + smMechanik0->iVisible = (MoverParameters->ActiveCab != 0); + smMechanik0->SetRotate(float3(0, 0, 1), MoverParameters->ActiveCab >= 0 ? + 0 : + 180); // obrót względem osi Z + } + if (smMechanik1) // mechanik od strony sprzęgu 1 + smMechanik1->iVisible = MoverParameters->ActiveCab < 0; + } + // ABu: Przechyly na zakretach + // Ra: przechyłkę załatwiamy na etapie przesuwania modelu + // if (ObjSqrDist<80000) ABuModelRoll(); //przechyłki od 400m } - btnOn=true; - } - //else - //{ - // btCPneumatic1.TurnOff(); - // btCPneumatic1r.TurnOff(); - //} - - if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_pneumatic)) - { - switch (cp2) - { - case 1: btCPneumatic2.TurnOn(); break; - case 2: btCPneumatic2.TurnxOn(); break; - case 3: btCPneumatic2r.TurnxOn(); break; - case 4: btCPneumatic2r.TurnOn(); break; + if (MoverParameters->Battery) + { // sygnały czoła pociagu //Ra: wyświetlamy bez ograniczeń odległości, by były widoczne z + // daleka + if (TestFlag(iLights[0], 1)) + { + btHeadSignals11.TurnOn(); + btnOn = true; + } + // else btHeadSignals11.TurnOff(); + if (TestFlag(iLights[0], 4)) + { + btHeadSignals12.TurnOn(); + btnOn = true; + } + // else btHeadSignals12.TurnOff(); + if (TestFlag(iLights[0], 16)) + { + btHeadSignals13.TurnOn(); + btnOn = true; + } + // else btHeadSignals13.TurnOff(); + if (TestFlag(iLights[1], 1)) + { + btHeadSignals21.TurnOn(); + btnOn = true; + } + // else btHeadSignals21.TurnOff(); + if (TestFlag(iLights[1], 4)) + { + btHeadSignals22.TurnOn(); + btnOn = true; + } + // else btHeadSignals22.TurnOff(); + if (TestFlag(iLights[1], 16)) + { + btHeadSignals23.TurnOn(); + btnOn = true; + } + // else btHeadSignals23.TurnOff(); } - btnOn=true; - } - //else - //{ - // btCPneumatic2.TurnOff(); - // btCPneumatic2r.TurnOff(); - //} - - //przewody zasilajace, j.w. (yB) - if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_scndpneumatic)) - { - switch (sp1) - { - case 1: btPneumatic1.TurnOn(); break; - case 2: btPneumatic1.TurnxOn(); break; - case 3: btPneumatic1r.TurnxOn(); break; - case 4: btPneumatic1r.TurnOn(); break; - } - btnOn=true; - } - //else - //{ - // btPneumatic1.TurnOff(); - // btPneumatic1r.TurnOff(); - //} - - if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_scndpneumatic)) - { - switch (sp2) - { - case 1: btPneumatic2.TurnOn(); break; - case 2: btPneumatic2.TurnxOn(); break; - case 3: btPneumatic2r.TurnxOn(); break; - case 4: btPneumatic2r.TurnOn(); break; - } - btnOn=true; - } - //else - //{ - // btPneumatic2.TurnOff(); - // btPneumatic2r.TurnOff(); - //} - } -//*********************************************************************************/ - else //po staremu ABu'oewmu - { - //przewody powietrzne j.w., ABu: decyzja czy rysowac tylko na podstawie 'render' - if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_pneumatic)) - { - if (MoverParameters->Couplers[0].Render) - btCPneumatic1.TurnOn(); - else - btCPneumatic1r.TurnOn(); - btnOn=true; - } - //else - //{ - // btCPneumatic1.TurnOff(); - // btCPneumatic1r.TurnOff(); - //} - - if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_pneumatic)) - { - if (MoverParameters->Couplers[1].Render) - btCPneumatic2.TurnOn(); - else - btCPneumatic2r.TurnOn(); - btnOn=true; - } - //else - //{ - // btCPneumatic2.TurnOff(); - // btCPneumatic2r.TurnOff(); - //} - - //przewody powietrzne j.w., ABu: decyzja czy rysowac tylko na podstawie 'render' //yB - zasilajace - if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_scndpneumatic)) - { - if (MoverParameters->Couplers[0].Render) - btPneumatic1.TurnOn(); - else - btPneumatic1r.TurnOn(); - btnOn=true; - } - //else - //{ - // btPneumatic1.TurnOff(); - // btPneumatic1r.TurnOff(); - //} - - if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_scndpneumatic)) - { - if (MoverParameters->Couplers[1].Render) - btPneumatic2.TurnOn(); - else - btPneumatic2r.TurnOn(); - btnOn=true; - } - //else - //{ - // btPneumatic2.TurnOff(); - // btPneumatic2r.TurnOff(); - //} - } - //*************************************************************/// koniec wezykow - // uginanie zderzakow - for (int i=0; i<2; i++) - { - double dist=MoverParameters->Couplers[i].Dist/2.0; - if (smBuforLewy[i]) - if (dist<0) - smBuforLewy[i]->SetTranslate(vector3(dist,0,0)); - if (smBuforPrawy[i]) - if (dist<0) - smBuforPrawy[i]->SetTranslate(vector3(dist,0,0)); - } - } - - //Winger 160204 - podnoszenie pantografow - - //przewody sterowania ukrotnionego - if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_controll)) - {btCCtrl1.TurnOn(); btnOn=true;} - //else btCCtrl1.TurnOff(); - if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_controll)) - {btCCtrl2.TurnOn(); btnOn=true;} - //else btCCtrl2.TurnOff(); - //McZapkie-181103: mostki przejsciowe - if (TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_passenger)) - {btCPass1.TurnOn(); btnOn=true;} - //else btCPass1.TurnOff(); - if (TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_passenger)) - {btCPass2.TurnOn(); btnOn=true;} - //else btCPass2.TurnOff(); - if (MoverParameters->Battery) - {//sygnaly konca pociagu - if (btEndSignals1.Active()) - { - if (TestFlag(iLights[0],2) - ||TestFlag(iLights[0],32)) - {btEndSignals1.TurnOn(); btnOn=true;} - //else btEndSignals1.TurnOff(); - } - else - { - if (TestFlag(iLights[0],2)) - {btEndSignals11.TurnOn(); btnOn=true;} - //else btEndSignals11.TurnOff(); - if (TestFlag(iLights[0],32)) - {btEndSignals13.TurnOn(); btnOn=true;} - //else btEndSignals13.TurnOff(); - } - if (btEndSignals2.Active()) - { - if (TestFlag(iLights[1],2) - ||TestFlag(iLights[1],32)) - {btEndSignals2.TurnOn(); btnOn=true;} - //else btEndSignals2.TurnOff(); - } - else - { - if (TestFlag(iLights[1],2)) - {btEndSignals21.TurnOn(); btnOn=true;} - //else btEndSignals21.TurnOff(); - if (TestFlag(iLights[1],32)) - {btEndSignals23.TurnOn(); btnOn=true;} - //else btEndSignals23.TurnOff(); - } - } - //tablice blaszane: - if (TestFlag(iLights[0],64)) - {btEndSignalsTab1.TurnOn(); btnOn=true;} - //else btEndSignalsTab1.TurnOff(); - if (TestFlag(iLights[1],64)) - {btEndSignalsTab2.TurnOn(); btnOn=true;} - //else btEndSignalsTab2.TurnOff(); - //McZapkie-181002: krecenie wahaczem (korzysta z kata obrotu silnika) - if (iAnimType[ANIM_LEVERS]) - for (int i=0;i<4;++i) - if (smWahacze[i]) - smWahacze[i]->SetRotate(float3(1,0,0),fWahaczeAmp*cos(MoverParameters->eAngle)); - if (Mechanik&&(Controller!=Humandriver)) - {//rysowanie figurki mechanika - if (smMechanik0) //mechanik od strony sprzęgu 0 - if (smMechanik1) //jak jest drugi, to pierwszego jedynie pokazujemy - smMechanik0->iVisible=MoverParameters->ActiveCab>0; - else - {//jak jest tylko jeden, to do drugiej kabiny go obracamy - smMechanik0->iVisible=(MoverParameters->ActiveCab!=0); - smMechanik0->SetRotate(float3(0,0,1),MoverParameters->ActiveCab>=0?0:180); //obrót względem osi Z - } - if (smMechanik1) //mechanik od strony sprzęgu 1 - smMechanik1->iVisible=MoverParameters->ActiveCab<0; - } - //ABu: Przechyly na zakretach - //Ra: przechyłkę załatwiamy na etapie przesuwania modelu - //if (ObjSqrDist<80000) ABuModelRoll(); //przechyłki od 400m - } - if (MoverParameters->Battery) - {//sygnały czoła pociagu //Ra: wyświetlamy bez ograniczeń odległości, by były widoczne z daleka - if (TestFlag(iLights[0],1)) - {btHeadSignals11.TurnOn(); btnOn=true;} - //else btHeadSignals11.TurnOff(); - if (TestFlag(iLights[0],4)) - {btHeadSignals12.TurnOn(); btnOn=true;} - //else btHeadSignals12.TurnOff(); - if (TestFlag(iLights[0],16)) - {btHeadSignals13.TurnOn(); btnOn=true;} - //else btHeadSignals13.TurnOff(); - if (TestFlag(iLights[1],1)) - {btHeadSignals21.TurnOn(); btnOn=true;} - //else btHeadSignals21.TurnOff(); - if (TestFlag(iLights[1],4)) - {btHeadSignals22.TurnOn(); btnOn=true;} - //else btHeadSignals22.TurnOff(); - if (TestFlag(iLights[1],16)) - {btHeadSignals23.TurnOn(); btnOn=true;} - //else btHeadSignals23.TurnOff(); - } } -//ABu 29.01.05 koniec przeklejenia ************************************* +// ABu 29.01.05 koniec przeklejenia ************************************* double __fastcall ABuAcos(const vector3 &calc_temp) -{ //Odpowiednik funkcji Arccos, bo cos mi tam nie dzialalo. - return atan2(-calc_temp.x,calc_temp.z); //Ra: tak prościej +{ // Odpowiednik funkcji Arccos, bo cos mi tam nie dzialalo. + return atan2(-calc_temp.x, calc_temp.z); // Ra: tak prościej } -TDynamicObject* __fastcall TDynamicObject::ABuFindNearestObject(TTrack *Track,TDynamicObject *MyPointer,int &CouplNr) -{//zwraca wskaznik do obiektu znajdujacego sie na torze (Track), którego sprzęg jest najblizszy kamerze - //służy np. do łączenia i rozpinania sprzęgów - //WE: Track - tor, na ktorym odbywa sie poszukiwanie - // MyPointer - wskaznik do obiektu szukajacego - //WY: CouplNr - który sprzęg znalezionego obiektu jest bliższy kamerze +TDynamicObject *__fastcall TDynamicObject::ABuFindNearestObject(TTrack *Track, + TDynamicObject *MyPointer, + int &CouplNr) +{ // zwraca wskaznik do obiektu znajdujacego sie na torze (Track), którego sprzęg jest najblizszy + // kamerze + // służy np. do łączenia i rozpinania sprzęgów + // WE: Track - tor, na ktorym odbywa sie poszukiwanie + // MyPointer - wskaznik do obiektu szukajacego + // WY: CouplNr - który sprzęg znalezionego obiektu jest bliższy kamerze - //Uwaga! Jesli CouplNr==-2 to szukamy njblizszego obiektu, a nie sprzegu!!! + // Uwaga! Jesli CouplNr==-2 to szukamy njblizszego obiektu, a nie sprzegu!!! - if ((Track->iNumDynamics)>0) - {//o ile w ogóle jest co przeglądać na tym torze - //vector3 poz; //pozycja pojazdu XYZ w scenerii - //vector3 kon; //wektor czoła względem środka pojazdu wzglęem początku toru - vector3 tmp; //wektor pomiędzy kamerą i sprzęgiem - double dist; //odległość - for (int i=0;iiNumDynamics;i++) - { - if (CouplNr==-2) - {//wektor [kamera-obiekt] - poszukiwanie obiektu - tmp=Global::GetCameraPosition()-Track->Dynamics[i]->vPosition; - dist=tmp.x*tmp.x+tmp.y*tmp.y+tmp.z*tmp.z; //odległość do kwadratu - if (dist<100.0) //10 metrów - return Track->Dynamics[i]; - } - else //jeśli (CouplNr) inne niz -2, szukamy sprzęgu - {//wektor [kamera-sprzeg0], potem [kamera-sprzeg1] - //Powinno byc wyliczone, ale nie zaszkodzi drugi raz: - //(bo co, jesli nie wykonuje sie obrotow wozkow?) - Ra: ale zawsze są liczone współrzędne sprzęgów - //Track->Dynamics[i]->modelRot.z=ABuAcos(Track->Dynamics[i]->Axle0.pPosition-Track->Dynamics[i]->Axle1.pPosition); - //poz=Track->Dynamics[i]->vPosition; //pozycja środka pojazdu - //kon=vector3( //położenie przodu względem środka - // -((0.5*Track->Dynamics[i]->MoverParameters->Dim.L)*sin(Track->Dynamics[i]->modelRot.z)), - // 0, //yyy... jeśli duże pochylenie i długi pojazd, to może być problem - // +((0.5*Track->Dynamics[i]->MoverParameters->Dim.L)*cos(Track->Dynamics[i]->modelRot.z)) - //); - tmp=Global::GetCameraPosition()-Track->Dynamics[i]->vCoulpler[0]; //Ra: pozycje sprzęgów też są zawsze liczone - dist=tmp.x*tmp.x+tmp.y*tmp.y+tmp.z*tmp.z; //odległość do kwadratu - if (dist<25.0) //5 metrów - { - CouplNr=0; - return Track->Dynamics[i]; + if ((Track->iNumDynamics) > 0) + { // o ile w ogóle jest co przeglądać na tym torze + // vector3 poz; //pozycja pojazdu XYZ w scenerii + // vector3 kon; //wektor czoła względem środka pojazdu wzglęem początku toru + vector3 tmp; // wektor pomiędzy kamerą i sprzęgiem + double dist; // odległość + for (int i = 0; i < Track->iNumDynamics; i++) + { + if (CouplNr == -2) + { // wektor [kamera-obiekt] - poszukiwanie obiektu + tmp = Global::GetCameraPosition() - Track->Dynamics[i]->vPosition; + dist = tmp.x * tmp.x + tmp.y * tmp.y + tmp.z * tmp.z; // odległość do kwadratu + if (dist < 100.0) // 10 metrów + return Track->Dynamics[i]; + } + else // jeśli (CouplNr) inne niz -2, szukamy sprzęgu + { // wektor [kamera-sprzeg0], potem [kamera-sprzeg1] + // Powinno byc wyliczone, ale nie zaszkodzi drugi raz: + //(bo co, jesli nie wykonuje sie obrotow wozkow?) - Ra: ale zawsze są liczone + //współrzędne sprzęgów + // Track->Dynamics[i]->modelRot.z=ABuAcos(Track->Dynamics[i]->Axle0.pPosition-Track->Dynamics[i]->Axle1.pPosition); + // poz=Track->Dynamics[i]->vPosition; //pozycja środka pojazdu + // kon=vector3( //położenie przodu względem środka + // -((0.5*Track->Dynamics[i]->MoverParameters->Dim.L)*sin(Track->Dynamics[i]->modelRot.z)), + // 0, //yyy... jeśli duże pochylenie i długi pojazd, to może być problem + // +((0.5*Track->Dynamics[i]->MoverParameters->Dim.L)*cos(Track->Dynamics[i]->modelRot.z)) + //); + tmp = + Global::GetCameraPosition() - + Track->Dynamics[i]->vCoulpler[0]; // Ra: pozycje sprzęgów też są zawsze liczone + dist = tmp.x * tmp.x + tmp.y * tmp.y + tmp.z * tmp.z; // odległość do kwadratu + if (dist < 25.0) // 5 metrów + { + CouplNr = 0; + return Track->Dynamics[i]; + } + tmp = Global::GetCameraPosition() - Track->Dynamics[i]->vCoulpler[1]; + dist = tmp.x * tmp.x + tmp.y * tmp.y + tmp.z * tmp.z; // odległość do kwadratu + if (dist < 25.0) // 5 metrów + { + CouplNr = 1; + return Track->Dynamics[i]; + } + } + } + return NULL; } - tmp=Global::GetCameraPosition()-Track->Dynamics[i]->vCoulpler[1]; - dist=tmp.x*tmp.x+tmp.y*tmp.y+tmp.z*tmp.z; //odległość do kwadratu - if (dist<25.0) //5 metrów - { - CouplNr=1; - return Track->Dynamics[i]; - } - } - } - return NULL; - } - return NULL; + return NULL; } - - -TDynamicObject* __fastcall TDynamicObject::ABuScanNearestObject(TTrack *Track,double ScanDir,double ScanDist,int &CouplNr) -{//skanowanie toru w poszukiwaniu obiektu najblizszego kamerze - //double MyScanDir=ScanDir; //Moja orientacja na torze. //Ra: nie używane - if (ABuGetDirection()<0) ScanDir=-ScanDir; - TDynamicObject* FoundedObj; - FoundedObj=ABuFindNearestObject(Track,this,CouplNr); //zwraca numer sprzęgu znalezionego pojazdu - if (FoundedObj==NULL) - { - double ActDist; //Przeskanowana odleglosc. - double CurrDist=0; //Aktualna dlugosc toru. - if (ScanDir>=0) ActDist=Track->Length()-RaTranslationGet(); //???-przesunięcie wózka względem Point1 toru - else ActDist=RaTranslationGet(); //przesunięcie wózka względem Point1 toru - while (ActDist0) //do przodu - { - if (Track->iNextDirection) +TDynamicObject *__fastcall TDynamicObject::ABuScanNearestObject(TTrack *Track, double ScanDir, + double ScanDist, int &CouplNr) +{ // skanowanie toru w poszukiwaniu obiektu najblizszego kamerze + // double MyScanDir=ScanDir; //Moja orientacja na torze. //Ra: nie używane + if (ABuGetDirection() < 0) + ScanDir = -ScanDir; + TDynamicObject *FoundedObj; + FoundedObj = + ABuFindNearestObject(Track, this, CouplNr); // zwraca numer sprzęgu znalezionego pojazdu + if (FoundedObj == NULL) { - Track=Track->CurrentNext(); - ScanDir=-ScanDir; - } - else - Track=Track->CurrentNext(); - } - else //do tyłu - { - if (Track->iPrevDirection) - Track=Track->CurrentPrev(); - else - { - Track=Track->CurrentPrev(); - ScanDir=-ScanDir; - } - } - if (Track!=NULL) - { //jesli jest kolejny odcinek toru - CurrDist=Track->Length(); - FoundedObj=ABuFindNearestObject(Track, this, CouplNr); - if (FoundedObj!=NULL) - ActDist=ScanDist; - } - else //Jesli nie ma, to wychodzimy. - ActDist=ScanDist; - } - } //Koniec szukania najblizszego toru z jakims obiektem. - return FoundedObj; + double ActDist; // Przeskanowana odleglosc. + double CurrDist = 0; // Aktualna dlugosc toru. + if (ScanDir >= 0) + ActDist = + Track->Length() - RaTranslationGet(); //???-przesunięcie wózka względem Point1 toru + else + ActDist = RaTranslationGet(); // przesunięcie wózka względem Point1 toru + while (ActDist < ScanDist) + { + ActDist += CurrDist; + if (ScanDir > 0) // do przodu + { + if (Track->iNextDirection) + { + Track = Track->CurrentNext(); + ScanDir = -ScanDir; + } + else + Track = Track->CurrentNext(); + } + else // do tyłu + { + if (Track->iPrevDirection) + Track = Track->CurrentPrev(); + else + { + Track = Track->CurrentPrev(); + ScanDir = -ScanDir; + } + } + if (Track != NULL) + { // jesli jest kolejny odcinek toru + CurrDist = Track->Length(); + FoundedObj = ABuFindNearestObject(Track, this, CouplNr); + if (FoundedObj != NULL) + ActDist = ScanDist; + } + else // Jesli nie ma, to wychodzimy. + ActDist = ScanDist; + } + } // Koniec szukania najblizszego toru z jakims obiektem. + return FoundedObj; } -//ABu 01.11.04 poczatek wyliczania przechylow pudla ********************** +// ABu 01.11.04 poczatek wyliczania przechylow pudla ********************** void __fastcall TDynamicObject::ABuModelRoll() -{//ustawienie przechyłki pojazdu i jego zawartości -// Ra: przechyłkę załatwiamy na etapie przesuwania modelu +{ // ustawienie przechyłki pojazdu i jego zawartości + // Ra: przechyłkę załatwiamy na etapie przesuwania modelu } -//ABu 06.05.04 poczatek wyliczania obrotow wozkow ********************** +// ABu 06.05.04 poczatek wyliczania obrotow wozkow ********************** void __fastcall TDynamicObject::ABuBogies() -{//Obracanie wozkow na zakretach. Na razie uwzględnia tylko zakręty, - //bez zadnych gorek i innych przeszkod. - if ((smBogie[0]!=NULL)&&(smBogie[1]!=NULL)) - { - //modelRot.z=ABuAcos(Axle0.pPosition-Axle1.pPosition); //kąt obrotu pojazdu [rad] - //bogieRot[0].z=ABuAcos(Axle0.pPosition-Axle3.pPosition); - bogieRot[0].z=Axle0.vAngles.z; - bogieRot[0]=RadToDeg(modelRot-bogieRot[0]); //mnożenie wektora przez stałą - smBogie[0]->SetRotateXYZ(bogieRot[0]); - //bogieRot[1].z=ABuAcos(Axle2.pPosition-Axle1.pPosition); - bogieRot[1].z=Axle1.vAngles.z; - bogieRot[1]=RadToDeg(modelRot-bogieRot[1]); - smBogie[1]->SetRotateXYZ(bogieRot[1]); - } +{ // Obracanie wozkow na zakretach. Na razie uwzględnia tylko zakręty, + // bez zadnych gorek i innych przeszkod. + if ((smBogie[0] != NULL) && (smBogie[1] != NULL)) + { + // modelRot.z=ABuAcos(Axle0.pPosition-Axle1.pPosition); //kąt obrotu pojazdu [rad] + // bogieRot[0].z=ABuAcos(Axle0.pPosition-Axle3.pPosition); + bogieRot[0].z = Axle0.vAngles.z; + bogieRot[0] = RadToDeg(modelRot - bogieRot[0]); // mnożenie wektora przez stałą + smBogie[0]->SetRotateXYZ(bogieRot[0]); + // bogieRot[1].z=ABuAcos(Axle2.pPosition-Axle1.pPosition); + bogieRot[1].z = Axle1.vAngles.z; + bogieRot[1] = RadToDeg(modelRot - bogieRot[1]); + smBogie[1]->SetRotateXYZ(bogieRot[1]); + } }; -//ABu 06.05.04 koniec wyliczania obrotow wozkow ************************ +// ABu 06.05.04 koniec wyliczania obrotow wozkow ************************ -//ABu 16.03.03 sledzenie toru przed obiektem: ************************** +// ABu 16.03.03 sledzenie toru przed obiektem: ************************** void __fastcall TDynamicObject::ABuCheckMyTrack() -{//Funkcja przypisujaca obiekt prawidlowej tablicy Dynamics, - //bo gdzies jest jakis blad i wszystkie obiekty z danego - //pociagu na poczatku stawiane sa na jednym torze i wpisywane - //do jednej tablicy. Wykonuje sie tylko raz - po to 'ABuChecked' - TTrack* OldTrack=MyTrack; - TTrack* NewTrack=Axle0.GetTrack(); - if ((NewTrack!=OldTrack)&&OldTrack) - { - OldTrack->RemoveDynamicObject(this); - NewTrack->AddDynamicObject(this); - } - iAxleFirst=0; //pojazd powiązany z przednią osią - Axle0 +{ // Funkcja przypisujaca obiekt prawidlowej tablicy Dynamics, + // bo gdzies jest jakis blad i wszystkie obiekty z danego + // pociagu na poczatku stawiane sa na jednym torze i wpisywane + // do jednej tablicy. Wykonuje sie tylko raz - po to 'ABuChecked' + TTrack *OldTrack = MyTrack; + TTrack *NewTrack = Axle0.GetTrack(); + if ((NewTrack != OldTrack) && OldTrack) + { + OldTrack->RemoveDynamicObject(this); + NewTrack->AddDynamicObject(this); + } + iAxleFirst = 0; // pojazd powiązany z przednią osią - Axle0 } -//Ra: w poniższej funkcji jest problem ze sprzęgami -TDynamicObject* __fastcall TDynamicObject::ABuFindObject(TTrack *Track,int ScanDir,Byte &CouplFound,double &dist) -{//Zwraca wskaźnik najbliższego obiektu znajdującego się - //na torze w określonym kierunku, ale tylko wtedy, kiedy - //obiekty mogą się zderzyć, tzn. nie mijają się. +// Ra: w poniższej funkcji jest problem ze sprzęgami +TDynamicObject *__fastcall TDynamicObject::ABuFindObject(TTrack *Track, int ScanDir, + Byte &CouplFound, double &dist) +{ // Zwraca wskaźnik najbliższego obiektu znajdującego się + // na torze w określonym kierunku, ale tylko wtedy, kiedy + // obiekty mogą się zderzyć, tzn. nie mijają się. - //WE: Track - tor, na ktorym odbywa sie poszukiwanie, - // MyPointer - wskaznik do obiektu szukajacego. //Ra: zamieniłem na "this" - // ScanDir - kierunek szukania na torze (+1:w stronę Point2, -1:w stronę Point1) - // MyScanDir - kierunek szukania obiektu szukajacego (na jego torze); Ra: nie potrzebne - // MyCouplFound - nr sprzegu obiektu szukajacego; Ra: nie potrzebne + // WE: Track - tor, na ktorym odbywa sie poszukiwanie, + // MyPointer - wskaznik do obiektu szukajacego. //Ra: zamieniłem na "this" + // ScanDir - kierunek szukania na torze (+1:w stronę Point2, -1:w stronę Point1) + // MyScanDir - kierunek szukania obiektu szukajacego (na jego torze); Ra: nie potrzebne + // MyCouplFound - nr sprzegu obiektu szukajacego; Ra: nie potrzebne - //WY: wskaznik do znalezionego obiektu. - // CouplFound - nr sprzegu znalezionego obiektu - if (Track->iNumDynamics>0) - {//sens szukania na tym torze jest tylko, gdy są na nim pojazdy - double ObjTranslation; //pozycja najblizszego obiektu na torze - double MyTranslation; //pozycja szukającego na torze - double MinDist=Track->Length(); //najmniejsza znaleziona odleglość (zaczynamy od długości toru) - double TestDist; //robocza odległość od kolejnych pojazdów na danym odcinku - int iMinDist=-1; //indeks wykrytego obiektu - //if (Track->iNumDynamics>1) - // iMinDist+=0; //tymczasowo pułapka - if (MyTrack==Track) //gdy szukanie na tym samym torze - MyTranslation=RaTranslationGet(); //położenie wózka względem Point1 toru - else //gdy szukanie na innym torze - if (ScanDir>0) - MyTranslation=0; //szukanie w kierunku Point2 (od zera) - jesteśmy w Point1 - else - MyTranslation=MinDist; //szukanie w kierunku Point1 (do zera) - jesteśmy w Point2 - if (ScanDir>=0) - {//jeśli szukanie w kierunku Point2 - for (int i=0;iiNumDynamics;i++) - {//pętla po pojazdach - if (Track->Dynamics[i]!=this) //szukający się nie liczy - { - TestDist=(Track->Dynamics[i]->RaTranslationGet())-MyTranslation; //odległogłość tamtego od szukającego - if ((TestDist>0)&&(TestDist<=MinDist)) - {//gdy jest po właściwej stronie i bliżej niż jakiś wcześniejszy - CouplFound=(Track->Dynamics[i]->RaDirectionGet()>0)?1:0; //to, bo (ScanDir>=0) - if (Track->iCategoryFlag&254) //trajektoria innego typu niż tor kolejowy - {//dla torów nie ma sensu tego sprawdzać, rzadko co jedzie po jednej szynie i się mija - //Ra: mijanie samochodów wcale nie jest proste - // Przesuniecie wzgledne pojazdow. Wyznaczane, zeby sprawdzic, - // czy pojazdy faktycznie sie zderzaja (moga byc przesuniete - // w/m siebie tak, ze nie zachodza na siebie i wtedy sie mijaja). - double RelOffsetH; //wzajemna odległość poprzeczna - if (CouplFound) //my na tym torze byśmy byli w kierunku Point2 - //dla CouplFound=1 są zwroty zgodne - istotna różnica przesunięć - RelOffsetH=(MoverParameters->OffsetTrackH-Track->Dynamics[i]->MoverParameters->OffsetTrackH); - else - //dla CouplFound=0 są zwroty przeciwne - przesunięcia sumują się - RelOffsetH=(MoverParameters->OffsetTrackH+Track->Dynamics[i]->MoverParameters->OffsetTrackH); - if (RelOffsetH<0) RelOffsetH=-RelOffsetH; - if (RelOffsetH+RelOffsetH>MoverParameters->Dim.W+Track->Dynamics[i]->MoverParameters->Dim.W) - continue; //odległość większa od połowy sumy szerokości - kolizji nie będzie - //jeśli zahaczenie jest niewielkie, a jest miejsce na poboczu, to zjechać na pobocze - } - iMinDist=i; //potencjalna kolizja - MinDist=TestDist; //odleglość pomiędzy aktywnymi osiami pojazdów - } + // WY: wskaznik do znalezionego obiektu. + // CouplFound - nr sprzegu znalezionego obiektu + if (Track->iNumDynamics > 0) + { // sens szukania na tym torze jest tylko, gdy są na nim pojazdy + double ObjTranslation; // pozycja najblizszego obiektu na torze + double MyTranslation; // pozycja szukającego na torze + double MinDist = + Track->Length(); // najmniejsza znaleziona odleglość (zaczynamy od długości toru) + double TestDist; // robocza odległość od kolejnych pojazdów na danym odcinku + int iMinDist = -1; // indeks wykrytego obiektu + // if (Track->iNumDynamics>1) + // iMinDist+=0; //tymczasowo pułapka + if (MyTrack == Track) // gdy szukanie na tym samym torze + MyTranslation = RaTranslationGet(); // położenie wózka względem Point1 toru + else // gdy szukanie na innym torze + if (ScanDir > 0) + MyTranslation = 0; // szukanie w kierunku Point2 (od zera) - jesteśmy w Point1 + else + MyTranslation = MinDist; // szukanie w kierunku Point1 (do zera) - jesteśmy w Point2 + if (ScanDir >= 0) + { // jeśli szukanie w kierunku Point2 + for (int i = 0; i < Track->iNumDynamics; i++) + { // pętla po pojazdach + if (Track->Dynamics[i] != this) // szukający się nie liczy + { + TestDist = (Track->Dynamics[i]->RaTranslationGet()) - + MyTranslation; // odległogłość tamtego od szukającego + if ((TestDist > 0) && (TestDist <= MinDist)) + { // gdy jest po właściwej stronie i bliżej niż jakiś wcześniejszy + CouplFound = (Track->Dynamics[i]->RaDirectionGet() > 0) ? + 1 : + 0; // to, bo (ScanDir>=0) + if (Track->iCategoryFlag & 254) // trajektoria innego typu niż tor kolejowy + { // dla torów nie ma sensu tego sprawdzać, rzadko co jedzie po jednej + // szynie i się mija + // Ra: mijanie samochodów wcale nie jest proste + // Przesuniecie wzgledne pojazdow. Wyznaczane, zeby sprawdzic, + // czy pojazdy faktycznie sie zderzaja (moga byc przesuniete + // w/m siebie tak, ze nie zachodza na siebie i wtedy sie mijaja). + double RelOffsetH; // wzajemna odległość poprzeczna + if (CouplFound) // my na tym torze byśmy byli w kierunku Point2 + // dla CouplFound=1 są zwroty zgodne - istotna różnica przesunięć + RelOffsetH = (MoverParameters->OffsetTrackH - + Track->Dynamics[i]->MoverParameters->OffsetTrackH); + else + // dla CouplFound=0 są zwroty przeciwne - przesunięcia sumują się + RelOffsetH = (MoverParameters->OffsetTrackH + + Track->Dynamics[i]->MoverParameters->OffsetTrackH); + if (RelOffsetH < 0) + RelOffsetH = -RelOffsetH; + if (RelOffsetH + RelOffsetH > + MoverParameters->Dim.W + Track->Dynamics[i]->MoverParameters->Dim.W) + continue; // odległość większa od połowy sumy szerokości - kolizji + // nie będzie + // jeśli zahaczenie jest niewielkie, a jest miejsce na poboczu, to + // zjechać na pobocze + } + iMinDist = i; // potencjalna kolizja + MinDist = TestDist; // odleglość pomiędzy aktywnymi osiami pojazdów + } + } + } + } + else //(ScanDir<0) + { + for (int i = 0; i < Track->iNumDynamics; i++) + { + if (Track->Dynamics[i] != this) + { + TestDist = + MyTranslation - + (Track->Dynamics[i] + ->RaTranslationGet()); //???-przesunięcie wózka względem Point1 toru + if ((TestDist > 0) && (TestDist < MinDist)) + { + CouplFound = (Track->Dynamics[i]->RaDirectionGet() > 0) ? + 0 : + 1; // odwrotnie, bo (ScanDir<0) + if (Track->iCategoryFlag & 254) // trajektoria innego typu niż tor kolejowy + { // dla torów nie ma sensu tego sprawdzać, rzadko co jedzie po jednej + // szynie i się mija + // Ra: mijanie samochodów wcale nie jest proste + // Przesunięcie względne pojazdów. Wyznaczane, żeby sprawdzić, + // czy pojazdy faktycznie się zderzają (mogą być przesunięte + // w/m siebie tak, że nie zachodzą na siebie i wtedy sie mijają). + double RelOffsetH; // wzajemna odległość poprzeczna + if (CouplFound) // my na tym torze byśmy byli w kierunku Point1 + // dla CouplFound=1 są zwroty zgodne - istotna różnica przesunięć + RelOffsetH = (MoverParameters->OffsetTrackH - + Track->Dynamics[i]->MoverParameters->OffsetTrackH); + else + // dla CouplFound=0 są zwroty przeciwne - przesunięcia sumują się + RelOffsetH = (MoverParameters->OffsetTrackH + + Track->Dynamics[i]->MoverParameters->OffsetTrackH); + if (RelOffsetH < 0) + RelOffsetH = -RelOffsetH; + if (RelOffsetH + RelOffsetH > + MoverParameters->Dim.W + Track->Dynamics[i]->MoverParameters->Dim.W) + continue; // odległość większa od połowy sumy szerokości - kolizji + // nie będzie + } + iMinDist = i; // potencjalna kolizja + MinDist = TestDist; // odleglość pomiędzy aktywnymi osiami pojazdów + } + } + } + } + dist += MinDist; // doliczenie odległości przeszkody albo długości odcinka do przeskanowanej + // odległości + return (iMinDist >= 0) ? Track->Dynamics[iMinDist] : NULL; } - } - } - else //(ScanDir<0) - { - for (int i=0;iiNumDynamics;i++) - { - if (Track->Dynamics[i]!=this) - { - TestDist=MyTranslation-(Track->Dynamics[i]->RaTranslationGet()); //???-przesunięcie wózka względem Point1 toru - if ((TestDist>0)&&(TestDistDynamics[i]->RaDirectionGet()>0)?0:1; //odwrotnie, bo (ScanDir<0) - if (Track->iCategoryFlag&254) //trajektoria innego typu niż tor kolejowy - {//dla torów nie ma sensu tego sprawdzać, rzadko co jedzie po jednej szynie i się mija - //Ra: mijanie samochodów wcale nie jest proste - // Przesunięcie względne pojazdów. Wyznaczane, żeby sprawdzić, - // czy pojazdy faktycznie się zderzają (mogą być przesunięte - // w/m siebie tak, że nie zachodzą na siebie i wtedy sie mijają). - double RelOffsetH; //wzajemna odległość poprzeczna - if (CouplFound) //my na tym torze byśmy byli w kierunku Point1 - //dla CouplFound=1 są zwroty zgodne - istotna różnica przesunięć - RelOffsetH=(MoverParameters->OffsetTrackH-Track->Dynamics[i]->MoverParameters->OffsetTrackH); - else - //dla CouplFound=0 są zwroty przeciwne - przesunięcia sumują się - RelOffsetH=(MoverParameters->OffsetTrackH+Track->Dynamics[i]->MoverParameters->OffsetTrackH); - if (RelOffsetH<0) RelOffsetH=-RelOffsetH; - if (RelOffsetH+RelOffsetH>MoverParameters->Dim.W+Track->Dynamics[i]->MoverParameters->Dim.W) - continue; //odległość większa od połowy sumy szerokości - kolizji nie będzie - } - iMinDist=i; //potencjalna kolizja - MinDist=TestDist; //odleglość pomiędzy aktywnymi osiami pojazdów - } - } - } - } - dist+=MinDist; //doliczenie odległości przeszkody albo długości odcinka do przeskanowanej odległości - return (iMinDist>=0)?Track->Dynamics[iMinDist]:NULL; - } - dist+=Track->Length(); //doliczenie długości odcinka do przeskanowanej odległości - return NULL; //nie ma pojazdów na torze, to jest NULL + dist += Track->Length(); // doliczenie długości odcinka do przeskanowanej odległości + return NULL; // nie ma pojazdów na torze, to jest NULL } int TDynamicObject::DettachStatus(int dir) -{//sprawdzenie odległości sprzęgów rzeczywistych od strony (dir): 0=przód,1=tył - //Ra: dziwne, że ta funkcja nie jest używana - if (!MoverParameters->Couplers[dir].CouplingFlag) - return 0; //jeśli nic nie podłączone, to jest OK - return (MoverParameters->DettachStatus(dir)); //czy jest w odpowiedniej odległości? +{ // sprawdzenie odległości sprzęgów rzeczywistych od strony (dir): 0=przód,1=tył + // Ra: dziwne, że ta funkcja nie jest używana + if (!MoverParameters->Couplers[dir].CouplingFlag) + return 0; // jeśli nic nie podłączone, to jest OK + return (MoverParameters->DettachStatus(dir)); // czy jest w odpowiedniej odległości? } int TDynamicObject::Dettach(int dir) -{//rozłączenie sprzęgów rzeczywistych od strony (dir): 0=przód,1=tył - //zwraca maskę bitową aktualnych sprzegów (0 jeśli rozłączony) - if (ctOwner) - {//jeśli pojazd ma przypisany obiekt nadzorujący skład, to póki są wskaźniki - TDynamicObject *d=this; - while (d) - { - d->ctOwner=NULL; //usuwanie właściciela - d=d->Prev(); - } - d=Next(); - while (d) - { - d->ctOwner=NULL; //usuwanie właściciela - d=d->Next(); //i w drugą stronę - } - } - if (MoverParameters->Couplers[dir].CouplingFlag) //odczepianie, o ile coś podłączone - MoverParameters->Dettach(dir); - return MoverParameters->Couplers[dir].CouplingFlag; //sprzęg po rozłączaniu (czego się nie da odpiąć +{ // rozłączenie sprzęgów rzeczywistych od strony (dir): 0=przód,1=tył + // zwraca maskę bitową aktualnych sprzegów (0 jeśli rozłączony) + if (ctOwner) + { // jeśli pojazd ma przypisany obiekt nadzorujący skład, to póki są wskaźniki + TDynamicObject *d = this; + while (d) + { + d->ctOwner = NULL; // usuwanie właściciela + d = d->Prev(); + } + d = Next(); + while (d) + { + d->ctOwner = NULL; // usuwanie właściciela + d = d->Next(); // i w drugą stronę + } + } + if (MoverParameters->Couplers[dir].CouplingFlag) // odczepianie, o ile coś podłączone + MoverParameters->Dettach(dir); + return MoverParameters->Couplers[dir] + .CouplingFlag; // sprzęg po rozłączaniu (czego się nie da odpiąć } -void TDynamicObject::CouplersDettach(double MinDist,int MyScanDir) -{//funkcja rozłączajaca podłączone sprzęgi, jeśli odległość przekracza (MinDist) - //MinDist - dystans minimalny, dla ktorego mozna rozłączać - if (MyScanDir>0) - { - if (PrevConnected) //pojazd od strony sprzęgu 0 - { - if (MoverParameters->Couplers[0].CoupleDist>MinDist) //sprzęgi wirtualne zawsze przekraczają - { - if ((PrevConnectedNo?PrevConnected->NextConnected:PrevConnected->PrevConnected)==this) - {//Ra: nie rozłączamy znalezionego, jeżeli nie do nas podłączony (może jechać w innym kierunku) - PrevConnected->MoverParameters->Couplers[PrevConnectedNo].Connected=NULL; - if (PrevConnectedNo==0) - { - PrevConnected->PrevConnectedNo=2; //sprzęg 0 nie podłączony - PrevConnected->PrevConnected=NULL; - } - else if (PrevConnectedNo==1) - { - PrevConnected->NextConnectedNo=2; //sprzęg 1 nie podłączony - PrevConnected->NextConnected=NULL; - } - } - //za to zawsze odłączamy siebie - PrevConnected=NULL; - PrevConnectedNo=2; //sprzęg 0 nie podłączony - MoverParameters->Couplers[0].Connected=NULL; - } - } - } - else - { - if (NextConnected) //pojazd od strony sprzęgu 1 - { - if (MoverParameters->Couplers[1].CoupleDist>MinDist) //sprzęgi wirtualne zawsze przekraczają - { - if ((NextConnectedNo?NextConnected->NextConnected:NextConnected->PrevConnected)==this) - {//Ra: nie rozłączamy znalezionego, jeżeli nie do nas podłączony (może jechać w innym kierunku) - NextConnected->MoverParameters->Couplers[NextConnectedNo].Connected=NULL; - if (NextConnectedNo==0) - { - NextConnected->PrevConnectedNo=2; //sprzęg 0 nie podłączony - NextConnected->PrevConnected=NULL; - } - else if (NextConnectedNo==1) - { - NextConnected->NextConnectedNo=2; //sprzęg 1 nie podłączony - NextConnected->NextConnected=NULL; - } - } - NextConnected=NULL; - NextConnectedNo=2; //sprzęg 1 nie podłączony - MoverParameters->Couplers[1].Connected=NULL; - } - } - } -} - -void TDynamicObject::ABuScanObjects(int ScanDir,double ScanDist) -{//skanowanie toru w poszukiwaniu kolidujących pojazdów - //ScanDir - określa kierunek poszukiwania zależnie od zwrotu prędkości pojazdu - // ScanDir=1 - od strony Coupler0, ScanDir=-1 - od strony Coupler1 - int MyScanDir=ScanDir; //zapamiętanie kierunku poszukiwań na torze początkowym, względem sprzęgów - TTrackFollower *FirstAxle=(MyScanDir>0?&Axle0:&Axle1); //można by to trzymać w trainset - TTrack *Track=FirstAxle->GetTrack(); //tor na którym "stoi" skrajny wózek (może być inny niż tor pojazdu) - if (FirstAxle->GetDirection()<0) //czy oś jest ustawiona w stronę Point1? - ScanDir=-ScanDir; //jeśli tak, to kierunek szukania będzie przeciwny (teraz względem toru) - Byte MyCouplFound; //numer sprzęgu do podłączenia w obiekcie szukajacym - MyCouplFound=(MyScanDir<0)?1:0; - Byte CouplFound; //numer sprzęgu w znalezionym obiekcie (znaleziony wypełni) - TDynamicObject *FoundedObj; //znaleziony obiekt - double ActDist=0; //przeskanowana odleglość; odległość do zawalidrogi - FoundedObj=ABuFindObject(Track,ScanDir,CouplFound,ActDist); //zaczynamy szukać na tym samym torze - -/* - if (FoundedObj) //jak coś znajdzie, to śledzimy - {//powtórzenie wyszukiwania tylko do zastawiania pułepek podczas testów - if (ABuGetDirection()<0) ScanDir=ScanDir; //ustalenie kierunku względem toru - FoundedObj=ABuFindObject(Track,this,ScanDir,CouplFound); - } -*/ - - if (DebugModeFlag) - if (FoundedObj) //kod służący do logowania błędów - if (CouplFound==0) - { - if (FoundedObj->PrevConnected) - if (FoundedObj->PrevConnected!=this) //odświeżenie tego samego się nie liczy - WriteLog("0! Coupler warning on "+asName+":"+AnsiString(MyCouplFound)+" - "+FoundedObj->asName+":0 connected to "+FoundedObj->PrevConnected->asName+":"+AnsiString(FoundedObj->PrevConnectedNo)); - } - else - { - if (FoundedObj->NextConnected) - if (FoundedObj->NextConnected!=this) //odświeżenie tego samego się nie liczy - WriteLog("0! Coupler warning on "+asName+":"+AnsiString(MyCouplFound)+" - "+FoundedObj->asName+":1 connected to "+FoundedObj->NextConnected->asName+":"+AnsiString(FoundedObj->NextConnectedNo)); - } - - - if (FoundedObj==NULL) //jeśli nie ma na tym samym, szukamy po okolicy - {//szukanie najblizszego toru z jakims obiektem - //praktycznie przeklejone z TraceRoute()... - //double CurrDist=0; //aktualna dlugosc toru - if (ScanDir>=0) //uwzględniamy kawalek przeanalizowanego wcześniej toru - ActDist=Track->Length()-FirstAxle->GetTranslation(); //odległość osi od Point2 toru - else - ActDist=FirstAxle->GetTranslation(); //odległość osi od Point1 toru - while (ActDist0) //w kierunku Point2 toru - { - if (Track?Track->iNextDirection:false) //jeśli następny tor jest podpięty od Point2 - ScanDir=-ScanDir; //to zmieniamy kierunek szukania na tym torze - Track=Track->CurrentNext(); //potem dopiero zmieniamy wskaźnik - } - else //w kierunku Point1 - { - if (Track?!Track->iPrevDirection:true) //jeśli poprzedni tor nie jest podpięty od Point2 - ScanDir=-ScanDir; //to zmieniamy kierunek szukania na tym torze - Track=Track->CurrentPrev(); //potem dopiero zmieniamy wskaźnik - } - if (Track) - {//jesli jest kolejny odcinek toru - //CurrDist=Track->Length(); //doliczenie tego toru do przejrzanego dystandu - FoundedObj=ABuFindObject(Track,ScanDir,CouplFound,ActDist); //przejrzenie pojazdów tego toru - if (FoundedObj) +void TDynamicObject::CouplersDettach(double MinDist, int MyScanDir) +{ // funkcja rozłączajaca podłączone sprzęgi, jeśli odległość przekracza (MinDist) + // MinDist - dystans minimalny, dla ktorego mozna rozłączać + if (MyScanDir > 0) { - //ActDist=ScanDist; //wyjście z pętli poszukiwania - break; + if (PrevConnected) // pojazd od strony sprzęgu 0 + { + if (MoverParameters->Couplers[0].CoupleDist > + MinDist) // sprzęgi wirtualne zawsze przekraczają + { + if ((PrevConnectedNo ? PrevConnected->NextConnected : + PrevConnected->PrevConnected) == this) + { // Ra: nie rozłączamy znalezionego, jeżeli nie do nas podłączony (może jechać w + // innym kierunku) + PrevConnected->MoverParameters->Couplers[PrevConnectedNo].Connected = NULL; + if (PrevConnectedNo == 0) + { + PrevConnected->PrevConnectedNo = 2; // sprzęg 0 nie podłączony + PrevConnected->PrevConnected = NULL; + } + else if (PrevConnectedNo == 1) + { + PrevConnected->NextConnectedNo = 2; // sprzęg 1 nie podłączony + PrevConnected->NextConnected = NULL; + } + } + // za to zawsze odłączamy siebie + PrevConnected = NULL; + PrevConnectedNo = 2; // sprzęg 0 nie podłączony + MoverParameters->Couplers[0].Connected = NULL; + } + } } - } - else //jeśli toru nie ma, to wychodzimy - { - ActDist=ScanDist+1.0; //koniec przeglądania torów - break; - } - } - } // Koniec szukania najbliższego toru z jakimś obiektem. - //teraz odczepianie i jeśli coś się znalazło, doczepianie. - if (MyScanDir>0?PrevConnected:NextConnected) - if ((MyScanDir>0?PrevConnected:NextConnected)!=FoundedObj) - CouplersDettach(1.0,MyScanDir); //odłączamy, jeśli dalej niż metr - // i łączenie sprzęgiem wirtualnym - if (FoundedObj) - {//siebie można bezpiecznie podłączyć jednostronnie do znalezionego - MoverParameters->Attach(MyCouplFound,CouplFound,FoundedObj->MoverParameters,ctrain_virtual); - //MoverParameters->Couplers[MyCouplFound].Render=false; //wirtualnego nie renderujemy - if (MyCouplFound==0) - { - PrevConnected=FoundedObj; //pojazd od strony sprzęgu 0 - PrevConnectedNo=CouplFound; - } - else - { - NextConnected=FoundedObj; //pojazd od strony sprzęgu 1 - NextConnectedNo=CouplFound; - } - if (FoundedObj->MoverParameters->Couplers[CouplFound].CouplingFlag==ctrain_virtual) - {//Ra: wpinamy się wirtualnym tylko jeśli znaleziony ma wirtualny sprzęg - FoundedObj->MoverParameters->Attach(CouplFound,MyCouplFound,this->MoverParameters,ctrain_virtual); - if (CouplFound==0) //jeśli widoczny sprzęg 0 znalezionego - { + else + { + if (NextConnected) // pojazd od strony sprzęgu 1 + { + if (MoverParameters->Couplers[1].CoupleDist > + MinDist) // sprzęgi wirtualne zawsze przekraczają + { + if ((NextConnectedNo ? NextConnected->NextConnected : + NextConnected->PrevConnected) == this) + { // Ra: nie rozłączamy znalezionego, jeżeli nie do nas podłączony (może jechać w + // innym kierunku) + NextConnected->MoverParameters->Couplers[NextConnectedNo].Connected = NULL; + if (NextConnectedNo == 0) + { + NextConnected->PrevConnectedNo = 2; // sprzęg 0 nie podłączony + NextConnected->PrevConnected = NULL; + } + else if (NextConnectedNo == 1) + { + NextConnected->NextConnectedNo = 2; // sprzęg 1 nie podłączony + NextConnected->NextConnected = NULL; + } + } + NextConnected = NULL; + NextConnectedNo = 2; // sprzęg 1 nie podłączony + MoverParameters->Couplers[1].Connected = NULL; + } + } + } +} + +void TDynamicObject::ABuScanObjects(int ScanDir, double ScanDist) +{ // skanowanie toru w poszukiwaniu kolidujących pojazdów + // ScanDir - określa kierunek poszukiwania zależnie od zwrotu prędkości pojazdu + // ScanDir=1 - od strony Coupler0, ScanDir=-1 - od strony Coupler1 + int MyScanDir = + ScanDir; // zapamiętanie kierunku poszukiwań na torze początkowym, względem sprzęgów + TTrackFollower *FirstAxle = (MyScanDir > 0 ? &Axle0 : &Axle1); // można by to trzymać w trainset + TTrack *Track = + FirstAxle->GetTrack(); // tor na którym "stoi" skrajny wózek (może być inny niż tor pojazdu) + if (FirstAxle->GetDirection() < 0) // czy oś jest ustawiona w stronę Point1? + ScanDir = -ScanDir; // jeśli tak, to kierunek szukania będzie przeciwny (teraz względem + // toru) + Byte MyCouplFound; // numer sprzęgu do podłączenia w obiekcie szukajacym + MyCouplFound = (MyScanDir < 0) ? 1 : 0; + Byte CouplFound; // numer sprzęgu w znalezionym obiekcie (znaleziony wypełni) + TDynamicObject *FoundedObj; // znaleziony obiekt + double ActDist = 0; // przeskanowana odleglość; odległość do zawalidrogi + FoundedObj = + ABuFindObject(Track, ScanDir, CouplFound, ActDist); // zaczynamy szukać na tym samym torze + + /* + if (FoundedObj) //jak coś znajdzie, to śledzimy + {//powtórzenie wyszukiwania tylko do zastawiania pułepek podczas testów + if (ABuGetDirection()<0) ScanDir=ScanDir; //ustalenie kierunku względem toru + FoundedObj=ABuFindObject(Track,this,ScanDir,CouplFound); + } + */ + if (DebugModeFlag) - if (FoundedObj->PrevConnected) - if (FoundedObj->PrevConnected!=this) - WriteLog("1! Coupler warning on "+asName+":"+AnsiString(MyCouplFound)+" - "+FoundedObj->asName+":0 connected to "+FoundedObj->PrevConnected->asName+":"+AnsiString(FoundedObj->PrevConnectedNo)); - FoundedObj->PrevConnected=this; - FoundedObj->PrevConnectedNo=MyCouplFound; - } - else //jeśli widoczny sprzęg 1 znalezionego - { - if (DebugModeFlag) - if (FoundedObj->NextConnected) - if (FoundedObj->NextConnected!=this) - WriteLog("1! Coupler warning on "+asName+":"+AnsiString(MyCouplFound)+" - "+FoundedObj->asName+":1 connected to "+FoundedObj->NextConnected->asName+":"+AnsiString(FoundedObj->NextConnectedNo)); - FoundedObj->NextConnected=this; - FoundedObj->NextConnectedNo=MyCouplFound; - } - } - //Ra: jeśli dwa samochody się mijają na odcinku przed zawrotką, to odległość między nimi nie może być liczona w linii prostej! - fTrackBlock=MoverParameters->Couplers[MyCouplFound].CoupleDist; //odległość do najbliższego pojazdu w linii prostej - if (Track->iCategoryFlag>1) //jeśli samochód - if (ActDist>MoverParameters->Dim.L+FoundedObj->MoverParameters->Dim.L) //przeskanowana odległość większa od długości pojazdów - //else if (ActDistasName); - } - else //nic nie znalezione, to nie ma przeszkód - fTrackBlock=10000.0; + if (FoundedObj) // kod służący do logowania błędów + if (CouplFound == 0) + { + if (FoundedObj->PrevConnected) + if (FoundedObj->PrevConnected != this) // odświeżenie tego samego się nie liczy + WriteLog("0! Coupler warning on " + asName + ":" + + AnsiString(MyCouplFound) + " - " + FoundedObj->asName + + ":0 connected to " + FoundedObj->PrevConnected->asName + ":" + + AnsiString(FoundedObj->PrevConnectedNo)); + } + else + { + if (FoundedObj->NextConnected) + if (FoundedObj->NextConnected != this) // odświeżenie tego samego się nie liczy + WriteLog("0! Coupler warning on " + asName + ":" + + AnsiString(MyCouplFound) + " - " + FoundedObj->asName + + ":1 connected to " + FoundedObj->NextConnected->asName + ":" + + AnsiString(FoundedObj->NextConnectedNo)); + } + + if (FoundedObj == NULL) // jeśli nie ma na tym samym, szukamy po okolicy + { // szukanie najblizszego toru z jakims obiektem + // praktycznie przeklejone z TraceRoute()... + // double CurrDist=0; //aktualna dlugosc toru + if (ScanDir >= 0) // uwzględniamy kawalek przeanalizowanego wcześniej toru + ActDist = Track->Length() - FirstAxle->GetTranslation(); // odległość osi od Point2 toru + else + ActDist = FirstAxle->GetTranslation(); // odległość osi od Point1 toru + while (ActDist < ScanDist) + { + // ActDist+=CurrDist; //odległość już przeanalizowana + if (ScanDir > 0) // w kierunku Point2 toru + { + if (Track ? Track->iNextDirection : + false) // jeśli następny tor jest podpięty od Point2 + ScanDir = -ScanDir; // to zmieniamy kierunek szukania na tym torze + Track = Track->CurrentNext(); // potem dopiero zmieniamy wskaźnik + } + else // w kierunku Point1 + { + if (Track ? !Track->iPrevDirection : + true) // jeśli poprzedni tor nie jest podpięty od Point2 + ScanDir = -ScanDir; // to zmieniamy kierunek szukania na tym torze + Track = Track->CurrentPrev(); // potem dopiero zmieniamy wskaźnik + } + if (Track) + { // jesli jest kolejny odcinek toru + // CurrDist=Track->Length(); //doliczenie tego toru do przejrzanego dystandu + FoundedObj = ABuFindObject(Track, ScanDir, CouplFound, + ActDist); // przejrzenie pojazdów tego toru + if (FoundedObj) + { + // ActDist=ScanDist; //wyjście z pętli poszukiwania + break; + } + } + else // jeśli toru nie ma, to wychodzimy + { + ActDist = ScanDist + 1.0; // koniec przeglądania torów + break; + } + } + } // Koniec szukania najbliższego toru z jakimś obiektem. + // teraz odczepianie i jeśli coś się znalazło, doczepianie. + if (MyScanDir > 0 ? PrevConnected : NextConnected) + if ((MyScanDir > 0 ? PrevConnected : NextConnected) != FoundedObj) + CouplersDettach(1.0, MyScanDir); // odłączamy, jeśli dalej niż metr + // i łączenie sprzęgiem wirtualnym + if (FoundedObj) + { // siebie można bezpiecznie podłączyć jednostronnie do znalezionego + MoverParameters->Attach(MyCouplFound, CouplFound, FoundedObj->MoverParameters, + ctrain_virtual); + // MoverParameters->Couplers[MyCouplFound].Render=false; //wirtualnego nie renderujemy + if (MyCouplFound == 0) + { + PrevConnected = FoundedObj; // pojazd od strony sprzęgu 0 + PrevConnectedNo = CouplFound; + } + else + { + NextConnected = FoundedObj; // pojazd od strony sprzęgu 1 + NextConnectedNo = CouplFound; + } + if (FoundedObj->MoverParameters->Couplers[CouplFound].CouplingFlag == ctrain_virtual) + { // Ra: wpinamy się wirtualnym tylko jeśli znaleziony ma wirtualny sprzęg + FoundedObj->MoverParameters->Attach(CouplFound, MyCouplFound, this->MoverParameters, + ctrain_virtual); + if (CouplFound == 0) // jeśli widoczny sprzęg 0 znalezionego + { + if (DebugModeFlag) + if (FoundedObj->PrevConnected) + if (FoundedObj->PrevConnected != this) + WriteLog("1! Coupler warning on " + asName + ":" + + AnsiString(MyCouplFound) + " - " + FoundedObj->asName + + ":0 connected to " + FoundedObj->PrevConnected->asName + ":" + + AnsiString(FoundedObj->PrevConnectedNo)); + FoundedObj->PrevConnected = this; + FoundedObj->PrevConnectedNo = MyCouplFound; + } + else // jeśli widoczny sprzęg 1 znalezionego + { + if (DebugModeFlag) + if (FoundedObj->NextConnected) + if (FoundedObj->NextConnected != this) + WriteLog("1! Coupler warning on " + asName + ":" + + AnsiString(MyCouplFound) + " - " + FoundedObj->asName + + ":1 connected to " + FoundedObj->NextConnected->asName + ":" + + AnsiString(FoundedObj->NextConnectedNo)); + FoundedObj->NextConnected = this; + FoundedObj->NextConnectedNo = MyCouplFound; + } + } + // Ra: jeśli dwa samochody się mijają na odcinku przed zawrotką, to odległość między nimi + // nie może być liczona w linii prostej! + fTrackBlock = MoverParameters->Couplers[MyCouplFound] + .CoupleDist; // odległość do najbliższego pojazdu w linii prostej + if (Track->iCategoryFlag > 1) // jeśli samochód + if (ActDist > MoverParameters->Dim.L + + FoundedObj->MoverParameters->Dim + .L) // przeskanowana odległość większa od długości pojazdów + // else if (ActDistasName); + } + else // nic nie znalezione, to nie ma przeszkód + fTrackBlock = 10000.0; } //----------ABu: koniec skanowania pojazdow __fastcall TDynamicObject::TDynamicObject() { - modelShake=vector3(0,0,0); - fTrackBlock=10000.0; //brak przeszkody na drodze - btnOn=false; - vUp=vWorldUp; - vFront=vWorldFront; - vLeft=vWorldLeft; - iNumAxles=0; - MoverParameters=NULL; - Mechanik=NULL; - MechInside=false; - //McZapkie-270202 - Controller=AIdriver; - bDisplayCab=false; //030303 - bBrakeAcc=false; - NextConnected=PrevConnected=NULL; - NextConnectedNo=PrevConnectedNo=2; //ABu: Numery sprzegow. 2=nie podłączony - CouplCounter=50; //będzie sprawdzać na początku - asName=""; - bEnabled=true; - MyTrack=NULL; - //McZapkie-260202 - dRailLength=25.0; - for (int i=0;iiLights; //wskaźnik na stan własnych świateł (zmienimy dla rozrządczych EZT) - //McZapkie: TypeName musi byc nazwą CHK/MMD pojazdu - if (!MoverParameters->LoadChkFile(asBaseDir)) - {//jak wczytanie CHK się nie uda, to błąd - if (ConversionError==-8) - ErrorLog("Missed file: "+BaseDir+"\\"+Type_Name+".fiz"); - Error("Cannot load dynamic object "+asName+" from:\r\n"+BaseDir+"\\"+Type_Name+".fiz\r\nError "+ConversionError+" in line "+LineCount); - return 0.0; //zerowa długość to brak pojazdu - } - bool driveractive=(fVel!=0.0); //jeśli prędkość niezerowa, to aktywujemy ruch - if (!MoverParameters->CheckLocomotiveParameters(driveractive,(fVel>0?1:-1)*Cab*(iDirection?1:-1))) //jak jedzie lub obsadzony to gotowy do drogi - { - Error("Parameters mismatch: dynamic object "+asName+" from\n"+BaseDir+"\\"+Type_Name); - return 0.0; //zerowa długość to brak pojazdu - } - MoverParameters->BrakeLevelSet(MoverParameters->BrakeCtrlPos); //poprawienie hamulca po ewentualnym przestawieniu przez Pascal - -//dodatkowe parametry yB - MoreParams+="."; //wykonuje o jedną iterację za mało, więc trzeba mu dodać kropkę na koniec - int kropka=MoreParams.Pos("."); //znajdź kropke - AnsiString ActPar; //na parametry - while (kropka>0) //jesli sa kropki jeszcze - { - int dlugosc=MoreParams.Length(); - ActPar=MoreParams.SubString(1,kropka-1).UpperCase(); //pierwszy parametr; - MoreParams=MoreParams.SubString(kropka+1,dlugosc-kropka); //reszta do dalszej obrobki - kropka=MoreParams.Pos("."); - - if(ActPar.SubString(1,1)=="B") //jesli hamulce - { //sprawdzanie kolejno nastaw - WriteLog("Wpis hamulca: " + ActPar); - if (ActPar.Pos("G")>0) {MoverParameters->BrakeDelaySwitch(bdelay_G);} - if (ActPar.Pos("P")>0) {MoverParameters->BrakeDelaySwitch(bdelay_P);} - if (ActPar.Pos("R")>0) {MoverParameters->BrakeDelaySwitch(bdelay_R);} - if (ActPar.Pos("M")>0) {MoverParameters->BrakeDelaySwitch(bdelay_R); MoverParameters->BrakeDelaySwitch(bdelay_R+bdelay_M);} - //wylaczanie hamulca - if (ActPar.Pos("<>")>0) //wylaczanie na probe hamowania naglego - { - MoverParameters->BrakeStatus|=128; //wylacz - } - if (ActPar.Pos("0")>0) //wylaczanie na sztywno - { - MoverParameters->BrakeStatus|=128; //wylacz - MoverParameters->Hamulec->ForceEmptiness(); - MoverParameters->BrakeReleaser(1); //odluznij automatycznie - } - if (ActPar.Pos("E")>0) //oprozniony - { - MoverParameters->Hamulec->ForceEmptiness(); - MoverParameters->BrakeReleaser(1); //odluznij automatycznie - MoverParameters->Pipe->CreatePress(0); - MoverParameters->Pipe2->CreatePress(0); - } - if (ActPar.Pos("Q")>0) //oprozniony - { -// MoverParameters->Hamulec->ForceEmptiness(); //TODO: sprawdzic, dlaczego pojawia sie blad przy uzyciu tej linijki w lokomotywie - MoverParameters->BrakeReleaser(1); //odluznij automatycznie - MoverParameters->Pipe->CreatePress(0.0); - MoverParameters->PipePress=0.0; - MoverParameters->Pipe2->CreatePress(0.0); - MoverParameters->ScndPipePress=0.0; - MoverParameters->PantVolume=1; - MoverParameters->PantPress=0; - MoverParameters->CompressedVolume=0; - } - - if (ActPar.Pos("1")>0) //wylaczanie 10% - { - if (random(10)<1) //losowanie 1/10 + AnsiString Name, // nazwa pojazdu, np. "EU07-424" + AnsiString BaseDir, // z którego katalogu wczytany, np. "PKP/EU07" + AnsiString asReplacableSkin, // nazwa wymiennej tekstury + AnsiString Type_Name, // nazwa CHK/MMD, np. "303E" + TTrack *Track, // tor początkowy wstwawienia (początek składu) + double fDist, // dystans względem punktu 1 + AnsiString DriverType, // typ obsady + double fVel, // prędkość początkowa + AnsiString TrainName, // nazwa składu, np. "PE2307" albo Vmax, jeśli pliku nie ma a są cyfry + float Load, // ilość ładunku + AnsiString LoadType, // nazwa ładunku + bool Reversed, // true, jeśli ma stać odwrotnie w składzie + AnsiString MoreParams // dodatkowe parametry wczytywane w postaci tekstowej + ) +{ // Ustawienie początkowe pojazdu + iDirection = (Reversed ? 0 : 1); // Ra: 0, jeśli ma być wstawiony jako obrócony tyłem + asBaseDir = "dynamic\\" + BaseDir + "\\"; // McZapkie-310302 + asName = Name; + AnsiString asAnimName = ""; // zmienna robocza do wyszukiwania osi i wózków + // Ra: zmieniamy znaczenie obsady na jednoliterowe, żeby dosadzić kierownika + if (DriverType == "headdriver") + DriverType = "1"; // sterujący kabiną +1 + else if (DriverType == "reardriver") + DriverType = "2"; // sterujący kabiną -1 + // else if (DriverType=="connected") DriverType="c"; //tego trzeba się pozbyć na rzecz + // ukrotnienia + else if (DriverType == "passenger") + DriverType = "p"; // to do przemyślenia + else if (DriverType == "nobody") + DriverType = ""; // nikt nie siedzi + int Cab = 0; // numer kabiny z obsadą (nie można zająć obu) + if (DriverType.Pos("1")) // od przodu składu + Cab = 1; // iDirection?1:-1; //iDirection=1 gdy normalnie, =0 odwrotnie + else if (DriverType.Pos("2")) // od tyłu składu + Cab = -1; // iDirection?-1:1; + else if (DriverType == "p") { - MoverParameters->BrakeStatus|=128; //wylacz - MoverParameters->Hamulec->ForceEmptiness(); - MoverParameters->BrakeReleaser(1); //odluznij automatycznie + if (random(6) < 3) + Cab = 1; + else + Cab = -1; // losowy przydział kabiny } - } - if (ActPar.Pos("X")>0) //agonalny wylaczanie 20%, usrednienie przekladni - { - if (random(100)<20) //losowanie 20/100 - { - MoverParameters->BrakeStatus|=128; //wylacz - MoverParameters->Hamulec->ForceEmptiness(); - MoverParameters->BrakeReleaser(1); //odluznij automatycznie - } - if (MoverParameters->BrakeCylMult[2]*MoverParameters->BrakeCylMult[1]>0.01) //jesli jest nastawiacz mechaniczny PL - { - float rnd=random(100); - if (rnd<20) //losowanie 20/100 usrednienie - { - MoverParameters->BrakeCylMult[2]=MoverParameters->BrakeCylMult[1]=(MoverParameters->BrakeCylMult[2]+MoverParameters->BrakeCylMult[1])/2; - } + /* to nie ma uzasadnienia else - if (rnd<70) //losowanie 70/100-20/100 oslabienie - { - MoverParameters->BrakeCylMult[1]=MoverParameters->BrakeCylMult[1]*0.50; - MoverParameters->BrakeCylMult[2]=MoverParameters->BrakeCylMult[2]*0.75; - } - else - if (rnd<80) //losowanie 80/100-70/100 tylko prozny - { - MoverParameters->BrakeCylMult[2]=MoverParameters->BrakeCylMult[1]; - } - else //tylko ladowny - { - MoverParameters->BrakeCylMult[1]=MoverParameters->BrakeCylMult[2]; + {//obsada nie rozpoznana + Cab=0; //McZapkie-010303: w przyszlosci dac tez pomocnika, palacza, konduktora itp. + Error("Unknown DriverType description: "+DriverType); + DriverType="nobody"; } + */ + // utworzenie parametrów fizyki + MoverParameters = + new TMoverParameters(iDirection ? fVel : -fVel, Type_Name, asName, Load, LoadType, Cab); + iLights = MoverParameters + ->iLights; // wskaźnik na stan własnych świateł (zmienimy dla rozrządczych EZT) + // McZapkie: TypeName musi byc nazwą CHK/MMD pojazdu + if (!MoverParameters->LoadChkFile(asBaseDir)) + { // jak wczytanie CHK się nie uda, to błąd + if (ConversionError == -8) + ErrorLog("Missed file: " + BaseDir + "\\" + Type_Name + ".fiz"); + Error("Cannot load dynamic object " + asName + " from:\r\n" + BaseDir + "\\" + Type_Name + + ".fiz\r\nError " + ConversionError + " in line " + LineCount); + return 0.0; // zerowa długość to brak pojazdu } - } - //nastawianie ladunku - if (ActPar.Pos("T")>0) //prozny - { MoverParameters->DecBrakeMult(); MoverParameters->DecBrakeMult(); } //dwa razy w dol - if (ActPar.Pos("H")>0) //ladowny I (dla P-Ł dalej prozny) - { MoverParameters->IncBrakeMult(); MoverParameters->IncBrakeMult(); MoverParameters->DecBrakeMult(); } //dwa razy w gore i obniz - if (ActPar.Pos("F")>0) //ladowny II - { MoverParameters->IncBrakeMult(); MoverParameters->IncBrakeMult(); } //dwa razy w gore - if (ActPar.Pos("N")>0) //parametr neutralny - { } - } //koniec hamulce - else if(ActPar.SubString(1,1)=="") //tu mozna wpisac inny prefiks i inne rzeczy - { - //jakies inne prefiksy - } + bool driveractive = (fVel != 0.0); // jeśli prędkość niezerowa, to aktywujemy ruch + if (!MoverParameters->CheckLocomotiveParameters( + driveractive, (fVel > 0 ? 1 : -1) * Cab * + (iDirection ? 1 : -1))) // jak jedzie lub obsadzony to gotowy do drogi + { + Error("Parameters mismatch: dynamic object " + asName + " from\n" + BaseDir + "\\" + + Type_Name); + return 0.0; // zerowa długość to brak pojazdu + } + MoverParameters->BrakeLevelSet( + MoverParameters + ->BrakeCtrlPos); // poprawienie hamulca po ewentualnym przestawieniu przez Pascal - } //koniec while kropka + // dodatkowe parametry yB + MoreParams += "."; // wykonuje o jedną iterację za mało, więc trzeba mu dodać kropkę na koniec + int kropka = MoreParams.Pos("."); // znajdź kropke + AnsiString ActPar; // na parametry + while (kropka > 0) // jesli sa kropki jeszcze + { + int dlugosc = MoreParams.Length(); + ActPar = MoreParams.SubString(1, kropka - 1).UpperCase(); // pierwszy parametr; + MoreParams = MoreParams.SubString(kropka + 1, dlugosc - kropka); // reszta do dalszej + // obrobki + kropka = MoreParams.Pos("."); - if (MoverParameters->CategoryFlag&2) //jeśli samochód - {//ustawianie samochodow na poboczu albo na środku drogi - if (Track->fTrackWidth<3.5) //jeśli droga wąska - MoverParameters->OffsetTrackH=0.0; //to stawiamy na środku, niezależnie od stanu ruchu - else - if (driveractive) //od 3.5m do 8.0m jedzie po środku pasa, dla szerszych w odległości 1.5m - MoverParameters->OffsetTrackH=Track->fTrackWidth<=8.0?-Track->fTrackWidth*0.25:-1.5; - else //jak stoi, to kołem na poboczu i pobieramy szerokość razem z poboczem, ale nie z chodnikiem - MoverParameters->OffsetTrackH=-0.5*(Track->WidthTotal()-MoverParameters->Dim.W)+0.05; - iHornWarning=0; //nie będzie trąbienia po podaniu zezwolenia na jazdę - if (fDist<0.0) //-0.5*MoverParameters->Dim.L) //jeśli jest przesunięcie do tyłu - if (!Track->CurrentPrev()) //a nie ma tam odcinka i trzeba by coś wygenerować - fDist=-fDist; //to traktujemy, jakby przesunięcie było w drugą stronę - } - //w wagonie tez niech jedzie - //if (MoverParameters->MainCtrlPosNo>0 && - // if (MoverParameters->CabNo!=0) - if (DriverType!="") - {//McZapkie-040602: jeśli coś siedzi w pojeździe - if (Name==AnsiString(Global::asHumanCtrlVehicle)) //jeśli pojazd wybrany do prowadzenia - { - if (DebugModeFlag?false:MoverParameters->EngineType!=Dumb) //jak nie Debugmode i nie jest dumbem - Controller=Humandriver; //wsadzamy tam sterującego - else //w przeciwnym razie trzeba włączyć pokazywanie kabiny - bDisplayCab=true; - } - //McZapkie-151102: rozkład jazdy czytany z pliku *.txt z katalogu w którym jest sceneria - if (DriverType.Pos("1")||DriverType.Pos("2")) - {//McZapkie-110303: mechanik i rozklad tylko gdy jest obsada - //MoverParameters->ActiveCab=MoverParameters->CabNo; //ustalenie aktywnej kabiny (rozrząd) - Mechanik=new TController(Controller,this,Aggressive); - if (TrainName.IsEmpty()) //jeśli nie w składzie - { - Mechanik->DirectionInitial(); //załączenie rozrządu (wirtualne kabiny) itd. - Mechanik->PutCommand("Timetable:",iDirection?-fVel:fVel,0,NULL); //tryb pociągowy z ustaloną prędkością (względem sprzęgów) - } - //if (TrainName!="none") - // Mechanik->PutCommand("Timetable:"+TrainName,fVel,0,NULL); - } - else - if (DriverType=="p") - {//obserwator w charakterze pasażera - //Ra: to jest niebezpieczne, bo w razie co będzie pomagał hamulcem bezpieczeństwa - Mechanik=new TController(Controller,this,Easyman,false); - } - } - // McZapkie-250202 - iAxles=(MaxAxlesNAxles)?MaxAxles:MoverParameters->NAxles; //ilość osi - //wczytywanie z pliku nazwatypu.mmd, w tym model - LoadMMediaFile(asBaseDir,Type_Name,asReplacableSkin); - //McZapkie-100402: wyszukiwanie submodeli sprzegów - btCoupler1.Init("coupler1",mdModel,false); //false - ma być wyłączony - btCoupler2.Init("coupler2",mdModel,false); - btCPneumatic1.Init("cpneumatic1",mdModel); - btCPneumatic2.Init("cpneumatic2",mdModel); - btCPneumatic1r.Init("cpneumatic1r",mdModel); - btCPneumatic2r.Init("cpneumatic2r",mdModel); - btPneumatic1.Init("pneumatic1",mdModel); - btPneumatic2.Init("pneumatic2",mdModel); - btPneumatic1r.Init("pneumatic1r",mdModel); - btPneumatic2r.Init("pneumatic2r",mdModel); - btCCtrl1.Init("cctrl1",mdModel,false); - btCCtrl2.Init("cctrl2",mdModel,false); - btCPass1.Init("cpass1",mdModel,false); - btCPass2.Init("cpass2",mdModel,false); - //sygnaly - //ABu 060205: Zmiany dla koncowek swiecacych: - btEndSignals11.Init("endsignal13",mdModel,false); - btEndSignals21.Init("endsignal23",mdModel,false); - btEndSignals13.Init("endsignal12",mdModel,false); - btEndSignals23.Init("endsignal22",mdModel,false); - iInventory|=btEndSignals11.Active() ?0x01:0; //informacja, czy ma poszczególne światła - iInventory|=btEndSignals21.Active() ?0x02:0; - iInventory|=btEndSignals13.Active() ?0x04:0; - iInventory|=btEndSignals23.Active() ?0x08:0; - //ABu: to niestety zostawione dla kompatybilnosci modeli: - btEndSignals1.Init("endsignals1",mdModel,false); - btEndSignals2.Init("endsignals2",mdModel,false); - btEndSignalsTab1.Init("endtab1",mdModel,false); - btEndSignalsTab2.Init("endtab2",mdModel,false); - iInventory|=btEndSignals1.Active() ?0x10:0; - iInventory|=btEndSignals2.Active() ?0x20:0; - iInventory|=btEndSignalsTab1.Active()?0x40:0; //tabliczki blaszane - iInventory|=btEndSignalsTab2.Active()?0x80:0; - //ABu Uwaga! tu zmienic w modelu! - btHeadSignals11.Init("headlamp13",mdModel,false); //lewe - btHeadSignals12.Init("headlamp11",mdModel,false); //górne - btHeadSignals13.Init("headlamp12",mdModel,false); //prawe - btHeadSignals21.Init("headlamp23",mdModel,false); - btHeadSignals22.Init("headlamp21",mdModel,false); - btHeadSignals23.Init("headlamp22",mdModel,false); - TurnOff(); //resetowanie zmiennych submodeli - //wyszukiwanie zderzakow - if (mdModel) //jeśli ma w czym szukać - for (int i=0;i<2;i++) - { - asAnimName=AnsiString("buffer_left0")+(i+1); - smBuforLewy[i]=mdModel->GetFromName(asAnimName.c_str()); - if (smBuforLewy[i]) - smBuforLewy[i]->WillBeAnimated(); //ustawienie flagi animacji - asAnimName=AnsiString("buffer_right0")+(i+1); - smBuforPrawy[i]=mdModel->GetFromName(asAnimName.c_str()); - if (smBuforPrawy[i]) - smBuforPrawy[i]->WillBeAnimated(); - } - for (int i=0;iDim.L))+fDist; - //McZapkie-250202 end. - Track->AddDynamicObject(this); //wstawiamy do toru na pozycję 0, a potem przesuniemy - //McZapkie: zmieniono na ilosc osi brane z chk - //iNumAxles=(MoverParameters->NAxles>3 ? 4 : 2 ); - iNumAxles=2; - //McZapkie-090402: odleglosc miedzy czopami skretu lub osiami - fAxleDist=Max0R(MoverParameters->BDist,MoverParameters->ADist); - if (fAxleDist<0.2) fAxleDist=0.2; //żeby się dało wektory policzyć - if (fAxleDist>MoverParameters->Dim.L-0.2) //nie mogą być za daleko - fAxleDist=MoverParameters->Dim.L-0.2; //bo będzie "walenie w mur" - double fAxleDistHalf=fAxleDist*0.5; - //WriteLog("Dynamic "+Type_Name+" of length "+MoverParameters->Dim.L+" at "+AnsiString(fDist)); - //if (Cab) //jeśli ma obsadę - zgodność wstecz, jeśli tor startowy ma Event0 - // if (Track->Event0) //jeśli tor ma Event0 - // if (fDist>=0.0) //jeśli jeśli w starych sceneriach początek składu byłby wysunięty na ten tor - // if (fDist<=0.5*MoverParameters->Dim.L+0.2) //ale nie jest wysunięty - // fDist+=0.5*MoverParameters->Dim.L+0.2; //wysunąć go na ten tor - //przesuwanie pojazdu tak, aby jego początek był we wskazanym miejcu - fDist-=0.5*MoverParameters->Dim.L; //dodajemy pół długości pojazdu, bo ustawiamy jego środek (zliczanie na minus) - switch (iNumAxles) - {//Ra: pojazdy wstawiane są na tor początkowy, a potem przesuwane - case 2: //ustawianie osi na torze - Axle0.Init(Track,this,iDirection?1:-1); - Axle0.Move((iDirection?fDist:-fDist)+fAxleDistHalf,false); - Axle1.Init(Track,this,iDirection?1:-1); - Axle1.Move((iDirection?fDist:-fDist)-fAxleDistHalf,false); //false, żeby nie generować eventów - //Axle2.Init(Track,this,iDirection?1:-1); - //Axle2.Move((iDirection?fDist:-fDist)-fAxleDistHalft+0.01),false); - //Axle3.Init(Track,this,iDirection?1:-1); - //Axle3.Move((iDirection?fDist:-fDist)+fAxleDistHalf-0.01),false); - break; - case 4: - Axle0.Init(Track,this,iDirection?1:-1); - Axle0.Move((iDirection?fDist:-fDist)+(fAxleDistHalf+MoverParameters->ADist*0.5),false); - Axle1.Init(Track,this,iDirection?1:-1); - Axle1.Move((iDirection?fDist:-fDist)-(fAxleDistHalf+MoverParameters->ADist*0.5),false); - //Axle2.Init(Track,this,iDirection?1:-1); - //Axle2.Move((iDirection?fDist:-fDist)-(fAxleDistHalf-MoverParameters->ADist*0.5),false); - //Axle3.Init(Track,this,iDirection?1:-1); - //Axle3.Move((iDirection?fDist:-fDist)+(fAxleDistHalf-MoverParameters->ADist*0.5),false); - break; - } - Move(0.0001); //potrzebne do wyliczenia aktualnej pozycji; nie może być zero, bo nie przeliczy pozycji - //teraz jeszcze trzeba przypisać pojazdy do nowego toru, bo przesuwanie początkowe osi nie zrobiło tego - ABuCheckMyTrack(); //zmiana toru na ten, co oś Axle0 (oś z przodu) - TLocation loc; //Ra: ustawienie pozycji do obliczania sprzęgów - loc.X=-vPosition.x; - loc.Y=vPosition.z; - loc.Z=vPosition.y; - MoverParameters->Loc=loc; //normalnie przesuwa ComputeMovement() w Update() - //pOldPos4=Axle1.pPosition; //Ra: nie używane - //pOldPos1=Axle0.pPosition; - //ActualTrack= GetTrack(); //McZapkie-030303 - //ABuWozki 060504 - if (mdModel) //jeśli ma w czym szukać - { - smBogie[0]=mdModel->GetFromName("bogie1"); //Ra: bo nazwy są małymi - smBogie[1]=mdModel->GetFromName("bogie2"); - if (!smBogie[0]) - smBogie[0]=mdModel->GetFromName("boogie01"); //Ra: alternatywna nazwa - if (!smBogie[1]) - smBogie[1]=mdModel->GetFromName("boogie02"); //Ra: alternatywna nazwa - if (smBogie[0]) - smBogie[0]->WillBeAnimated(); - if (smBogie[1]) - smBogie[1]->WillBeAnimated(); - } - //ABu: zainicjowanie zmiennej, zeby nic sie nie ruszylo - //w pierwszej klatce, potem juz liczona prawidlowa wartosc masy - MoverParameters->ComputeConstans(); - /*Ra: to nie działa - Event0 musi być wykonywany ciągle - if (fVel==0.0) //jeśli stoi - if (MoverParameters->CabNo!=0) //i ma kogoś w kabinie - if (Track->Event0) //a jest w tym torze event od stania - RaAxleEvent(Track->Event0); //dodanie eventu stania do kolejki - */ - vFloor=vector3(0,0,MoverParameters->Floor); //wektor podłogi dla wagonów, przesuwa ładunek - return MoverParameters->Dim.L; //długość większa od zera oznacza OK; 2mm docisku? + if (ActPar.SubString(1, 1) == "B") // jesli hamulce + { // sprawdzanie kolejno nastaw + WriteLog("Wpis hamulca: " + ActPar); + if (ActPar.Pos("G") > 0) + { + MoverParameters->BrakeDelaySwitch(bdelay_G); + } + if (ActPar.Pos("P") > 0) + { + MoverParameters->BrakeDelaySwitch(bdelay_P); + } + if (ActPar.Pos("R") > 0) + { + MoverParameters->BrakeDelaySwitch(bdelay_R); + } + if (ActPar.Pos("M") > 0) + { + MoverParameters->BrakeDelaySwitch(bdelay_R); + MoverParameters->BrakeDelaySwitch(bdelay_R + bdelay_M); + } + // wylaczanie hamulca + if (ActPar.Pos("<>") > 0) // wylaczanie na probe hamowania naglego + { + MoverParameters->BrakeStatus |= 128; // wylacz + } + if (ActPar.Pos("0") > 0) // wylaczanie na sztywno + { + MoverParameters->BrakeStatus |= 128; // wylacz + MoverParameters->Hamulec->ForceEmptiness(); + MoverParameters->BrakeReleaser(1); // odluznij automatycznie + } + if (ActPar.Pos("E") > 0) // oprozniony + { + MoverParameters->Hamulec->ForceEmptiness(); + MoverParameters->BrakeReleaser(1); // odluznij automatycznie + MoverParameters->Pipe->CreatePress(0); + MoverParameters->Pipe2->CreatePress(0); + } + if (ActPar.Pos("Q") > 0) // oprozniony + { + // MoverParameters->Hamulec->ForceEmptiness(); //TODO: sprawdzic, dlaczego + // pojawia sie blad przy uzyciu tej linijki w lokomotywie + MoverParameters->BrakeReleaser(1); // odluznij automatycznie + MoverParameters->Pipe->CreatePress(0.0); + MoverParameters->PipePress = 0.0; + MoverParameters->Pipe2->CreatePress(0.0); + MoverParameters->ScndPipePress = 0.0; + MoverParameters->PantVolume = 1; + MoverParameters->PantPress = 0; + MoverParameters->CompressedVolume = 0; + } + + if (ActPar.Pos("1") > 0) // wylaczanie 10% + { + if (random(10) < 1) // losowanie 1/10 + { + MoverParameters->BrakeStatus |= 128; // wylacz + MoverParameters->Hamulec->ForceEmptiness(); + MoverParameters->BrakeReleaser(1); // odluznij automatycznie + } + } + if (ActPar.Pos("X") > 0) // agonalny wylaczanie 20%, usrednienie przekladni + { + if (random(100) < 20) // losowanie 20/100 + { + MoverParameters->BrakeStatus |= 128; // wylacz + MoverParameters->Hamulec->ForceEmptiness(); + MoverParameters->BrakeReleaser(1); // odluznij automatycznie + } + if (MoverParameters->BrakeCylMult[2] * MoverParameters->BrakeCylMult[1] > + 0.01) // jesli jest nastawiacz mechaniczny PL + { + float rnd = random(100); + if (rnd < 20) // losowanie 20/100 usrednienie + { + MoverParameters->BrakeCylMult[2] = MoverParameters->BrakeCylMult[1] = + (MoverParameters->BrakeCylMult[2] + MoverParameters->BrakeCylMult[1]) / + 2; + } + else if (rnd < 70) // losowanie 70/100-20/100 oslabienie + { + MoverParameters->BrakeCylMult[1] = MoverParameters->BrakeCylMult[1] * 0.50; + MoverParameters->BrakeCylMult[2] = MoverParameters->BrakeCylMult[2] * 0.75; + } + else if (rnd < 80) // losowanie 80/100-70/100 tylko prozny + { + MoverParameters->BrakeCylMult[2] = MoverParameters->BrakeCylMult[1]; + } + else // tylko ladowny + { + MoverParameters->BrakeCylMult[1] = MoverParameters->BrakeCylMult[2]; + } + } + } + // nastawianie ladunku + if (ActPar.Pos("T") > 0) // prozny + { + MoverParameters->DecBrakeMult(); + MoverParameters->DecBrakeMult(); + } // dwa razy w dol + if (ActPar.Pos("H") > 0) // ladowny I (dla P-Ł dalej prozny) + { + MoverParameters->IncBrakeMult(); + MoverParameters->IncBrakeMult(); + MoverParameters->DecBrakeMult(); + } // dwa razy w gore i obniz + if (ActPar.Pos("F") > 0) // ladowny II + { + MoverParameters->IncBrakeMult(); + MoverParameters->IncBrakeMult(); + } // dwa razy w gore + if (ActPar.Pos("N") > 0) // parametr neutralny + { + } + } // koniec hamulce + else if (ActPar.SubString(1, 1) == "") // tu mozna wpisac inny prefiks i inne rzeczy + { + // jakies inne prefiksy + } + + } // koniec while kropka + + if (MoverParameters->CategoryFlag & 2) // jeśli samochód + { // ustawianie samochodow na poboczu albo na środku drogi + if (Track->fTrackWidth < 3.5) // jeśli droga wąska + MoverParameters->OffsetTrackH = 0.0; // to stawiamy na środku, niezależnie od stanu + // ruchu + else if (driveractive) // od 3.5m do 8.0m jedzie po środku pasa, dla szerszych w odległości + // 1.5m + MoverParameters->OffsetTrackH = + Track->fTrackWidth <= 8.0 ? -Track->fTrackWidth * 0.25 : -1.5; + else // jak stoi, to kołem na poboczu i pobieramy szerokość razem z poboczem, ale nie z + // chodnikiem + MoverParameters->OffsetTrackH = + -0.5 * (Track->WidthTotal() - MoverParameters->Dim.W) + 0.05; + iHornWarning = 0; // nie będzie trąbienia po podaniu zezwolenia na jazdę + if (fDist < 0.0) //-0.5*MoverParameters->Dim.L) //jeśli jest przesunięcie do tyłu + if (!Track->CurrentPrev()) // a nie ma tam odcinka i trzeba by coś wygenerować + fDist = -fDist; // to traktujemy, jakby przesunięcie było w drugą stronę + } + // w wagonie tez niech jedzie + // if (MoverParameters->MainCtrlPosNo>0 && + // if (MoverParameters->CabNo!=0) + if (DriverType != "") + { // McZapkie-040602: jeśli coś siedzi w pojeździe + if (Name == AnsiString(Global::asHumanCtrlVehicle)) // jeśli pojazd wybrany do prowadzenia + { + if (DebugModeFlag ? false : MoverParameters->EngineType != + Dumb) // jak nie Debugmode i nie jest dumbem + Controller = Humandriver; // wsadzamy tam sterującego + else // w przeciwnym razie trzeba włączyć pokazywanie kabiny + bDisplayCab = true; + } + // McZapkie-151102: rozkład jazdy czytany z pliku *.txt z katalogu w którym jest sceneria + if (DriverType.Pos("1") || DriverType.Pos("2")) + { // McZapkie-110303: mechanik i rozklad tylko gdy jest obsada + // MoverParameters->ActiveCab=MoverParameters->CabNo; //ustalenie aktywnej kabiny + // (rozrząd) + Mechanik = new TController(Controller, this, Aggressive); + if (TrainName.IsEmpty()) // jeśli nie w składzie + { + Mechanik->DirectionInitial(); // załączenie rozrządu (wirtualne kabiny) itd. + Mechanik->PutCommand( + "Timetable:", iDirection ? -fVel : fVel, 0, + NULL); // tryb pociągowy z ustaloną prędkością (względem sprzęgów) + } + // if (TrainName!="none") + // Mechanik->PutCommand("Timetable:"+TrainName,fVel,0,NULL); + } + else if (DriverType == "p") + { // obserwator w charakterze pasażera + // Ra: to jest niebezpieczne, bo w razie co będzie pomagał hamulcem bezpieczeństwa + Mechanik = new TController(Controller, this, Easyman, false); + } + } + // McZapkie-250202 + iAxles = (MaxAxles < MoverParameters->NAxles) ? MaxAxles : MoverParameters->NAxles; // ilość osi + // wczytywanie z pliku nazwatypu.mmd, w tym model + LoadMMediaFile(asBaseDir, Type_Name, asReplacableSkin); + // McZapkie-100402: wyszukiwanie submodeli sprzegów + btCoupler1.Init("coupler1", mdModel, false); // false - ma być wyłączony + btCoupler2.Init("coupler2", mdModel, false); + btCPneumatic1.Init("cpneumatic1", mdModel); + btCPneumatic2.Init("cpneumatic2", mdModel); + btCPneumatic1r.Init("cpneumatic1r", mdModel); + btCPneumatic2r.Init("cpneumatic2r", mdModel); + btPneumatic1.Init("pneumatic1", mdModel); + btPneumatic2.Init("pneumatic2", mdModel); + btPneumatic1r.Init("pneumatic1r", mdModel); + btPneumatic2r.Init("pneumatic2r", mdModel); + btCCtrl1.Init("cctrl1", mdModel, false); + btCCtrl2.Init("cctrl2", mdModel, false); + btCPass1.Init("cpass1", mdModel, false); + btCPass2.Init("cpass2", mdModel, false); + // sygnaly + // ABu 060205: Zmiany dla koncowek swiecacych: + btEndSignals11.Init("endsignal13", mdModel, false); + btEndSignals21.Init("endsignal23", mdModel, false); + btEndSignals13.Init("endsignal12", mdModel, false); + btEndSignals23.Init("endsignal22", mdModel, false); + iInventory |= btEndSignals11.Active() ? 0x01 : 0; // informacja, czy ma poszczególne światła + iInventory |= btEndSignals21.Active() ? 0x02 : 0; + iInventory |= btEndSignals13.Active() ? 0x04 : 0; + iInventory |= btEndSignals23.Active() ? 0x08 : 0; + // ABu: to niestety zostawione dla kompatybilnosci modeli: + btEndSignals1.Init("endsignals1", mdModel, false); + btEndSignals2.Init("endsignals2", mdModel, false); + btEndSignalsTab1.Init("endtab1", mdModel, false); + btEndSignalsTab2.Init("endtab2", mdModel, false); + iInventory |= btEndSignals1.Active() ? 0x10 : 0; + iInventory |= btEndSignals2.Active() ? 0x20 : 0; + iInventory |= btEndSignalsTab1.Active() ? 0x40 : 0; // tabliczki blaszane + iInventory |= btEndSignalsTab2.Active() ? 0x80 : 0; + // ABu Uwaga! tu zmienic w modelu! + btHeadSignals11.Init("headlamp13", mdModel, false); // lewe + btHeadSignals12.Init("headlamp11", mdModel, false); // górne + btHeadSignals13.Init("headlamp12", mdModel, false); // prawe + btHeadSignals21.Init("headlamp23", mdModel, false); + btHeadSignals22.Init("headlamp21", mdModel, false); + btHeadSignals23.Init("headlamp22", mdModel, false); + TurnOff(); // resetowanie zmiennych submodeli + // wyszukiwanie zderzakow + if (mdModel) // jeśli ma w czym szukać + for (int i = 0; i < 2; i++) + { + asAnimName = AnsiString("buffer_left0") + (i + 1); + smBuforLewy[i] = mdModel->GetFromName(asAnimName.c_str()); + if (smBuforLewy[i]) + smBuforLewy[i]->WillBeAnimated(); // ustawienie flagi animacji + asAnimName = AnsiString("buffer_right0") + (i + 1); + smBuforPrawy[i] = mdModel->GetFromName(asAnimName.c_str()); + if (smBuforPrawy[i]) + smBuforPrawy[i]->WillBeAnimated(); + } + for (int i = 0; i < iAxles; i++) // wyszukiwanie osi (0 jest na końcu, dlatego dodajemy + // długość?) + dRailPosition[i] = + (Reversed ? -dWheelsPosition[i] : (dWheelsPosition[i] + MoverParameters->Dim.L)) + + fDist; + // McZapkie-250202 end. + Track->AddDynamicObject(this); // wstawiamy do toru na pozycję 0, a potem przesuniemy + // McZapkie: zmieniono na ilosc osi brane z chk + // iNumAxles=(MoverParameters->NAxles>3 ? 4 : 2 ); + iNumAxles = 2; + // McZapkie-090402: odleglosc miedzy czopami skretu lub osiami + fAxleDist = Max0R(MoverParameters->BDist, MoverParameters->ADist); + if (fAxleDist < 0.2) + fAxleDist = 0.2; //żeby się dało wektory policzyć + if (fAxleDist > MoverParameters->Dim.L - 0.2) // nie mogą być za daleko + fAxleDist = MoverParameters->Dim.L - 0.2; // bo będzie "walenie w mur" + double fAxleDistHalf = fAxleDist * 0.5; + // WriteLog("Dynamic "+Type_Name+" of length "+MoverParameters->Dim.L+" at "+AnsiString(fDist)); + // if (Cab) //jeśli ma obsadę - zgodność wstecz, jeśli tor startowy ma Event0 + // if (Track->Event0) //jeśli tor ma Event0 + // if (fDist>=0.0) //jeśli jeśli w starych sceneriach początek składu byłby wysunięty na ten + // tor + // if (fDist<=0.5*MoverParameters->Dim.L+0.2) //ale nie jest wysunięty + // fDist+=0.5*MoverParameters->Dim.L+0.2; //wysunąć go na ten tor + // przesuwanie pojazdu tak, aby jego początek był we wskazanym miejcu + fDist -= 0.5 * + MoverParameters->Dim + .L; // dodajemy pół długości pojazdu, bo ustawiamy jego środek (zliczanie na minus) + switch (iNumAxles) + { // Ra: pojazdy wstawiane są na tor początkowy, a potem przesuwane + case 2: // ustawianie osi na torze + Axle0.Init(Track, this, iDirection ? 1 : -1); + Axle0.Move((iDirection ? fDist : -fDist) + fAxleDistHalf, false); + Axle1.Init(Track, this, iDirection ? 1 : -1); + Axle1.Move((iDirection ? fDist : -fDist) - fAxleDistHalf, + false); // false, żeby nie generować eventów + // Axle2.Init(Track,this,iDirection?1:-1); + // Axle2.Move((iDirection?fDist:-fDist)-fAxleDistHalft+0.01),false); + // Axle3.Init(Track,this,iDirection?1:-1); + // Axle3.Move((iDirection?fDist:-fDist)+fAxleDistHalf-0.01),false); + break; + case 4: + Axle0.Init(Track, this, iDirection ? 1 : -1); + Axle0.Move((iDirection ? fDist : -fDist) + (fAxleDistHalf + MoverParameters->ADist * 0.5), + false); + Axle1.Init(Track, this, iDirection ? 1 : -1); + Axle1.Move((iDirection ? fDist : -fDist) - (fAxleDistHalf + MoverParameters->ADist * 0.5), + false); + // Axle2.Init(Track,this,iDirection?1:-1); + // Axle2.Move((iDirection?fDist:-fDist)-(fAxleDistHalf-MoverParameters->ADist*0.5),false); + // Axle3.Init(Track,this,iDirection?1:-1); + // Axle3.Move((iDirection?fDist:-fDist)+(fAxleDistHalf-MoverParameters->ADist*0.5),false); + break; + } + Move(0.0001); // potrzebne do wyliczenia aktualnej pozycji; nie może być zero, bo nie przeliczy + // pozycji + // teraz jeszcze trzeba przypisać pojazdy do nowego toru, bo przesuwanie początkowe osi nie + // zrobiło tego + ABuCheckMyTrack(); // zmiana toru na ten, co oś Axle0 (oś z przodu) + TLocation loc; // Ra: ustawienie pozycji do obliczania sprzęgów + loc.X = -vPosition.x; + loc.Y = vPosition.z; + loc.Z = vPosition.y; + MoverParameters->Loc = loc; // normalnie przesuwa ComputeMovement() w Update() + // pOldPos4=Axle1.pPosition; //Ra: nie używane + // pOldPos1=Axle0.pPosition; + // ActualTrack= GetTrack(); //McZapkie-030303 + // ABuWozki 060504 + if (mdModel) // jeśli ma w czym szukać + { + smBogie[0] = mdModel->GetFromName("bogie1"); // Ra: bo nazwy są małymi + smBogie[1] = mdModel->GetFromName("bogie2"); + if (!smBogie[0]) + smBogie[0] = mdModel->GetFromName("boogie01"); // Ra: alternatywna nazwa + if (!smBogie[1]) + smBogie[1] = mdModel->GetFromName("boogie02"); // Ra: alternatywna nazwa + if (smBogie[0]) + smBogie[0]->WillBeAnimated(); + if (smBogie[1]) + smBogie[1]->WillBeAnimated(); + } + // ABu: zainicjowanie zmiennej, zeby nic sie nie ruszylo + // w pierwszej klatce, potem juz liczona prawidlowa wartosc masy + MoverParameters->ComputeConstans(); + /*Ra: to nie działa - Event0 musi być wykonywany ciągle + if (fVel==0.0) //jeśli stoi + if (MoverParameters->CabNo!=0) //i ma kogoś w kabinie + if (Track->Event0) //a jest w tym torze event od stania + RaAxleEvent(Track->Event0); //dodanie eventu stania do kolejki + */ + vFloor = vector3(0, 0, MoverParameters->Floor); // wektor podłogi dla wagonów, przesuwa ładunek + return MoverParameters->Dim.L; // długość większa od zera oznacza OK; 2mm docisku? } void __fastcall TDynamicObject::FastMove(double fDistance) { - MoverParameters->dMoveLen=MoverParameters->dMoveLen+fDistance; + MoverParameters->dMoveLen = MoverParameters->dMoveLen + fDistance; } void __fastcall TDynamicObject::Move(double fDistance) -{//przesuwanie pojazdu po trajektorii polega na przesuwaniu poszczególnych osi - //Ra: wartość prędkości 2km/h ma ograniczyć aktywację eventów w przypadku drgań - if (Axle0.GetTrack()==Axle1.GetTrack()) //przed przesunięciem - {//powiązanie pojazdu z osią można zmienić tylko wtedy, gdy skrajne osie są na tym samym torze - if (MoverParameters->Vel>2) //|[km/h]| nie ma sensu zmiana osi, jesli pojazd drga na postoju - iAxleFirst=(MoverParameters->V>=0.0)?1:0; //[m/s] ?1:0 - aktywna druga oś w kierunku jazdy - //aktualnie eventy aktywuje druga oś, żeby AI nie wyłączało sobie semafora za szybko - } - if (fDistance>0.0) - {//gdy ruch w stronę sprzęgu 0, doliczyć korektę do osi 1 - bEnabled&=Axle0.Move(fDistance,!iAxleFirst); //oś z przodu pojazdu - bEnabled&=Axle1.Move(fDistance/*-fAdjustment*/,iAxleFirst); //oś z tyłu pojazdu - } - else if (fDistance<0.0) - {//gdy ruch w stronę sprzęgu 1, doliczyć korektę do osi 0 - bEnabled&=Axle1.Move(fDistance,iAxleFirst); //oś z tyłu pojazdu prusza się pierwsza - bEnabled&=Axle0.Move(fDistance/*-fAdjustment*/,!iAxleFirst); //oś z przodu pojazdu - } - //Axle2.Move(fDistance,false); //te nigdy pierwsze nie są - //Axle3.Move(fDistance,false); - if (fDistance!=0.0) //nie liczyć ponownie, jeśli stoi - {//liczenie pozycji pojazdu tutaj, bo jest używane w wielu miejscach - vPosition=0.5*(Axle1.pPosition+Axle0.pPosition); //środek między skrajnymi osiami - vFront=Axle0.pPosition-Axle1.pPosition; //wektor pomiędzy skrajnymi osiami - //Ra 2F1J: to nie jest stabilne (powoduje rzucanie taborem) i wymaga dopracowania - fAdjustment=vFront.Length()-fAxleDist; //na łuku będzie ujemny - //if (fabs(fAdjustment)>0.02) //jeśli jest zbyt dużo, to rozłożyć na kilka przeliczeń (wygasza drgania?) - //{//parę centymetrów trzeba by już skorygować; te błędy mogą się też generować na ostrych łukach - // fAdjustment*=0.5; //w jednym kroku korygowany jest ułamek błędu - //} - //else - // fAdjustment=0.0; - vFront=Normalize(vFront); //kierunek ustawienia pojazdu (wektor jednostkowy) - vLeft=Normalize(CrossProduct(vWorldUp,vFront)); //wektor poziomy w lewo, normalizacja potrzebna z powodu pochylenia (vFront) - vUp=CrossProduct(vFront,vLeft); //wektor w górę, będzie jednostkowy - modelRot.z=atan2(-vFront.x,vFront.z); //kąt obrotu pojazdu [rad]; z ABuBogies() - double a=((Axle1.GetRoll()+Axle0.GetRoll())); //suma przechyłek - if (a!=0.0) - {//wyznaczanie przechylenia tylko jeśli jest przechyłka - //można by pobrać wektory normalne z toru... - mMatrix.Identity(); //ta macierz jest potrzebna głównie do wyświetlania - mMatrix.Rotation(a*0.5,vFront); //obrót wzdłuż osi o przechyłkę - vUp=mMatrix*vUp; //wektor w górę pojazdu (przekręcenie na przechyłce) - //vLeft=mMatrix*DynamicObject->vLeft; - //vUp=CrossProduct(vFront,vLeft); //wektor w górę - //vLeft=Normalize(CrossProduct(vWorldUp,vFront)); //wektor w lewo - vLeft=Normalize(CrossProduct(vUp,vFront)); //wektor w lewo - //vUp=CrossProduct(vFront,vLeft); //wektor w górę - } - mMatrix.Identity(); //to też można by od razu policzyć, ale potrzebne jest do wyświetlania - mMatrix.BasisChange(vLeft,vUp,vFront); //przesuwanie jest jednak rzadziej niż renderowanie - mMatrix=Inverse(mMatrix); //wyliczenie macierzy dla pojazdu (potrzebna tylko do wyświetlania?) - //if (MoverParameters->CategoryFlag&2) - {//przesunięcia są używane po wyrzuceniu pociągu z toru - vPosition.x+=MoverParameters->OffsetTrackH*vLeft.x; //dodanie przesunięcia w bok - vPosition.z+=MoverParameters->OffsetTrackH*vLeft.z; //vLeft jest wektorem poprzecznym - //if () na przechyłce będzie dodatkowo zmiana wysokości samochodu - vPosition.y+=MoverParameters->OffsetTrackV; //te offsety są liczone przez moverparam - } - //Ra: skopiowanie pozycji do fizyki, tam potrzebna do zrywania sprzęgów - //MoverParameters->Loc.X=-vPosition.x; //robi to {Fast}ComputeMovement() - //MoverParameters->Loc.Y= vPosition.z; - //MoverParameters->Loc.Z= vPosition.y; - //obliczanie pozycji sprzęgów do liczenia zderzeń - vector3 dir=(0.5*MoverParameters->Dim.L)*vFront; //wektor sprzęgu - vCoulpler[0]=vPosition+dir; //współrzędne sprzęgu na początku - vCoulpler[1]=vPosition-dir; //współrzędne sprzęgu na końcu - MoverParameters->vCoulpler[0]=vCoulpler[0]; //tymczasowo kopiowane na inny poziom - MoverParameters->vCoulpler[1]=vCoulpler[1]; - //bCameraNear= - //if (bCameraNear) //jeśli istotne są szczegóły (blisko kamery) - {//przeliczenie cienia - TTrack *t0=Axle0.GetTrack(); //już po przesunięciu - TTrack *t1=Axle1.GetTrack(); - if ((t0->eEnvironment==e_flat)&&(t1->eEnvironment==e_flat)) //może być e_bridge... - fShade=0.0; //standardowe oświetlenie - else - {//jeżeli te tory mają niestandardowy stopień zacienienia (e_canyon, e_tunnel) - if (t0->eEnvironment==t1->eEnvironment) - {switch (t0->eEnvironment) - {//typ zmiany oświetlenia - case e_canyon: fShade=0.65; break; //zacienienie w kanionie - case e_tunnel: fShade=0.20; break; //zacienienie w tunelu - } +{ // przesuwanie pojazdu po trajektorii polega na przesuwaniu poszczególnych osi + // Ra: wartość prędkości 2km/h ma ograniczyć aktywację eventów w przypadku drgań + if (Axle0.GetTrack() == Axle1.GetTrack()) // przed przesunięciem + { // powiązanie pojazdu z osią można zmienić tylko wtedy, gdy skrajne osie są na tym samym torze + if (MoverParameters->Vel > + 2) //|[km/h]| nie ma sensu zmiana osi, jesli pojazd drga na postoju + iAxleFirst = (MoverParameters->V >= 0.0) ? + 1 : + 0; //[m/s] ?1:0 - aktywna druga oś w kierunku jazdy + // aktualnie eventy aktywuje druga oś, żeby AI nie wyłączało sobie semafora za szybko } - else //dwa różne - {//liczymy proporcję - double d=Axle0.GetTranslation(); //aktualne położenie na torze - if (Axle0.GetDirection()<0) - d=t0->fTrackLength-d; //od drugiej strony liczona długość - d/=fAxleDist; //rozsataw osi procentowe znajdowanie się na torze - switch (t0->eEnvironment) - {//typ zmiany oświetlenia - zakładam, że drugi tor ma e_flat - case e_canyon: fShade=(d*0.65)+(1.0-d); break; //zacienienie w kanionie - case e_tunnel: fShade=(d*0.20)+(1.0-d); break; //zacienienie w tunelu - } - switch (t1->eEnvironment) - {//typ zmiany oświetlenia - zakładam, że pierwszy tor ma e_flat - case e_canyon: fShade=d+(1.0-d)*0.65; break; //zacienienie w kanionie - case e_tunnel: fShade=d+(1.0-d)*0.20; break; //zacienienie w tunelu - } + if (fDistance > 0.0) + { // gdy ruch w stronę sprzęgu 0, doliczyć korektę do osi 1 + bEnabled &= Axle0.Move(fDistance, !iAxleFirst); // oś z przodu pojazdu + bEnabled &= Axle1.Move(fDistance /*-fAdjustment*/, iAxleFirst); // oś z tyłu pojazdu + } + else if (fDistance < 0.0) + { // gdy ruch w stronę sprzęgu 1, doliczyć korektę do osi 0 + bEnabled &= Axle1.Move(fDistance, iAxleFirst); // oś z tyłu pojazdu prusza się pierwsza + bEnabled &= Axle0.Move(fDistance /*-fAdjustment*/, !iAxleFirst); // oś z przodu pojazdu + } + // Axle2.Move(fDistance,false); //te nigdy pierwsze nie są + // Axle3.Move(fDistance,false); + if (fDistance != 0.0) // nie liczyć ponownie, jeśli stoi + { // liczenie pozycji pojazdu tutaj, bo jest używane w wielu miejscach + vPosition = 0.5 * (Axle1.pPosition + Axle0.pPosition); //środek między skrajnymi osiami + vFront = Axle0.pPosition - Axle1.pPosition; // wektor pomiędzy skrajnymi osiami + // Ra 2F1J: to nie jest stabilne (powoduje rzucanie taborem) i wymaga dopracowania + fAdjustment = vFront.Length() - fAxleDist; // na łuku będzie ujemny + // if (fabs(fAdjustment)>0.02) //jeśli jest zbyt dużo, to rozłożyć na kilka przeliczeń + // (wygasza drgania?) + //{//parę centymetrów trzeba by już skorygować; te błędy mogą się też generować na ostrych + //łukach + // fAdjustment*=0.5; //w jednym kroku korygowany jest ułamek błędu + //} + // else + // fAdjustment=0.0; + vFront = Normalize(vFront); // kierunek ustawienia pojazdu (wektor jednostkowy) + vLeft = Normalize(CrossProduct( + vWorldUp, + vFront)); // wektor poziomy w lewo, normalizacja potrzebna z powodu pochylenia (vFront) + vUp = CrossProduct(vFront, vLeft); // wektor w górę, będzie jednostkowy + modelRot.z = atan2(-vFront.x, vFront.z); // kąt obrotu pojazdu [rad]; z ABuBogies() + double a = ((Axle1.GetRoll() + Axle0.GetRoll())); // suma przechyłek + if (a != 0.0) + { // wyznaczanie przechylenia tylko jeśli jest przechyłka + // można by pobrać wektory normalne z toru... + mMatrix.Identity(); // ta macierz jest potrzebna głównie do wyświetlania + mMatrix.Rotation(a * 0.5, vFront); // obrót wzdłuż osi o przechyłkę + vUp = mMatrix * vUp; // wektor w górę pojazdu (przekręcenie na przechyłce) + // vLeft=mMatrix*DynamicObject->vLeft; + // vUp=CrossProduct(vFront,vLeft); //wektor w górę + // vLeft=Normalize(CrossProduct(vWorldUp,vFront)); //wektor w lewo + vLeft = Normalize(CrossProduct(vUp, vFront)); // wektor w lewo + // vUp=CrossProduct(vFront,vLeft); //wektor w górę + } + mMatrix.Identity(); // to też można by od razu policzyć, ale potrzebne jest do wyświetlania + mMatrix.BasisChange(vLeft, vUp, vFront); // przesuwanie jest jednak rzadziej niż + // renderowanie + mMatrix = + Inverse(mMatrix); // wyliczenie macierzy dla pojazdu (potrzebna tylko do wyświetlania?) + // if (MoverParameters->CategoryFlag&2) + { // przesunięcia są używane po wyrzuceniu pociągu z toru + vPosition.x += MoverParameters->OffsetTrackH * vLeft.x; // dodanie przesunięcia w bok + vPosition.z += + MoverParameters->OffsetTrackH * vLeft.z; // vLeft jest wektorem poprzecznym + // if () na przechyłce będzie dodatkowo zmiana wysokości samochodu + vPosition.y += MoverParameters->OffsetTrackV; // te offsety są liczone przez moverparam + } + // Ra: skopiowanie pozycji do fizyki, tam potrzebna do zrywania sprzęgów + // MoverParameters->Loc.X=-vPosition.x; //robi to {Fast}ComputeMovement() + // MoverParameters->Loc.Y= vPosition.z; + // MoverParameters->Loc.Z= vPosition.y; + // obliczanie pozycji sprzęgów do liczenia zderzeń + vector3 dir = (0.5 * MoverParameters->Dim.L) * vFront; // wektor sprzęgu + vCoulpler[0] = vPosition + dir; // współrzędne sprzęgu na początku + vCoulpler[1] = vPosition - dir; // współrzędne sprzęgu na końcu + MoverParameters->vCoulpler[0] = vCoulpler[0]; // tymczasowo kopiowane na inny poziom + MoverParameters->vCoulpler[1] = vCoulpler[1]; + // bCameraNear= + // if (bCameraNear) //jeśli istotne są szczegóły (blisko kamery) + { // przeliczenie cienia + TTrack *t0 = Axle0.GetTrack(); // już po przesunięciu + TTrack *t1 = Axle1.GetTrack(); + if ((t0->eEnvironment == e_flat) && (t1->eEnvironment == e_flat)) // może być + // e_bridge... + fShade = 0.0; // standardowe oświetlenie + else + { // jeżeli te tory mają niestandardowy stopień zacienienia (e_canyon, e_tunnel) + if (t0->eEnvironment == t1->eEnvironment) + { + switch (t0->eEnvironment) + { // typ zmiany oświetlenia + case e_canyon: + fShade = 0.65; + break; // zacienienie w kanionie + case e_tunnel: + fShade = 0.20; + break; // zacienienie w tunelu + } + } + else // dwa różne + { // liczymy proporcję + double d = Axle0.GetTranslation(); // aktualne położenie na torze + if (Axle0.GetDirection() < 0) + d = t0->fTrackLength - d; // od drugiej strony liczona długość + d /= fAxleDist; // rozsataw osi procentowe znajdowanie się na torze + switch (t0->eEnvironment) + { // typ zmiany oświetlenia - zakładam, że drugi tor ma e_flat + case e_canyon: + fShade = (d * 0.65) + (1.0 - d); + break; // zacienienie w kanionie + case e_tunnel: + fShade = (d * 0.20) + (1.0 - d); + break; // zacienienie w tunelu + } + switch (t1->eEnvironment) + { // typ zmiany oświetlenia - zakładam, że pierwszy tor ma e_flat + case e_canyon: + fShade = d + (1.0 - d) * 0.65; + break; // zacienienie w kanionie + case e_tunnel: + fShade = d + (1.0 - d) * 0.20; + break; // zacienienie w tunelu + } + } + } + } } - } - } - } }; void __fastcall TDynamicObject::AttachPrev(TDynamicObject *Object, int iType) -{//Ra: doczepia Object na końcu składu (nazwa funkcji może być myląca) - //Ra: używane tylko przy wczytywaniu scenerii - /* - //Ra: po wstawieniu pojazdu do scenerii nie miał on ustawionej pozycji, teraz już ma - TLocation loc; - loc.X=-vPosition.x; - loc.Y=vPosition.z; - loc.Z=vPosition.y; - MoverParameters->Loc=loc; //Ra: do obliczania sprzęgów, na starcie nie są przesunięte - loc.X=-Object->vPosition.x; - loc.Y=Object->vPosition.z; - loc.Z=Object->vPosition.y; - Object->MoverParameters->Loc=loc; //ustawienie dodawanego pojazdu - */ - MoverParameters->Attach(iDirection,Object->iDirection^1,Object->MoverParameters,iType,true); - MoverParameters->Couplers[iDirection].Render=false; - Object->MoverParameters->Attach(Object->iDirection^1,iDirection,MoverParameters,iType,true); - Object->MoverParameters->Couplers[Object->iDirection^1].Render=true; //rysowanie sprzęgu w dołączanym - if (iDirection) - {//łączenie standardowe - NextConnected=Object; //normalnie doczepiamy go sobie do sprzęgu 1 - NextConnectedNo=Object->iDirection^1; - } - else - {//łączenie odwrotne - PrevConnected=Object; //doczepiamy go sobie do sprzęgu 0, gdy stoimy odwrotnie - PrevConnectedNo=Object->iDirection^1; - } - if (Object->iDirection) - {//dołączany jest normalnie ustawiany - Object->PrevConnected=this; //on ma nas z przodu - Object->PrevConnectedNo=iDirection; - } - else - {//dołączany jest odwrotnie ustawiany - Object->NextConnected=this; //on ma nas z tyłu - Object->NextConnectedNo=iDirection; - } - if (MoverParameters->TrainType&dt_EZT) //w przypadku łączenia członów, światła w rozrządczym zależą od stanu w silnikowym - if (MoverParameters->Couplers[iDirection].AllowedFlag&ctrain_depot) //gdy sprzęgi łączone warsztatowo (powiedzmy) - if ((MoverParameters->Power<1.0)&&(Object->MoverParameters->Power>1.0)) //my nie mamy mocy, ale ten drugi ma - iLights=Object->MoverParameters->iLights; //to w tym z mocą będą światła załączane, a w tym bez tylko widoczne - else if ((MoverParameters->Power>1.0)&&(Object->MoverParameters->Power<1.0)) //my mamy moc, ale ten drugi nie ma - Object->iLights=MoverParameters->iLights; //to w tym z mocą będą światła załączane, a w tym bez tylko widoczne - return; - //SetPneumatic(1,1); //Ra: to i tak się nie wykonywało po return - //SetPneumatic(1,0); - //SetPneumatic(0,1); - //SetPneumatic(0,0); +{ // Ra: doczepia Object na końcu składu (nazwa funkcji może być myląca) + // Ra: używane tylko przy wczytywaniu scenerii + /* + //Ra: po wstawieniu pojazdu do scenerii nie miał on ustawionej pozycji, teraz już ma + TLocation loc; + loc.X=-vPosition.x; + loc.Y=vPosition.z; + loc.Z=vPosition.y; + MoverParameters->Loc=loc; //Ra: do obliczania sprzęgów, na starcie nie są przesunięte + loc.X=-Object->vPosition.x; + loc.Y=Object->vPosition.z; + loc.Z=Object->vPosition.y; + Object->MoverParameters->Loc=loc; //ustawienie dodawanego pojazdu + */ + MoverParameters->Attach(iDirection, Object->iDirection ^ 1, Object->MoverParameters, iType, + true); + MoverParameters->Couplers[iDirection].Render = false; + Object->MoverParameters->Attach(Object->iDirection ^ 1, iDirection, MoverParameters, iType, + true); + Object->MoverParameters->Couplers[Object->iDirection ^ 1].Render = + true; // rysowanie sprzęgu w dołączanym + if (iDirection) + { //łączenie standardowe + NextConnected = Object; // normalnie doczepiamy go sobie do sprzęgu 1 + NextConnectedNo = Object->iDirection ^ 1; + } + else + { //łączenie odwrotne + PrevConnected = Object; // doczepiamy go sobie do sprzęgu 0, gdy stoimy odwrotnie + PrevConnectedNo = Object->iDirection ^ 1; + } + if (Object->iDirection) + { // dołączany jest normalnie ustawiany + Object->PrevConnected = this; // on ma nas z przodu + Object->PrevConnectedNo = iDirection; + } + else + { // dołączany jest odwrotnie ustawiany + Object->NextConnected = this; // on ma nas z tyłu + Object->NextConnectedNo = iDirection; + } + if (MoverParameters->TrainType & + dt_EZT) // w przypadku łączenia członów, światła w rozrządczym zależą od stanu w silnikowym + if (MoverParameters->Couplers[iDirection].AllowedFlag & + ctrain_depot) // gdy sprzęgi łączone warsztatowo (powiedzmy) + if ((MoverParameters->Power < 1.0) && + (Object->MoverParameters->Power > 1.0)) // my nie mamy mocy, ale ten drugi ma + iLights = Object->MoverParameters->iLights; // to w tym z mocą będą światła + // załączane, a w tym bez tylko widoczne + else if ((MoverParameters->Power > 1.0) && + (Object->MoverParameters->Power < 1.0)) // my mamy moc, ale ten drugi nie ma + Object->iLights = MoverParameters->iLights; // to w tym z mocą będą światła + // załączane, a w tym bez tylko widoczne + return; + // SetPneumatic(1,1); //Ra: to i tak się nie wykonywało po return + // SetPneumatic(1,0); + // SetPneumatic(0,1); + // SetPneumatic(0,0); } bool __fastcall TDynamicObject::UpdateForce(double dt, double dt1, bool FullVer) { - if (!bEnabled) - return false; - if (dt>0) - MoverParameters->ComputeTotalForce(dt,dt1,FullVer); //wywalenie WS zależy od ustawienia kierunku - return true; + if (!bEnabled) + return false; + if (dt > 0) + MoverParameters->ComputeTotalForce(dt, dt1, + FullVer); // wywalenie WS zależy od ustawienia kierunku + return true; } void __fastcall TDynamicObject::LoadUpdate() -{//przeładowanie modelu ładunku - // Ra: nie próbujemy wczytywać modeli miliony razy podczas renderowania!!! - if ((mdLoad==NULL)&&(MoverParameters->Load>0)) - { - AnsiString asLoadName=asBaseDir+MoverParameters->LoadType+".t3d"; //zapamiętany katalog pojazdu - //asLoadName=MoverParameters->LoadType; - //if (MoverParameters->LoadType!=AnsiString("passengers")) - Global::asCurrentTexturePath=asBaseDir; //bieżąca ścieżka do tekstur to dynamic/... - mdLoad=TModelsManager::GetModel(asLoadName.c_str()); //nowy ładunek - Global::asCurrentTexturePath=AnsiString(szTexturePath); //z powrotem defaultowa sciezka do tekstur - //Ra: w MMD można by zapisać położenie modelu ładunku (np. węgiel) w zależności od załadowania - } - else if (MoverParameters->Load==0) - mdLoad=NULL; //nie ma ładunku - //if ((mdLoad==NULL)&&(MoverParameters->Load>0)) - // { - // mdLoad=NULL; //Ra: to jest tu bez sensu - co autor miał na myśli? - // } - MoverParameters->LoadStatus&=3; //po zakończeniu będzie równe zero +{ // przeładowanie modelu ładunku + // Ra: nie próbujemy wczytywać modeli miliony razy podczas renderowania!!! + if ((mdLoad == NULL) && (MoverParameters->Load > 0)) + { + AnsiString asLoadName = + asBaseDir + MoverParameters->LoadType + ".t3d"; // zapamiętany katalog pojazdu + // asLoadName=MoverParameters->LoadType; + // if (MoverParameters->LoadType!=AnsiString("passengers")) + Global::asCurrentTexturePath = asBaseDir; // bieżąca ścieżka do tekstur to dynamic/... + mdLoad = TModelsManager::GetModel(asLoadName.c_str()); // nowy ładunek + Global::asCurrentTexturePath = + AnsiString(szTexturePath); // z powrotem defaultowa sciezka do tekstur + // Ra: w MMD można by zapisać położenie modelu ładunku (np. węgiel) w zależności od + // załadowania + } + else if (MoverParameters->Load == 0) + mdLoad = NULL; // nie ma ładunku + // if ((mdLoad==NULL)&&(MoverParameters->Load>0)) + // { + // mdLoad=NULL; //Ra: to jest tu bez sensu - co autor miał na myśli? + // } + MoverParameters->LoadStatus &= 3; // po zakończeniu będzie równe zero }; /* @@ -1916,31 +2229,31 @@ double __fastcall ComputeRadius(double p1x, double p1z, double p2x, double p2z, */ double __fastcall TDynamicObject::ComputeRadius(vector3 p1, vector3 p2, vector3 p3, vector3 p4) { -// vector3 v1 + // vector3 v1 -// TLine l1= TLine(p1,p1-p2); -// TLine l4= TLine(p4,p4-p3); -// TPlane p1= l1.GetPlane(); -// vector3 pt; -// CrossPoint(pt,l4,p1); - double R= 0.0; - vector3 p12= p1-p2; - vector3 p34= p3-p4; - p12= CrossProduct(p12,vector3(0.0,0.1,0.0)); - p12=Normalize(p12); - p34= CrossProduct(p34,vector3(0.0,0.1,0.0)); - p34=Normalize(p34); - if (fabs(p1.x-p2.x)>0.01) - { - if (fabs(p12.x-p34.x)>0.001) - R=(p1.x-p4.x)/(p34.x-p12.x); - } - else - { - if (fabs(p12.z-p34.z)>0.001) - R=(p1.z-p4.z)/(p34.z-p12.z); - } - return(R); + // TLine l1= TLine(p1,p1-p2); + // TLine l4= TLine(p4,p4-p3); + // TPlane p1= l1.GetPlane(); + // vector3 pt; + // CrossPoint(pt,l4,p1); + double R = 0.0; + vector3 p12 = p1 - p2; + vector3 p34 = p3 - p4; + p12 = CrossProduct(p12, vector3(0.0, 0.1, 0.0)); + p12 = Normalize(p12); + p34 = CrossProduct(p34, vector3(0.0, 0.1, 0.0)); + p34 = Normalize(p34); + if (fabs(p1.x - p2.x) > 0.01) + { + if (fabs(p12.x - p34.x) > 0.001) + R = (p1.x - p4.x) / (p34.x - p12.x); + } + else + { + if (fabs(p12.z - p34.z) > 0.001) + R = (p1.z - p4.z) / (p34.z - p12.z); + } + return (R); } /* @@ -1986,2373 +2299,2776 @@ na sprz histerezę czasową, aby te tryby pracy nie przełączały się zbyt szybko. */ - bool __fastcall TDynamicObject::Update(double dt, double dt1) { - if (dt==0) return true; //Ra: pauza - if (!MoverParameters->PhysicActivation&&!MechInside) //to drugie, bo będąc w maszynowym blokuje się fizyka - return true; //McZapkie: wylaczanie fizyki gdy nie potrzeba - if (!MyTrack) - return false; //pojazdy postawione na torach portalowych mają MyTrack==NULL - if (!bEnabled) - return false; //a normalnie powinny mieć bEnabled==false + if (dt == 0) + return true; // Ra: pauza + if (!MoverParameters->PhysicActivation && + !MechInside) // to drugie, bo będąc w maszynowym blokuje się fizyka + return true; // McZapkie: wylaczanie fizyki gdy nie potrzeba + if (!MyTrack) + return false; // pojazdy postawione na torach portalowych mają MyTrack==NULL + if (!bEnabled) + return false; // a normalnie powinny mieć bEnabled==false -//Ra: przeniosłem - no już lepiej tu, niż w wyświetlaniu! -//if ((MoverParameters->ConverterFlag==false) && (MoverParameters->TrainType!=dt_ET22)) -//Ra: to nie może tu być, bo wyłącza sprężarkę w rozrządczym EZT! -//if ((MoverParameters->ConverterFlag==false)&&(MoverParameters->CompressorPower!=0)) -// MoverParameters->CompressorFlag=false; -//if (MoverParameters->CompressorPower==2) -// MoverParameters->CompressorAllow=MoverParameters->ConverterFlag; + // Ra: przeniosłem - no już lepiej tu, niż w wyświetlaniu! + // if ((MoverParameters->ConverterFlag==false) && (MoverParameters->TrainType!=dt_ET22)) + // Ra: to nie może tu być, bo wyłącza sprężarkę w rozrządczym EZT! + // if ((MoverParameters->ConverterFlag==false)&&(MoverParameters->CompressorPower!=0)) + // MoverParameters->CompressorFlag=false; + // if (MoverParameters->CompressorPower==2) + // MoverParameters->CompressorAllow=MoverParameters->ConverterFlag; - //McZapkie-260202 - if ((MoverParameters->EnginePowerSource.SourceType==CurrentCollector)&&(MoverParameters->Power>1.0)) //aby rozrządczy nie opuszczał silnikowemu - if ((MechInside)||(MoverParameters->TrainType==dt_EZT)) - { - //if ((!MoverParameters->PantCompFlag)&&(MoverParameters->CompressedVolume>=2.8)) - // MoverParameters->PantVolume=MoverParameters->CompressedVolume; - if (MoverParameters->PantPress<(MoverParameters->TrainType==dt_EZT?2.4:3.5)) - {// 3.5 wg http://www.transportszynowy.pl/eu06-07pneumat.php - //"Wyłączniki ciśnieniowe odbieraków prądu wyłączają sterowanie wyłącznika szybkiego oraz uniemożliwiają podniesienie odbieraków prądu, gdy w instalacji rozrządu ciśnienie spadnie poniżej wartości 3,5 bara." - //Ra 2013-12: Niebugocław mówi, że w EZT podnoszą się przy 2.5 - //if (!MoverParameters->PantCompFlag) - // MoverParameters->PantVolume=MoverParameters->CompressedVolume; - MoverParameters->PantFront(false); //opuszczenie pantografów przy niskim ciśnieniu - MoverParameters->PantRear(false); //to idzie w ukrotnieniu, a nie powinno... - } - //Winger - automatyczne wylaczanie malej sprezarki - else if (MoverParameters->PantPress>=4.8) - MoverParameters->PantCompFlag=false; - } //Ra: do Mover to trzeba przenieść, żeby AI też mogło sobie podpompować + // McZapkie-260202 + if ((MoverParameters->EnginePowerSource.SourceType == CurrentCollector) && + (MoverParameters->Power > 1.0)) // aby rozrządczy nie opuszczał silnikowemu + if ((MechInside) || (MoverParameters->TrainType == dt_EZT)) + { + // if ((!MoverParameters->PantCompFlag)&&(MoverParameters->CompressedVolume>=2.8)) + // MoverParameters->PantVolume=MoverParameters->CompressedVolume; + if (MoverParameters->PantPress < (MoverParameters->TrainType == dt_EZT ? 2.4 : 3.5)) + { // 3.5 wg http://www.transportszynowy.pl/eu06-07pneumat.php + //"Wyłączniki ciśnieniowe odbieraków prądu wyłączają sterowanie wyłącznika szybkiego + //oraz uniemożliwiają podniesienie odbieraków prądu, gdy w instalacji rozrządu + //ciśnienie spadnie poniżej wartości 3,5 bara." + // Ra 2013-12: Niebugocław mówi, że w EZT podnoszą się przy 2.5 + // if (!MoverParameters->PantCompFlag) + // MoverParameters->PantVolume=MoverParameters->CompressedVolume; + MoverParameters->PantFront(false); // opuszczenie pantografów przy niskim ciśnieniu + MoverParameters->PantRear(false); // to idzie w ukrotnieniu, a nie powinno... + } + // Winger - automatyczne wylaczanie malej sprezarki + else if (MoverParameters->PantPress >= 4.8) + MoverParameters->PantCompFlag = false; + } // Ra: do Mover to trzeba przenieść, żeby AI też mogło sobie podpompować double dDOMoveLen; TLocation l; - l.X=-vPosition.x; //przekazanie pozycji do fizyki - l.Y=vPosition.z; - l.Z=vPosition.y; + l.X = -vPosition.x; // przekazanie pozycji do fizyki + l.Y = vPosition.z; + l.Z = vPosition.y; TRotation r; - r.Rx=r.Ry=r.Rz=0; -//McZapkie: parametry powinny byc pobierane z toru + r.Rx = r.Ry = r.Rz = 0; + // McZapkie: parametry powinny byc pobierane z toru - //TTrackShape ts; - //ts.R=MyTrack->fRadius; - //if (ABuGetDirection()<0) ts.R=-ts.R; -// ts.R=MyTrack->fRadius; //ujemne promienie są już zamienione przy wczytywaniu - if (Axle0.vAngles.z!=Axle1.vAngles.z) - {//wyliczenie promienia z obrotów osi - modyfikację zgłosił youBy - ts.R=Axle0.vAngles.z-Axle1.vAngles.z; //różnica może dawać stałą ±M_2PI - if (ts.R>M_PI) ts.R-=M_2PI else if (ts.R<-M_PI) ts.R+=M_2PI; //normalizacja -// ts.R=fabs(0.5*MoverParameters->BDist/sin(ts.R*0.5)); - ts.R=-0.5*MoverParameters->BDist/sin(ts.R*0.5); - if ((ts.R>15000.0)||(ts.R<-15000.0)) ts.R=0.0; //szkoda czasu na zbyt duże promienie, 4km to promień nie wymagający przechyłki + // TTrackShape ts; + // ts.R=MyTrack->fRadius; + // if (ABuGetDirection()<0) ts.R=-ts.R; + // ts.R=MyTrack->fRadius; //ujemne promienie są już zamienione przy wczytywaniu + if (Axle0.vAngles.z != Axle1.vAngles.z) + { // wyliczenie promienia z obrotów osi - modyfikację zgłosił youBy + ts.R = Axle0.vAngles.z - Axle1.vAngles.z; // różnica może dawać stałą ±M_2PI + if (ts.R > M_PI) + ts.R -= M_2PI else if (ts.R < -M_PI) ts.R += M_2PI; // normalizacja + // ts.R=fabs(0.5*MoverParameters->BDist/sin(ts.R*0.5)); + ts.R = -0.5 * MoverParameters->BDist / sin(ts.R * 0.5); + if ((ts.R > 15000.0) || (ts.R < -15000.0)) + ts.R = 0.0; // szkoda czasu na zbyt duże promienie, 4km to promień nie wymagający + // przechyłki } - else ts.R=0.0; - //ts.R=ComputeRadius(Axle1.pPosition,Axle2.pPosition,Axle3.pPosition,Axle0.pPosition); - //Ra: składową pochylenia wzdłużnego mamy policzoną w jednostkowym wektorze vFront - ts.Len=1.0; //Max0R(MoverParameters->BDist,MoverParameters->ADist); - ts.dHtrack=-vFront.y; //Axle1.pPosition.y-Axle0.pPosition.y; //wektor między skrajnymi osiami (!!!odwrotny) - ts.dHrail=(Axle1.GetRoll()+Axle0.GetRoll())*0.5; //średnia przechyłka pudła - //TTrackParam tp; - tp.Width=MyTrack->fTrackWidth; -//McZapkie-250202 - tp.friction=MyTrack->fFriction*Global::fFriction; - tp.CategoryFlag=MyTrack->iCategoryFlag&15; - tp.DamageFlag=MyTrack->iDamageFlag; - tp.QualityFlag=MyTrack->iQualityFlag; - if ((MoverParameters->Couplers[0].CouplingFlag>0) - &&(MoverParameters->Couplers[1].CouplingFlag>0)) + else + ts.R = 0.0; + // ts.R=ComputeRadius(Axle1.pPosition,Axle2.pPosition,Axle3.pPosition,Axle0.pPosition); + // Ra: składową pochylenia wzdłużnego mamy policzoną w jednostkowym wektorze vFront + ts.Len = 1.0; // Max0R(MoverParameters->BDist,MoverParameters->ADist); + ts.dHtrack = -vFront.y; // Axle1.pPosition.y-Axle0.pPosition.y; //wektor między skrajnymi osiami + // (!!!odwrotny) + ts.dHrail = (Axle1.GetRoll() + Axle0.GetRoll()) * 0.5; //średnia przechyłka pudła + // TTrackParam tp; + tp.Width = MyTrack->fTrackWidth; + // McZapkie-250202 + tp.friction = MyTrack->fFriction * Global::fFriction; + tp.CategoryFlag = MyTrack->iCategoryFlag & 15; + tp.DamageFlag = MyTrack->iDamageFlag; + tp.QualityFlag = MyTrack->iQualityFlag; + if ((MoverParameters->Couplers[0].CouplingFlag > 0) && + (MoverParameters->Couplers[1].CouplingFlag > 0)) { - MoverParameters->InsideConsist=true; + MoverParameters->InsideConsist = true; } else { - MoverParameters->InsideConsist=false; + MoverParameters->InsideConsist = false; } - //napiecie sieci trakcyjnej - //Ra 15-01: przeliczenie poboru prądu powinno być robione wcześniej, żeby na tym etapie były znane napięcia - //TTractionParam tmpTraction; - //tmpTraction.TractionVoltage=0; - if (MoverParameters->EnginePowerSource.SourceType==CurrentCollector) - {//dla EZT tylko silnikowy - //if (Global::bLiveTraction) - {//Ra 2013-12: to niżej jest chyba trochę bez sensu - double v=MoverParameters->PantRearVolt; - if (v==0.0) - {v=MoverParameters->PantFrontVolt; - if (v==0.0) - if (MoverParameters->TrainType&(dt_EZT|dt_ET40|dt_ET41|dt_ET42)) //dwuczłony mogą mieć sprzęg WN - v=MoverParameters->GetTrainsetVoltage(); //ostatnia szansa - } - if (v!=0.0) - {//jeśli jest zasilanie - NoVoltTime=0; - tmpTraction.TractionVoltage=v; - } - else - { -/* - if (MoverParameters->Vel>0.1f) //jeśli jedzie - if (NoVoltTime==0.0) //tylko przy pierwszym zaniku napięcia - if (MoverParameters->PantFrontUp||MoverParameters->PantRearUp) - //if ((pants[0].fParamPants->PantTraction>1.0)||(pants[1].fParamPants->PantTraction>1.0)) - {//wspomagacz usuwania problemów z siecią - if (!Global::iPause) - {//Ra: tymczasowa teleportacja do miejsca, gdzie brakuje prądu - Global::SetCameraPosition(vPosition+vector3(0,0,5)); //nowa pozycja dla generowania obiektów - Global::pCamera->Init(vPosition+vector3(0,0,5),Global::pFreeCameraInitAngle[0]); //przestawienie - } - Global:l::pGround->Silence(Global::pCamera->Pos); //wyciszenie wszystkiego z poprzedniej pozycji - Globa:iPause|=1; //tymczasowe zapauzowanie, gdy problem z siecią + // napiecie sieci trakcyjnej + // Ra 15-01: przeliczenie poboru prądu powinno być robione wcześniej, żeby na tym etapie były + // znane napięcia + // TTractionParam tmpTraction; + // tmpTraction.TractionVoltage=0; + if (MoverParameters->EnginePowerSource.SourceType == CurrentCollector) + { // dla EZT tylko silnikowy + // if (Global::bLiveTraction) + { // Ra 2013-12: to niżej jest chyba trochę bez sensu + double v = MoverParameters->PantRearVolt; + if (v == 0.0) + { + v = MoverParameters->PantFrontVolt; + if (v == 0.0) + if (MoverParameters->TrainType & + (dt_EZT | dt_ET40 | dt_ET41 | dt_ET42)) // dwuczłony mogą mieć sprzęg WN + v = MoverParameters->GetTrainsetVoltage(); // ostatnia szansa + } + if (v != 0.0) + { // jeśli jest zasilanie + NoVoltTime = 0; + tmpTraction.TractionVoltage = v; + } + else + { + /* + if (MoverParameters->Vel>0.1f) //jeśli jedzie + if (NoVoltTime==0.0) //tylko przy pierwszym zaniku napięcia + if (MoverParameters->PantFrontUp||MoverParameters->PantRearUp) + //if + ((pants[0].fParamPants->PantTraction>1.0)||(pants[1].fParamPants->PantTraction>1.0)) + {//wspomagacz usuwania problemów z siecią + if (!Global::iPause) + {//Ra: tymczasowa teleportacja do miejsca, gdzie brakuje prądu + Global::SetCameraPosition(vPosition+vector3(0,0,5)); //nowa pozycja dla + generowania obiektów + Global::pCamera->Init(vPosition+vector3(0,0,5),Global::pFreeCameraInitAngle[0]); + //przestawienie + } + Global:l::pGround->Silence(Global::pCamera->Pos); //wyciszenie wszystkiego + z poprzedniej pozycji + Globa:iPause|=1; //tymczasowe zapauzowanie, gdy problem z siecią + } + */ + NoVoltTime = NoVoltTime + dt; + if (NoVoltTime > 0.2) // jeśli brak zasilania dłużej niż 0.2 sekundy (25km/h pod + // izolatorem daje 0.15s) + { // Ra 2F1H: prowizorka, trzeba przechować napięcie, żeby nie wywalało WS pod + // izolatorem + if (MoverParameters->Vel > 0.5) // jeśli jedzie + if (MoverParameters->PantFrontUp || + MoverParameters->PantRearUp) // Ra 2014-07: doraźna blokada logowania + // zimnych lokomotyw - zrobić to trzeba + // inaczej + // if (NoVoltTime>0.02) //tu można ograniczyć czas rozłączenia + // if (DebugModeFlag) //logowanie nie zawsze + if (MoverParameters->Mains) + { // Ra 15-01: logować tylko, jeśli WS załączony + // if (MoverParameters->PantFrontUp&&pants) + // Ra 15-01: bezwzględne współrzędne pantografu nie są dostępne, + // więc lepiej się tego nie zaloguje + ErrorLog("Voltage loss: by " + MoverParameters->Name + " at " + + FloatToStrF(vPosition.x, ffFixed, 7, 2) + " " + + FloatToStrF(vPosition.y, ffFixed, 7, 2) + " " + + FloatToStrF(vPosition.z, ffFixed, 7, 2) + ", time " + + FloatToStrF(NoVoltTime, ffFixed, 7, 2)); + // if (MoverParameters->PantRearUp) + // if (iAnimType[ANIM_PANTS]>1) + // if (pants[1]) + // ErrorLog("Voltage loss: by "+MoverParameters->Name+" at + // "+FloatToStrF(vPosition.x,ffFixed,7,2)+" + // "+FloatToStrF(vPosition.y,ffFixed,7,2)+" + // "+FloatToStrF(vPosition.z,ffFixed,7,2)+", time + // "+FloatToStrF(NoVoltTime,ffFixed,7,2)); + } + // Ra 2F1H: nie było sensu wpisywać tu zera po upływie czasu, bo zmienna była + // tymczasowa, a napięcie zerowane od razu + tmpTraction.TractionVoltage = 0; // Ra 2013-12: po co tak? + // pControlled->MainSwitch(false); //może tak? + } + } } -*/ - NoVoltTime=NoVoltTime+dt; - if (NoVoltTime>0.2) //jeśli brak zasilania dłużej niż 0.2 sekundy (25km/h pod izolatorem daje 0.15s) - {//Ra 2F1H: prowizorka, trzeba przechować napięcie, żeby nie wywalało WS pod izolatorem - if (MoverParameters->Vel>0.5) //jeśli jedzie - if (MoverParameters->PantFrontUp||MoverParameters->PantRearUp) //Ra 2014-07: doraźna blokada logowania zimnych lokomotyw - zrobić to trzeba inaczej - //if (NoVoltTime>0.02) //tu można ograniczyć czas rozłączenia - //if (DebugModeFlag) //logowanie nie zawsze - if (MoverParameters->Mains) - {//Ra 15-01: logować tylko, jeśli WS załączony - //if (MoverParameters->PantFrontUp&&pants) - //Ra 15-01: bezwzględne współrzędne pantografu nie są dostępne, więc lepiej się tego nie zaloguje - ErrorLog("Voltage loss: by "+MoverParameters->Name+" at "+FloatToStrF(vPosition.x,ffFixed,7,2)+" "+FloatToStrF(vPosition.y,ffFixed,7,2)+" "+FloatToStrF(vPosition.z,ffFixed,7,2)+", time "+FloatToStrF(NoVoltTime,ffFixed,7,2)); - //if (MoverParameters->PantRearUp) - // if (iAnimType[ANIM_PANTS]>1) - // if (pants[1]) - // ErrorLog("Voltage loss: by "+MoverParameters->Name+" at "+FloatToStrF(vPosition.x,ffFixed,7,2)+" "+FloatToStrF(vPosition.y,ffFixed,7,2)+" "+FloatToStrF(vPosition.z,ffFixed,7,2)+", time "+FloatToStrF(NoVoltTime,ffFixed,7,2)); - } - //Ra 2F1H: nie było sensu wpisywać tu zera po upływie czasu, bo zmienna była tymczasowa, a napięcie zerowane od razu - tmpTraction.TractionVoltage=0; //Ra 2013-12: po co tak? - //pControlled->MainSwitch(false); //może tak? - } - } + // else //Ra: nie no, trzeba podnieść pantografy, jak nie będzie drutu, to będą miały prąd + // po osiągnięciu 1.4m + // tmpTraction.TractionVoltage=0.95*MoverParameters->EnginePowerSource.MaxVoltage; } - //else //Ra: nie no, trzeba podnieść pantografy, jak nie będzie drutu, to będą miały prąd po osiągnięciu 1.4m - // tmpTraction.TractionVoltage=0.95*MoverParameters->EnginePowerSource.MaxVoltage; - } - else - tmpTraction.TractionVoltage=0.95*MoverParameters->EnginePowerSource.MaxVoltage; - tmpTraction.TractionFreq=0; - tmpTraction.TractionMaxCurrent=7500; //Ra: chyba za dużo? powinno wywalać przy 1500 - tmpTraction.TractionResistivity=0.3; + else + tmpTraction.TractionVoltage = 0.95 * MoverParameters->EnginePowerSource.MaxVoltage; + tmpTraction.TractionFreq = 0; + tmpTraction.TractionMaxCurrent = 7500; // Ra: chyba za dużo? powinno wywalać przy 1500 + tmpTraction.TractionResistivity = 0.3; -//McZapkie: predkosc w torze przekazac do TrackParam -//McZapkie: Vel ma wymiar [km/h] (absolutny), V ma wymiar [m/s], taka przyjalem notacje - tp.Velmax=MyTrack->VelocityGet(); + // McZapkie: predkosc w torze przekazac do TrackParam + // McZapkie: Vel ma wymiar [km/h] (absolutny), V ma wymiar [m/s], taka przyjalem notacje + tp.Velmax = MyTrack->VelocityGet(); if (Mechanik) - {//Ra 2F3F: do Driver.cpp to przenieść? - MoverParameters->EqvtPipePress=GetEPP(); //srednie cisnienie w PG - if ((Mechanik->Primary())&&(MoverParameters->EngineType==ElectricInductionMotor)) //jesli glowny i z asynchronami, to niech steruje - { //hamulcem lacznie dla calego pociagu/ezt - //1. ustal wymagana sile hamowania calego pociagu - // - opoznienie moze byc ustalane na podstawie charakterystyki - // - opoznienie moze byc ustalane na podstawie mas i cisnien granicznych - // + { // Ra 2F3F: do Driver.cpp to przenieść? + MoverParameters->EqvtPipePress = GetEPP(); // srednie cisnienie w PG + if ((Mechanik->Primary()) && + (MoverParameters->EngineType == + ElectricInductionMotor)) // jesli glowny i z asynchronami, to niech steruje + { // hamulcem lacznie dla calego pociagu/ezt + // 1. ustal wymagana sile hamowania calego pociagu + // - opoznienie moze byc ustalane na podstawie charakterystyki + // - opoznienie moze byc ustalane na podstawie mas i cisnien granicznych + // - //2. ustal mozliwa do realizacji sile hamowania ED - // - w szczegolnosci powinien brac pod uwage rozne sily hamowania - float FED=0; -// for(TDynamicObject *p=GetFirstDynamic(4);p;p->NextC(4)) -// FED+=p->MoverParameters->eimv[eimv_Fmax]; - //3. ustaw pojazdom sile hamowania ED - // - proporcjonalnie do mozliwosci + // 2. ustal mozliwa do realizacji sile hamowania ED + // - w szczegolnosci powinien brac pod uwage rozne sily hamowania + float FED = 0; + // for(TDynamicObject *p=GetFirstDynamic(4);p;p->NextC(4)) + // FED+=p->MoverParameters->eimv[eimv_Fmax]; + // 3. ustaw pojazdom sile hamowania ED + // - proporcjonalnie do mozliwosci - //4. ustal potrzebne dohamowanie pneumatyczne - // - od sily zadanej trzeba odjac realizowana przez ED - //5. w razie potrzeby wlacz hamulec utrzymujacy - // - gdy zahamowany ma ponizej 2 km/h - //6. ustaw pojazdom sile hamowania ep - // - proporcjonalnie do masy, do liczby osi, rowne cisnienia - jak bedzie, tak bedzie dobrze - } - -//yB: cos (AI) tu jest nie kompatybilne z czyms (hamulce) -// if (Controller!=Humandriver) -// if (Mechanik->LastReactionTime>0.5) -// { -// MoverParameters->BrakeCtrlPos=0; -// Mechanik->LastReactionTime=0; -// } - - Mechanik->UpdateSituation(dt1); //przebłyski świadomości AI - } - - //fragment "z EXE Kursa" - if (MoverParameters->Mains) //nie wchodzić w funkcję bez potrzeby - if ((!MoverParameters->Battery)&&(Controller==Humandriver)&&(MoverParameters->EngineType!=DieselEngine)&&(MoverParameters->EngineType!=WheelsDriven)) - {//jeśli bateria wyłączona, a nie diesel ani drezyna reczna - if (MoverParameters->MainSwitch(false)) //wyłączyć zasilanie - MoverParameters->EventFlag=true; - } - if (MoverParameters->TrainType==dt_ET42) - {//powinny być wszystkie dwuczłony oraz EZT -/* - //Ra: to jest bez sensu, bo wyłącza WS przy przechodzeniu przez "wewnętrzne" kabiny (z powodu ActiveCab) - //trzeba to zrobić inaczej, np. dla członu A sprawdzać, czy jest B - //albo sprawdzać w momencie załączania WS i zmiany w sprzęgach - if (((TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab>0)&&(NextConnected->MoverParameters->TrainType!=dt_ET42))||((TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab<0)&&(PrevConnected->MoverParameters->TrainType!=dt_ET42))) - {//sprawdzenie, czy z tyłu kabiny mamy drugi człon - if (MoverParameters->MainSwitch(false)) - MoverParameters->EventFlag=true; - } - if ((!(TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab>0))||(!(TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab<0))) - { - if (MoverParameters->MainSwitch(false)) - MoverParameters->EventFlag=true; - } -*/ - } - - -//McZapkie-260202 - dMoveLen przyda sie przy stukocie kol - dDOMoveLen=GetdMoveLen()+MoverParameters->ComputeMovement(dt,dt1,ts,tp,tmpTraction,l,r); - //yB: zeby zawsze wrzucalo w jedna strone zakretu - MoverParameters->AccN*=-ABuGetDirection(); - //if (dDOMoveLen!=0.0) //Ra: nie może być, bo blokuje Event0 - Move(dDOMoveLen); - if (!bEnabled) //usuwane pojazdy nie mają toru - {//pojazd do usunięcia - Global::pGround->bDynamicRemove=true; //sprawdzić - return false; - } - Global::ABuDebug=dDOMoveLen/dt1; - ResetdMoveLen(); -//McZapkie-260202 -//tupot mew, tfu, stukot kol: - DWORD stat; -//taka prowizorka zeby sciszyc stukot dalekiej lokomotywy - double ObjectDist; - double vol=0; - //double freq; //Ra: nie używane - ObjectDist=SquareMagnitude(Global::pCameraPosition-vPosition); -//McZapkie-270202 - if (MyTrack->fSoundDistance!=-1) - { - if (ObjectDistiDamageFlag)/21; - if (MyTrack->eEnvironment==e_tunnel) - { - vol*=1.1; - //freq=1.02; - } - else - if (MyTrack->eEnvironment==e_bridge) - { - vol*=1.2; - //freq=0.99; //MC: stukot w zaleznosci od tego gdzie jest tor - } - if (MyTrack->fSoundDistance!=dRailLength) - { - dRailLength=MyTrack->fSoundDistance; - for (int i=0; iDim.L; - } - } - if (dRailLength!=-1) - { - if (abs(MoverParameters->V)>0) - { - for (int i=0; iAccV+= 0.5*GetVelocity()/(1+MoverParameters->Vmax); - } - else - {rsStukot[i+1].Stop();} - rsStukot[i].Play(vol,0,MechInside,vPosition); //poprawic pozycje o uklad osi - if (i==1) - MoverParameters->AccV-= 0.5*GetVelocity()/(1+MoverParameters->Vmax); - dRailPosition[i]+=dRailLength; - } - } - } + // 4. ustal potrzebne dohamowanie pneumatyczne + // - od sily zadanej trzeba odjac realizowana przez ED + // 5. w razie potrzeby wlacz hamulec utrzymujacy + // - gdy zahamowany ma ponizej 2 km/h + // 6. ustaw pojazdom sile hamowania ep + // - proporcjonalnie do masy, do liczby osi, rowne cisnienia - jak bedzie, tak bedzie + // dobrze } - } - } -//McZapkie-260202 end -//yB: przyspieszacz (moze zadziala, ale dzwiek juz jest) -int flag=MoverParameters->Hamulec->GetSoundFlag(); -if ((bBrakeAcc)&&(TestFlag(flag,sf_Acc))&&(ObjectDist<2500)) - { - sBrakeAcc->SetVolume(-ObjectDist*3-(FreeFlyModeFlag?0:2000)); - sBrakeAcc->Play(0,0,0); - sBrakeAcc->SetPan(10000*sin(ModCamRot)); - } -if ((rsUnbrake.AM!=0)&&(ObjectDist<5000)) - { - if ((TestFlag(flag,sf_CylU)) && ((MoverParameters->BrakePress*MoverParameters->MaxBrakePress[3])>0.05)) + // yB: cos (AI) tu jest nie kompatybilne z czyms (hamulce) + // if (Controller!=Humandriver) + // if (Mechanik->LastReactionTime>0.5) + // { + // MoverParameters->BrakeCtrlPos=0; + // Mechanik->LastReactionTime=0; + // } + + Mechanik->UpdateSituation(dt1); // przebłyski świadomości AI + } + + // fragment "z EXE Kursa" + if (MoverParameters->Mains) // nie wchodzić w funkcję bez potrzeby + if ((!MoverParameters->Battery) && (Controller == Humandriver) && + (MoverParameters->EngineType != DieselEngine) && + (MoverParameters->EngineType != WheelsDriven)) + { // jeśli bateria wyłączona, a nie diesel ani drezyna reczna + if (MoverParameters->MainSwitch(false)) // wyłączyć zasilanie + MoverParameters->EventFlag = true; + } + if (MoverParameters->TrainType == dt_ET42) + { // powinny być wszystkie dwuczłony oraz EZT + /* + //Ra: to jest bez sensu, bo wyłącza WS przy przechodzeniu przez "wewnętrzne" kabiny (z + powodu ActiveCab) + //trzeba to zrobić inaczej, np. dla członu A sprawdzać, czy jest B + //albo sprawdzać w momencie załączania WS i zmiany w sprzęgach + if + (((TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab>0)&&(NextConnected->MoverParameters->TrainType!=dt_ET42))||((TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab<0)&&(PrevConnected->MoverParameters->TrainType!=dt_ET42))) + {//sprawdzenie, czy z tyłu kabiny mamy drugi człon + if (MoverParameters->MainSwitch(false)) + MoverParameters->EventFlag=true; + } + if + ((!(TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab>0))||(!(TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab<0))) + { + if (MoverParameters->MainSwitch(false)) + MoverParameters->EventFlag=true; + } + */ + } + + // McZapkie-260202 - dMoveLen przyda sie przy stukocie kol + dDOMoveLen = + GetdMoveLen() + MoverParameters->ComputeMovement(dt, dt1, ts, tp, tmpTraction, l, r); + // yB: zeby zawsze wrzucalo w jedna strone zakretu + MoverParameters->AccN *= -ABuGetDirection(); + // if (dDOMoveLen!=0.0) //Ra: nie może być, bo blokuje Event0 + Move(dDOMoveLen); + if (!bEnabled) // usuwane pojazdy nie mają toru + { // pojazd do usunięcia + Global::pGround->bDynamicRemove = true; // sprawdzić + return false; + } + Global::ABuDebug = dDOMoveLen / dt1; + ResetdMoveLen(); + // McZapkie-260202 + // tupot mew, tfu, stukot kol: + DWORD stat; + // taka prowizorka zeby sciszyc stukot dalekiej lokomotywy + double ObjectDist; + double vol = 0; + // double freq; //Ra: nie używane + ObjectDist = SquareMagnitude(Global::pCameraPosition - vPosition); + // McZapkie-270202 + if (MyTrack->fSoundDistance != -1) { - vol=Min0R(0.2+1.6*sqrt((MoverParameters->BrakePress>0?MoverParameters->BrakePress:0)/MoverParameters->MaxBrakePress[3]),1); - vol=vol+(FreeFlyModeFlag?0:-0.5)-ObjectDist/5000; - rsUnbrake.SetPan(10000*sin(ModCamRot)); - rsUnbrake.Play(vol,DSBPLAY_LOOPING,MechInside,GetPosition()); - } - else - rsUnbrake.Stop(); - } - - - //fragment z EXE Kursa - /* if (MoverParameters->TrainType==dt_ET42) - { - if ((MoverParameters->DynamicBrakeType=dbrake_switch) && ((MoverParameters->BrakePress > 0.2) || ( MoverParameters->PipePress < 0.36 ))) - { - MoverParameters->StLinFlag=true; - } - else - if ((MoverParameters->DynamicBrakeType=dbrake_switch) && (MoverParameters->BrakePress < 0.1)) - { - MoverParameters->StLinFlag=false; - - } - } */ - if ((MoverParameters->TrainType==dt_ET40) || (MoverParameters->TrainType==dt_EP05)) - {//dla ET40 i EU05 automatyczne cofanie nastawnika - i tak nie będzie to działać dobrze... - /* if ((MoverParameters->MainCtrlPos>MoverParameters->MainCtrlActualPos)&&(abs(MoverParameters->Im)>MoverParameters->IminHi)) + if (ObjectDist < rsStukot[0].dSoundAtt * rsStukot[0].dSoundAtt * 15.0) { - MoverParameters->DecMainCtrl(1); - } */ - if (( !Console::Pressed(Global::Keys[k_IncMainCtrl]))&&(MoverParameters->MainCtrlPos>MoverParameters->MainCtrlActualPos)) - { - MoverParameters->DecMainCtrl(1); - } - if (( !Console::Pressed(Global::Keys[k_DecMainCtrl]))&&(MoverParameters->MainCtrlPosMainCtrlActualPos)) - { - MoverParameters->IncMainCtrl(1); //Ra 15-01: a to nie miało być tylko cofanie? - } + vol = (20.0 + MyTrack->iDamageFlag) / 21; + if (MyTrack->eEnvironment == e_tunnel) + { + vol *= 1.1; + // freq=1.02; + } + else if (MyTrack->eEnvironment == e_bridge) + { + vol *= 1.2; + // freq=0.99; //MC: stukot w zaleznosci od tego gdzie + // jest tor + } + if (MyTrack->fSoundDistance != dRailLength) + { + dRailLength = MyTrack->fSoundDistance; + for (int i = 0; i < iAxles; i++) + { + dRailPosition[i] = dWheelsPosition[i] + MoverParameters->Dim.L; + } + } + if (dRailLength != -1) + { + if (abs(MoverParameters->V) > 0) + { + for (int i = 0; i < iAxles; i++) + { + dRailPosition[i] -= dDOMoveLen * Sign(dDOMoveLen); + if (dRailPosition[i] < 0) + { + // McZapkie-040302 + if (i == iAxles - 1) + { + rsStukot[0].Stop(); + MoverParameters->AccV += + 0.5 * GetVelocity() / (1 + MoverParameters->Vmax); + } + else + { + rsStukot[i + 1].Stop(); + } + rsStukot[i].Play(vol, 0, MechInside, + vPosition); // poprawic pozycje o uklad osi + if (i == 1) + MoverParameters->AccV -= + 0.5 * GetVelocity() / (1 + MoverParameters->Vmax); + dRailPosition[i] += dRailLength; + } + } + } + } + } + } + // McZapkie-260202 end + + // yB: przyspieszacz (moze zadziala, ale dzwiek juz jest) + int flag = MoverParameters->Hamulec->GetSoundFlag(); + if ((bBrakeAcc) && (TestFlag(flag, sf_Acc)) && (ObjectDist < 2500)) + { + sBrakeAcc->SetVolume(-ObjectDist * 3 - (FreeFlyModeFlag ? 0 : 2000)); + sBrakeAcc->Play(0, 0, 0); + sBrakeAcc->SetPan(10000 * sin(ModCamRot)); + } + if ((rsUnbrake.AM != 0) && (ObjectDist < 5000)) + { + if ((TestFlag(flag, sf_CylU)) && + ((MoverParameters->BrakePress * MoverParameters->MaxBrakePress[3]) > 0.05)) + { + vol = Min0R( + 0.2 + + 1.6 * sqrt((MoverParameters->BrakePress > 0 ? MoverParameters->BrakePress : 0) / + MoverParameters->MaxBrakePress[3]), + 1); + vol = vol + (FreeFlyModeFlag ? 0 : -0.5) - ObjectDist / 5000; + rsUnbrake.SetPan(10000 * sin(ModCamRot)); + rsUnbrake.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition()); + } + else + rsUnbrake.Stop(); } + // fragment z EXE Kursa + /* if (MoverParameters->TrainType==dt_ET42) + { + if ((MoverParameters->DynamicBrakeType=dbrake_switch) && ((MoverParameters->BrakePress > + 0.2) || ( MoverParameters->PipePress < 0.36 ))) + { + MoverParameters->StLinFlag=true; + } + else + if ((MoverParameters->DynamicBrakeType=dbrake_switch) && (MoverParameters->BrakePress < + 0.1)) + { + MoverParameters->StLinFlag=false; + } + } */ + if ((MoverParameters->TrainType == dt_ET40) || (MoverParameters->TrainType == dt_EP05)) + { // dla ET40 i EU05 automatyczne cofanie nastawnika - i tak nie będzie to działać dobrze... + /* if + ((MoverParameters->MainCtrlPos>MoverParameters->MainCtrlActualPos)&&(abs(MoverParameters->Im)>MoverParameters->IminHi)) + { + MoverParameters->DecMainCtrl(1); + } */ + if ((!Console::Pressed(Global::Keys[k_IncMainCtrl])) && + (MoverParameters->MainCtrlPos > MoverParameters->MainCtrlActualPos)) + { + MoverParameters->DecMainCtrl(1); + } + if ((!Console::Pressed(Global::Keys[k_DecMainCtrl])) && + (MoverParameters->MainCtrlPos < MoverParameters->MainCtrlActualPos)) + { + MoverParameters->IncMainCtrl(1); // Ra 15-01: a to nie miało być tylko cofanie? + } + } - if (MoverParameters->Vel!=0) - {//McZapkie-050402: krecenie kolami: - dWheelAngle[0]+=114.59155902616464175359630962821*MoverParameters->V*dt1/MoverParameters->WheelDiameterL; //przednie toczne - dWheelAngle[1]+=MoverParameters->nrot*dt1*360.0; //napędne - dWheelAngle[2]+=114.59155902616464175359630962821*MoverParameters->V*dt1/MoverParameters->WheelDiameterT; //tylne toczne - if (dWheelAngle[0]>360.0) dWheelAngle[0]-=360.0; //a w drugą stronę jak się kręcą? - if (dWheelAngle[1]>360.0) dWheelAngle[1]-=360.0; - if (dWheelAngle[2]>360.0) dWheelAngle[2]-=360.0; - } - if (pants) //pantograf może być w wagonie kuchennym albo pojeździe rewizyjnym (np. SR61) - {//przeliczanie kątów dla pantografów - double k; //tymczasowy kąt - double PantDiff; - TAnimPant *p; //wskaźnik do obiektu danych pantografu - double fCurrent=(MoverParameters->DynamicBrakeFlag&&MoverParameters->ResistorsFlag?0:fabs(MoverParameters->Itot))+MoverParameters->TotalCurrent; //prąd pobierany przez pojazd - bez sensu z tym (TotalCurrent) - //fCurrent+=fabs(MoverParameters->Voltage)*1e-6; //prąd płynący przez woltomierz, rozładowuje kondensator orgromowy 4µF - double fPantCurrent=fCurrent; //normalnie cały prąd przez jeden pantograf - if (pants) - if (iAnimType[ANIM_PANTS]>1) //a jeśli są dwa pantografy //Ra 1014-11: proteza, trzeba zrobić sensowniej - if (pants[0].fParamPants->hvPowerWire&&pants[1].fParamPants->hvPowerWire) //i oba podłączone do drutów - fPantCurrent=fCurrent*0.5; //to dzielimy prąd równo na oba (trochę bez sensu, ale lepiej tak niż podwoić prąd) - for (int i=0;iPantWys<0) - {//patograf został połamany, liczony nie będzie - if (p->fAngleL>p->fAngleL0) - p->fAngleL-=0.2*dt1; //nieco szybciej niż jak dla opuszczania - if (p->fAngleLfAngleL0) - p->fAngleL=p->fAngleL0; //kąt graniczny - if (p->fAngleUfAngleU+=0.5*dt1; //górne się musi ruszać szybciej. - if (p->fAngleU>M_PI) - p->fAngleU=M_PI; - if (i&1) //zgłoszono, że po połamaniu potrafi zostać zasilanie - MoverParameters->PantRearVolt=0.0; + if (MoverParameters->Vel != 0) + { // McZapkie-050402: krecenie kolami: + dWheelAngle[0] += 114.59155902616464175359630962821 * MoverParameters->V * dt1 / + MoverParameters->WheelDiameterL; // przednie toczne + dWheelAngle[1] += MoverParameters->nrot * dt1 * 360.0; // napędne + dWheelAngle[2] += 114.59155902616464175359630962821 * MoverParameters->V * dt1 / + MoverParameters->WheelDiameterT; // tylne toczne + if (dWheelAngle[0] > 360.0) + dWheelAngle[0] -= 360.0; // a w drugą stronę jak się kręcą? + if (dWheelAngle[1] > 360.0) + dWheelAngle[1] -= 360.0; + if (dWheelAngle[2] > 360.0) + dWheelAngle[2] -= 360.0; + } + if (pants) // pantograf może być w wagonie kuchennym albo pojeździe rewizyjnym (np. SR61) + { // przeliczanie kątów dla pantografów + double k; // tymczasowy kąt + double PantDiff; + TAnimPant *p; // wskaźnik do obiektu danych pantografu + double fCurrent = + (MoverParameters->DynamicBrakeFlag && MoverParameters->ResistorsFlag ? + 0 : + fabs(MoverParameters->Itot)) + + MoverParameters + ->TotalCurrent; // prąd pobierany przez pojazd - bez sensu z tym (TotalCurrent) + // fCurrent+=fabs(MoverParameters->Voltage)*1e-6; //prąd płynący przez woltomierz, + // rozładowuje kondensator orgromowy 4µF + double fPantCurrent = fCurrent; // normalnie cały prąd przez jeden pantograf + if (pants) + if (iAnimType[ANIM_PANTS] > + 1) // a jeśli są dwa pantografy //Ra 1014-11: proteza, trzeba zrobić sensowniej + if (pants[0].fParamPants->hvPowerWire && + pants[1].fParamPants->hvPowerWire) // i oba podłączone do drutów + fPantCurrent = fCurrent * 0.5; // to dzielimy prąd równo na oba (trochę bez + // sensu, ale lepiej tak niż podwoić prąd) + for (int i = 0; i < iAnimType[ANIM_PANTS]; ++i) + { // pętla po wszystkich pantografach + p = pants[i].fParamPants; + if (p->PantWys < 0) + { // patograf został połamany, liczony nie będzie + if (p->fAngleL > p->fAngleL0) + p->fAngleL -= 0.2 * dt1; // nieco szybciej niż jak dla opuszczania + if (p->fAngleL < p->fAngleL0) + p->fAngleL = p->fAngleL0; // kąt graniczny + if (p->fAngleU < M_PI) + p->fAngleU += 0.5 * dt1; // górne się musi ruszać szybciej. + if (p->fAngleU > M_PI) + p->fAngleU = M_PI; + if (i & 1) // zgłoszono, że po połamaniu potrafi zostać zasilanie + MoverParameters->PantRearVolt = 0.0; + else + MoverParameters->PantFrontVolt = 0.0; + continue; // reszta wtedy nie jest wykonywana + } + PantDiff = p->PantTraction - p->PantWys; // docelowy-aktualny + switch (i) // numer pantografu + { // trzeba usunąć to rozróżnienie + case 0: + if (Global::bLiveTraction ? false : + !p->hvPowerWire) // jeśli nie ma drutu, może pooszukiwać + MoverParameters->PantFrontVolt = + (p->PantWys >= 1.2) ? 0.95 * MoverParameters->EnginePowerSource.MaxVoltage : + 0.0; + else if (MoverParameters->PantFrontUp ? (PantDiff < 0.01) : + false) // tolerancja niedolegania + { + if ((MoverParameters->PantFrontVolt == 0.0) && + (MoverParameters->PantRearVolt == 0.0)) + sPantUp.Play(vol, 0, MechInside, vPosition); + if (p->hvPowerWire) // TODO: wyliczyć trzeba prąd przypadający na pantograf i + // wstawić do GetVoltage() + { + MoverParameters->PantFrontVolt = + p->hvPowerWire->VoltageGet(MoverParameters->Voltage, fPantCurrent); + fCurrent -= fPantCurrent; // taki prąd płynie przez powyższy pantograf + } + else + MoverParameters->PantFrontVolt = 0.0; + } + else + MoverParameters->PantFrontVolt = 0.0; + break; + case 1: + if (Global::bLiveTraction ? false : + !p->hvPowerWire) // jeśli nie ma drutu, może pooszukiwać + MoverParameters->PantRearVolt = + (p->PantWys >= 1.2) ? 0.95 * MoverParameters->EnginePowerSource.MaxVoltage : + 0.0; + else if (MoverParameters->PantRearUp ? (PantDiff < 0.01) : false) + { + if ((MoverParameters->PantRearVolt == 0.0) && + (MoverParameters->PantFrontVolt == 0.0)) + sPantUp.Play(vol, 0, MechInside, vPosition); + if (p->hvPowerWire) // TODO: wyliczyć trzeba prąd przypadający na pantograf i + // wstawić do GetVoltage() + { + MoverParameters->PantRearVolt = + p->hvPowerWire->VoltageGet(MoverParameters->Voltage, fPantCurrent); + fCurrent -= fPantCurrent; // taki prąd płynie przez powyższy pantograf + } + else + MoverParameters->PantRearVolt = 0.0; + } + else + MoverParameters->PantRearVolt = 0.0; + break; + } // pozostałe na razie nie obsługiwane + if (MoverParameters->PantPress > + (MoverParameters->TrainType == dt_EZT ? + 2.5 : + 3.3)) // Ra 2013-12: Niebugocław mówi, że w EZT podnoszą się przy 2.5 + pantspeedfactor = 0.015 * (MoverParameters->PantPress) * + dt1; // z EXE Kursa //Ra: wysokość zależy od ciśnienia !!! + else + pantspeedfactor = 0.0; + if (pantspeedfactor < 0) + pantspeedfactor = 0; + k = p->fAngleL; + if (i ? MoverParameters->PantRearUp : + MoverParameters->PantFrontUp) // jeśli ma być podniesiony + { + if (PantDiff > 0.001) // jeśli nie dolega do drutu + { // jeśli poprzednia wysokość jest mniejsza niż pożądana, zwiększyć kąt dolnego + // ramienia zgodnie z ciśnieniem + if (pantspeedfactor > + 0.55 * PantDiff) // 0.55 to około pochodna kąta po wysokości + k += 0.55 * PantDiff; // ograniczenie "skoku" w danej klatce + else + k += pantspeedfactor; // dolne ramię + // jeśli przekroczono kąt graniczny, zablokować pantograf (wymaga interwencji + // pociągu sieciowego) + } + else if (PantDiff < -0.001) + { // drut się obniżył albo pantograf podniesiony za wysoko + // jeśli wysokość jest zbyt duża, wyznaczyć zmniejszenie kąta + // jeśli zmniejszenie kąta jest zbyt duże, przejść do trybu łamania pantografu + // if (PantFrontDiff<-0.05) //skok w dół o 5cm daje złąmanie pantografu + k += 0.4 * PantDiff; // mniej niż pochodna kąta po wysokości + } // jeśli wysokość jest dobra, nic więcej nie liczyć + } + else + { // jeśli ma być na dole + if (k > p->fAngleL0) // jeśli wyżej niż położenie wyjściowe + k -= 0.15 * dt1; // ruch w dół + if (k < p->fAngleL0) + k = p->fAngleL0; // położenie minimalne + } + if (k != p->fAngleL) + { //żeby nie liczyć w kilku miejscach ani gdy nie potrzeba + if (k + p->fAngleU < M_PI) + { // o ile nie został osiągnięty kąt maksymalny + p->fAngleL = k; // zmieniony kąt + // wyliczyć kąt górnego ramienia z wzoru (a)cosinusowego + //=acos((b*cos()+c)/a) + // p->dPantAngleT=acos((1.22*cos(k)+0.535)/1.755); //górne ramię + p->fAngleU = acos((p->fLenL1 * cos(k) + p->fHoriz) / p->fLenU1); // górne ramię + // wyliczyć aktualną wysokość z wzoru sinusowego + // h=a*sin()+b*sin() + p->PantWys = p->fLenL1 * sin(k) + p->fLenU1 * sin(p->fAngleU) + + p->fHeight; // wysokość całości + } + } + } // koniec pętli po pantografach + if ((MoverParameters->PantFrontSP == false) && (MoverParameters->PantFrontUp == false)) + { + sPantDown.Play(vol, 0, MechInside, vPosition); + MoverParameters->PantFrontSP = true; + } + if ((MoverParameters->PantRearSP == false) && (MoverParameters->PantRearUp == false)) + { + sPantDown.Play(vol, 0, MechInside, vPosition); + MoverParameters->PantRearSP = true; + } + if (MoverParameters->EnginePowerSource.SourceType == CurrentCollector) + { // Winger 240404 - wylaczanie sprezarki i przetwornicy przy braku napiecia + if (tmpTraction.TractionVoltage == 0) + { // to coś wyłączało dźwięk silnika w ST43! + MoverParameters->ConverterFlag = false; + MoverParameters->CompressorFlag = false; // Ra: to jest wątpliwe - wyłączenie + // sprężarki powinno być w jednym miejscu! + } + } + } + else if (MoverParameters->EnginePowerSource.SourceType == InternalSource) + if (MoverParameters->EnginePowerSource.PowerType == SteamPower) + // if (smPatykird1[0]) + { // Ra: animacja rozrządu parowozu, na razie nieoptymalizowane + /* //Ra: tymczasowo wyłączone ze względu na porządkowanie animacji pantografów + double fi,dx,c2,ka,kc; + double sin_fi,cos_fi; + double L1=1.6688888888888889; + double L2=5.6666666666666667; //2550/450 + double Lc=0.4; + double L=5.686422222; //2558.89/450 + double G1,G2,G3,ksi,sin_ksi,gam; + double G1_2,G2_2,G3_2; //kwadraty + //ruch tłoków oraz korbowodów + for (int i=0;i<=1;++i) + {//obie strony w ten sam sposób + fi=DegToRad(dWheelAngle[1]+(i?pant2x:pant1x)); //kąt obrotu koła dla tłoka 1 + sin_fi=sin(fi); + cos_fi=cos(fi); + dx=panty*cos_fi+sqrt(panth*panth-panty*panty*sin_fi*sin_fi)-panth; //nieoptymalne + if (smPatykird1[i]) //na razie zabezpieczenie + smPatykird1[i]->SetTranslate(float3(dx,0,0)); + ka=-asin(panty/panth)*sin_fi; + if (smPatykirg1[i]) //na razie zabezpieczenie + smPatykirg1[i]->SetRotateXYZ(vector3(RadToDeg(ka),0,0)); + //smPatykirg1[0]->SetRotate(float3(0,1,0),RadToDeg(fi)); //obracamy + //ruch drążka mimośrodkowego oraz jarzma + //korzystałem z pliku PDF "mm.pdf" (opis czworoboku korbowo-wahaczowego): + //"MECHANIKA MASZYN. Szkic wykładu i laboratorium komputerowego." + //Prof. dr hab. inż. Jerzy Zajączkowski, 2007, Politechnika Łódzka + //L1 - wysokość (w pionie) osi jarzma ponad osią koła + //L2 - odległość w poziomie osi jarzma od osi koła + //Lc - długość korby mimośrodu na kole + //Lr - promień jarzma =1.0 (pozostałe przeliczone proporcjonalnie) + //L - długość drążka mimośrodowego + //fi - kąt obrotu koła + //ksi - kąt obrotu jarzma (od pionu) + //gam - odchylenie drążka mimośrodowego od poziomu + //G1=(Lr*Lr+L1*L1+L2*L2+Kc*Lc-L*L-2.0*Lc*L2*cos(fi)+2.0*Lc*L1*sin(fi))/(Lr*Lr); + //G2=2.0*(L2-Lc*cos(fi))/Lr; + //G3=2.0*(L1-Lc*sin(fi))/Lr; + fi=DegToRad(dWheelAngle[1]+(i?pant2x:pant1x)-96.77416667); //kąt obrotu koła dla + tłoka 1 + //1) dla dWheelAngle[1]=0° korba jest w dół, a mimośród w stronę jarzma, czyli + fi=-7° + //2) dla dWheelAngle[1]=90° korba jest do tyłu, a mimośród w dół, czyli fi=83° + sin_fi=sin(fi); + cos_fi=cos(fi); + G1=(1.0+L1*L1+L2*L2+Lc*Lc-L*L-2.0*Lc*L2*cos_fi+2.0*Lc*L1*sin_fi); + G1_2=G1*G1; + G2=2.0*(L2-Lc*cos_fi); + G2_2=G2*G2; + G3=2.0*(L1-Lc*sin_fi); + G3_2=G3*G3; + sin_ksi=(G1*G2-G3*_fm_sqrt(G2_2+G3_2-G1_2))/(G2_2+G3_2); //x1 (minus delta) + ksi=asin(sin_ksi); //kąt jarzma + if (smPatykirg2[i]) + smPatykirg2[i]->SetRotateXYZ(vector3(RadToDeg(ksi),0,0)); //obrócenie jarzma + //1) ksi=-23°, gam= + //2) ksi=10°, gam= + //gam=acos((L2-sin_ksi-Lc*cos_fi)/L); //kąt od poziomu, liczony względem poziomu + //gam=asin((L1-cos_ksi-Lc*sin_fi)/L); //kąt od poziomu, liczony względem pionu + gam=atan2((L1-cos(ksi)+Lc*sin_fi),(L2-sin_ksi+Lc*cos_fi)); //kąt od poziomu + if (smPatykird2[i]) //na razie zabezpieczenie + smPatykird2[i]->SetRotateXYZ(vector3(RadToDeg(-gam-ksi),0,0)); //obrócenie drążka + mimośrodowego + } + */ + } + + // NBMX Obsluga drzwi, MC: zuniwersalnione + if ((dDoorMoveL < MoverParameters->DoorMaxShiftL) && (MoverParameters->DoorLeftOpened)) + dDoorMoveL += dt1 * 0.5 * MoverParameters->DoorOpenSpeed; + if ((dDoorMoveL > 0) && (!MoverParameters->DoorLeftOpened)) + { + dDoorMoveL -= dt1 * MoverParameters->DoorCloseSpeed; + if (dDoorMoveL < 0) + dDoorMoveL = 0; + } + if ((dDoorMoveR < MoverParameters->DoorMaxShiftR) && (MoverParameters->DoorRightOpened)) + dDoorMoveR += dt1 * 0.5 * MoverParameters->DoorOpenSpeed; + if ((dDoorMoveR > 0) && (!MoverParameters->DoorRightOpened)) + { + dDoorMoveR -= dt1 * MoverParameters->DoorCloseSpeed; + if (dDoorMoveR < 0) + dDoorMoveR = 0; + } + + // ABu-160303 sledzenie toru przed obiektem: ******************************* + // Z obserwacji: v>0 -> Coupler 0; v<0 ->coupler1 (Ra: prędkość jest związana z pojazdem) + // Rozroznienie jest tutaj, zeby niepotrzebnie nie skakac do funkcji. Nie jest uzaleznione + // od obecnosci AI, zeby uwzglednic np. jadace bez lokomotywy wagony. + // Ra: można by przenieść na poziom obiektu reprezentującego skład, aby nie sprawdzać środkowych + if (CouplCounter > 25) // licznik, aby nie robić za każdym razem + { // poszukiwanie czegoś do zderzenia się + fTrackBlock = 10000.0; // na razie nie ma przeszkód (na wypadek nie uruchomienia skanowania) + // jeśli nie ma zwrotnicy po drodze, to tylko przeliczyć odległość? + if (MoverParameters->V > 0.03) //[m/s] jeśli jedzie do przodu (w kierunku Coupler 0) + { + if (MoverParameters->Couplers[0].CouplingFlag == + ctrain_virtual) // brak pojazdu podpiętego? + { + ABuScanObjects(1, fScanDist); // szukanie czegoś do podłączenia + // WriteLog(asName+" - block 0: "+AnsiString(fTrackBlock)); + } + } + else if (MoverParameters->V < -0.03) //[m/s] jeśli jedzie do tyłu (w kierunku Coupler 1) + if (MoverParameters->Couplers[1].CouplingFlag == + ctrain_virtual) // brak pojazdu podpiętego? + { + ABuScanObjects(-1, fScanDist); + // WriteLog(asName+" - block 1: "+AnsiString(fTrackBlock)); + } + CouplCounter = random(20); // ponowne sprawdzenie po losowym czasie + } + if (MoverParameters->Vel > 0.1) //[km/h] + ++CouplCounter; // jazda sprzyja poszukiwaniu połączenia else - MoverParameters->PantFrontVolt=0.0; - continue; //reszta wtedy nie jest wykonywana - } - PantDiff=p->PantTraction-p->PantWys; //docelowy-aktualny - switch (i) //numer pantografu - {//trzeba usunąć to rozróżnienie - case 0: - if (Global::bLiveTraction?false:!p->hvPowerWire) //jeśli nie ma drutu, może pooszukiwać - MoverParameters->PantFrontVolt=(p->PantWys>=1.2)?0.95*MoverParameters->EnginePowerSource.MaxVoltage:0.0; - else - if (MoverParameters->PantFrontUp?(PantDiff<0.01):false) //tolerancja niedolegania - { - if ((MoverParameters->PantFrontVolt==0.0)&&(MoverParameters->PantRearVolt==0.0)) - sPantUp.Play(vol,0,MechInside,vPosition); - if (p->hvPowerWire) //TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage() - {MoverParameters->PantFrontVolt=p->hvPowerWire->VoltageGet(MoverParameters->Voltage,fPantCurrent); - fCurrent-=fPantCurrent; //taki prąd płynie przez powyższy pantograf - } - else - MoverParameters->PantFrontVolt=0.0; - } - else - MoverParameters->PantFrontVolt=0.0; - break; - case 1: - if (Global::bLiveTraction?false:!p->hvPowerWire) //jeśli nie ma drutu, może pooszukiwać - MoverParameters->PantRearVolt=(p->PantWys>=1.2)?0.95*MoverParameters->EnginePowerSource.MaxVoltage:0.0; - else - if (MoverParameters->PantRearUp?(PantDiff<0.01):false) - { - if ((MoverParameters->PantRearVolt==0.0)&&(MoverParameters->PantFrontVolt==0.0)) - sPantUp.Play(vol,0,MechInside,vPosition); - if (p->hvPowerWire) //TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage() - {MoverParameters->PantRearVolt=p->hvPowerWire->VoltageGet(MoverParameters->Voltage,fPantCurrent); - fCurrent-=fPantCurrent; //taki prąd płynie przez powyższy pantograf - } - else - MoverParameters->PantRearVolt=0.0; - } - else - MoverParameters->PantRearVolt=0.0; - break; - } //pozostałe na razie nie obsługiwane - if (MoverParameters->PantPress>(MoverParameters->TrainType==dt_EZT?2.5:3.3)) //Ra 2013-12: Niebugocław mówi, że w EZT podnoszą się przy 2.5 - pantspeedfactor=0.015*(MoverParameters->PantPress)*dt1; //z EXE Kursa //Ra: wysokość zależy od ciśnienia !!! - else - pantspeedfactor=0.0; - if (pantspeedfactor<0) pantspeedfactor=0; - k=p->fAngleL; - if (i?MoverParameters->PantRearUp:MoverParameters->PantFrontUp) //jeśli ma być podniesiony - {if (PantDiff>0.001) //jeśli nie dolega do drutu - {//jeśli poprzednia wysokość jest mniejsza niż pożądana, zwiększyć kąt dolnego ramienia zgodnie z ciśnieniem - if (pantspeedfactor>0.55*PantDiff) //0.55 to około pochodna kąta po wysokości - k+=0.55*PantDiff; //ograniczenie "skoku" w danej klatce - else - k+=pantspeedfactor; //dolne ramię - //jeśli przekroczono kąt graniczny, zablokować pantograf (wymaga interwencji pociągu sieciowego) + { + CouplCounter = 25; // a bezruch nie, ale trzeba zaktualizować odległość, bo zawalidroga może + // sobie pojechać } - else if (PantDiff<-0.001) - {//drut się obniżył albo pantograf podniesiony za wysoko - //jeśli wysokość jest zbyt duża, wyznaczyć zmniejszenie kąta - //jeśli zmniejszenie kąta jest zbyt duże, przejść do trybu łamania pantografu - //if (PantFrontDiff<-0.05) //skok w dół o 5cm daje złąmanie pantografu - k+=0.4*PantDiff; //mniej niż pochodna kąta po wysokości - } //jeśli wysokość jest dobra, nic więcej nie liczyć - } - else - {//jeśli ma być na dole - if (k>p->fAngleL0) //jeśli wyżej niż położenie wyjściowe - k-=0.15*dt1; //ruch w dół - if (kfAngleL0) - k=p->fAngleL0; //położenie minimalne - } - if (k!=p->fAngleL) - {//żeby nie liczyć w kilku miejscach ani gdy nie potrzeba - if (k+p->fAngleUfAngleL=k; //zmieniony kąt - //wyliczyć kąt górnego ramienia z wzoru (a)cosinusowego - //=acos((b*cos()+c)/a) - //p->dPantAngleT=acos((1.22*cos(k)+0.535)/1.755); //górne ramię - p->fAngleU=acos((p->fLenL1*cos(k)+p->fHoriz)/p->fLenU1); //górne ramię - //wyliczyć aktualną wysokość z wzoru sinusowego - //h=a*sin()+b*sin() - p->PantWys=p->fLenL1*sin(k)+p->fLenU1*sin(p->fAngleU)+p->fHeight; //wysokość całości + if (MoverParameters->DerailReason > 0) + { + switch (MoverParameters->DerailReason) + { + case 1: + ErrorLog("Bad driving: " + asName + " derailed due to end of track"); + break; + case 2: + ErrorLog("Bad driving: " + asName + " derailed due to too high speed"); + break; + case 3: + ErrorLog("Bad dynamic: " + asName + " derailed due to track width"); + break; // błąd w scenerii + case 4: + ErrorLog("Bad dynamic: " + asName + " derailed due to wrong track type"); + break; // błąd w scenerii + } + MoverParameters->DerailReason = 0; //żeby tylko raz } - } - } //koniec pętli po pantografach - if ((MoverParameters->PantFrontSP==false)&&(MoverParameters->PantFrontUp==false)) - { - sPantDown.Play(vol,0,MechInside,vPosition); - MoverParameters->PantFrontSP=true; - } - if ((MoverParameters->PantRearSP==false)&&(MoverParameters->PantRearUp==false)) - { - sPantDown.Play(vol,0,MechInside,vPosition); - MoverParameters->PantRearSP=true; - } - if (MoverParameters->EnginePowerSource.SourceType==CurrentCollector) - {//Winger 240404 - wylaczanie sprezarki i przetwornicy przy braku napiecia - if (tmpTraction.TractionVoltage==0) - {//to coś wyłączało dźwięk silnika w ST43! - MoverParameters->ConverterFlag=false; - MoverParameters->CompressorFlag=false; //Ra: to jest wątpliwe - wyłączenie sprężarki powinno być w jednym miejscu! - } - } - } - else if (MoverParameters->EnginePowerSource.SourceType==InternalSource) - if (MoverParameters->EnginePowerSource.PowerType==SteamPower) - //if (smPatykird1[0]) - {//Ra: animacja rozrządu parowozu, na razie nieoptymalizowane -/* //Ra: tymczasowo wyłączone ze względu na porządkowanie animacji pantografów - double fi,dx,c2,ka,kc; - double sin_fi,cos_fi; - double L1=1.6688888888888889; - double L2=5.6666666666666667; //2550/450 - double Lc=0.4; - double L=5.686422222; //2558.89/450 - double G1,G2,G3,ksi,sin_ksi,gam; - double G1_2,G2_2,G3_2; //kwadraty - //ruch tłoków oraz korbowodów - for (int i=0;i<=1;++i) - {//obie strony w ten sam sposób - fi=DegToRad(dWheelAngle[1]+(i?pant2x:pant1x)); //kąt obrotu koła dla tłoka 1 - sin_fi=sin(fi); - cos_fi=cos(fi); - dx=panty*cos_fi+sqrt(panth*panth-panty*panty*sin_fi*sin_fi)-panth; //nieoptymalne - if (smPatykird1[i]) //na razie zabezpieczenie - smPatykird1[i]->SetTranslate(float3(dx,0,0)); - ka=-asin(panty/panth)*sin_fi; - if (smPatykirg1[i]) //na razie zabezpieczenie - smPatykirg1[i]->SetRotateXYZ(vector3(RadToDeg(ka),0,0)); - //smPatykirg1[0]->SetRotate(float3(0,1,0),RadToDeg(fi)); //obracamy - //ruch drążka mimośrodkowego oraz jarzma - //korzystałem z pliku PDF "mm.pdf" (opis czworoboku korbowo-wahaczowego): - //"MECHANIKA MASZYN. Szkic wykładu i laboratorium komputerowego." - //Prof. dr hab. inż. Jerzy Zajączkowski, 2007, Politechnika Łódzka - //L1 - wysokość (w pionie) osi jarzma ponad osią koła - //L2 - odległość w poziomie osi jarzma od osi koła - //Lc - długość korby mimośrodu na kole - //Lr - promień jarzma =1.0 (pozostałe przeliczone proporcjonalnie) - //L - długość drążka mimośrodowego - //fi - kąt obrotu koła - //ksi - kąt obrotu jarzma (od pionu) - //gam - odchylenie drążka mimośrodowego od poziomu - //G1=(Lr*Lr+L1*L1+L2*L2+Kc*Lc-L*L-2.0*Lc*L2*cos(fi)+2.0*Lc*L1*sin(fi))/(Lr*Lr); - //G2=2.0*(L2-Lc*cos(fi))/Lr; - //G3=2.0*(L1-Lc*sin(fi))/Lr; - fi=DegToRad(dWheelAngle[1]+(i?pant2x:pant1x)-96.77416667); //kąt obrotu koła dla tłoka 1 - //1) dla dWheelAngle[1]=0° korba jest w dół, a mimośród w stronę jarzma, czyli fi=-7° - //2) dla dWheelAngle[1]=90° korba jest do tyłu, a mimośród w dół, czyli fi=83° - sin_fi=sin(fi); - cos_fi=cos(fi); - G1=(1.0+L1*L1+L2*L2+Lc*Lc-L*L-2.0*Lc*L2*cos_fi+2.0*Lc*L1*sin_fi); - G1_2=G1*G1; - G2=2.0*(L2-Lc*cos_fi); - G2_2=G2*G2; - G3=2.0*(L1-Lc*sin_fi); - G3_2=G3*G3; - sin_ksi=(G1*G2-G3*_fm_sqrt(G2_2+G3_2-G1_2))/(G2_2+G3_2); //x1 (minus delta) - ksi=asin(sin_ksi); //kąt jarzma - if (smPatykirg2[i]) - smPatykirg2[i]->SetRotateXYZ(vector3(RadToDeg(ksi),0,0)); //obrócenie jarzma - //1) ksi=-23°, gam= - //2) ksi=10°, gam= - //gam=acos((L2-sin_ksi-Lc*cos_fi)/L); //kąt od poziomu, liczony względem poziomu - //gam=asin((L1-cos_ksi-Lc*sin_fi)/L); //kąt od poziomu, liczony względem pionu - gam=atan2((L1-cos(ksi)+Lc*sin_fi),(L2-sin_ksi+Lc*cos_fi)); //kąt od poziomu - if (smPatykird2[i]) //na razie zabezpieczenie - smPatykird2[i]->SetRotateXYZ(vector3(RadToDeg(-gam-ksi),0,0)); //obrócenie drążka mimośrodowego - } -*/ - } - -//NBMX Obsluga drzwi, MC: zuniwersalnione - if ((dDoorMoveLDoorMaxShiftL) && (MoverParameters->DoorLeftOpened)) - dDoorMoveL+=dt1*0.5*MoverParameters->DoorOpenSpeed; - if ((dDoorMoveL>0) && (!MoverParameters->DoorLeftOpened)) - { - dDoorMoveL-=dt1*MoverParameters->DoorCloseSpeed; - if (dDoorMoveL<0) - dDoorMoveL=0; - } - if ((dDoorMoveRDoorMaxShiftR) && (MoverParameters->DoorRightOpened)) - dDoorMoveR+=dt1*0.5*MoverParameters->DoorOpenSpeed; - if ((dDoorMoveR>0) && (!MoverParameters->DoorRightOpened)) - { - dDoorMoveR-=dt1*MoverParameters->DoorCloseSpeed; - if (dDoorMoveR<0) - dDoorMoveR=0; - } - - -//ABu-160303 sledzenie toru przed obiektem: ******************************* - //Z obserwacji: v>0 -> Coupler 0; v<0 ->coupler1 (Ra: prędkość jest związana z pojazdem) - //Rozroznienie jest tutaj, zeby niepotrzebnie nie skakac do funkcji. Nie jest uzaleznione - //od obecnosci AI, zeby uwzglednic np. jadace bez lokomotywy wagony. - //Ra: można by przenieść na poziom obiektu reprezentującego skład, aby nie sprawdzać środkowych - if (CouplCounter>25) //licznik, aby nie robić za każdym razem - {//poszukiwanie czegoś do zderzenia się - fTrackBlock=10000.0; //na razie nie ma przeszkód (na wypadek nie uruchomienia skanowania) - //jeśli nie ma zwrotnicy po drodze, to tylko przeliczyć odległość? - if (MoverParameters->V>0.03) //[m/s] jeśli jedzie do przodu (w kierunku Coupler 0) - {if (MoverParameters->Couplers[0].CouplingFlag==ctrain_virtual) //brak pojazdu podpiętego? - {ABuScanObjects(1,fScanDist); //szukanie czegoś do podłączenia - //WriteLog(asName+" - block 0: "+AnsiString(fTrackBlock)); - } - } - else if (MoverParameters->V<-0.03) //[m/s] jeśli jedzie do tyłu (w kierunku Coupler 1) - if (MoverParameters->Couplers[1].CouplingFlag==ctrain_virtual) //brak pojazdu podpiętego? - {ABuScanObjects(-1,fScanDist); - //WriteLog(asName+" - block 1: "+AnsiString(fTrackBlock)); - } - CouplCounter=random(20); //ponowne sprawdzenie po losowym czasie - } - if (MoverParameters->Vel>0.1) //[km/h] - ++CouplCounter; //jazda sprzyja poszukiwaniu połączenia - else - {CouplCounter=25; //a bezruch nie, ale trzeba zaktualizować odległość, bo zawalidroga może sobie pojechać - } - if (MoverParameters->DerailReason>0) - {switch (MoverParameters->DerailReason) - {case 1: ErrorLog("Bad driving: "+asName+" derailed due to end of track"); break; - case 2: ErrorLog("Bad driving: "+asName+" derailed due to too high speed"); break; - case 3: ErrorLog("Bad dynamic: "+asName+" derailed due to track width"); break; //błąd w scenerii - case 4: ErrorLog("Bad dynamic: "+asName+" derailed due to wrong track type"); break; //błąd w scenerii - } - MoverParameters->DerailReason=0; //żeby tylko raz - } - if (MoverParameters->LoadStatus) - LoadUpdate(); //zmiana modelu ładunku - return true; //Ra: chyba tak? + if (MoverParameters->LoadStatus) + LoadUpdate(); // zmiana modelu ładunku + return true; // Ra: chyba tak? } bool __fastcall TDynamicObject::FastUpdate(double dt) { - if (dt==0.0) return true; //Ra: pauza + if (dt == 0.0) + return true; // Ra: pauza double dDOMoveLen; if (!MoverParameters->PhysicActivation) - return true; //McZapkie: wylaczanie fizyki gdy nie potrzeba + return true; // McZapkie: wylaczanie fizyki gdy nie potrzeba if (!bEnabled) return false; TLocation l; - l.X=-vPosition.x; - l.Y=vPosition.z; - l.Z=vPosition.y; + l.X = -vPosition.x; + l.Y = vPosition.z; + l.Z = vPosition.y; TRotation r; - r.Rx=r.Ry=r.Rz= 0; + r.Rx = r.Ry = r.Rz = 0; -//McZapkie: parametry powinny byc pobierane z toru - //ts.R=MyTrack->fRadius; - //ts.Len= Max0R(MoverParameters->BDist,MoverParameters->ADist); - //ts.dHtrack=Axle1.pPosition.y-Axle0.pPosition.y; - //ts.dHrail=((Axle1.GetRoll())+(Axle0.GetRoll()))*0.5f; - //tp.Width=MyTrack->fTrackWidth; - //McZapkie-250202 - //tp.friction= MyTrack->fFriction; - //tp.CategoryFlag= MyTrack->iCategoryFlag&15; - //tp.DamageFlag=MyTrack->iDamageFlag; - //tp.QualityFlag=MyTrack->iQualityFlag; - dDOMoveLen=MoverParameters->FastComputeMovement(dt,ts,tp,l,r); // ,ts,tp,tmpTraction); - //Move(dDOMoveLen); - //ResetdMoveLen(); + // McZapkie: parametry powinny byc pobierane z toru + // ts.R=MyTrack->fRadius; + // ts.Len= Max0R(MoverParameters->BDist,MoverParameters->ADist); + // ts.dHtrack=Axle1.pPosition.y-Axle0.pPosition.y; + // ts.dHrail=((Axle1.GetRoll())+(Axle0.GetRoll()))*0.5f; + // tp.Width=MyTrack->fTrackWidth; + // McZapkie-250202 + // tp.friction= MyTrack->fFriction; + // tp.CategoryFlag= MyTrack->iCategoryFlag&15; + // tp.DamageFlag=MyTrack->iDamageFlag; + // tp.QualityFlag=MyTrack->iQualityFlag; + dDOMoveLen = MoverParameters->FastComputeMovement(dt, ts, tp, l, r); // ,ts,tp,tmpTraction); + // Move(dDOMoveLen); + // ResetdMoveLen(); FastMove(dDOMoveLen); - if (MoverParameters->LoadStatus) - LoadUpdate(); //zmiana modelu ładunku - return true; //Ra: chyba tak? + if (MoverParameters->LoadStatus) + LoadUpdate(); // zmiana modelu ładunku + return true; // Ra: chyba tak? } -//McZapkie-040402: liczenie pozycji uwzgledniajac wysokosc szyn itp. -//vector3 __fastcall TDynamicObject::GetPosition() +// McZapkie-040402: liczenie pozycji uwzgledniajac wysokosc szyn itp. +// vector3 __fastcall TDynamicObject::GetPosition() //{//Ra: pozycja pojazdu jest liczona zaraz po przesunięciu // return vPosition; //}; void __fastcall TDynamicObject::TurnOff() -{//wyłączenie rysowania submodeli zmiennych dla egemplarza pojazdu - btnOn=false; - btCoupler1.TurnOff(); - btCoupler2.TurnOff(); - btCPneumatic1.TurnOff(); - btCPneumatic1r.TurnOff(); - btCPneumatic2.TurnOff(); - btCPneumatic2r.TurnOff(); - btPneumatic1.TurnOff(); - btPneumatic1r.TurnOff(); - btPneumatic2.TurnOff(); - btPneumatic2r.TurnOff(); - btCCtrl1.TurnOff(); - btCCtrl2.TurnOff(); - btCPass1.TurnOff(); - btCPass2.TurnOff(); - btEndSignals11.TurnOff(); - btEndSignals13.TurnOff(); - btEndSignals21.TurnOff(); - btEndSignals23.TurnOff(); - btEndSignals1.TurnOff(); - btEndSignals2.TurnOff(); - btEndSignalsTab1.TurnOff(); - btEndSignalsTab2.TurnOff(); - btHeadSignals11.TurnOff(); - btHeadSignals12.TurnOff(); - btHeadSignals13.TurnOff(); - btHeadSignals21.TurnOff(); - btHeadSignals22.TurnOff(); - btHeadSignals23.TurnOff(); +{ // wyłączenie rysowania submodeli zmiennych dla egemplarza pojazdu + btnOn = false; + btCoupler1.TurnOff(); + btCoupler2.TurnOff(); + btCPneumatic1.TurnOff(); + btCPneumatic1r.TurnOff(); + btCPneumatic2.TurnOff(); + btCPneumatic2r.TurnOff(); + btPneumatic1.TurnOff(); + btPneumatic1r.TurnOff(); + btPneumatic2.TurnOff(); + btPneumatic2r.TurnOff(); + btCCtrl1.TurnOff(); + btCCtrl2.TurnOff(); + btCPass1.TurnOff(); + btCPass2.TurnOff(); + btEndSignals11.TurnOff(); + btEndSignals13.TurnOff(); + btEndSignals21.TurnOff(); + btEndSignals23.TurnOff(); + btEndSignals1.TurnOff(); + btEndSignals2.TurnOff(); + btEndSignalsTab1.TurnOff(); + btEndSignalsTab2.TurnOff(); + btHeadSignals11.TurnOff(); + btHeadSignals12.TurnOff(); + btHeadSignals13.TurnOff(); + btHeadSignals21.TurnOff(); + btHeadSignals22.TurnOff(); + btHeadSignals23.TurnOff(); }; void __fastcall TDynamicObject::Render() -{//rysowanie elementów nieprzezroczystych - //youBy - sprawdzamy, czy jest sens renderowac - double modelrotate; - vector3 tempangle; - // zmienne - renderme=false; - //przeklejka - double ObjSqrDist=SquareMagnitude(Global::pCameraPosition-vPosition); - //koniec przeklejki - if (ObjSqrDist<500) //jak jest blisko - do 70m - modelrotate=0.01; //mały kąt, żeby nie znikało - else - {//Global::pCameraRotation to kąt bewzględny w świecie (zero - na północ) - tempangle=(vPosition-Global::pCameraPosition); //wektor od kamery - modelrotate=ABuAcos(tempangle); //określenie kąta - //if (modelrotate>M_PI) modelrotate-=(2*M_PI); - modelrotate+=Global::pCameraRotation; - } - if (modelrotate>M_PI) modelrotate-=(2*M_PI); - if (modelrotate<-M_PI) modelrotate+=(2*M_PI); - ModCamRot=modelrotate; +{ // rysowanie elementów nieprzezroczystych + // youBy - sprawdzamy, czy jest sens renderowac + double modelrotate; + vector3 tempangle; + // zmienne + renderme = false; + // przeklejka + double ObjSqrDist = SquareMagnitude(Global::pCameraPosition - vPosition); + // koniec przeklejki + if (ObjSqrDist < 500) // jak jest blisko - do 70m + modelrotate = 0.01; // mały kąt, żeby nie znikało + else + { // Global::pCameraRotation to kąt bewzględny w świecie (zero - na północ) + tempangle = (vPosition - Global::pCameraPosition); // wektor od kamery + modelrotate = ABuAcos(tempangle); // określenie kąta + // if (modelrotate>M_PI) modelrotate-=(2*M_PI); + modelrotate += Global::pCameraRotation; + } + if (modelrotate > M_PI) + modelrotate -= (2 * M_PI); + if (modelrotate < -M_PI) + modelrotate += (2 * M_PI); + ModCamRot = modelrotate; - modelrotate=abs(modelrotate); + modelrotate = abs(modelrotate); - if (modelrotate) //tu trzeba by ustawić animacje na modelu zewnętrznym - glLoadIdentity(); //zacząć od macierzy jedynkowej - Global::pCamera->SetCabMatrix(vPosition); //specjalne ustawienie kamery - } - else - glTranslated(vPosition.x,vPosition.y,vPosition.z); //standardowe przesunięcie względem początku scenerii - glMultMatrixd(mMatrix.getArray()); - if (fShade>0.0) - {//Ra: zmiana oswietlenia w tunelu, wykopie - GLfloat ambientLight[4]= {0.5f,0.5f,0.5f,1.0f}; - GLfloat diffuseLight[4]= {0.5f,0.5f,0.5f,1.0f}; - GLfloat specularLight[4]={0.5f,0.5f,0.5f,1.0f}; - //trochę problem z ambientem w wykopie... - for (int li=0;li<3;li++) - { - ambientLight[li]= Global::ambientDayLight[li]*fShade; - diffuseLight[li]= Global::diffuseDayLight[li]*fShade; - specularLight[li]=Global::specularDayLight[li]*fShade; - } - glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,specularLight); - } - if (Global::bUseVBO) - {//wersja VBO - if (mdLowPolyInt) - if (FreeFlyModeFlag?true:!mdKabina||!bDisplayCab) - mdLowPolyInt->RaRender(ObjSqrDist,ReplacableSkinID,iAlpha); - mdModel->RaRender(ObjSqrDist,ReplacableSkinID,iAlpha); - if (mdLoad) //renderowanie nieprzezroczystego ładunku - mdLoad->RaRender(ObjSqrDist,ReplacableSkinID,iAlpha); - if (mdPrzedsionek) - mdPrzedsionek->RaRender(ObjSqrDist,ReplacableSkinID,iAlpha); - } - else - {//wersja Display Lists - if (mdLowPolyInt) - if (FreeFlyModeFlag?true:!mdKabina||!bDisplayCab) - mdLowPolyInt->Render(ObjSqrDist,ReplacableSkinID,iAlpha); - mdModel->Render(ObjSqrDist,ReplacableSkinID,iAlpha); - if (mdLoad) //renderowanie nieprzezroczystego ładunku - mdLoad->Render(ObjSqrDist,ReplacableSkinID,iAlpha); - if (mdPrzedsionek) - mdPrzedsionek->Render(ObjSqrDist,ReplacableSkinID,iAlpha); - } + glPushMatrix(); + // vector3 pos= vPosition; + // double ObjDist= SquareMagnitude(Global::pCameraPosition-pos); + if (this == Global::pUserDynamic) + { // specjalne ustawienie, aby nie trzęsło + if (Global::bSmudge) + { // jak jest widoczna smuga, to pojazd renderować po wyrenderowaniu smugi + glPopMatrix(); // a to trzeba zebrać przed wyjściem + return; + } + // if (Global::pWorld->) //tu trzeba by ustawić animacje na modelu zewnętrznym + glLoadIdentity(); // zacząć od macierzy jedynkowej + Global::pCamera->SetCabMatrix(vPosition); // specjalne ustawienie kamery + } + else + glTranslated(vPosition.x, vPosition.y, + vPosition.z); // standardowe przesunięcie względem początku scenerii + glMultMatrixd(mMatrix.getArray()); + if (fShade > 0.0) + { // Ra: zmiana oswietlenia w tunelu, wykopie + GLfloat ambientLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + GLfloat diffuseLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + GLfloat specularLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + // trochę problem z ambientem w wykopie... + for (int li = 0; li < 3; li++) + { + ambientLight[li] = Global::ambientDayLight[li] * fShade; + diffuseLight[li] = Global::diffuseDayLight[li] * fShade; + specularLight[li] = Global::specularDayLight[li] * fShade; + } + glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); + } + if (Global::bUseVBO) + { // wersja VBO + if (mdLowPolyInt) + if (FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab) + mdLowPolyInt->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha); + mdModel->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha); + if (mdLoad) // renderowanie nieprzezroczystego ładunku + mdLoad->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha); + if (mdPrzedsionek) + mdPrzedsionek->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha); + } + else + { // wersja Display Lists + if (mdLowPolyInt) + if (FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab) + mdLowPolyInt->Render(ObjSqrDist, ReplacableSkinID, iAlpha); + mdModel->Render(ObjSqrDist, ReplacableSkinID, iAlpha); + if (mdLoad) // renderowanie nieprzezroczystego ładunku + mdLoad->Render(ObjSqrDist, ReplacableSkinID, iAlpha); + if (mdPrzedsionek) + mdPrzedsionek->Render(ObjSqrDist, ReplacableSkinID, iAlpha); + } - //Ra: czy ta kabina tu ma sens? - //Ra: czy nie renderuje się dwukrotnie? - //Ra: dlaczego jest zablokowana w przezroczystych? - if (mdKabina) //jeśli ma model kabiny - if ((mdKabina!=mdModel) && bDisplayCab && FreeFlyModeFlag) - {//rendering kabiny gdy jest oddzielnym modelem i ma byc wyswietlana - //ABu: tylko w trybie FreeFly, zwykly tryb w world.cpp - //Ra: świetła są ustawione dla zewnętrza danego pojazdu - //oswietlenie kabiny - GLfloat ambientCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; - GLfloat diffuseCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; - GLfloat specularCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; - for (int li=0; li<3; li++) - { - ambientCabLight[li]= Global::ambientDayLight[li]*0.9; - diffuseCabLight[li]= Global::diffuseDayLight[li]*0.5; - specularCabLight[li]=Global::specularDayLight[li]*0.5; - } - switch (MyTrack->eEnvironment) - { - case e_canyon: - { - for (int li=0; li<3; li++) - { - diffuseCabLight[li]*= 0.6; - specularCabLight[li]*= 0.7; + // Ra: czy ta kabina tu ma sens? + // Ra: czy nie renderuje się dwukrotnie? + // Ra: dlaczego jest zablokowana w przezroczystych? + if (mdKabina) // jeśli ma model kabiny + if ((mdKabina != mdModel) && bDisplayCab && FreeFlyModeFlag) + { // rendering kabiny gdy jest oddzielnym modelem i ma byc wyswietlana + // ABu: tylko w trybie FreeFly, zwykly tryb w world.cpp + // Ra: świetła są ustawione dla zewnętrza danego pojazdu + // oswietlenie kabiny + GLfloat ambientCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + GLfloat diffuseCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + GLfloat specularCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + for (int li = 0; li < 3; li++) + { + ambientCabLight[li] = Global::ambientDayLight[li] * 0.9; + diffuseCabLight[li] = Global::diffuseDayLight[li] * 0.5; + specularCabLight[li] = Global::specularDayLight[li] * 0.5; + } + switch (MyTrack->eEnvironment) + { + case e_canyon: + { + for (int li = 0; li < 3; li++) + { + diffuseCabLight[li] *= 0.6; + specularCabLight[li] *= 0.7; + } + } + break; + case e_tunnel: + { + for (int li = 0; li < 3; li++) + { + ambientCabLight[li] *= 0.3; + diffuseCabLight[li] *= 0.1; + specularCabLight[li] *= 0.2; + } + } + break; + } + glLightfv(GL_LIGHT0, GL_AMBIENT, ambientCabLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseCabLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, specularCabLight); + if (Global::bUseVBO) + mdKabina->RaRender(ObjSqrDist, 0); + else + mdKabina->Render(ObjSqrDist, 0); + glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); + } + if (fShade != 0.0) // tylko jeśli było zmieniane + { // przywrócenie standardowego oświetlenia + glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); } - } - break; - case e_tunnel: - { - for (int li=0; li<3; li++) - { - ambientCabLight[li]*= 0.3; - diffuseCabLight[li]*= 0.1; - specularCabLight[li]*= 0.2; - } - } - break; - } - glLightfv(GL_LIGHT0,GL_AMBIENT,ambientCabLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseCabLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,specularCabLight); - if (Global::bUseVBO) - mdKabina->RaRender(ObjSqrDist,0); - else - mdKabina->Render(ObjSqrDist,0); - glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); - } - if (fShade!=0.0) //tylko jeśli było zmieniane - {//przywrócenie standardowego oświetlenia - glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); - } - glPopMatrix(); - if (btnOn) TurnOff(); //przywrócenie domyślnych pozycji submodeli - } //yB - koniec mieszania z grafika + glPopMatrix(); + if (btnOn) + TurnOff(); // przywrócenie domyślnych pozycji submodeli + } // yB - koniec mieszania z grafika }; void __fastcall TDynamicObject::RenderSounds() -{//przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem - //McZapkie-010302: ulepszony dzwiek silnika - double freq; - double vol=0; - double dt=Timer::GetDeltaTime(); +{ // przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem + // McZapkie-010302: ulepszony dzwiek silnika + double freq; + double vol = 0; + double dt = Timer::GetDeltaTime(); -// double sounddist; -// sounddist=SquareMagnitude(Global::pCameraPosition-vPosition); + // double sounddist; + // sounddist=SquareMagnitude(Global::pCameraPosition-vPosition); - if (MoverParameters->Power>0) - { - if ((rsSilnik.AM!=0) && ((MoverParameters->Mains) || (MoverParameters->EngineType==DieselEngine))) //McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach - { - if ((fabs(MoverParameters->enrot)>0.01) || (MoverParameters->EngineType==Dumb)) //&& (MoverParameters->EnginePower>0.1)) - { - freq=rsSilnik.FM*fabs(MoverParameters->enrot)+rsSilnik.FA; - if (MoverParameters->EngineType==Dumb) - freq=freq-0.2*MoverParameters->EnginePower/(1+MoverParameters->Power*1000); - rsSilnik.AdjFreq(freq,dt); - if (MoverParameters->EngineType==DieselEngine) - { - if (MoverParameters->enrot>0) - { - if (MoverParameters->EnginePower>0) - vol=rsSilnik.AM*MoverParameters->dizel_fill+rsSilnik.AA; - else - vol=rsSilnik.AM*fabs(MoverParameters->enrot/MoverParameters->nmax)+rsSilnik.AA*0.9; - } - else - vol=0; - } - else if (MoverParameters->EngineType==DieselElectric) - vol=rsSilnik.AM*(MoverParameters->EnginePower/1000/MoverParameters->Power)+0.2*(MoverParameters->enrot*60)/(MoverParameters->DElist[MoverParameters->MainCtrlPosNo].RPM)+rsSilnik.AA; - else if (MoverParameters->EngineType==ElectricInductionMotor) - vol=rsSilnik.AM*(MoverParameters->EnginePower+fabs(MoverParameters->enrot*2))+rsSilnik.AA; - else - vol=rsSilnik.AM*(MoverParameters->EnginePower/1000+fabs(MoverParameters->enrot)*60.0)+rsSilnik.AA; -// McZapkie-250302 - natezenie zalezne od obrotow i mocy - if ((vol<1) && (MoverParameters->EngineType==ElectricSeriesMotor) && (MoverParameters->EnginePower<100)) - { - float volrnd=random(100)*MoverParameters->enrot/(1+MoverParameters->nmax); - if (volrnd<2) - vol=vol+volrnd/200.0; - } - switch (MyTrack->eEnvironment) + if (MoverParameters->Power > 0) + { + if ((rsSilnik.AM != 0) && + ((MoverParameters->Mains) || + (MoverParameters->EngineType == + DieselEngine))) // McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach + { + if ((fabs(MoverParameters->enrot) > 0.01) || + (MoverParameters->EngineType == Dumb)) //&& (MoverParameters->EnginePower>0.1)) { + freq = rsSilnik.FM * fabs(MoverParameters->enrot) + rsSilnik.FA; + if (MoverParameters->EngineType == Dumb) + freq = freq - + 0.2 * MoverParameters->EnginePower / (1 + MoverParameters->Power * 1000); + rsSilnik.AdjFreq(freq, dt); + if (MoverParameters->EngineType == DieselEngine) + { + if (MoverParameters->enrot > 0) + { + if (MoverParameters->EnginePower > 0) + vol = rsSilnik.AM * MoverParameters->dizel_fill + rsSilnik.AA; + else + vol = + rsSilnik.AM * fabs(MoverParameters->enrot / MoverParameters->nmax) + + rsSilnik.AA * 0.9; + } + else + vol = 0; + } + else if (MoverParameters->EngineType == DieselElectric) + vol = rsSilnik.AM * + (MoverParameters->EnginePower / 1000 / MoverParameters->Power) + + 0.2 * (MoverParameters->enrot * 60) / + (MoverParameters->DElist[MoverParameters->MainCtrlPosNo].RPM) + + rsSilnik.AA; + else if (MoverParameters->EngineType == ElectricInductionMotor) + vol = rsSilnik.AM * + (MoverParameters->EnginePower + fabs(MoverParameters->enrot * 2)) + + rsSilnik.AA; + else + vol = rsSilnik.AM * (MoverParameters->EnginePower / 1000 + + fabs(MoverParameters->enrot) * 60.0) + + rsSilnik.AA; + // McZapkie-250302 - natezenie zalezne od obrotow i mocy + if ((vol < 1) && (MoverParameters->EngineType == ElectricSeriesMotor) && + (MoverParameters->EnginePower < 100)) + { + float volrnd = + random(100) * MoverParameters->enrot / (1 + MoverParameters->nmax); + if (volrnd < 2) + vol = vol + volrnd / 200.0; + } + switch (MyTrack->eEnvironment) + { case e_tunnel: - { - vol+=0.1; - } + { + vol += 0.1; + } break; case e_canyon: - { - vol+=0.05; - } + { + vol += 0.05; + } break; + } + if ((MoverParameters->DynamicBrakeFlag) && (MoverParameters->EnginePower > 0.1) && + (MoverParameters->EngineType == + ElectricSeriesMotor)) // Szociu - 29012012 - jeżeli uruchomiony jest hamulec + // elektrodynamiczny, odtwarzany jest dźwięk silnika + vol += 0.8; + + if (enginevolume > 0.0001) + if (MoverParameters->EngineType != DieselElectric) + { + rsSilnik.Play(enginevolume, DSBPLAY_LOOPING, MechInside, GetPosition()); + } + else + { + sConverter.UpdateAF(vol, freq, MechInside, GetPosition()); + + float fincvol; + fincvol = 0; + if ((MoverParameters->ConverterFlag) && + (MoverParameters->enrot * 60 > MoverParameters->DElist[0].RPM)) + { + fincvol = (MoverParameters->DElist[MoverParameters->MainCtrlPos].RPM - + (MoverParameters->enrot * 60)); + fincvol /= (0.05 * MoverParameters->DElist[0].RPM); + }; + if (fincvol > 0.02) + rsDiesielInc.Play(fincvol, DSBPLAY_LOOPING, MechInside, GetPosition()); + else + rsDiesielInc.Stop(); + } } - if ((MoverParameters->DynamicBrakeFlag) && (MoverParameters->EnginePower>0.1) && (MoverParameters->EngineType==ElectricSeriesMotor)) //Szociu - 29012012 - jeżeli uruchomiony jest hamulec elektrodynamiczny, odtwarzany jest dźwięk silnika - vol +=0.8; - - if (enginevolume>0.0001) - if (MoverParameters->EngineType!=DieselElectric) - { rsSilnik.Play(enginevolume,DSBPLAY_LOOPING,MechInside,GetPosition()); } - else - { - sConverter.UpdateAF(vol,freq,MechInside,GetPosition()); - - float fincvol; - fincvol=0; - if ((MoverParameters->ConverterFlag)&&(MoverParameters->enrot*60>MoverParameters->DElist[0].RPM)) - { - fincvol=(MoverParameters->DElist[MoverParameters->MainCtrlPos].RPM-(MoverParameters->enrot*60)); - fincvol/=(0.05*MoverParameters->DElist[0].RPM); - }; - if (fincvol>0.02) - rsDiesielInc.Play(fincvol,DSBPLAY_LOOPING,MechInside,GetPosition()); - else - rsDiesielInc.Stop(); - } - } - else - rsSilnik.Stop(); - } - enginevolume=(enginevolume+vol)/2; - if (enginevolume<0.01) - rsSilnik.Stop(); - if ((MoverParameters->EngineType==ElectricSeriesMotor)||(MoverParameters->EngineType==ElectricInductionMotor) && rsWentylator.AM!=0) - { - if (MoverParameters->RventRot>0.1) - { - freq=rsWentylator.FM*MoverParameters->RventRot+rsWentylator.FA; - rsWentylator.AdjFreq(freq,dt); - if (MoverParameters->EngineType==ElectricInductionMotor) - vol=rsWentylator.AM*sqrt(fabs(MoverParameters->dizel_fill))+rsWentylator.AA; else - vol=rsWentylator.AM*MoverParameters->RventRot+rsWentylator.AA; - rsWentylator.Play(vol,DSBPLAY_LOOPING,MechInside,GetPosition()); - } - else - rsWentylator.Stop(); + rsSilnik.Stop(); } - if (MoverParameters->TrainType==dt_ET40) + enginevolume = (enginevolume + vol) / 2; + if (enginevolume < 0.01) + rsSilnik.Stop(); + if ((MoverParameters->EngineType == ElectricSeriesMotor) || + (MoverParameters->EngineType == ElectricInductionMotor) && rsWentylator.AM != 0) { - if (MoverParameters->Vel>0.1) - { - freq=rsPrzekladnia.FM*(MoverParameters->Vel)+rsPrzekladnia.FA; - rsPrzekladnia.AdjFreq(freq,dt); - vol=rsPrzekladnia.AM*(MoverParameters->Vel)+rsPrzekladnia.AA; - rsPrzekladnia.Play(vol,DSBPLAY_LOOPING,MechInside,GetPosition()); - } - else - rsPrzekladnia.Stop(); + if (MoverParameters->RventRot > 0.1) + { + freq = rsWentylator.FM * MoverParameters->RventRot + rsWentylator.FA; + rsWentylator.AdjFreq(freq, dt); + if (MoverParameters->EngineType == ElectricInductionMotor) + vol = + rsWentylator.AM * sqrt(fabs(MoverParameters->dizel_fill)) + rsWentylator.AA; + else + vol = rsWentylator.AM * MoverParameters->RventRot + rsWentylator.AA; + rsWentylator.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition()); + } + else + rsWentylator.Stop(); } - } + if (MoverParameters->TrainType == dt_ET40) + { + if (MoverParameters->Vel > 0.1) + { + freq = rsPrzekladnia.FM * (MoverParameters->Vel) + rsPrzekladnia.FA; + rsPrzekladnia.AdjFreq(freq, dt); + vol = rsPrzekladnia.AM * (MoverParameters->Vel) + rsPrzekladnia.AA; + rsPrzekladnia.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition()); + } + else + rsPrzekladnia.Stop(); + } + } -//youBy: dzwiek ostrych lukow i ciasnych zwrotek + // youBy: dzwiek ostrych lukow i ciasnych zwrotek - if ((ts.R*ts.R>1)&&(MoverParameters->Vel>0)) - vol=MoverParameters->AccN*MoverParameters->AccN; - else - vol=0; -// vol+=(50000/ts.R*ts.R); + if ((ts.R * ts.R > 1) && (MoverParameters->Vel > 0)) + vol = MoverParameters->AccN * MoverParameters->AccN; + else + vol = 0; + // vol+=(50000/ts.R*ts.R); - if (vol>0.001) - { - rscurve.Play(2*vol,DSBPLAY_LOOPING,MechInside,GetPosition()); - } - else - rscurve.Stop(); + if (vol > 0.001) + { + rscurve.Play(2 * vol, DSBPLAY_LOOPING, MechInside, GetPosition()); + } + else + rscurve.Stop(); -//McZapkie-280302 - pisk mocno zacisnietych hamulcow - trzeba jeszcze zabezpieczyc przed brakiem deklaracji w mmedia.dta - if (rsPisk.AM!=0) + // McZapkie-280302 - pisk mocno zacisnietych hamulcow - trzeba jeszcze zabezpieczyc przed + // brakiem deklaracji w mmedia.dta + if (rsPisk.AM != 0) + { + if ((MoverParameters->Vel > (rsPisk.GetStatus() != 0 ? 0.01 : 0.5)) && + (!MoverParameters->SlippingWheels) && (MoverParameters->UnitBrakeForce > rsPisk.AM)) + { + vol = MoverParameters->UnitBrakeForce / (rsPisk.AM + 1) + rsPisk.AA; + rsPisk.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition()); + } + else + rsPisk.Stop(); + } + + // if ((MoverParameters->ConverterFlag==false) && (MoverParameters->TrainType!=dt_ET22)) + // if ((MoverParameters->ConverterFlag==false)&&(MoverParameters->CompressorPower!=0)) + // MoverParameters->CompressorFlag=false; //Ra: wywalić to stąd, tu tylko dla wyświetlanych! + // Ra: no to już wiemy, dlaczego pociągi jeżdżą lepiej, gdy się na nie patrzy! + // if (MoverParameters->CompressorPower==2) + // MoverParameters->CompressorAllow=MoverParameters->ConverterFlag; + + // McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka + if (MoverParameters->VeselVolume != 0) + { + if (MoverParameters->CompressorFlag) + sCompressor.TurnOn(MechInside, GetPosition()); + else + sCompressor.TurnOff(MechInside, GetPosition()); + sCompressor.Update(MechInside, GetPosition()); + } + if (MoverParameters->PantCompFlag) // Winger 160404 - dzwiek malej sprezarki + sSmallCompressor.TurnOn(MechInside, GetPosition()); + else + sSmallCompressor.TurnOff(MechInside, GetPosition()); + sSmallCompressor.Update(MechInside, GetPosition()); + + // youBy - przenioslem, bo diesel tez moze miec turbo + if ((MoverParameters->MainCtrlPos) >= + (MoverParameters + ->TurboTest)) // hunter-250312: dlaczego zakomentowane? Ra: bo nie działało dobrze + { + // udawanie turbo: (6.66*(eng_vol-0.85)) + if (eng_turbo > 6.66 * (enginevolume - 0.8) + 0.2 * dt) + eng_turbo = eng_turbo - 0.2 * dt; // 0.125 + else if (eng_turbo < 6.66 * (enginevolume - 0.8) - 0.4 * dt) + eng_turbo = eng_turbo + 0.4 * dt; // 0.333 + else + eng_turbo = 6.66 * (enginevolume - 0.8); + + sTurbo.TurnOn(MechInside, GetPosition()); + // sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition()); + sTurbo.UpdateAF(3 * eng_turbo - 1, 0.4 + eng_turbo * 0.4, MechInside, GetPosition()); + // eng_vol_act=enginevolume; + // eng_frq_act=eng_frq; + } + else + sTurbo.TurnOff(MechInside, GetPosition()); + + if (MoverParameters->TrainType == dt_PseudoDiesel) + { + // ABu: udawanie woodwarda dla lok. spalinowych + // jesli silnik jest podpiety pod dzwiek przetwornicy + if (MoverParameters->ConverterFlag) // NBMX dzwiek przetwornicy + { + sConverter.TurnOn(MechInside, GetPosition()); + } + else + sConverter.TurnOff(MechInside, GetPosition()); + + // glosnosc zalezy od stosunku mocy silnika el. do mocy max + double eng_vol; + if (MoverParameters->Power > 1) + // 0.85+0.000015*(...) + eng_vol = 0.8 + 0.00002 * (MoverParameters->EnginePower / MoverParameters->Power); + else + eng_vol = 1; + + eng_dfrq = eng_dfrq + (eng_vol_act - eng_vol); + if (eng_dfrq > 0) + { + eng_dfrq = eng_dfrq - 0.025 * dt; + if (eng_dfrq < 0.025 * dt) + eng_dfrq = 0; + } + else if (eng_dfrq < 0) + { + eng_dfrq = eng_dfrq + 0.025 * dt; + if (eng_dfrq > -0.025 * dt) + eng_dfrq = 0; + } + double defrot; + if (MoverParameters->MainCtrlPos != 0) + { + double CtrlPos = MoverParameters->MainCtrlPos; + double CtrlPosNo = MoverParameters->MainCtrlPosNo; + // defrot=1+0.4*(CtrlPos/CtrlPosNo); + defrot = 1 + 0.5 * (CtrlPos / CtrlPosNo); + } + else + defrot = 1; + + if (eng_frq_act < defrot) + { + // if (MoverParameters->MainCtrlPos==1) eng_frq_act=eng_frq_act+0.1*dt; + eng_frq_act = eng_frq_act + 0.4 * dt; // 0.05 + if (eng_frq_act > defrot - 0.4 * dt) + eng_frq_act = defrot; + } + else if (eng_frq_act > defrot) + { + eng_frq_act = eng_frq_act - 0.1 * dt; // 0.05 + if (eng_frq_act < defrot + 0.1 * dt) + eng_frq_act = defrot; + } + sConverter.UpdateAF(eng_vol_act, eng_frq_act + eng_dfrq, MechInside, GetPosition()); + // udawanie turbo: (6.66*(eng_vol-0.85)) + if (eng_turbo > 6.66 * (eng_vol - 0.8) + 0.2 * dt) + eng_turbo = eng_turbo - 0.2 * dt; // 0.125 + else if (eng_turbo < 6.66 * (eng_vol - 0.8) - 0.4 * dt) + eng_turbo = eng_turbo + 0.4 * dt; // 0.333 + else + eng_turbo = 6.66 * (eng_vol - 0.8); + + sTurbo.TurnOn(MechInside, GetPosition()); + // sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition()); + sTurbo.UpdateAF(3 * eng_turbo - 1, 0.4 + eng_turbo * 0.4, MechInside, GetPosition()); + eng_vol_act = eng_vol; + // eng_frq_act=eng_frq; + } + else + { + if (MoverParameters->ConverterFlag) // NBMX dzwiek przetwornicy + sConverter.TurnOn(MechInside, GetPosition()); + else + sConverter.TurnOff(MechInside, GetPosition()); + sConverter.Update(MechInside, GetPosition()); + } + if (MoverParameters->WarningSignal > 0) + { + if (TestFlag(MoverParameters->WarningSignal, 1)) + sHorn1.TurnOn(MechInside, GetPosition()); + else + sHorn1.TurnOff(MechInside, GetPosition()); + if (TestFlag(MoverParameters->WarningSignal, 2)) + sHorn2.TurnOn(MechInside, GetPosition()); + else + sHorn2.TurnOff(MechInside, GetPosition()); + } + else + { + sHorn1.TurnOff(MechInside, GetPosition()); + sHorn2.TurnOff(MechInside, GetPosition()); + } + if (MoverParameters->DoorClosureWarning) + { + if (MoverParameters->DepartureSignal) // NBMX sygnal odjazdu, MC: pod warunkiem ze jest + // zdefiniowane w chk + sDepartureSignal.TurnOn(MechInside, GetPosition()); + else + sDepartureSignal.TurnOff(MechInside, GetPosition()); + sDepartureSignal.Update(MechInside, GetPosition()); + } + sHorn1.Update(MechInside, GetPosition()); + sHorn2.Update(MechInside, GetPosition()); + // McZapkie: w razie wykolejenia + if (MoverParameters->EventFlag) + { + if (TestFlag(MoverParameters->DamageFlag, dtrain_out) && GetVelocity() > 0) + rsDerailment.Play(1, 0, true, GetPosition()); + if (GetVelocity() == 0) + rsDerailment.Stop(); + } + /* //Ra: dwa razy? + if (MoverParameters->EventFlag) { - if ((MoverParameters->Vel>(rsPisk.GetStatus()!=0?0.01:0.5)) && (!MoverParameters->SlippingWheels) && (MoverParameters->UnitBrakeForce>rsPisk.AM)) - { - vol=MoverParameters->UnitBrakeForce/(rsPisk.AM+1)+rsPisk.AA; - rsPisk.Play(vol,DSBPLAY_LOOPING,MechInside,GetPosition()); - } - else - rsPisk.Stop(); + if (TestFlag(MoverParameters->DamageFlag,dtrain_out) && GetVelocity()>0) + rsDerailment.Play(1,0,true,GetPosition()); + if (GetVelocity()==0) + rsDerailment.Stop(); } - -//if ((MoverParameters->ConverterFlag==false) && (MoverParameters->TrainType!=dt_ET22)) -//if ((MoverParameters->ConverterFlag==false)&&(MoverParameters->CompressorPower!=0)) -// MoverParameters->CompressorFlag=false; //Ra: wywalić to stąd, tu tylko dla wyświetlanych! -//Ra: no to już wiemy, dlaczego pociągi jeżdżą lepiej, gdy się na nie patrzy! -//if (MoverParameters->CompressorPower==2) -// MoverParameters->CompressorAllow=MoverParameters->ConverterFlag; - -// McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka - if (MoverParameters->VeselVolume!=0) - { - if (MoverParameters->CompressorFlag) - sCompressor.TurnOn(MechInside,GetPosition()); - else - sCompressor.TurnOff(MechInside,GetPosition()); - sCompressor.Update(MechInside,GetPosition()); - } - if (MoverParameters->PantCompFlag) // Winger 160404 - dzwiek malej sprezarki - sSmallCompressor.TurnOn(MechInside,GetPosition()); - else - sSmallCompressor.TurnOff(MechInside,GetPosition()); - sSmallCompressor.Update(MechInside,GetPosition()); - -//youBy - przenioslem, bo diesel tez moze miec turbo -if ((MoverParameters->MainCtrlPos)>=(MoverParameters->TurboTest)) //hunter-250312: dlaczego zakomentowane? Ra: bo nie działało dobrze -{ - //udawanie turbo: (6.66*(eng_vol-0.85)) - if (eng_turbo>6.66*(enginevolume-0.8)+0.2*dt) - eng_turbo=eng_turbo-0.2*dt; //0.125 - else - if (eng_turbo<6.66*(enginevolume-0.8)-0.4*dt) - eng_turbo=eng_turbo+0.4*dt; //0.333 - else - eng_turbo=6.66*(enginevolume-0.8); - - sTurbo.TurnOn(MechInside,GetPosition()); - //sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition()); - sTurbo.UpdateAF(3*eng_turbo-1,0.4+eng_turbo*0.4,MechInside,GetPosition()); -// eng_vol_act=enginevolume; - //eng_frq_act=eng_frq; -} -else sTurbo.TurnOff(MechInside,GetPosition()); - - - - if (MoverParameters->TrainType==dt_PseudoDiesel) - { - //ABu: udawanie woodwarda dla lok. spalinowych - //jesli silnik jest podpiety pod dzwiek przetwornicy - if (MoverParameters->ConverterFlag) //NBMX dzwiek przetwornicy - { - sConverter.TurnOn(MechInside,GetPosition()); - } - else - sConverter.TurnOff(MechInside,GetPosition()); - - //glosnosc zalezy od stosunku mocy silnika el. do mocy max - double eng_vol; - if (MoverParameters->Power>1) - //0.85+0.000015*(...) - eng_vol=0.8+0.00002*(MoverParameters->EnginePower/MoverParameters->Power); - else - eng_vol=1; - - eng_dfrq=eng_dfrq+(eng_vol_act-eng_vol); - if(eng_dfrq>0) - { - eng_dfrq=eng_dfrq-0.025*dt; - if(eng_dfrq<0.025*dt) - eng_dfrq=0; - } - else - if(eng_dfrq<0) - { - eng_dfrq=eng_dfrq+0.025*dt; - if(eng_dfrq>-0.025*dt) - eng_dfrq=0; - } - double defrot; - if (MoverParameters->MainCtrlPos!=0) - { - double CtrlPos=MoverParameters->MainCtrlPos; - double CtrlPosNo=MoverParameters->MainCtrlPosNo; - //defrot=1+0.4*(CtrlPos/CtrlPosNo); - defrot=1+0.5*(CtrlPos/CtrlPosNo); - } - else - defrot=1; - - if (eng_frq_actMainCtrlPos==1) eng_frq_act=eng_frq_act+0.1*dt; - eng_frq_act=eng_frq_act+0.4*dt; //0.05 - if (eng_frq_act>defrot-0.4*dt) - eng_frq_act=defrot; - } - else - if (eng_frq_act>defrot) - { - eng_frq_act=eng_frq_act-0.1*dt; //0.05 - if (eng_frq_act6.66*(eng_vol-0.8)+0.2*dt) - eng_turbo=eng_turbo-0.2*dt; //0.125 - else - if (eng_turbo<6.66*(eng_vol-0.8)-0.4*dt) - eng_turbo=eng_turbo+0.4*dt; //0.333 - else - eng_turbo=6.66*(eng_vol-0.8); - - sTurbo.TurnOn(MechInside,GetPosition()); - //sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition()); - sTurbo.UpdateAF(3*eng_turbo-1,0.4+eng_turbo*0.4,MechInside,GetPosition()); - eng_vol_act=eng_vol; - //eng_frq_act=eng_frq; - } - else - { - if (MoverParameters->ConverterFlag) //NBMX dzwiek przetwornicy - sConverter.TurnOn(MechInside,GetPosition()); - else - sConverter.TurnOff(MechInside,GetPosition()); - sConverter.Update(MechInside,GetPosition()); - } - if (MoverParameters->WarningSignal>0) - { - if (TestFlag(MoverParameters->WarningSignal,1)) - sHorn1.TurnOn(MechInside,GetPosition()); - else - sHorn1.TurnOff(MechInside,GetPosition()); - if (TestFlag(MoverParameters->WarningSignal,2)) - sHorn2.TurnOn(MechInside,GetPosition()); - else - sHorn2.TurnOff(MechInside,GetPosition()); - } - else - { - sHorn1.TurnOff(MechInside,GetPosition()); - sHorn2.TurnOff(MechInside,GetPosition()); - } - if (MoverParameters->DoorClosureWarning) - { - if (MoverParameters->DepartureSignal) //NBMX sygnal odjazdu, MC: pod warunkiem ze jest zdefiniowane w chk - sDepartureSignal.TurnOn(MechInside,GetPosition()); - else - sDepartureSignal.TurnOff(MechInside,GetPosition()); - sDepartureSignal.Update(MechInside,GetPosition()); - } - sHorn1.Update(MechInside,GetPosition()); - sHorn2.Update(MechInside,GetPosition()); - //McZapkie: w razie wykolejenia - if (MoverParameters->EventFlag) - { - if (TestFlag(MoverParameters->DamageFlag,dtrain_out) && GetVelocity()>0) - rsDerailment.Play(1,0,true,GetPosition()); - if (GetVelocity()==0) - rsDerailment.Stop(); - } -/* //Ra: dwa razy? - if (MoverParameters->EventFlag) - { - if (TestFlag(MoverParameters->DamageFlag,dtrain_out) && GetVelocity()>0) - rsDerailment.Play(1,0,true,GetPosition()); - if (GetVelocity()==0) - rsDerailment.Stop(); - } -*/ + */ }; void __fastcall TDynamicObject::RenderAlpha() -{//rysowanie elementów półprzezroczystych - if (renderme) - { - TSubModel::iInstance=(int)this; //żeby nie robić cudzych animacji - double ObjSqrDist=SquareMagnitude(Global::pCameraPosition-vPosition); - ABuLittleUpdate(ObjSqrDist); //ustawianie zmiennych submodeli dla wspólnego modelu - glPushMatrix(); - if (this==Global::pUserDynamic) - {//specjalne ustawienie, aby nie trzęsło - if (Global::bSmudge) - {//jak smuga, to rysować po smudze - glPopMatrix(); //to trzeba zebrać przed wyściem - return; - } - glLoadIdentity(); //zacząć od macierzy jedynkowej - Global::pCamera->SetCabMatrix(vPosition); //specjalne ustawienie kamery - } - else - glTranslated(vPosition.x,vPosition.y,vPosition.z); //standardowe przesunięcie względem początku scenerii - glMultMatrixd(mMatrix.getArray()); - if (fShade>0.0) - {//Ra: zmiana oswietlenia w tunelu, wykopie - GLfloat ambientLight[4]= {0.5f,0.5f,0.5f,1.0f}; - GLfloat diffuseLight[4]= {0.5f,0.5f,0.5f,1.0f}; - GLfloat specularLight[4]={0.5f,0.5f,0.5f,1.0f}; - //trochę problem z ambientem w wykopie... - for (int li=0;li<3;li++) - { - ambientLight[li]= Global::ambientDayLight[li]*fShade; - diffuseLight[li]= Global::diffuseDayLight[li]*fShade; - specularLight[li]=Global::specularDayLight[li]*fShade; - } - glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,specularLight); - } - if (Global::bUseVBO) - {//wersja VBO - if (mdLowPolyInt) - if (FreeFlyModeFlag?true:!mdKabina||!bDisplayCab) - mdLowPolyInt->RaRenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha); - mdModel->RaRenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha); - if (mdLoad) - mdLoad->RaRenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha); - //if (mdPrzedsionek) //Ra: przedsionków tu wcześniej nie było - włączyć? - // mdPrzedsionek->RaRenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha); - } - else - {//wersja Display Lists - if (mdLowPolyInt) - if (FreeFlyModeFlag?true:!mdKabina||!bDisplayCab) - mdLowPolyInt->RenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha); - mdModel->RenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha); - if (mdLoad) - mdLoad->RenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha); - //if (mdPrzedsionek) //Ra: przedsionków tu wcześniej nie było - włączyć? - // mdPrzedsionek->RenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha); - } -/* skoro false to można wyciąc - //ABu: Tylko w trybie freefly - if (false)//((mdKabina!=mdModel) && bDisplayCab && FreeFlyModeFlag) +{ // rysowanie elementów półprzezroczystych + if (renderme) { -//oswietlenie kabiny - GLfloat ambientCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; - GLfloat diffuseCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; - GLfloat specularCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; - for (int li=0; li<3; li++) - { - ambientCabLight[li]= Global::ambientDayLight[li]*0.9; - diffuseCabLight[li]= Global::diffuseDayLight[li]*0.5; - specularCabLight[li]= Global::specularDayLight[li]*0.5; - } - switch (MyTrack->eEnvironment) - { - case e_canyon: - { - for (int li=0; li<3; li++) - { - diffuseCabLight[li]*= 0.6; - specularCabLight[li]*= 0.8; - } + TSubModel::iInstance = (int)this; //żeby nie robić cudzych animacji + double ObjSqrDist = SquareMagnitude(Global::pCameraPosition - vPosition); + ABuLittleUpdate(ObjSqrDist); // ustawianie zmiennych submodeli dla wspólnego modelu + glPushMatrix(); + if (this == Global::pUserDynamic) + { // specjalne ustawienie, aby nie trzęsło + if (Global::bSmudge) + { // jak smuga, to rysować po smudze + glPopMatrix(); // to trzeba zebrać przed wyściem + return; + } + glLoadIdentity(); // zacząć od macierzy jedynkowej + Global::pCamera->SetCabMatrix(vPosition); // specjalne ustawienie kamery } - break; - case e_tunnel: - { - for (int li=0; li<3; li++) - { - ambientCabLight[li]*= 0.3; - diffuseCabLight[li]*= 0.1; - specularCabLight[li]*= 0.2; - } + else + glTranslated(vPosition.x, vPosition.y, + vPosition.z); // standardowe przesunięcie względem początku scenerii + glMultMatrixd(mMatrix.getArray()); + if (fShade > 0.0) + { // Ra: zmiana oswietlenia w tunelu, wykopie + GLfloat ambientLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + GLfloat diffuseLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + GLfloat specularLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + // trochę problem z ambientem w wykopie... + for (int li = 0; li < 3; li++) + { + ambientLight[li] = Global::ambientDayLight[li] * fShade; + diffuseLight[li] = Global::diffuseDayLight[li] * fShade; + specularLight[li] = Global::specularDayLight[li] * fShade; + } + glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); } - break; - } -// dorobic swiatlo od drugiej strony szyby + if (Global::bUseVBO) + { // wersja VBO + if (mdLowPolyInt) + if (FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab) + mdLowPolyInt->RaRenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); + mdModel->RaRenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); + if (mdLoad) + mdLoad->RaRenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); + // if (mdPrzedsionek) //Ra: przedsionków tu wcześniej nie było - włączyć? + // mdPrzedsionek->RaRenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha); + } + else + { // wersja Display Lists + if (mdLowPolyInt) + if (FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab) + mdLowPolyInt->RenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); + mdModel->RenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); + if (mdLoad) + mdLoad->RenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha); + // if (mdPrzedsionek) //Ra: przedsionków tu wcześniej nie było - włączyć? + // mdPrzedsionek->RenderAlpha(ObjSqrDist,ReplacableSkinID,iAlpha); + } + /* skoro false to można wyciąc + //ABu: Tylko w trybie freefly + if (false)//((mdKabina!=mdModel) && bDisplayCab && FreeFlyModeFlag) + { + //oswietlenie kabiny + GLfloat ambientCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; + GLfloat diffuseCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; + GLfloat specularCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; + for (int li=0; li<3; li++) + { + ambientCabLight[li]= Global::ambientDayLight[li]*0.9; + diffuseCabLight[li]= Global::diffuseDayLight[li]*0.5; + specularCabLight[li]= Global::specularDayLight[li]*0.5; + } + switch (MyTrack->eEnvironment) + { + case e_canyon: + { + for (int li=0; li<3; li++) + { + diffuseCabLight[li]*= 0.6; + specularCabLight[li]*= 0.8; + } + } + break; + case e_tunnel: + { + for (int li=0; li<3; li++) + { + ambientCabLight[li]*= 0.3; + diffuseCabLight[li]*= 0.1; + specularCabLight[li]*= 0.2; + } + } + break; + } + // dorobic swiatlo od drugiej strony szyby - glLightfv(GL_LIGHT0,GL_AMBIENT,ambientCabLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseCabLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,specularCabLight); + glLightfv(GL_LIGHT0,GL_AMBIENT,ambientCabLight); + glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseCabLight); + glLightfv(GL_LIGHT0,GL_SPECULAR,specularCabLight); - mdKabina->RenderAlpha(ObjSqrDist,0); -//smierdzi -// mdModel->RenderAlpha(SquareMagnitude(Global::pCameraPosition-pos),0); + mdKabina->RenderAlpha(ObjSqrDist,0); + //smierdzi + // mdModel->RenderAlpha(SquareMagnitude(Global::pCameraPosition-pos),0); - glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); + glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); + glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); + glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); + } + */ + if (fShade != 0.0) // tylko jeśli było zmieniane + { // przywrócenie standardowego oświetlenia + glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); + } + glPopMatrix(); + if (btnOn) + TurnOff(); // przywrócenie domyślnych pozycji submodeli } -*/ - if (fShade!=0.0) //tylko jeśli było zmieniane - {//przywrócenie standardowego oświetlenia - glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); - } - glPopMatrix(); - if (btnOn) TurnOff(); //przywrócenie domyślnych pozycji submodeli - } - return; -} //koniec renderalpha + return; +} // koniec renderalpha - -//McZapkie-250202 -//wczytywanie pliku z danymi multimedialnymi (dzwieki) -void __fastcall TDynamicObject::LoadMMediaFile(AnsiString BaseDir,AnsiString TypeName,AnsiString ReplacableSkin) +// McZapkie-250202 +// wczytywanie pliku z danymi multimedialnymi (dzwieki) +void __fastcall TDynamicObject::LoadMMediaFile(AnsiString BaseDir, AnsiString TypeName, + AnsiString ReplacableSkin) { - double dSDist; - TFileStream *fs; - //asBaseDir=BaseDir; - Global::asCurrentDynamicPath=BaseDir; - AnsiString asFileName=BaseDir+TypeName+".mmd"; - AnsiString asLoadName=BaseDir+MoverParameters->LoadType+".t3d"; - if (!FileExists(asFileName)) - { - ErrorLog("Missed file: "+asFileName); //brak MMD - return; - } - fs=new TFileStream(asFileName,fmOpenRead|fmShareCompat); - if (!fs) return; - int size=fs->Size; - if (!size) {return delete fs;}; - AnsiString asAnimName; - bool Stop_InternalData=false; - char* buf=new char[size+1]; //ciąg bajtów o długości równej rozmiwarowi pliku - buf[size]='\0'; //zakończony zerem na wszelki wypadek - fs->Read(buf,size); - delete fs; - TQueryParserComp *Parser; - Parser=new TQueryParserComp(NULL); - Parser->TextToParse=AnsiString(buf); - delete[] buf; - AnsiString str; - //Parser->LoadStringToParse(asFile); - Parser->First(); - //DecimalSeparator= '.'; - pants=NULL; //wskaźnik pierwszego obiektu animującego dla pantografów - int i; - while (!Parser->EndOfFile && !Stop_InternalData) - { - str=Parser->GetNextSymbol().LowerCase(); - if (str==AnsiString("models:")) //modele i podmodele - { - iMultiTex=0; //czy jest wiele tekstur wymiennych? - asModel=Parser->GetNextSymbol().LowerCase(); - if (asModel.Pos("#")==asModel.Length()) //Ra 2015-01: nie podoba mi się to - {//model wymaga wielu tekstur wymiennych - iMultiTex=1; - asModel=asModel.SubString(1,asModel.Length()-1); - } - if ((i=asModel.Pos(","))>0) - {//Ra 2015-01: może szukać przecinka w nazwie modelu, a po przecinku była by liczba tekstur? - if (i1) iMultiTex=1; //na razie ustawiamy na 1 - } - asModel=BaseDir+asModel; //McZapkie 2002-07-20: dynamics maja swoje modele w dynamics/basedir - Global::asCurrentTexturePath=BaseDir; //biezaca sciezka do tekstur to dynamic/... - mdModel=TModelsManager::GetModel(asModel.c_str(),true); - if (ReplacableSkin!=AnsiString("none")) - {//tekstura wymienna jest raczej jedynie w "dynamic\" - ReplacableSkin=Global::asCurrentTexturePath+ReplacableSkin; //skory tez z dynamic/... - if ((i=ReplacableSkin.Pos("|"))>0) //replacable dzielone - {iMultiTex=-1; - ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering); - ReplacableSkin.Delete(1,i); //usunięcie razem z pionową kreską - ReplacableSkin=Global::asCurrentTexturePath+ReplacableSkin; //odtworzenie początku ścieżki - //sprawdzić, ile jest i ustawić iMultiTex na liczbę podanych tekstur - if (!ReplacableSkin.IsEmpty()) - {//próba wycięcia drugiej nazwy - iMultiTex=-2; //skoro zostało coś po kresce, to są co najmniej dwie - if ((i=ReplacableSkin.Pos("|"))==0) //gdy nie ma już kreski - ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering); - else - {//jak jest kreska, to wczytać drugą i próbować trzecią - ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering); - ReplacableSkin.Delete(1,i); //usunięcie razem z pionową kreską - ReplacableSkin=Global::asCurrentTexturePath+ReplacableSkin; //odtworzenie początku ścieżki - if (!ReplacableSkin.IsEmpty()) - {//próba wycięcia trzeciej nazwy - iMultiTex=-3; //skoro zostało coś po kresce, to są co najmniej trzy - if ((i=ReplacableSkin.Pos("|"))==0) //gdy nie ma już kreski - ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering); - else - {//jak jest kreska, to wczytać trzecią i próbować czwartą - ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering); - ReplacableSkin.Delete(1,i); //usunięcie razem z pionową kreską - ReplacableSkin=Global::asCurrentTexturePath+ReplacableSkin; //odtworzenie początku ścieżki - if (!ReplacableSkin.IsEmpty()) - {//próba wycięcia trzeciej nazwy - iMultiTex=-4; //skoro zostało coś po kresce, to są co najmniej cztery - ReplacableSkinID[-iMultiTex]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.SubString(1,i-1).c_str(),Global::iDynamicFiltering); - //więcej na razie nie zadziała, a u tak trzeba to do modeli przenieść - } - } - } - } - } + double dSDist; + TFileStream *fs; + // asBaseDir=BaseDir; + Global::asCurrentDynamicPath = BaseDir; + AnsiString asFileName = BaseDir + TypeName + ".mmd"; + AnsiString asLoadName = BaseDir + MoverParameters->LoadType + ".t3d"; + if (!FileExists(asFileName)) + { + ErrorLog("Missed file: " + asFileName); // brak MMD + return; } - if (iMultiTex>0) - {//jeśli model ma 4 tekstury - ReplacableSkinID[1]=TTexturesManager::GetTextureID(NULL,NULL,(ReplacableSkin+",1").c_str(),Global::iDynamicFiltering); - if (ReplacableSkinID[1]) - {//pierwsza z zestawu znaleziona - ReplacableSkinID[2]=TTexturesManager::GetTextureID(NULL,NULL,(ReplacableSkin+",2").c_str(),Global::iDynamicFiltering); - if (ReplacableSkinID[2]) - {iMultiTex=2; //już są dwie - ReplacableSkinID[3]=TTexturesManager::GetTextureID(NULL,NULL,(ReplacableSkin+",3").c_str(),Global::iDynamicFiltering); - if (ReplacableSkinID[3]) - {iMultiTex=3; //a teraz nawet trzy - ReplacableSkinID[4]=TTexturesManager::GetTextureID(NULL,NULL,(ReplacableSkin+",4").c_str(),Global::iDynamicFiltering); - if (ReplacableSkinID[4]) iMultiTex=4; //jak są cztery, to blokujemy podmianę tekstury rozkładem - } - } - } - else - {//zestaw nie zadziałał, próbujemy normanie - iMultiTex=0; - ReplacableSkinID[1]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.c_str(),Global::iDynamicFiltering); - } + fs = new TFileStream(asFileName, fmOpenRead | fmShareCompat); + if (!fs) + return; + int size = fs->Size; + if (!size) + { + return delete fs; + }; + AnsiString asAnimName; + bool Stop_InternalData = false; + char *buf = new char[size + 1]; // ciąg bajtów o długości równej rozmiwarowi pliku + buf[size] = '\0'; // zakończony zerem na wszelki wypadek + fs->Read(buf, size); + delete fs; + TQueryParserComp *Parser; + Parser = new TQueryParserComp(NULL); + Parser->TextToParse = AnsiString(buf); + delete[] buf; + AnsiString str; + // Parser->LoadStringToParse(asFile); + Parser->First(); + // DecimalSeparator= '.'; + pants = NULL; // wskaźnik pierwszego obiektu animującego dla pantografów + int i; + while (!Parser->EndOfFile && !Stop_InternalData) + { + str = Parser->GetNextSymbol().LowerCase(); + if (str == AnsiString("models:")) // modele i podmodele + { + iMultiTex = 0; // czy jest wiele tekstur wymiennych? + asModel = Parser->GetNextSymbol().LowerCase(); + if (asModel.Pos("#") == asModel.Length()) // Ra 2015-01: nie podoba mi się to + { // model wymaga wielu tekstur wymiennych + iMultiTex = 1; + asModel = asModel.SubString(1, asModel.Length() - 1); + } + if ((i = asModel.Pos(",")) > 0) + { // Ra 2015-01: może szukać przecinka w nazwie modelu, a po przecinku była by liczba + // tekstur? + if (i < asModel.Length()) + iMultiTex = asModel[i + 1] - '0'; + if (iMultiTex < 0) + iMultiTex = 0; + else if (iMultiTex > 1) + iMultiTex = 1; // na razie ustawiamy na 1 + } + asModel = BaseDir + + asModel; // McZapkie 2002-07-20: dynamics maja swoje modele w dynamics/basedir + Global::asCurrentTexturePath = BaseDir; // biezaca sciezka do tekstur to dynamic/... + mdModel = TModelsManager::GetModel(asModel.c_str(), true); + if (ReplacableSkin != AnsiString("none")) + { // tekstura wymienna jest raczej jedynie w "dynamic\" + ReplacableSkin = + Global::asCurrentTexturePath + ReplacableSkin; // skory tez z dynamic/... + if ((i = ReplacableSkin.Pos("|")) > 0) // replacable dzielone + { + iMultiTex = -1; + ReplacableSkinID[-iMultiTex] = TTexturesManager::GetTextureID( + NULL, NULL, ReplacableSkin.SubString(1, i - 1).c_str(), + Global::iDynamicFiltering); + ReplacableSkin.Delete(1, i); // usunięcie razem z pionową kreską + ReplacableSkin = Global::asCurrentTexturePath + + ReplacableSkin; // odtworzenie początku ścieżki + // sprawdzić, ile jest i ustawić iMultiTex na liczbę podanych tekstur + if (!ReplacableSkin.IsEmpty()) + { // próba wycięcia drugiej nazwy + iMultiTex = -2; // skoro zostało coś po kresce, to są co najmniej dwie + if ((i = ReplacableSkin.Pos("|")) == 0) // gdy nie ma już kreski + ReplacableSkinID[-iMultiTex] = TTexturesManager::GetTextureID( + NULL, NULL, ReplacableSkin.SubString(1, i - 1).c_str(), + Global::iDynamicFiltering); + else + { // jak jest kreska, to wczytać drugą i próbować trzecią + ReplacableSkinID[-iMultiTex] = TTexturesManager::GetTextureID( + NULL, NULL, ReplacableSkin.SubString(1, i - 1).c_str(), + Global::iDynamicFiltering); + ReplacableSkin.Delete(1, i); // usunięcie razem z pionową kreską + ReplacableSkin = Global::asCurrentTexturePath + + ReplacableSkin; // odtworzenie początku ścieżki + if (!ReplacableSkin.IsEmpty()) + { // próba wycięcia trzeciej nazwy + iMultiTex = + -3; // skoro zostało coś po kresce, to są co najmniej trzy + if ((i = ReplacableSkin.Pos("|")) == 0) // gdy nie ma już kreski + ReplacableSkinID[-iMultiTex] = TTexturesManager::GetTextureID( + NULL, NULL, ReplacableSkin.SubString(1, i - 1).c_str(), + Global::iDynamicFiltering); + else + { // jak jest kreska, to wczytać trzecią i próbować czwartą + ReplacableSkinID[-iMultiTex] = TTexturesManager::GetTextureID( + NULL, NULL, ReplacableSkin.SubString(1, i - 1).c_str(), + Global::iDynamicFiltering); + ReplacableSkin.Delete(1, i); // usunięcie razem z pionową kreską + ReplacableSkin = Global::asCurrentTexturePath + + ReplacableSkin; // odtworzenie początku ścieżki + if (!ReplacableSkin.IsEmpty()) + { // próba wycięcia trzeciej nazwy + iMultiTex = -4; // skoro zostało coś po kresce, to są co + // najmniej cztery + ReplacableSkinID[-iMultiTex] = + TTexturesManager::GetTextureID( + NULL, NULL, + ReplacableSkin.SubString(1, i - 1).c_str(), + Global::iDynamicFiltering); + // więcej na razie nie zadziała, a u tak trzeba to do modeli + // przenieść + } + } + } + } + } + } + if (iMultiTex > 0) + { // jeśli model ma 4 tekstury + ReplacableSkinID[1] = TTexturesManager::GetTextureID( + NULL, NULL, (ReplacableSkin + ",1").c_str(), Global::iDynamicFiltering); + if (ReplacableSkinID[1]) + { // pierwsza z zestawu znaleziona + ReplacableSkinID[2] = TTexturesManager::GetTextureID( + NULL, NULL, (ReplacableSkin + ",2").c_str(), Global::iDynamicFiltering); + if (ReplacableSkinID[2]) + { + iMultiTex = 2; // już są dwie + ReplacableSkinID[3] = TTexturesManager::GetTextureID( + NULL, NULL, (ReplacableSkin + ",3").c_str(), + Global::iDynamicFiltering); + if (ReplacableSkinID[3]) + { + iMultiTex = 3; // a teraz nawet trzy + ReplacableSkinID[4] = TTexturesManager::GetTextureID( + NULL, NULL, (ReplacableSkin + ",4").c_str(), + Global::iDynamicFiltering); + if (ReplacableSkinID[4]) + iMultiTex = 4; // jak są cztery, to blokujemy podmianę tekstury + // rozkładem + } + } + } + else + { // zestaw nie zadziałał, próbujemy normanie + iMultiTex = 0; + ReplacableSkinID[1] = TTexturesManager::GetTextureID( + NULL, NULL, ReplacableSkin.c_str(), Global::iDynamicFiltering); + } + } + else + ReplacableSkinID[1] = TTexturesManager::GetTextureID( + NULL, NULL, ReplacableSkin.c_str(), Global::iDynamicFiltering); + if (TTexturesManager::GetAlpha(ReplacableSkinID[1])) + iAlpha = 0x31310031; // tekstura -1 z kanałem alfa - nie renderować w cyklu + // nieprzezroczystych + else + iAlpha = 0x30300030; // wszystkie tekstury nieprzezroczyste - nie renderować w + // cyklu przezroczystych + if (ReplacableSkinID[2]) + if (TTexturesManager::GetAlpha(ReplacableSkinID[2])) + iAlpha |= 0x02020002; // tekstura -2 z kanałem alfa - nie renderować w cyklu + // nieprzezroczystych + if (ReplacableSkinID[3]) + if (TTexturesManager::GetAlpha(ReplacableSkinID[3])) + iAlpha |= 0x04040004; // tekstura -3 z kanałem alfa - nie renderować w cyklu + // nieprzezroczystych + if (ReplacableSkinID[4]) + if (TTexturesManager::GetAlpha(ReplacableSkinID[4])) + iAlpha |= 0x08080008; // tekstura -4 z kanałem alfa - nie renderować w cyklu + // nieprzezroczystych + } + // Winger 040304 - ladowanie przedsionkow dla EZT + if (MoverParameters->TrainType == dt_EZT) + { + asModel = "przedsionki.t3d"; + asModel = BaseDir + asModel; + mdPrzedsionek = TModelsManager::GetModel(asModel.c_str(), true); + } + if (!MoverParameters->LoadAccepted.IsEmpty()) + // if (MoverParameters->LoadAccepted!=AnsiString("")); // && + // MoverParameters->LoadType!=AnsiString("passengers")) + if (MoverParameters->EnginePowerSource.SourceType == CurrentCollector) + { // wartość niby "pantstate" - nazwa dla formalności, ważna jest ilość + if (MoverParameters->Load == 1) + MoverParameters->PantFront(true); + else if (MoverParameters->Load == 2) + MoverParameters->PantRear(true); + else if (MoverParameters->Load == 3) + { + MoverParameters->PantFront(true); + MoverParameters->PantRear(true); + } + else if (MoverParameters->Load == 4) + MoverParameters->DoubleTr = -1; + else if (MoverParameters->Load == 5) + { + MoverParameters->DoubleTr = -1; + MoverParameters->PantRear(true); + } + else if (MoverParameters->Load == 6) + { + MoverParameters->DoubleTr = -1; + MoverParameters->PantFront(true); + } + else if (MoverParameters->Load == 7) + { + MoverParameters->DoubleTr = -1; + MoverParameters->PantFront(true); + MoverParameters->PantRear(true); + } + } + else // Ra: tu wczytywanie modelu ładunku jest w porządku + mdLoad = TModelsManager::GetModel(asLoadName.c_str(), true); // ladunek + Global::asCurrentTexturePath = + AnsiString(szTexturePath); // z powrotem defaultowa sciezka do tekstur + while (!Parser->EndOfFile && str != AnsiString("endmodels")) + { + str = Parser->GetNextSymbol().LowerCase(); + if (str == AnsiString("animations:")) + { // Ra: ustawienie ilości poszczególnych animacji - musi być jako pierwsze, inaczej + // ilości będą domyślne + if (!pAnimations) + { // jeśli nie ma jeszcze tabeli animacji, można odczytać nowe ilości + int co = 0, ile; + iAnimations = 0; + do + { // kolejne liczby to ilość animacj, -1 to znacznik końca + ile = Parser->GetNextSymbol().ToIntDef(-1); // ilość danego typu + // animacji + // if (co==ANIM_PANTS) + // if (!Global::bLoadTraction) + // if (!DebugModeFlag) //w debugmode pantografy mają "niby działać" + // ile=0; //wyłączenie animacji pantografów + if (co < ANIM_TYPES) + if (ile >= 0) + { + iAnimType[co] = ile; // zapamiętanie + iAnimations += ile; // ogólna ilość animacji + } + ++co; + } while (ile >= 0); //-1 to znacznik końca + while (co < ANIM_TYPES) + iAnimType[co++] = 0; // zerowanie pozostałych + str = Parser->GetNextSymbol().LowerCase(); + } + // WriteLog("Total animations: "+AnsiString(iAnimations)); + } + if (!pAnimations) + { // Ra: tworzenie tabeli animacji, jeśli jeszcze nie było + if (!iAnimations) // jeśli nie podano jawnie, ile ma być animacji + iAnimations = 28; // tyle było kiedyś w każdym pojeździe (2 wiązary wypadły) + /* //pojazd może mieć pantograf do innych celów niż napęd + if (MoverParameters->EnginePowerSource.SourceType!=CurrentCollector) + {//nie będzie pantografów, to się trochę uprości + iAnimations-=iAnimType[ANIM_PANTS]; //domyślnie były 2 pantografy + iAnimType[ANIM_PANTS]=0; + } + */ + pAnimations = new TAnim[iAnimations]; + int i, j, k = 0, sm = 0; + for (j = 0; j < ANIM_TYPES; ++j) + for (i = 0; i < iAnimType[j]; ++i) + { + if (j == ANIM_PANTS) // zliczamy poprzednie animacje + if (!pants) + if (iAnimType[ANIM_PANTS]) // o ile jakieś pantografy są (a + // domyślnie są) + pants = pAnimations + + k; // zapamiętanie na potrzeby wyszukania submodeli + pAnimations[k].iShift = sm; // przesunięcie do przydzielenia wskaźnika + sm += pAnimations[k++].TypeSet( + j); // ustawienie typu animacji i zliczanie tablicowanych submodeli + } + if (sm) // o ile są bardziej złożone animacje + { + pAnimated = new TSubModel *[sm]; // tabela na animowane submodele + for (k = 0; k < iAnimations; ++k) + pAnimations[k].smElement = + pAnimated + + pAnimations[k].iShift; // przydzielenie wskaźnika do tabelki + } + } + if (str == AnsiString("lowpolyinterior:")) // ABu: wnetrze lowpoly + { + asModel = Parser->GetNextSymbol().LowerCase(); + asModel = + BaseDir + + asModel; // McZapkie-200702 - dynamics maja swoje modele w dynamic/basedir + Global::asCurrentTexturePath = + BaseDir; // biezaca sciezka do tekstur to dynamic/... + mdLowPolyInt = TModelsManager::GetModel(asModel.c_str(), true); + // Global::asCurrentTexturePath=AnsiString(szTexturePath); //kiedyś uproszczone + // wnętrze mieszało tekstury nieba + } + if (str == AnsiString("brakemode:")) + { // Ra 15-01: gałka nastawy hamulca + asAnimName = Parser->GetNextSymbol().LowerCase(); + smBrakeMode = mdModel->GetFromName(asAnimName.c_str()); + // jeszcze wczytać kąty obrotu dla poszczególnych ustawień + } + if (str == AnsiString("loadmode:")) + { // Ra 15-01: gałka nastawy hamulca + asAnimName = Parser->GetNextSymbol().LowerCase(); + smLoadMode = mdModel->GetFromName(asAnimName.c_str()); + // jeszcze wczytać kąty obrotu dla poszczególnych ustawień + } + else if (str == AnsiString("animwheelprefix:")) + { // prefiks kręcących się kół + int i, j, k, m; + str = Parser->GetNextSymbol(); + for (i = 0; i < iAnimType[ANIM_WHEELS]; ++i) // liczba osi + { // McZapkie-050402: wyszukiwanie kol o nazwie str* + asAnimName = str + AnsiString(i + 1); + pAnimations[i].smAnimated = + mdModel->GetFromName(asAnimName.c_str()); // ustalenie submodelu + if (pAnimations[i].smAnimated) + { //++iAnimatedAxles; + pAnimations[i].smAnimated->WillBeAnimated(); // wyłączenie optymalizacji + // transformu + pAnimations[i].yUpdate = UpdateAxle; // animacja osi + pAnimations[i].fMaxDist = + 50 * + MoverParameters->WheelDiameter; // nie kręcić w większej odległości + pAnimations[i].fMaxDist *= + pAnimations[i].fMaxDist * + MoverParameters + ->WheelDiameter; // 50m do kwadratu, a średnica do trzeciej + pAnimations[i].fMaxDist *= Global::fDistanceFactor; // współczynnik + // przeliczeniowy + // jakości ekranu + } + } + // Ra: ustawianie indeksów osi + for (i = 0; i < iAnimType[ANIM_WHEELS]; + ++i) // ilość osi (zabezpieczenie przed błędami w CHK) + pAnimations[i].dWheelAngle = + dWheelAngle + 1; // domyślnie wskaźnik na napędzające + i = 0; + j = 1; + k = 0; + m = 0; // numer osi; kolejny znak; ile osi danego typu; która średnica + if ((MoverParameters->WheelDiameterL != MoverParameters->WheelDiameter) || + (MoverParameters->WheelDiameterT != MoverParameters->WheelDiameter)) + { // obsługa różnych średnic, o ile występują + while ((i < iAnimType[ANIM_WHEELS]) && + (j <= MoverParameters->AxleArangement.Length())) + { // wersja ze wskaźnikami jest bardziej elastyczna na nietypowe układy + if ((k >= 'A') && (k <= 'J')) // 10 chyba maksimum? + { + pAnimations[i++].dWheelAngle = + dWheelAngle + 1; // obrót osi napędzających + --k; // następna będzie albo taka sama, albo bierzemy kolejny znak + m = 2; // następujące toczne będą miały inną średnicę + } + else if ((k >= '1') && (k <= '9')) + { + pAnimations[i++].dWheelAngle = dWheelAngle + m; // obrót osi + // tocznych + --k; // następna będzie albo taka sama, albo bierzemy kolejny znak + } + else + k = MoverParameters->AxleArangement[j++]; // pobranie kolejnego + // znaku + } + } + } + // else if (str==AnsiString("animrodprefix:")) //prefiks wiazarow dwoch + // { + // str= Parser->GetNextSymbol(); + // for (int i=1; i<=2; i++) + // {//McZapkie-050402: wyszukiwanie max 2 wiazarow o nazwie str* + // asAnimName=str+i; + // smWiazary[i-1]=mdModel->GetFromName(asAnimName.c_str()); + // smWiazary[i-1]->WillBeAnimated(); + // } + // } + else if (str == AnsiString("animpantprefix:")) + { // Ra: pantografy po nowemu mają literki i numerki + } + // Pantografy - Winger 160204 + if (str == AnsiString("animpantrd1prefix:")) + { // prefiks ramion dolnych 1 + str = Parser->GetNextSymbol(); + float4x4 m; // macierz do wyliczenia pozycji i wektora ruchu pantografu + TSubModel *sm; + if (pants) + for (int i = 0; i < iAnimType[ANIM_PANTS]; i++) + { // Winger 160204: wyszukiwanie max 2 patykow o nazwie str* + asAnimName = str + AnsiString(i + 1); + sm = mdModel->GetFromName(asAnimName.c_str()); + pants[i].smElement[0] = sm; // jak NULL, to nie będzie animowany + if (sm) + { // w EP09 wywalało się tu z powodu NULL + sm->WillBeAnimated(); + sm->ParentMatrix(&m); // pobranie macierzy transformacji + // m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak) + if ((mdModel->Flags() & 0x8000) == 0) // jeśli wczytano z T3D + m.InitialRotate(); // może być potrzebny dodatkowy obrót, jeśli + // wczytano z T3D, tzn. przed wykonaniem + // Init() + pants[i].fParamPants->vPos.z = + m[3][0]; // przesunięcie w bok (asymetria) + pants[i].fParamPants->vPos.y = + m[3][1]; // przesunięcie w górę odczytane z modelu + if ((sm = pants[i].smElement[0]->ChildGet()) != NULL) + { // jeśli ma potomny, można policzyć długość (odległość potomnego + // od osi obrotu) + m = float4x4(*sm->GetMatrix()); // wystarczyłby wskaźnik, nie + // trzeba kopiować + // może trzeba: pobrać macierz dolnego ramienia, wyzerować + // przesunięcie, przemnożyć przez macierz górnego + pants[i].fParamPants->fHoriz = -fabs(m[3][1]); + pants[i].fParamPants->fLenL1 = + hypot(m[3][1], m[3][2]); // po osi OX nie potrzeba + pants[i].fParamPants->fAngleL0 = + atan2(fabs(m[3][2]), fabs(m[3][1])); + // if (pants[i].fParamPants->fAngleL0fAngleL0+=M_PI; //gdyby w odwrotną + // stronę wyszło + // if + // ((pants[i].fParamPants->fAngleL0<0.03)||(pants[i].fParamPants->fAngleL0>0.09)) + // //normalnie ok. 0.05 + // pants[i].fParamPants->fAngleL0=pants[i].fParamPants->fAngleL; + pants[i].fParamPants->fAngleL = + pants[i].fParamPants->fAngleL0; // początkowy kąt dolnego + // ramienia + if ((sm = sm->ChildGet()) != NULL) + { // jeśli dalej jest ślizg, można policzyć długość górnego + // ramienia + m = float4x4(*sm->GetMatrix()); // wystarczyłby wskaźnik, + // nie trzeba kopiować + // trzeba by uwzględnić macierz dolnego ramienia, żeby + // uzyskać kąt do poziomu... + pants[i].fParamPants->fHoriz += + fabs(m(3)[1]); // różnica długości rzutów ramion na + // płaszczyznę podstawy (jedna dodatnia, + // druga ujemna) + pants[i].fParamPants->fLenU1 = + hypot(m[3][1], m[3][2]); // po osi OX nie potrzeba + // pants[i].fParamPants->pantu=acos((1.22*cos(pants[i].fParamPants->fAngleL)+0.535)/1.755); + // //górne ramię + // pants[i].fParamPants->fAngleU0=acos((1.176289*cos(pants[i].fParamPants->fAngleL)+0.54555075)/1.724482197); + // //górne ramię + pants[i].fParamPants->fAngleU0 = + atan2(fabs(m[3][2]), + fabs(m[3][1])); // początkowy kąt górnego + // ramienia, odczytany z modelu + // if (pants[i].fParamPants->fAngleU0fAngleU0+=M_PI; //gdyby w odwrotną + // stronę wyszło + // if (pants[i].fParamPants->fAngleU0<0) + // pants[i].fParamPants->fAngleU0=-pants[i].fParamPants->fAngleU0; + // if + // ((pants[i].fParamPants->fAngleU0<0.00)||(pants[i].fParamPants->fAngleU0>0.09)) + // //normalnie ok. 0.07 + // pants[i].fParamPants->fAngleU0=acos((pants[i].fParamPants->fLenL1*cos(pants[i].fParamPants->fAngleL)+pants[i].fParamPants->fHoriz)/pants[i].fParamPants->fLenU1); + pants[i].fParamPants->fAngleU = + pants[i].fParamPants->fAngleU0; // początkowy kąt + // Ra: ze względu na to, że niektóre modele pantografów są + // zrąbane, ich mierzenie ma obecnie ograniczony sens + sm->ParentMatrix(&m); // pobranie macierzy transformacji + // pivota ślizgu względem wstawienia + // pojazdu + if ((mdModel->Flags() & 0x8000) == 0) // jeśli wczytano z + // T3D + m.InitialRotate(); // może być potrzebny dodatkowy + // obrót, jeśli wczytano z T3D, tzn. + // przed wykonaniem Init() + float det = Det(m); + if (fabs(det - 1.0) < 0.001) // dopuszczamy 1 promil błędu + // na skalowaniu ślizgu + { // skalowanie jest w normie, można pobrać wymiary z modelu + pants[i].fParamPants->fHeight = + sm->MaxY(m); // przeliczenie maksimum wysokości + // wierzchołków względem macierzy + pants[i].fParamPants->fHeight -= + m[3][1]; // odjęcie wysokości pivota ślizgu + pants[i].fParamPants->vPos.x = + m[3][2]; // przy okazji odczytać z modelu pozycję w + // długości + // ErrorLog("Model OK: "+asModel+", + // height="+pants[i].fParamPants->fHeight); + // ErrorLog("Model OK: "+asModel+", + // pos.x="+pants[i].fParamPants->vPos.x); + } + else + { // gdy ktoś przesadził ze skalowaniem + pants[i].fParamPants->fHeight = + 0.0; // niech będzie odczyt z pantfactors: + ErrorLog("Bad model: " + asModel + ", scale of " + + AnsiString(sm->pName) + " is " + + AnsiString(100.0 * det) + "%"); + } + } + } + } + else + ErrorLog("Bad model: " + asFileName + " - missed submodel " + + asAnimName); // brak ramienia + } + } + else if (str == AnsiString("animpantrd2prefix:")) + { // prefiks ramion dolnych 2 + str = Parser->GetNextSymbol(); + float4x4 m; // macierz do wyliczenia pozycji i wektora ruchu pantografu + TSubModel *sm; + if (pants) + for (int i = 0; i < iAnimType[ANIM_PANTS]; i++) + { // Winger 160204: wyszukiwanie max 2 patykow o nazwie str* + asAnimName = str + AnsiString(i + 1); + sm = mdModel->GetFromName(asAnimName.c_str()); + pants[i].smElement[1] = sm; // jak NULL, to nie będzie animowany + if (sm) + { // w EP09 wywalało się tu z powodu NULL + sm->WillBeAnimated(); + if (pants[i].fParamPants->vPos.y == 0.0) + { // jeśli pierwsze ramię nie ustawiło tej wartości, próbować drugim + //!!!! docelowo zrobić niezależną animację ramion z każdej + //strony + m = float4x4( + *sm->GetMatrix()); // skopiowanie, bo będziemy mnożyć + m(3)[1] = + m[3][1] + 0.054; // w górę o wysokość ślizgu (na razie tak) + while (sm->Parent) + { + if (sm->Parent->GetMatrix()) + m = *sm->Parent->GetMatrix() * m; + sm = sm->Parent; + } + pants[i].fParamPants->vPos.z = + m[3][0]; // przesunięcie w bok (asymetria) + pants[i].fParamPants->vPos.y = + m[3][1]; // przesunięcie w górę odczytane z modelu + } + } + else + ErrorLog("Bad model: " + asFileName + " - missed submodel " + + asAnimName); // brak ramienia + } + } + else if (str == AnsiString("animpantrg1prefix:")) + { // prefiks ramion górnych 1 + str = Parser->GetNextSymbol(); + if (pants) + for (int i = 0; i < iAnimType[ANIM_PANTS]; i++) + { // Winger 160204: wyszukiwanie max 2 patykow o nazwie str* + asAnimName = str + AnsiString(i + 1); + pants[i].smElement[2] = mdModel->GetFromName(asAnimName.c_str()); + pants[i].smElement[2]->WillBeAnimated(); + } + } + else if (str == AnsiString("animpantrg2prefix:")) + { // prefiks ramion górnych 2 + str = Parser->GetNextSymbol(); + if (pants) + for (int i = 0; i < iAnimType[ANIM_PANTS]; i++) + { // Winger 160204: wyszukiwanie max 2 patykow o nazwie str* + asAnimName = str + AnsiString(i + 1); + pants[i].smElement[3] = mdModel->GetFromName(asAnimName.c_str()); + pants[i].smElement[3]->WillBeAnimated(); + } + } + else if (str == AnsiString("animpantslprefix:")) + { // prefiks ślizgaczy + str = Parser->GetNextSymbol(); + if (pants) + for (int i = 0; i < iAnimType[ANIM_PANTS]; i++) + { // Winger 160204: wyszukiwanie max 2 patykow o nazwie str* + asAnimName = str + AnsiString(i + 1); + pants[i].smElement[4] = mdModel->GetFromName(asAnimName.c_str()); + pants[i].smElement[4]->WillBeAnimated(); + pants[i].yUpdate = UpdatePant; + pants[i].fMaxDist = 300 * 300; // nie podnosić w większej odległości + pants[i].iNumber = i; + } + } + else if (str == AnsiString("pantfactors:")) + { // Winger 010304: parametry pantografow + double pant1x = Parser->GetNextSymbol().ToDouble(); + double pant2x = Parser->GetNextSymbol().ToDouble(); + double pant1h = Parser->GetNextSymbol().ToDouble(); // wysokość pierwszego + // ślizgu + double pant2h = Parser->GetNextSymbol().ToDouble(); // wysokość drugiego ślizgu + if (pant1h > 0.5) + pant1h = pant2h; // tu może być zbyt duża wartość + if ((pant1x < 0) && + (pant2x > 0)) // pierwsza powinna być dodatnia, a druga ujemna + { + pant1x = -pant1x; + pant2x = -pant2x; + } + if (pants) + for (int i = 0; i < iAnimType[ANIM_PANTS]; ++i) + { // przepisanie współczynników do pantografów (na razie nie będzie lepiej) + pants[i].fParamPants->fAngleL = + pants[i].fParamPants->fAngleL0; // początkowy kąt dolnego ramienia + pants[i].fParamPants->fAngleU = + pants[i].fParamPants->fAngleU0; // początkowy kąt + // pants[i].fParamPants->PantWys=1.22*sin(pants[i].fParamPants->fAngleL)+1.755*sin(pants[i].fParamPants->fAngleU); + // //wysokość początkowa + // pants[i].fParamPants->PantWys=1.176289*sin(pants[i].fParamPants->fAngleL)+1.724482197*sin(pants[i].fParamPants->fAngleU); + // //wysokość początkowa + if (pants[i].fParamPants->fHeight == + 0.0) // gdy jest nieprawdopodobna wartość (np. nie znaleziony ślizg) + { // gdy pomiary modelu nie udały się, odczyt podanych parametrów z MMD + pants[i].fParamPants->vPos.x = (i & 1) ? pant2x : pant1x; + pants[i].fParamPants->fHeight = + (i & 1) ? pant2h : + pant1h; // wysokość ślizgu jest zapisana w MMD + } + pants[i].fParamPants->PantWys = + pants[i].fParamPants->fLenL1 * sin(pants[i].fParamPants->fAngleL) + + pants[i].fParamPants->fLenU1 * sin(pants[i].fParamPants->fAngleU) + + pants[i].fParamPants->fHeight; // wysokość początkowa + // pants[i].fParamPants->vPos.y=panty-panth-pants[i].fParamPants->PantWys; + // //np. 4.429-0.097=4.332=~4.335 + // pants[i].fParamPants->vPos.z=0; //niezerowe dla pantografów + // asymetrycznych + pants[i].fParamPants->PantTraction = pants[i].fParamPants->PantWys; + pants[i].fParamPants->fWidth = + 0.5 * + MoverParameters->EnginePowerSource.CollectorParameters + .CSW; // połowa szerokości ślizgu; jest w "Power: CSW=" + } + } + else if (str == AnsiString("animpistonprefix:")) + { // prefiks tłoczysk - na razie używamy modeli pantografów + str = Parser->GetNextSymbol(); + for (int i = 1; i <= 2; i++) + { + // asAnimName=str+i; + // smPatykird1[i-1]=mdModel->GetFromName(asAnimName.c_str()); + // smPatykird1[i-1]->WillBeAnimated(); + } + } + else if (str == AnsiString("animconrodprefix:")) + { // prefiks korbowodów - na razie używamy modeli pantografów + str = Parser->GetNextSymbol(); + for (int i = 1; i <= 2; i++) + { + // asAnimName=str+i; + // smPatykirg1[i-1]=mdModel->GetFromName(asAnimName.c_str()); + // smPatykirg1[i-1]->WillBeAnimated(); + } + } + else if (str == AnsiString("pistonfactors:")) + { // Ra: parametry silnika parowego (tłoka) + /* //Ra: tymczasowo wyłączone ze względu na porządkowanie animacji pantografów + pant1x=Parser->GetNextSymbol().ToDouble(); //kąt przesunięcia dla + pierwszego tłoka + pant2x=Parser->GetNextSymbol().ToDouble(); //kąt przesunięcia dla + drugiego tłoka + panty=Parser->GetNextSymbol().ToDouble(); //długość korby (r) + panth=Parser->GetNextSymbol().ToDouble(); //długoś korbowodu (k) + */ + MoverParameters->EnginePowerSource.PowerType = + SteamPower; // Ra: po chamsku, ale z CHK nie działa + } + else if (str == AnsiString("animreturnprefix:")) + { // prefiks drążka mimośrodowego - na razie używamy modeli pantografów + str = Parser->GetNextSymbol(); + for (int i = 1; i <= 2; i++) + { + // asAnimName=str+i; + // smPatykird2[i-1]=mdModel->GetFromName(asAnimName.c_str()); + // smPatykird2[i-1]->WillBeAnimated(); + } + } + else if (str == AnsiString("animexplinkprefix:")) // animreturnprefix: + { // prefiks jarzma - na razie używamy modeli pantografów + str = Parser->GetNextSymbol(); + for (int i = 1; i <= 2; i++) + { + // asAnimName=str+i; + // smPatykirg2[i-1]=mdModel->GetFromName(asAnimName.c_str()); + // smPatykirg2[i-1]->WillBeAnimated(); + } + } + else if (str == AnsiString("animpendulumprefix:")) + { // prefiks wahaczy + str = Parser->GetNextSymbol(); + asAnimName = ""; + for (int i = 1; i <= 4; i++) + { // McZapkie-050402: wyszukiwanie max 4 wahaczy o nazwie str* + asAnimName = str + AnsiString(i); + smWahacze[i - 1] = mdModel->GetFromName(asAnimName.c_str()); + smWahacze[i - 1]->WillBeAnimated(); + } + str = Parser->GetNextSymbol().LowerCase(); + if (str == AnsiString("pendulumamplitude:")) + fWahaczeAmp = Parser->GetNextSymbol().ToDouble(); + } + else if (str == AnsiString("engineer:")) + { // nazwa submodelu maszynisty + str = Parser->GetNextSymbol(); + smMechanik0 = mdModel->GetFromName(str.c_str()); + if (!smMechanik0) + { // jak nie ma bez numerka, to może jest z numerkiem? + smMechanik0 = mdModel->GetFromName(AnsiString(str + "1").c_str()); + smMechanik1 = mdModel->GetFromName(AnsiString(str + "2").c_str()); + } + // aby dało się go obracać, musi mieć włączoną animację w T3D! + // if (!smMechanik1) //jeśli drugiego nie ma + // if (smMechanik0) //a jest pierwszy + // smMechanik0->WillBeAnimated(); //to będziemy go obracać + } + else if (str == AnsiString("animdoorprefix:")) + { // nazwa animowanych drzwi + int i, j, k, m; + str = Parser->GetNextSymbol(); + for (i = 0, j = 0; i < ANIM_DOORS; ++i) + j += iAnimType[i]; // zliczanie wcześniejszych animacji + for (i = 0; i < iAnimType[ANIM_DOORS]; ++i) // liczba drzwi + { // NBMX wrzesien 2003: wyszukiwanie drzwi o nazwie str* + asAnimName = str + AnsiString(i + 1); + pAnimations[i + j].smAnimated = + mdModel->GetFromName(asAnimName.c_str()); // ustalenie submodelu + if (pAnimations[i + j].smAnimated) + { //++iAnimatedDoors; + pAnimations[i + j].smAnimated->WillBeAnimated(); // wyłączenie + // optymalizacji + // transformu + switch (MoverParameters->DoorOpenMethod) + { // od razu zapinamy potrzebny typ animacji + case 1: + pAnimations[i + j].yUpdate = UpdateDoorTranslate; + break; + case 2: + pAnimations[i + j].yUpdate = UpdateDoorRotate; + break; + case 3: + pAnimations[i + j].yUpdate = UpdateDoorFold; + break; // obrót 3 kolejnych submodeli + } + pAnimations[i + j].iNumber = + i; // parzyste działają inaczej niż nieparzyste + pAnimations[i + j].fMaxDist = 300 * 300; // drzwi to z daleka widać + pAnimations[i + j].fSpeed = + random(150); // oryginalny koncept z DoorSpeedFactor + pAnimations[i + j].fSpeed = (pAnimations[i + j].fSpeed + 100) / 100; + // Ra: te współczynniki są bez sensu, bo modyfikują wektor przesunięcia + } + } + } + } + } + else if (str == AnsiString("sounds:")) // dzwieki + while (!Parser->EndOfFile && str != AnsiString("endsounds")) + { + str = Parser->GetNextSymbol().LowerCase(); + if (str == AnsiString("wheel_clatter:")) // polozenia osi w/m srodka pojazdu + { + dSDist = Parser->GetNextSymbol().ToDouble(); + for (int i = 0; i < iAxles; i++) + { + str = Parser->GetNextSymbol(); + dWheelsPosition[i] = str.ToDouble(); + str = Parser->GetNextSymbol().LowerCase(); + if (str != AnsiString("end")) + rsStukot[i].Init(str.c_str(), dSDist, GetPosition().x, + GetPosition().y + dWheelsPosition[i], GetPosition().z, + true); + } + if (str != AnsiString("end")) + str = Parser->GetNextSymbol(); + } + else if ((str == AnsiString("engine:")) && + (MoverParameters->Power > + 0)) // plik z dzwiekiem silnika, mnozniki i ofsety amp. i czest. + { + str = Parser->GetNextSymbol(); + rsSilnik.Init(str.c_str(), Parser->GetNextSymbol().ToDouble(), GetPosition().x, + GetPosition().y, GetPosition().z, true, true); + if (rsSilnik.GetWaveTime() == 0) + ErrorLog("Missed sound: \"" + str + "\" for " + asFileName); + if (MoverParameters->EngineType == DieselEngine) + rsSilnik.AM = Parser->GetNextSymbol().ToDouble() / + (MoverParameters->Power + MoverParameters->nmax * 60); + else if (MoverParameters->EngineType == DieselElectric) + rsSilnik.AM = + Parser->GetNextSymbol().ToDouble() / (MoverParameters->Power * 3); + else + rsSilnik.AM = Parser->GetNextSymbol().ToDouble() / + (MoverParameters->Power + MoverParameters->nmax * 60 + + MoverParameters->Power + MoverParameters->Power); + rsSilnik.AA = Parser->GetNextSymbol().ToDouble(); + rsSilnik.FM = Parser->GetNextSymbol().ToDouble(); // MoverParameters->nmax; + rsSilnik.FA = Parser->GetNextSymbol().ToDouble(); + } + else if (((str == AnsiString("ventilator:")) && + ((MoverParameters->EngineType == ElectricSeriesMotor) || + (MoverParameters->EngineType == + ElectricInductionMotor)))) // plik z dzwiekiem wentylatora, mnozniki i + // ofsety amp. i czest. + { + str = Parser->GetNextSymbol(); + rsWentylator.Init(str.c_str(), Parser->GetNextSymbol().ToDouble(), + GetPosition().x, GetPosition().y, GetPosition().z, true, + true); + rsWentylator.AM = + Parser->GetNextSymbol().ToDouble() / MoverParameters->RVentnmax; + rsWentylator.AA = Parser->GetNextSymbol().ToDouble(); + rsWentylator.FM = + Parser->GetNextSymbol().ToDouble() / MoverParameters->RVentnmax; + rsWentylator.FA = Parser->GetNextSymbol().ToDouble(); + } + else if ((str == AnsiString("transmission:")) && + (MoverParameters->EngineType == + ElectricSeriesMotor)) // plik z dzwiekiem, mnozniki i ofsety amp. i czest. + { + str = Parser->GetNextSymbol(); + rsPrzekladnia.Init(str.c_str(), Parser->GetNextSymbol().ToDouble(), + GetPosition().x, GetPosition().y, GetPosition().z, true); + rsPrzekladnia.AM = 0.029; + rsPrzekladnia.AA = 0.1; + rsPrzekladnia.FM = 0.005; + rsPrzekladnia.FA = 1.0; + } + else if (str == + AnsiString( + "brake:")) // plik z piskiem hamulca, mnozniki i ofsety amplitudy. + { + str = Parser->GetNextSymbol(); + rsPisk.Init(str.c_str(), Parser->GetNextSymbol().ToDouble(), GetPosition().x, + GetPosition().y, GetPosition().z, true); + rsPisk.AM = Parser->GetNextSymbol().ToDouble(); + rsPisk.AA = Parser->GetNextSymbol().ToDouble() * (105 - random(10)) / 100; + rsPisk.FM = 1.0; + rsPisk.FA = 0.0; + } + else if (str == + AnsiString( + "brakeacc:")) // plik z przyspieszaczem (upust po zlapaniu hamowania) + { + str = Parser->GetNextSymbol(); + // sBrakeAcc.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true); + sBrakeAcc = TSoundsManager::GetFromName(str.c_str(), true); + bBrakeAcc = true; + // sBrakeAcc.AM=1.0; + // sBrakeAcc.AA=0.0; + // sBrakeAcc.FM=1.0; + // sBrakeAcc.FA=0.0; + } + else if (str == + AnsiString( + "unbrake:")) // plik z piskiem hamulca, mnozniki i ofsety amplitudy. + { + str = Parser->GetNextSymbol(); + rsUnbrake.Init(str.c_str(), Parser->GetNextSymbol().ToDouble(), GetPosition().x, + GetPosition().y, GetPosition().z, true); + rsUnbrake.AM = 1.0; + rsUnbrake.AA = 0.0; + rsUnbrake.FM = 1.0; + rsUnbrake.FA = 0.0; + } + else if (str == AnsiString("derail:")) // dzwiek przy wykolejeniu + { + str = Parser->GetNextSymbol(); + rsDerailment.Init(str.c_str(), Parser->GetNextSymbol().ToDouble(), + GetPosition().x, GetPosition().y, GetPosition().z, true); + rsDerailment.AM = 1.0; + rsDerailment.AA = 0.0; + rsDerailment.FM = 1.0; + rsDerailment.FA = 0.0; + } + else if (str == AnsiString("dieselinc:")) // dzwiek przy wlazeniu na obroty + // woodwarda + { + str = Parser->GetNextSymbol(); + rsDiesielInc.Init(str.c_str(), Parser->GetNextSymbol().ToDouble(), + GetPosition().x, GetPosition().y, GetPosition().z, true); + rsDiesielInc.AM = 1.0; + rsDiesielInc.AA = 0.0; + rsDiesielInc.FM = 1.0; + rsDiesielInc.FA = 0.0; + } + else if (str == AnsiString("curve:")) + { + str = Parser->GetNextSymbol(); + rscurve.Init(str.c_str(), Parser->GetNextSymbol().ToDouble(), GetPosition().x, + GetPosition().y, GetPosition().z, true); + rscurve.AM = 1.0; + rscurve.AA = 0.0; + rscurve.FM = 1.0; + rscurve.FA = 0.0; + } + else if (str == AnsiString("horn1:")) // pliki z trabieniem + { + sHorn1.Load(Parser, GetPosition()); + } + if (str == AnsiString("horn2:")) // pliki z trabieniem wysokoton. + { + sHorn2.Load(Parser, GetPosition()); + if (iHornWarning) + iHornWarning = 2; // numer syreny do użycia po otrzymaniu sygnału do jazdy + } + if (str == AnsiString("departuresignal:")) // pliki z sygnalem odjazdu + { + sDepartureSignal.Load(Parser, GetPosition()); + } + if (str == AnsiString("pantographup:")) // pliki dzwiekow pantografow + { + str = Parser->GetNextSymbol(); + sPantUp.Init(str.c_str(), 50, GetPosition().x, GetPosition().y, GetPosition().z, + true); + sPantUp.AM = 50000; + sPantUp.AA = -1 * (105 - random(10)) / 100; + sPantUp.FM = 1.0; + sPantUp.FA = 0.0; + } + if (str == AnsiString("pantographdown:")) // pliki dzwiekow pantografow + { + str = Parser->GetNextSymbol(); + sPantDown.Init(str.c_str(), 50, GetPosition().x, GetPosition().y, + GetPosition().z, true); + sPantDown.AM = 50000; + sPantDown.AA = -1 * (105 - random(10)) / 100; + sPantDown.FM = 1.0; + sPantDown.FA = 0.0; + } + else if (str == AnsiString("compressor:")) // pliki ze sprezarka + { + sCompressor.Load(Parser, GetPosition()); + } + else if (str == AnsiString("converter:")) // pliki z przetwornica + { + // if (MoverParameters->EngineType==DieselElectric) //będzie modulowany? + sConverter.Load(Parser, GetPosition()); + } + else if (str == AnsiString("turbo:")) // pliki z turbogeneratorem + { + sTurbo.Load(Parser, GetPosition()); + } + else if (str == AnsiString("small-compressor:")) // pliki z przetwornica + { + sSmallCompressor.Load(Parser, GetPosition()); + } + else if (str == AnsiString("dooropen:")) + { + str = Parser->GetNextSymbol(); + rsDoorOpen.Init(str.c_str(), 50, GetPosition().x, GetPosition().y, + GetPosition().z, true); + rsDoorOpen.AM = 50000; + rsDoorOpen.AA = -1 * (105 - random(10)) / 100; + rsDoorOpen.FM = 1.0; + rsDoorOpen.FA = 0.0; + } + else if (str == AnsiString("doorclose:")) + { + str = Parser->GetNextSymbol(); + rsDoorClose.Init(str.c_str(), 50, GetPosition().x, GetPosition().y, + GetPosition().z, true); + rsDoorClose.AM = 50000; + rsDoorClose.AA = -1 * (105 - random(10)) / 100; + rsDoorClose.FM = 1.0; + rsDoorClose.FA = 0.0; + } + } + else if (str == AnsiString("internaldata:")) // dalej nie czytaj + { + while (!Parser->EndOfFile) + { // zbieranie informacji o kabinach + str = Parser->GetNextSymbol().LowerCase(); + if (str == "cab0model:") + { + str = Parser->GetNextSymbol(); + if (str != "none") + iCabs = 2; + } + else if (str == "cab1model:") + { + str = Parser->GetNextSymbol(); + if (str != "none") + iCabs = 1; + } + else if (str == "cab2model:") + { + str = Parser->GetNextSymbol(); + if (str != "none") + iCabs = 4; + } + } + Stop_InternalData = true; + } } - else - ReplacableSkinID[1]=TTexturesManager::GetTextureID(NULL,NULL,ReplacableSkin.c_str(),Global::iDynamicFiltering); - if (TTexturesManager::GetAlpha(ReplacableSkinID[1])) - iAlpha=0x31310031; //tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych - else - iAlpha=0x30300030; //wszystkie tekstury nieprzezroczyste - nie renderować w cyklu przezroczystych - if (ReplacableSkinID[2]) - if (TTexturesManager::GetAlpha(ReplacableSkinID[2])) - iAlpha|=0x02020002; //tekstura -2 z kanałem alfa - nie renderować w cyklu nieprzezroczystych - if (ReplacableSkinID[3]) - if (TTexturesManager::GetAlpha(ReplacableSkinID[3])) - iAlpha|=0x04040004; //tekstura -3 z kanałem alfa - nie renderować w cyklu nieprzezroczystych - if (ReplacableSkinID[4]) - if (TTexturesManager::GetAlpha(ReplacableSkinID[4])) - iAlpha|=0x08080008; //tekstura -4 z kanałem alfa - nie renderować w cyklu nieprzezroczystych - } - //Winger 040304 - ladowanie przedsionkow dla EZT - if (MoverParameters->TrainType==dt_EZT) - { - asModel="przedsionki.t3d"; - asModel=BaseDir+asModel; - mdPrzedsionek=TModelsManager::GetModel(asModel.c_str(),true); - } - if (!MoverParameters->LoadAccepted.IsEmpty()) - //if (MoverParameters->LoadAccepted!=AnsiString("")); // && MoverParameters->LoadType!=AnsiString("passengers")) - if (MoverParameters->EnginePowerSource.SourceType==CurrentCollector) - {//wartość niby "pantstate" - nazwa dla formalności, ważna jest ilość - if (MoverParameters->Load==1) - MoverParameters->PantFront(true); - else if (MoverParameters->Load==2) - MoverParameters->PantRear(true); - else if (MoverParameters->Load==3) - { - MoverParameters->PantFront(true); - MoverParameters->PantRear(true); - } - else if (MoverParameters->Load==4) - MoverParameters->DoubleTr=-1; - else if (MoverParameters->Load==5) - { - MoverParameters->DoubleTr=-1; - MoverParameters->PantRear(true); - } - else if (MoverParameters->Load==6) - { - MoverParameters->DoubleTr=-1; - MoverParameters->PantFront(true); - } - else if (MoverParameters->Load==7) - { - MoverParameters->DoubleTr=-1; - MoverParameters->PantFront(true); - MoverParameters->PantRear(true); - } - } - else //Ra: tu wczytywanie modelu ładunku jest w porządku - mdLoad=TModelsManager::GetModel(asLoadName.c_str(),true); //ladunek - Global::asCurrentTexturePath=AnsiString(szTexturePath); //z powrotem defaultowa sciezka do tekstur - while (!Parser->EndOfFile && str!=AnsiString("endmodels")) - { - str=Parser->GetNextSymbol().LowerCase(); - if (str==AnsiString("animations:")) - {//Ra: ustawienie ilości poszczególnych animacji - musi być jako pierwsze, inaczej ilości będą domyślne - if (!pAnimations) - {//jeśli nie ma jeszcze tabeli animacji, można odczytać nowe ilości - int co=0,ile; - iAnimations=0; - do - {//kolejne liczby to ilość animacj, -1 to znacznik końca - ile=Parser->GetNextSymbol().ToIntDef(-1); //ilość danego typu animacji - //if (co==ANIM_PANTS) - // if (!Global::bLoadTraction) - // if (!DebugModeFlag) //w debugmode pantografy mają "niby działać" - // ile=0; //wyłączenie animacji pantografów - if (co=0) - {iAnimType[co]=ile; //zapamiętanie - iAnimations+=ile; //ogólna ilość animacji - } - ++co; - } while (ile>=0); //-1 to znacznik końca - while (coGetNextSymbol().LowerCase(); - } - //WriteLog("Total animations: "+AnsiString(iAnimations)); - } - if (!pAnimations) - {//Ra: tworzenie tabeli animacji, jeśli jeszcze nie było - if (!iAnimations) //jeśli nie podano jawnie, ile ma być animacji - iAnimations=28; //tyle było kiedyś w każdym pojeździe (2 wiązary wypadły) - /* //pojazd może mieć pantograf do innych celów niż napęd - if (MoverParameters->EnginePowerSource.SourceType!=CurrentCollector) - {//nie będzie pantografów, to się trochę uprości - iAnimations-=iAnimType[ANIM_PANTS]; //domyślnie były 2 pantografy - iAnimType[ANIM_PANTS]=0; - } - */ - pAnimations=new TAnim[iAnimations]; - int i,j,k=0,sm=0; - for (j=0;jGetNextSymbol().LowerCase(); - asModel=BaseDir+asModel; //McZapkie-200702 - dynamics maja swoje modele w dynamic/basedir - Global::asCurrentTexturePath=BaseDir; //biezaca sciezka do tekstur to dynamic/... - mdLowPolyInt=TModelsManager::GetModel(asModel.c_str(),true); - //Global::asCurrentTexturePath=AnsiString(szTexturePath); //kiedyś uproszczone wnętrze mieszało tekstury nieba - } - if (str==AnsiString("brakemode:")) - {//Ra 15-01: gałka nastawy hamulca - asAnimName=Parser->GetNextSymbol().LowerCase(); - smBrakeMode=mdModel->GetFromName(asAnimName.c_str()); - //jeszcze wczytać kąty obrotu dla poszczególnych ustawień - } - if (str==AnsiString("loadmode:")) - {//Ra 15-01: gałka nastawy hamulca - asAnimName=Parser->GetNextSymbol().LowerCase(); - smLoadMode=mdModel->GetFromName(asAnimName.c_str()); - //jeszcze wczytać kąty obrotu dla poszczególnych ustawień - } - else if (str==AnsiString("animwheelprefix:")) - {//prefiks kręcących się kół - int i,j,k,m; - str=Parser->GetNextSymbol(); - for (i=0;iGetFromName(asAnimName.c_str()); //ustalenie submodelu - if (pAnimations[i].smAnimated) - {//++iAnimatedAxles; - pAnimations[i].smAnimated->WillBeAnimated(); //wyłączenie optymalizacji transformu - pAnimations[i].yUpdate=UpdateAxle; //animacja osi - pAnimations[i].fMaxDist=50*MoverParameters->WheelDiameter; //nie kręcić w większej odległości - pAnimations[i].fMaxDist*=pAnimations[i].fMaxDist*MoverParameters->WheelDiameter; //50m do kwadratu, a średnica do trzeciej - pAnimations[i].fMaxDist*=Global::fDistanceFactor; //współczynnik przeliczeniowy jakości ekranu - } - } - //Ra: ustawianie indeksów osi - for (i=0;iWheelDiameterL!=MoverParameters->WheelDiameter)||(MoverParameters->WheelDiameterT!=MoverParameters->WheelDiameter)) - {//obsługa różnych średnic, o ile występują - while ((iAxleArangement.Length())) - {//wersja ze wskaźnikami jest bardziej elastyczna na nietypowe układy - if ((k>='A')&&(k<='J')) //10 chyba maksimum? - {pAnimations[i++].dWheelAngle=dWheelAngle+1; //obrót osi napędzających - --k; //następna będzie albo taka sama, albo bierzemy kolejny znak - m=2; //następujące toczne będą miały inną średnicę - } - else if ((k>='1')&&(k<='9')) - {pAnimations[i++].dWheelAngle=dWheelAngle+m; //obrót osi tocznych - --k; //następna będzie albo taka sama, albo bierzemy kolejny znak - } - else - k=MoverParameters->AxleArangement[j++]; //pobranie kolejnego znaku - } - } - } - //else if (str==AnsiString("animrodprefix:")) //prefiks wiazarow dwoch - // { - // str= Parser->GetNextSymbol(); - // for (int i=1; i<=2; i++) - // {//McZapkie-050402: wyszukiwanie max 2 wiazarow o nazwie str* - // asAnimName=str+i; - // smWiazary[i-1]=mdModel->GetFromName(asAnimName.c_str()); - // smWiazary[i-1]->WillBeAnimated(); - // } - // } - else if (str==AnsiString("animpantprefix:")) - {//Ra: pantografy po nowemu mają literki i numerki - } -//Pantografy - Winger 160204 - if (str==AnsiString("animpantrd1prefix:")) - {//prefiks ramion dolnych 1 - str=Parser->GetNextSymbol(); - float4x4 m; //macierz do wyliczenia pozycji i wektora ruchu pantografu - TSubModel *sm; - if (pants) - for (int i=0;iGetFromName(asAnimName.c_str()); - pants[i].smElement[0]=sm; //jak NULL, to nie będzie animowany - if (sm) - {//w EP09 wywalało się tu z powodu NULL - sm->WillBeAnimated(); - sm->ParentMatrix(&m); //pobranie macierzy transformacji - //m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak) - if ((mdModel->Flags()&0x8000)==0) //jeśli wczytano z T3D - m.InitialRotate(); //może być potrzebny dodatkowy obrót, jeśli wczytano z T3D, tzn. przed wykonaniem Init() - pants[i].fParamPants->vPos.z=m[3][0]; //przesunięcie w bok (asymetria) - pants[i].fParamPants->vPos.y=m[3][1]; //przesunięcie w górę odczytane z modelu - if ((sm=pants[i].smElement[0]->ChildGet())!=NULL) - {//jeśli ma potomny, można policzyć długość (odległość potomnego od osi obrotu) - m=float4x4(*sm->GetMatrix()); //wystarczyłby wskaźnik, nie trzeba kopiować - //może trzeba: pobrać macierz dolnego ramienia, wyzerować przesunięcie, przemnożyć przez macierz górnego - pants[i].fParamPants->fHoriz=-fabs(m[3][1]); - pants[i].fParamPants->fLenL1=hypot(m[3][1],m[3][2]); //po osi OX nie potrzeba - pants[i].fParamPants->fAngleL0=atan2(fabs(m[3][2]),fabs(m[3][1])); - //if (pants[i].fParamPants->fAngleL0fAngleL0+=M_PI; //gdyby w odwrotną stronę wyszło - //if ((pants[i].fParamPants->fAngleL0<0.03)||(pants[i].fParamPants->fAngleL0>0.09)) //normalnie ok. 0.05 - // pants[i].fParamPants->fAngleL0=pants[i].fParamPants->fAngleL; - pants[i].fParamPants->fAngleL=pants[i].fParamPants->fAngleL0; //początkowy kąt dolnego ramienia - if ((sm=sm->ChildGet())!=NULL) - {//jeśli dalej jest ślizg, można policzyć długość górnego ramienia - m=float4x4(*sm->GetMatrix()); //wystarczyłby wskaźnik, nie trzeba kopiować - //trzeba by uwzględnić macierz dolnego ramienia, żeby uzyskać kąt do poziomu... - pants[i].fParamPants->fHoriz+=fabs(m(3)[1]); //różnica długości rzutów ramion na płaszczyznę podstawy (jedna dodatnia, druga ujemna) - pants[i].fParamPants->fLenU1=hypot(m[3][1],m[3][2]); //po osi OX nie potrzeba - //pants[i].fParamPants->pantu=acos((1.22*cos(pants[i].fParamPants->fAngleL)+0.535)/1.755); //górne ramię - //pants[i].fParamPants->fAngleU0=acos((1.176289*cos(pants[i].fParamPants->fAngleL)+0.54555075)/1.724482197); //górne ramię - pants[i].fParamPants->fAngleU0=atan2(fabs(m[3][2]),fabs(m[3][1])); //początkowy kąt górnego ramienia, odczytany z modelu - //if (pants[i].fParamPants->fAngleU0fAngleU0+=M_PI; //gdyby w odwrotną stronę wyszło - //if (pants[i].fParamPants->fAngleU0<0) - // pants[i].fParamPants->fAngleU0=-pants[i].fParamPants->fAngleU0; - //if ((pants[i].fParamPants->fAngleU0<0.00)||(pants[i].fParamPants->fAngleU0>0.09)) //normalnie ok. 0.07 - // pants[i].fParamPants->fAngleU0=acos((pants[i].fParamPants->fLenL1*cos(pants[i].fParamPants->fAngleL)+pants[i].fParamPants->fHoriz)/pants[i].fParamPants->fLenU1); - pants[i].fParamPants->fAngleU=pants[i].fParamPants->fAngleU0; //początkowy kąt - //Ra: ze względu na to, że niektóre modele pantografów są zrąbane, ich mierzenie ma obecnie ograniczony sens - sm->ParentMatrix(&m); //pobranie macierzy transformacji pivota ślizgu względem wstawienia pojazdu - if ((mdModel->Flags()&0x8000)==0) //jeśli wczytano z T3D - m.InitialRotate(); //może być potrzebny dodatkowy obrót, jeśli wczytano z T3D, tzn. przed wykonaniem Init() - float det=Det(m); - if (fabs(det-1.0)<0.001) //dopuszczamy 1 promil błędu na skalowaniu ślizgu - {//skalowanie jest w normie, można pobrać wymiary z modelu - pants[i].fParamPants->fHeight=sm->MaxY(m); //przeliczenie maksimum wysokości wierzchołków względem macierzy - pants[i].fParamPants->fHeight-=m[3][1]; //odjęcie wysokości pivota ślizgu - pants[i].fParamPants->vPos.x=m[3][2]; //przy okazji odczytać z modelu pozycję w długości - //ErrorLog("Model OK: "+asModel+", height="+pants[i].fParamPants->fHeight); - //ErrorLog("Model OK: "+asModel+", pos.x="+pants[i].fParamPants->vPos.x); - } - else - {//gdy ktoś przesadził ze skalowaniem - pants[i].fParamPants->fHeight=0.0; //niech będzie odczyt z pantfactors: - ErrorLog("Bad model: "+asModel+", scale of "+AnsiString(sm->pName)+" is "+AnsiString(100.0*det)+"%"); - } - } - } - } - else - ErrorLog("Bad model: "+asFileName+" - missed submodel "+asAnimName); //brak ramienia - } - } - else if (str==AnsiString("animpantrd2prefix:")) - {//prefiks ramion dolnych 2 - str=Parser->GetNextSymbol(); - float4x4 m; //macierz do wyliczenia pozycji i wektora ruchu pantografu - TSubModel *sm; - if (pants) - for (int i=0;iGetFromName(asAnimName.c_str()); - pants[i].smElement[1]=sm; //jak NULL, to nie będzie animowany - if (sm) - {//w EP09 wywalało się tu z powodu NULL - sm->WillBeAnimated(); - if (pants[i].fParamPants->vPos.y==0.0) - {//jeśli pierwsze ramię nie ustawiło tej wartości, próbować drugim - //!!!! docelowo zrobić niezależną animację ramion z każdej strony - m=float4x4(*sm->GetMatrix()); //skopiowanie, bo będziemy mnożyć - m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak) - while (sm->Parent) - { - if (sm->Parent->GetMatrix()) - m=*sm->Parent->GetMatrix()*m; - sm=sm->Parent; - } - pants[i].fParamPants->vPos.z=m[3][0]; //przesunięcie w bok (asymetria) - pants[i].fParamPants->vPos.y=m[3][1]; //przesunięcie w górę odczytane z modelu - } - } - else - ErrorLog("Bad model: "+asFileName+" - missed submodel "+asAnimName); //brak ramienia - } - } - else if (str==AnsiString("animpantrg1prefix:")) - {//prefiks ramion górnych 1 - str=Parser->GetNextSymbol(); - if (pants) - for (int i=0;iGetFromName(asAnimName.c_str()); - pants[i].smElement[2]->WillBeAnimated(); - } - } - else - if (str==AnsiString("animpantrg2prefix:")) - {//prefiks ramion górnych 2 - str=Parser->GetNextSymbol(); - if (pants) - for (int i=0;iGetFromName(asAnimName.c_str()); - pants[i].smElement[3]->WillBeAnimated(); - } - } - else if (str==AnsiString("animpantslprefix:")) - {//prefiks ślizgaczy - str=Parser->GetNextSymbol(); - if (pants) - for (int i=0;iGetFromName(asAnimName.c_str()); - pants[i].smElement[4]->WillBeAnimated(); - pants[i].yUpdate=UpdatePant; - pants[i].fMaxDist=300*300; //nie podnosić w większej odległości - pants[i].iNumber=i; - } - } - else if (str==AnsiString("pantfactors:")) - {//Winger 010304: parametry pantografow - double pant1x=Parser->GetNextSymbol().ToDouble(); - double pant2x=Parser->GetNextSymbol().ToDouble(); - double pant1h=Parser->GetNextSymbol().ToDouble(); //wysokość pierwszego ślizgu - double pant2h=Parser->GetNextSymbol().ToDouble(); //wysokość drugiego ślizgu - if (pant1h>0.5) pant1h=pant2h; //tu może być zbyt duża wartość - if ((pant1x<0)&&(pant2x>0)) //pierwsza powinna być dodatnia, a druga ujemna - {pant1x=-pant1x; pant2x=-pant2x;} - if (pants) - for (int i=0;ifAngleL=pants[i].fParamPants->fAngleL0; //początkowy kąt dolnego ramienia - pants[i].fParamPants->fAngleU=pants[i].fParamPants->fAngleU0; //początkowy kąt - //pants[i].fParamPants->PantWys=1.22*sin(pants[i].fParamPants->fAngleL)+1.755*sin(pants[i].fParamPants->fAngleU); //wysokość początkowa - //pants[i].fParamPants->PantWys=1.176289*sin(pants[i].fParamPants->fAngleL)+1.724482197*sin(pants[i].fParamPants->fAngleU); //wysokość początkowa - if (pants[i].fParamPants->fHeight==0.0) //gdy jest nieprawdopodobna wartość (np. nie znaleziony ślizg) - {//gdy pomiary modelu nie udały się, odczyt podanych parametrów z MMD - pants[i].fParamPants->vPos.x=(i&1)?pant2x:pant1x; - pants[i].fParamPants->fHeight=(i&1)?pant2h:pant1h; //wysokość ślizgu jest zapisana w MMD - } - pants[i].fParamPants->PantWys=pants[i].fParamPants->fLenL1*sin(pants[i].fParamPants->fAngleL)+pants[i].fParamPants->fLenU1*sin(pants[i].fParamPants->fAngleU)+pants[i].fParamPants->fHeight; //wysokość początkowa - //pants[i].fParamPants->vPos.y=panty-panth-pants[i].fParamPants->PantWys; //np. 4.429-0.097=4.332=~4.335 - //pants[i].fParamPants->vPos.z=0; //niezerowe dla pantografów asymetrycznych - pants[i].fParamPants->PantTraction=pants[i].fParamPants->PantWys; - pants[i].fParamPants->fWidth=0.5*MoverParameters->EnginePowerSource.CollectorParameters.CSW; //połowa szerokości ślizgu; jest w "Power: CSW=" - } - } - else if (str==AnsiString("animpistonprefix:")) - {//prefiks tłoczysk - na razie używamy modeli pantografów - str=Parser->GetNextSymbol(); - for (int i=1;i<=2;i++) - { - //asAnimName=str+i; - //smPatykird1[i-1]=mdModel->GetFromName(asAnimName.c_str()); - //smPatykird1[i-1]->WillBeAnimated(); - } - } - else if (str==AnsiString("animconrodprefix:")) - {//prefiks korbowodów - na razie używamy modeli pantografów - str=Parser->GetNextSymbol(); - for (int i=1;i<=2;i++) - { - //asAnimName=str+i; - //smPatykirg1[i-1]=mdModel->GetFromName(asAnimName.c_str()); - //smPatykirg1[i-1]->WillBeAnimated(); - } - } - else if (str==AnsiString("pistonfactors:")) - {//Ra: parametry silnika parowego (tłoka) -/* //Ra: tymczasowo wyłączone ze względu na porządkowanie animacji pantografów - pant1x=Parser->GetNextSymbol().ToDouble(); //kąt przesunięcia dla pierwszego tłoka - pant2x=Parser->GetNextSymbol().ToDouble(); //kąt przesunięcia dla drugiego tłoka - panty=Parser->GetNextSymbol().ToDouble(); //długość korby (r) - panth=Parser->GetNextSymbol().ToDouble(); //długoś korbowodu (k) -*/ - MoverParameters->EnginePowerSource.PowerType=SteamPower; //Ra: po chamsku, ale z CHK nie działa - } - else if (str==AnsiString("animreturnprefix:")) - {//prefiks drążka mimośrodowego - na razie używamy modeli pantografów - str=Parser->GetNextSymbol(); - for (int i=1;i<=2;i++) - { - //asAnimName=str+i; - //smPatykird2[i-1]=mdModel->GetFromName(asAnimName.c_str()); - //smPatykird2[i-1]->WillBeAnimated(); - } - } - else if (str==AnsiString("animexplinkprefix:")) //animreturnprefix: - {//prefiks jarzma - na razie używamy modeli pantografów - str=Parser->GetNextSymbol(); - for (int i=1;i<=2;i++) - { - //asAnimName=str+i; - //smPatykirg2[i-1]=mdModel->GetFromName(asAnimName.c_str()); - //smPatykirg2[i-1]->WillBeAnimated(); - } - } - else if (str==AnsiString("animpendulumprefix:")) - {//prefiks wahaczy - str=Parser->GetNextSymbol(); - asAnimName=""; - for (int i=1; i<=4; i++) - {//McZapkie-050402: wyszukiwanie max 4 wahaczy o nazwie str* - asAnimName=str+AnsiString(i); - smWahacze[i-1]=mdModel->GetFromName(asAnimName.c_str()); - smWahacze[i-1]->WillBeAnimated(); - } - str=Parser->GetNextSymbol().LowerCase(); - if (str==AnsiString("pendulumamplitude:")) - fWahaczeAmp=Parser->GetNextSymbol().ToDouble(); - } - else - if (str==AnsiString("engineer:")) - {//nazwa submodelu maszynisty - str=Parser->GetNextSymbol(); - smMechanik0=mdModel->GetFromName(str.c_str()); - if (!smMechanik0) - {//jak nie ma bez numerka, to może jest z numerkiem? - smMechanik0=mdModel->GetFromName(AnsiString(str+"1").c_str()); - smMechanik1=mdModel->GetFromName(AnsiString(str+"2").c_str()); - } - //aby dało się go obracać, musi mieć włączoną animację w T3D! - //if (!smMechanik1) //jeśli drugiego nie ma - // if (smMechanik0) //a jest pierwszy - // smMechanik0->WillBeAnimated(); //to będziemy go obracać - } - else if (str==AnsiString("animdoorprefix:")) - {//nazwa animowanych drzwi - int i,j,k,m; - str=Parser->GetNextSymbol(); - for (i=0,j=0;iGetFromName(asAnimName.c_str()); //ustalenie submodelu - if (pAnimations[i+j].smAnimated) - {//++iAnimatedDoors; - pAnimations[i+j].smAnimated->WillBeAnimated(); //wyłączenie optymalizacji transformu - switch (MoverParameters->DoorOpenMethod) - {//od razu zapinamy potrzebny typ animacji - case 1: pAnimations[i+j].yUpdate=UpdateDoorTranslate; break; - case 2: pAnimations[i+j].yUpdate=UpdateDoorRotate; break; - case 3: pAnimations[i+j].yUpdate=UpdateDoorFold; break; //obrót 3 kolejnych submodeli - } - pAnimations[i+j].iNumber=i; //parzyste działają inaczej niż nieparzyste - pAnimations[i+j].fMaxDist=300*300; //drzwi to z daleka widać - pAnimations[i+j].fSpeed=random(150); //oryginalny koncept z DoorSpeedFactor - pAnimations[i+j].fSpeed=(pAnimations[i+j].fSpeed+100)/100; - //Ra: te współczynniki są bez sensu, bo modyfikują wektor przesunięcia - } - } - } - } - } - else - if (str==AnsiString("sounds:")) //dzwieki - while (!Parser->EndOfFile && str!=AnsiString("endsounds")) - { - str= Parser->GetNextSymbol().LowerCase(); - if (str==AnsiString("wheel_clatter:")) //polozenia osi w/m srodka pojazdu - { - dSDist=Parser->GetNextSymbol().ToDouble(); - for (int i=0; iGetNextSymbol(); - dWheelsPosition[i]=str.ToDouble(); - str= Parser->GetNextSymbol().LowerCase(); - if (str!=AnsiString("end")) - rsStukot[i].Init(str.c_str(),dSDist,GetPosition().x,GetPosition().y+dWheelsPosition[i],GetPosition().z,true); - } - if (str!=AnsiString("end")) - str= Parser->GetNextSymbol(); - } - else - if ((str==AnsiString("engine:")) && (MoverParameters->Power>0)) //plik z dzwiekiem silnika, mnozniki i ofsety amp. i czest. - { - str= Parser->GetNextSymbol(); - rsSilnik.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true,true); - if (rsSilnik.GetWaveTime()==0) - ErrorLog("Missed sound: \""+str+"\" for "+asFileName); - if (MoverParameters->EngineType==DieselEngine) - rsSilnik.AM=Parser->GetNextSymbol().ToDouble()/(MoverParameters->Power+MoverParameters->nmax*60); - else if (MoverParameters->EngineType==DieselElectric) - rsSilnik.AM=Parser->GetNextSymbol().ToDouble()/(MoverParameters->Power*3); - else - rsSilnik.AM=Parser->GetNextSymbol().ToDouble()/(MoverParameters->Power+MoverParameters->nmax*60+MoverParameters->Power+MoverParameters->Power); - rsSilnik.AA=Parser->GetNextSymbol().ToDouble(); - rsSilnik.FM=Parser->GetNextSymbol().ToDouble();//MoverParameters->nmax; - rsSilnik.FA=Parser->GetNextSymbol().ToDouble(); - } - else - if (((str==AnsiString("ventilator:")) && ((MoverParameters->EngineType==ElectricSeriesMotor)||(MoverParameters->EngineType==ElectricInductionMotor)))) //plik z dzwiekiem wentylatora, mnozniki i ofsety amp. i czest. - { - str= Parser->GetNextSymbol(); - rsWentylator.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true,true); - rsWentylator.AM=Parser->GetNextSymbol().ToDouble()/MoverParameters->RVentnmax; - rsWentylator.AA=Parser->GetNextSymbol().ToDouble(); - rsWentylator.FM=Parser->GetNextSymbol().ToDouble()/MoverParameters->RVentnmax; - rsWentylator.FA=Parser->GetNextSymbol().ToDouble(); - } - else - if ((str==AnsiString("transmission:")) && (MoverParameters->EngineType==ElectricSeriesMotor)) //plik z dzwiekiem, mnozniki i ofsety amp. i czest. - { - str= Parser->GetNextSymbol(); - rsPrzekladnia.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true); - rsPrzekladnia.AM=0.029; - rsPrzekladnia.AA=0.1; - rsPrzekladnia.FM=0.005; - rsPrzekladnia.FA=1.0; - } - else - if (str==AnsiString("brake:")) //plik z piskiem hamulca, mnozniki i ofsety amplitudy. - { - str= Parser->GetNextSymbol(); - rsPisk.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true); - rsPisk.AM=Parser->GetNextSymbol().ToDouble(); - rsPisk.AA=Parser->GetNextSymbol().ToDouble()*(105-random(10))/100; - rsPisk.FM=1.0; - rsPisk.FA=0.0; - } - else - if (str==AnsiString("brakeacc:")) //plik z przyspieszaczem (upust po zlapaniu hamowania) - { - str= Parser->GetNextSymbol(); -// sBrakeAcc.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true); - sBrakeAcc=TSoundsManager::GetFromName(str.c_str(),true); - bBrakeAcc=true; -// sBrakeAcc.AM=1.0; -// sBrakeAcc.AA=0.0; -// sBrakeAcc.FM=1.0; -// sBrakeAcc.FA=0.0; - } - else - if (str==AnsiString("unbrake:")) //plik z piskiem hamulca, mnozniki i ofsety amplitudy. - { - str= Parser->GetNextSymbol(); - rsUnbrake.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true); - rsUnbrake.AM=1.0; - rsUnbrake.AA=0.0; - rsUnbrake.FM=1.0; - rsUnbrake.FA=0.0; - } - else - if (str==AnsiString("derail:")) //dzwiek przy wykolejeniu - { - str= Parser->GetNextSymbol(); - rsDerailment.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true); - rsDerailment.AM=1.0; - rsDerailment.AA=0.0; - rsDerailment.FM=1.0; - rsDerailment.FA=0.0; - } - else - if (str==AnsiString("dieselinc:")) //dzwiek przy wlazeniu na obroty woodwarda - { - str= Parser->GetNextSymbol(); - rsDiesielInc.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true); - rsDiesielInc.AM=1.0; - rsDiesielInc.AA=0.0; - rsDiesielInc.FM=1.0; - rsDiesielInc.FA=0.0; - } - else - if (str==AnsiString("curve:")) - { - str= Parser->GetNextSymbol(); - rscurve.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true); - rscurve.AM=1.0; - rscurve.AA=0.0; - rscurve.FM=1.0; - rscurve.FA=0.0; - } - else - if (str==AnsiString("horn1:")) //pliki z trabieniem - { - sHorn1.Load(Parser,GetPosition()); - } - if (str==AnsiString("horn2:")) //pliki z trabieniem wysokoton. - { - sHorn2.Load(Parser,GetPosition()); - if (iHornWarning) iHornWarning=2; //numer syreny do użycia po otrzymaniu sygnału do jazdy - } - if (str==AnsiString("departuresignal:")) //pliki z sygnalem odjazdu - { - sDepartureSignal.Load(Parser,GetPosition()); - } - if (str==AnsiString("pantographup:")) //pliki dzwiekow pantografow - { - str=Parser->GetNextSymbol(); - sPantUp.Init(str.c_str(),50,GetPosition().x,GetPosition().y,GetPosition().z,true); - sPantUp.AM=50000; - sPantUp.AA=-1*(105-random(10))/100; - sPantUp.FM=1.0; - sPantUp.FA=0.0; - } - if (str==AnsiString("pantographdown:")) //pliki dzwiekow pantografow - { - str= Parser->GetNextSymbol(); - sPantDown.Init(str.c_str(),50,GetPosition().x,GetPosition().y,GetPosition().z,true); - sPantDown.AM=50000; - sPantDown.AA=-1*(105-random(10))/100; - sPantDown.FM=1.0; - sPantDown.FA=0.0; - } - else if (str==AnsiString("compressor:")) //pliki ze sprezarka - { - sCompressor.Load(Parser,GetPosition()); - } - else if (str==AnsiString("converter:")) //pliki z przetwornica - { - //if (MoverParameters->EngineType==DieselElectric) //będzie modulowany? - sConverter.Load(Parser,GetPosition()); - } - else if (str==AnsiString("turbo:")) //pliki z turbogeneratorem - { - sTurbo.Load(Parser,GetPosition()); - } - else if (str==AnsiString("small-compressor:")) //pliki z przetwornica - { - sSmallCompressor.Load(Parser,GetPosition()); - } - else if (str==AnsiString("dooropen:")) - { - str=Parser->GetNextSymbol(); - rsDoorOpen.Init(str.c_str(),50,GetPosition().x,GetPosition().y,GetPosition().z,true); - rsDoorOpen.AM=50000; - rsDoorOpen.AA=-1*(105-random(10))/100; - rsDoorOpen.FM=1.0; - rsDoorOpen.FA=0.0; - } - else if (str==AnsiString("doorclose:")) - { - str=Parser->GetNextSymbol(); - rsDoorClose.Init(str.c_str(),50,GetPosition().x,GetPosition().y,GetPosition().z,true); - rsDoorClose.AM=50000; - rsDoorClose.AA=-1*(105-random(10))/100; - rsDoorClose.FM=1.0; - rsDoorClose.FA=0.0; - } - } - else - if (str==AnsiString("internaldata:")) //dalej nie czytaj - {while (!Parser->EndOfFile) - {//zbieranie informacji o kabinach - str=Parser->GetNextSymbol().LowerCase(); - if (str=="cab0model:") - {str=Parser->GetNextSymbol(); - if (str!="none") iCabs=2; - } - else if (str=="cab1model:") - {str=Parser->GetNextSymbol(); - if (str!="none") iCabs=1; - } - else if (str=="cab2model:") - {str=Parser->GetNextSymbol(); - if (str!="none") iCabs=4; - } - } - Stop_InternalData=true; - } - } - //ABu 050205 - tego wczesniej nie bylo i uciekala pamiec: - delete Parser; - if (mdModel) mdModel->Init(); //obrócenie modelu oraz optymalizacja, również zapisanie binarnego - if (mdLoad) mdLoad->Init(); - if (mdPrzedsionek) mdPrzedsionek->Init(); - if (mdLowPolyInt) mdLowPolyInt->Init(); - //sHorn2.CopyIfEmpty(sHorn1); //żeby jednak trąbił też drugim - Global::asCurrentTexturePath=AnsiString(szTexturePath); //kiedyś uproszczone wnętrze mieszało tekstury nieba + // ABu 050205 - tego wczesniej nie bylo i uciekala pamiec: + delete Parser; + if (mdModel) + mdModel->Init(); // obrócenie modelu oraz optymalizacja, również zapisanie binarnego + if (mdLoad) + mdLoad->Init(); + if (mdPrzedsionek) + mdPrzedsionek->Init(); + if (mdLowPolyInt) + mdLowPolyInt->Init(); + // sHorn2.CopyIfEmpty(sHorn1); //żeby jednak trąbił też drugim + Global::asCurrentTexturePath = + AnsiString(szTexturePath); // kiedyś uproszczone wnętrze mieszało tekstury nieba } //--------------------------------------------------------------------------- void __fastcall TDynamicObject::RadioStop() -{//zatrzymanie pojazdu - if (Mechanik) //o ile ktoś go prowadzi - if (MoverParameters->SecuritySystem.RadioStop) //jeśli pojazd ma RadioStop i jest on aktywny - Mechanik->PutCommand("Emergency_brake",1.0,1.0,&vPosition,stopRadio); +{ // zatrzymanie pojazdu + if (Mechanik) // o ile ktoś go prowadzi + if (MoverParameters->SecuritySystem.RadioStop) // jeśli pojazd ma RadioStop i jest on + // aktywny + Mechanik->PutCommand("Emergency_brake", 1.0, 1.0, &vPosition, stopRadio); }; -void __fastcall TDynamicObject::RaLightsSet(int head,int rear) -{//zapalenie świateł z przodu i z tyłu, zależne od kierunku pojazdu - if (!MoverParameters) return; //może tego nie być na początku - if (rear==2+32+64) - {//jeśli koniec pociągu, to trzeba ustalić, czy jest tam czynna lokomotywa - //EN57 może nie mieć końcówek od środka członu - if (MoverParameters->Power>1.0) //jeśli ma moc napędową - if (!MoverParameters->ActiveDir) //jeśli nie ma ustawionego kierunku - {//jeśli ma zarówno światła jak i końcówki, ustalić, czy jest w stanie aktywnym - //np. lokomotywa na zimno będzie mieć końcówki a nie światła - rear=64; //tablice blaszane - //trzeba to uzależnić od "załączenia baterii" w pojeździe - } - if (rear==2+32+64) //jeśli nadal obydwie możliwości - if (iInventory&(iDirection?0x2A:0x15)) //czy ma jakieś światła czerowone od danej strony - rear=2+32; //dwa światła czerwone - else - rear=64; //tablice blaszane - } - if (iDirection) //w zależności od kierunku pojazdu w składzie - {//jesli pojazd stoi sprzęgiem 0 w stronę czoła - if (head>=0) iLights[0]=head; - if (rear>=0) iLights[1]=rear; - } - else - {//jak jest odwrócony w składzie (-1), to zapalamy odwrotnie - if (head>=0) iLights[1]=head; - if (rear>=0) iLights[0]=rear; - } +void __fastcall TDynamicObject::RaLightsSet(int head, int rear) +{ // zapalenie świateł z przodu i z tyłu, zależne od kierunku pojazdu + if (!MoverParameters) + return; // może tego nie być na początku + if (rear == 2 + 32 + 64) + { // jeśli koniec pociągu, to trzeba ustalić, czy jest tam czynna lokomotywa + // EN57 może nie mieć końcówek od środka członu + if (MoverParameters->Power > 1.0) // jeśli ma moc napędową + if (!MoverParameters->ActiveDir) // jeśli nie ma ustawionego kierunku + { // jeśli ma zarówno światła jak i końcówki, ustalić, czy jest w stanie aktywnym + // np. lokomotywa na zimno będzie mieć końcówki a nie światła + rear = 64; // tablice blaszane + // trzeba to uzależnić od "załączenia baterii" w pojeździe + } + if (rear == 2 + 32 + 64) // jeśli nadal obydwie możliwości + if (iInventory & + (iDirection ? 0x2A : 0x15)) // czy ma jakieś światła czerowone od danej strony + rear = 2 + 32; // dwa światła czerwone + else + rear = 64; // tablice blaszane + } + if (iDirection) // w zależności od kierunku pojazdu w składzie + { // jesli pojazd stoi sprzęgiem 0 w stronę czoła + if (head >= 0) + iLights[0] = head; + if (rear >= 0) + iLights[1] = rear; + } + else + { // jak jest odwrócony w składzie (-1), to zapalamy odwrotnie + if (head >= 0) + iLights[1] = head; + if (rear >= 0) + iLights[0] = rear; + } }; int __fastcall TDynamicObject::DirectionSet(int d) -{//ustawienie kierunku w składzie (wykonuje AI) - iDirection=d>0?1:0; //d:1=zgodny,-1=przeciwny; iDirection:1=zgodny,0=przeciwny; - CouplCounter=20; //żeby normalnie skanować kolizje, to musi ruszyć z miejsca - if (MyTrack) - {//podczas wczytywania wstawiane jest AI, ale może jeszcze nie być toru - //AI ustawi kierunek ponownie po uruchomieniu silnika - if (iDirection) //jeśli w kierunku Coupler 0 - {if (MoverParameters->Couplers[0].CouplingFlag==ctrain_virtual) //brak pojazdu podpiętego? - ABuScanObjects(1,300); //szukanie czegoś do podłączenia - } - else - if (MoverParameters->Couplers[1].CouplingFlag==ctrain_virtual) //brak pojazdu podpiętego? - ABuScanObjects(-1,300); - } - return 1-(iDirection?NextConnectedNo:PrevConnectedNo); //informacja o położeniu następnego +{ // ustawienie kierunku w składzie (wykonuje AI) + iDirection = d > 0 ? 1 : 0; // d:1=zgodny,-1=przeciwny; iDirection:1=zgodny,0=przeciwny; + CouplCounter = 20; //żeby normalnie skanować kolizje, to musi ruszyć z miejsca + if (MyTrack) + { // podczas wczytywania wstawiane jest AI, ale może jeszcze nie być toru + // AI ustawi kierunek ponownie po uruchomieniu silnika + if (iDirection) // jeśli w kierunku Coupler 0 + { + if (MoverParameters->Couplers[0].CouplingFlag == + ctrain_virtual) // brak pojazdu podpiętego? + ABuScanObjects(1, 300); // szukanie czegoś do podłączenia + } + else if (MoverParameters->Couplers[1].CouplingFlag == + ctrain_virtual) // brak pojazdu podpiętego? + ABuScanObjects(-1, 300); + } + return 1 - (iDirection ? NextConnectedNo : PrevConnectedNo); // informacja o położeniu + // następnego }; -TDynamicObject* __fastcall TDynamicObject::PrevAny() -{//wskaźnik na poprzedni, nawet wirtualny - return iDirection?PrevConnected:NextConnected; +TDynamicObject *__fastcall TDynamicObject::PrevAny() +{ // wskaźnik na poprzedni, nawet wirtualny + return iDirection ? PrevConnected : NextConnected; }; -TDynamicObject* __fastcall TDynamicObject::Prev() +TDynamicObject *__fastcall TDynamicObject::Prev() { - if (MoverParameters->Couplers[iDirection^1].CouplingFlag) - return iDirection?PrevConnected:NextConnected; - return NULL; //gdy sprzęg wirtualny, to jakby nic nie było + if (MoverParameters->Couplers[iDirection ^ 1].CouplingFlag) + return iDirection ? PrevConnected : NextConnected; + return NULL; // gdy sprzęg wirtualny, to jakby nic nie było }; -TDynamicObject* __fastcall TDynamicObject::Next() +TDynamicObject *__fastcall TDynamicObject::Next() { - if (MoverParameters->Couplers[iDirection].CouplingFlag) - return iDirection?NextConnected:PrevConnected; - return NULL; //gdy sprzęg wirtualny, to jakby nic nie było + if (MoverParameters->Couplers[iDirection].CouplingFlag) + return iDirection ? NextConnected : PrevConnected; + return NULL; // gdy sprzęg wirtualny, to jakby nic nie było }; -TDynamicObject* __fastcall TDynamicObject::NextC(int C) +TDynamicObject *__fastcall TDynamicObject::NextC(int C) { - if (MoverParameters->Couplers[iDirection].CouplingFlag&C) - return iDirection?NextConnected:PrevConnected; - return NULL; //gdy sprzęg inny, to jakby nic nie było + if (MoverParameters->Couplers[iDirection].CouplingFlag & C) + return iDirection ? NextConnected : PrevConnected; + return NULL; // gdy sprzęg inny, to jakby nic nie było }; double __fastcall TDynamicObject::NextDistance(double d) -{//ustalenie odległości do następnego pojazdu, potrzebne do wstecznego skanowania - if (!MoverParameters->Couplers[iDirection].Connected) - return d; //jeśli nic nie ma, zwrócenie domyślnej wartości - if ((d<=0.0)||(MoverParameters->Couplers[iDirection].CoupleDistCouplers[iDirection].Dist; - else - return d; +{ // ustalenie odległości do następnego pojazdu, potrzebne do wstecznego skanowania + if (!MoverParameters->Couplers[iDirection].Connected) + return d; // jeśli nic nie ma, zwrócenie domyślnej wartości + if ((d <= 0.0) || (MoverParameters->Couplers[iDirection].CoupleDist < d)) + return MoverParameters->Couplers[iDirection].Dist; + else + return d; }; -TDynamicObject* __fastcall TDynamicObject::Neightbour(int &dir) -{//ustalenie następnego (1) albo poprzedniego (0) w składzie bez względu na prawidłowość iDirection - int d=dir; //zapamiętanie kierunku - dir=1-(dir?NextConnectedNo:PrevConnectedNo); //nowa wartość - return (d?(MoverParameters->Couplers[1].CouplingFlag?NextConnected:NULL):(MoverParameters->Couplers[0].CouplingFlag?PrevConnected:NULL)); +TDynamicObject *__fastcall TDynamicObject::Neightbour(int &dir) +{ // ustalenie następnego (1) albo poprzedniego (0) w składzie bez względu na prawidłowość + // iDirection + int d = dir; // zapamiętanie kierunku + dir = 1 - (dir ? NextConnectedNo : PrevConnectedNo); // nowa wartość + return (d ? (MoverParameters->Couplers[1].CouplingFlag ? NextConnected : NULL) : + (MoverParameters->Couplers[0].CouplingFlag ? PrevConnected : NULL)); }; void __fastcall TDynamicObject::CoupleDist() -{//obliczenie odległości sprzęgów - if (MyTrack?(MyTrack->iCategoryFlag&1):true) //jeśli nie ma przypisanego toru, to liczyć jak dla kolei - {//jeśli jedzie po szynach (również unimog), liczenie kul wystarczy - MoverParameters->SetCoupleDist(); - } - else - {//na drodze trzeba uwzględnić wektory ruchu - double d0=MoverParameters->Couplers[0].CoupleDist; - //double d1=MoverParameters->Couplers[1].CoupleDist; //sprzęg z tyłu samochodu można olać, dopóki nie jeździ na wstecznym - vector3 p1,p2; - double d,w; //dopuszczalny dystans w poprzek - MoverParameters->SetCoupleDist(); //liczenie standardowe - if (MoverParameters->Couplers[0].Connected) //jeśli cokolwiek podłączone - if (MoverParameters->Couplers[0].CouplingFlag==0) //jeśli wirtualny - if (MoverParameters->Couplers[0].CoupleDist<300.0) //i mniej niż 300m - {//przez MoverParameters->Couplers[0].Connected nie da się dostać do DynObj, stąd prowizorka - //WriteLog("Collision of "+AnsiString(MoverParameters->Couplers[0].CoupleDist)+"m detected by "+asName+":0."); - w=0.5*(MoverParameters->Couplers[0].Connected->Dim.W+MoverParameters->Dim.W); //minimalna odległość minięcia - d=-DotProduct(vLeft,vCoulpler[0]); //odległość prostej ruchu od początku układu współrzędnych - d=fabs(DotProduct(vLeft,((TMoverParameters*)(MoverParameters->Couplers[0].Connected))->vCoulpler[MoverParameters->Couplers[0].ConnectedNr])+d); - //WriteLog("Distance "+AnsiString(d)+"m from "+asName+":0."); - if (d>w) - MoverParameters->Couplers[0].CoupleDist=(d0<10?50:d0); //przywrócenie poprzedniej +{ // obliczenie odległości sprzęgów + if (MyTrack ? (MyTrack->iCategoryFlag & 1) : + true) // jeśli nie ma przypisanego toru, to liczyć jak dla kolei + { // jeśli jedzie po szynach (również unimog), liczenie kul wystarczy + MoverParameters->SetCoupleDist(); } - if (MoverParameters->Couplers[1].Connected) //jeśli cokolwiek podłączone - if (MoverParameters->Couplers[1].CouplingFlag==0) //jeśli wirtualny - if (MoverParameters->Couplers[1].CoupleDist<300.0) //i mniej niż 300m - { - //WriteLog("Collision of "+AnsiString(MoverParameters->Couplers[1].CoupleDist)+"m detected by "+asName+":1."); - w=0.5*(MoverParameters->Couplers[1].Connected->Dim.W+MoverParameters->Dim.W); //minimalna odległość minięcia - d=-DotProduct(vLeft,vCoulpler[1]); //odległość prostej ruchu od początku układu współrzędnych - d=fabs(DotProduct(vLeft,((TMoverParameters*)(MoverParameters->Couplers[1].Connected))->vCoulpler[MoverParameters->Couplers[1].ConnectedNr])+d); - //WriteLog("Distance "+AnsiString(d)+"m from "+asName+":1."); - if (d>w) - MoverParameters->Couplers[0].CoupleDist=(d0<10?50:d0); //przywrócenie poprzedniej + else + { // na drodze trzeba uwzględnić wektory ruchu + double d0 = MoverParameters->Couplers[0].CoupleDist; + // double d1=MoverParameters->Couplers[1].CoupleDist; //sprzęg z tyłu samochodu można olać, + // dopóki nie jeździ na wstecznym + vector3 p1, p2; + double d, w; // dopuszczalny dystans w poprzek + MoverParameters->SetCoupleDist(); // liczenie standardowe + if (MoverParameters->Couplers[0].Connected) // jeśli cokolwiek podłączone + if (MoverParameters->Couplers[0].CouplingFlag == 0) // jeśli wirtualny + if (MoverParameters->Couplers[0].CoupleDist < 300.0) // i mniej niż 300m + { // przez MoverParameters->Couplers[0].Connected nie da się dostać do DynObj, stąd + // prowizorka + // WriteLog("Collision of + // "+AnsiString(MoverParameters->Couplers[0].CoupleDist)+"m detected by + // "+asName+":0."); + w = 0.5 * (MoverParameters->Couplers[0].Connected->Dim.W + + MoverParameters->Dim.W); // minimalna odległość minięcia + d = -DotProduct(vLeft, vCoulpler[0]); // odległość prostej ruchu od początku + // układu współrzędnych + d = fabs( + DotProduct(vLeft, + ((TMoverParameters *)(MoverParameters->Couplers[0].Connected)) + ->vCoulpler[MoverParameters->Couplers[0].ConnectedNr]) + + d); + // WriteLog("Distance "+AnsiString(d)+"m from "+asName+":0."); + if (d > w) + MoverParameters->Couplers[0].CoupleDist = + (d0 < 10 ? 50 : d0); // przywrócenie poprzedniej + } + if (MoverParameters->Couplers[1].Connected) // jeśli cokolwiek podłączone + if (MoverParameters->Couplers[1].CouplingFlag == 0) // jeśli wirtualny + if (MoverParameters->Couplers[1].CoupleDist < 300.0) // i mniej niż 300m + { + // WriteLog("Collision of + // "+AnsiString(MoverParameters->Couplers[1].CoupleDist)+"m detected by + // "+asName+":1."); + w = 0.5 * (MoverParameters->Couplers[1].Connected->Dim.W + + MoverParameters->Dim.W); // minimalna odległość minięcia + d = -DotProduct(vLeft, vCoulpler[1]); // odległość prostej ruchu od początku + // układu współrzędnych + d = fabs( + DotProduct(vLeft, + ((TMoverParameters *)(MoverParameters->Couplers[1].Connected)) + ->vCoulpler[MoverParameters->Couplers[1].ConnectedNr]) + + d); + // WriteLog("Distance "+AnsiString(d)+"m from "+asName+":1."); + if (d > w) + MoverParameters->Couplers[0].CoupleDist = + (d0 < 10 ? 50 : d0); // przywrócenie poprzedniej + } } - } }; -TDynamicObject* __fastcall TDynamicObject::ControlledFind() -{//taka proteza: chcę podłączyć kabinę EN57 bezpośrednio z silnikowym, aby nie robić tego przez ukrotnienie - //drugi silnikowy i tak musi być ukrotniony, podobnie jak kolejna jednostka - //lepiej by było przesyłać komendy sterowania, co jednak wymaga przebudowy transmisji komend (LD) - //problem się robi ze światłami, które będą zapalane w silnikowym, ale muszą świecić się w rozrządczych - //dla EZT światłą czołowe będą "zapalane w silnikowym", ale widziane z rozrządczych - //również wczytywanie MMD powinno dotyczyć aktualnego członu - //problematyczna może być kwestia wybranej kabiny (w silnikowym...) - //jeśli silnikowy będzie zapięty odwrotnie (tzn. -1), to i tak powinno jeździć dobrze - //również hamowanie wykonuje się zaworem w członie, a nie w silnikowym... - TDynamicObject *d=this; //zaczynamy od aktualnego - if (d->MoverParameters->TrainType&dt_EZT) //na razie dotyczy to EZT - if (d->NextConnected?d->MoverParameters->Couplers[1].AllowedFlag&ctrain_depot:false) - {//gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy) - if ((d->MoverParameters->Power<1.0)&&(d->NextConnected->MoverParameters->Power>1.0)) //my nie mamy mocy, ale ten drugi ma - d=d->NextConnected; //będziemy sterować tym z mocą - } - else if (d->PrevConnected?d->MoverParameters->Couplers[0].AllowedFlag&ctrain_depot:false) - {//gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy) - if ((d->MoverParameters->Power<1.0)&&(d->PrevConnected->MoverParameters->Power>1.0)) //my nie mamy mocy, ale ten drugi ma - d=d->PrevConnected; //będziemy sterować tym z mocą - } - return d; +TDynamicObject *__fastcall TDynamicObject::ControlledFind() +{ // taka proteza: chcę podłączyć kabinę EN57 bezpośrednio z silnikowym, aby nie robić tego przez + // ukrotnienie + // drugi silnikowy i tak musi być ukrotniony, podobnie jak kolejna jednostka + // lepiej by było przesyłać komendy sterowania, co jednak wymaga przebudowy transmisji komend + // (LD) + // problem się robi ze światłami, które będą zapalane w silnikowym, ale muszą świecić się w + // rozrządczych + // dla EZT światłą czołowe będą "zapalane w silnikowym", ale widziane z rozrządczych + // również wczytywanie MMD powinno dotyczyć aktualnego członu + // problematyczna może być kwestia wybranej kabiny (w silnikowym...) + // jeśli silnikowy będzie zapięty odwrotnie (tzn. -1), to i tak powinno jeździć dobrze + // również hamowanie wykonuje się zaworem w członie, a nie w silnikowym... + TDynamicObject *d = this; // zaczynamy od aktualnego + if (d->MoverParameters->TrainType & dt_EZT) // na razie dotyczy to EZT + if (d->NextConnected ? d->MoverParameters->Couplers[1].AllowedFlag & ctrain_depot : false) + { // gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy) + if ((d->MoverParameters->Power < 1.0) && (d->NextConnected->MoverParameters->Power > + 1.0)) // my nie mamy mocy, ale ten drugi ma + d = d->NextConnected; // będziemy sterować tym z mocą + } + else if (d->PrevConnected ? d->MoverParameters->Couplers[0].AllowedFlag & ctrain_depot : + false) + { // gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy) + if ((d->MoverParameters->Power < 1.0) && (d->PrevConnected->MoverParameters->Power > + 1.0)) // my nie mamy mocy, ale ten drugi ma + d = d->PrevConnected; // będziemy sterować tym z mocą + } + return d; }; //--------------------------------------------------------------------------- -void __fastcall TDynamicObject::ParamSet(int what,int into) -{//ustawienie lokalnego parametru (what) na stan (into) - switch (what&0xFF00) - { - case 0x0100: //to np. są drzwi, bity 0..7 określają numer 1..254 albo maskę dla 8 różnych - if (what&1) //na razie mamy lewe oraz prawe, czyli używamy maskę 1=lewe, 2=prawe, 3=wszystkie - if (MoverParameters->DoorLeftOpened) - {//są otwarte - if (!into) //jeśli zamykanie - { - //dźwięk zamykania - } +void __fastcall TDynamicObject::ParamSet(int what, int into) +{ // ustawienie lokalnego parametru (what) na stan (into) + switch (what & 0xFF00) + { + case 0x0100: // to np. są drzwi, bity 0..7 określają numer 1..254 albo maskę dla 8 różnych + if (what & + 1) // na razie mamy lewe oraz prawe, czyli używamy maskę 1=lewe, 2=prawe, 3=wszystkie + if (MoverParameters->DoorLeftOpened) + { // są otwarte + if (!into) // jeśli zamykanie + { + // dźwięk zamykania + } + } + else + { // są zamknięte + if (into) // jeśli otwieranie + { + // dźwięk otwierania + } + } + if (what & 2) // prawe działają niezależnie od lewych + if (MoverParameters->DoorRightOpened) + { // są otwarte + if (!into) // jeśli zamykanie + { + // dźwięk zamykania + } + } + else + { // są zamknięte + if (into) // jeśli otwieranie + { + // dźwięk otwierania + } + } + break; } - else - {//są zamknięte - if (into) //jeśli otwieranie - { - //dźwięk otwierania - } - } - if (what&2) //prawe działają niezależnie od lewych - if (MoverParameters->DoorRightOpened) - {//są otwarte - if (!into) //jeśli zamykanie - { - //dźwięk zamykania - } - } - else - {//są zamknięte - if (into) //jeśli otwieranie - { - //dźwięk otwierania - } - } - break; - } }; int __fastcall TDynamicObject::RouteWish(TTrack *tr) -{//zapytanie do AI, po którym segmencie (-6..6) jechać na skrzyżowaniu (tr) - return Mechanik?Mechanik->CrossRoute(tr):0; //wg AI albo prosto +{ // zapytanie do AI, po którym segmencie (-6..6) jechać na skrzyżowaniu (tr) + return Mechanik ? Mechanik->CrossRoute(tr) : 0; // wg AI albo prosto }; AnsiString __fastcall TDynamicObject::TextureTest(AnsiString &name) -{//Ra 2015-01: sprawdzenie dostępności tekstury o podanej nazwie - AnsiString x=name+".dds"; //na razie prymitywnie - if (FileExists(x)) - return x; - else - {x=name+".tga"; //w zasadzie to należałoby uwzględnić deklarowaną kolejność - if (FileExists(x)) - return x; - else - {x=name+".bmp"; - if (FileExists(x)) - return x; - } - } - return ""; //nie znaleziona +{ // Ra 2015-01: sprawdzenie dostępności tekstury o podanej nazwie + AnsiString x = name + ".dds"; // na razie prymitywnie + if (FileExists(x)) + return x; + else + { + x = name + ".tga"; // w zasadzie to należałoby uwzględnić deklarowaną kolejność + if (FileExists(x)) + return x; + else + { + x = name + ".bmp"; + if (FileExists(x)) + return x; + } + } + return ""; // nie znaleziona }; void __fastcall TDynamicObject::DestinationSet(AnsiString to) -{//ustawienie stacji docelowej oraz wymiennej tekstury 4, jeśli istnieje plik - //w zasadzie, to każdy wagon mógłby mieć inną stację docelową - //zwłaszcza w towarowych, pod kątem zautomatyzowania maewrów albo pracy górki - //ale to jeszcze potrwa, zanim będzie możliwe, na razie można wpisać stację z rozkładu - if (abs(iMultiTex)>=4) return; //jak są 4 tekstury wymienne, to nie zmieniać rozkładem - asDestination=to; - to=Global::Bezogonkow(to); //do szukania pliku obcinamy ogonki - AnsiString x; - if (to.IsEmpty()) to="nowhere"; - x=TextureTest(asBaseDir+to+"@"+MoverParameters->TypeName); //w pierwszej kolejności z nazwą FIZ/MMD - if (!x.IsEmpty()) - { - ReplacableSkinID[4]=TTexturesManager::GetTextureID(NULL,NULL,x.c_str(),9); //rozmywania 0,1,4,5 nie nadają się - return; - } - x=TextureTest(asBaseDir+to); //na razie prymitywnie - if (!x.IsEmpty()) - ReplacableSkinID[4]=TTexturesManager::GetTextureID(NULL,NULL,x.c_str(),9); //rozmywania 0,1,4,5 nie nadają się - else - ReplacableSkinID[4]=0; //0 to brak? -1 odpada, bo inaczej się będzie mapować - //Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa tekstury nr 4 +{ // ustawienie stacji docelowej oraz wymiennej tekstury 4, jeśli istnieje plik + // w zasadzie, to każdy wagon mógłby mieć inną stację docelową + // zwłaszcza w towarowych, pod kątem zautomatyzowania maewrów albo pracy górki + // ale to jeszcze potrwa, zanim będzie możliwe, na razie można wpisać stację z rozkładu + if (abs(iMultiTex) >= 4) + return; // jak są 4 tekstury wymienne, to nie zmieniać rozkładem + asDestination = to; + to = Global::Bezogonkow(to); // do szukania pliku obcinamy ogonki + AnsiString x; + if (to.IsEmpty()) + to = "nowhere"; + x = TextureTest(asBaseDir + to + "@" + + MoverParameters->TypeName); // w pierwszej kolejności z nazwą FIZ/MMD + if (!x.IsEmpty()) + { + ReplacableSkinID[4] = TTexturesManager::GetTextureID( + NULL, NULL, x.c_str(), 9); // rozmywania 0,1,4,5 nie nadają się + return; + } + x = TextureTest(asBaseDir + to); // na razie prymitywnie + if (!x.IsEmpty()) + ReplacableSkinID[4] = TTexturesManager::GetTextureID( + NULL, NULL, x.c_str(), 9); // rozmywania 0,1,4,5 nie nadają się + else + ReplacableSkinID[4] = 0; // 0 to brak? -1 odpada, bo inaczej się będzie mapować + // Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa tekstury nr 4 }; void __fastcall TDynamicObject::OverheadTrack(float o) -{//ewentualne wymuszanie jazdy bezprądowej z powodu informacji w torze - if (ctOwner) //jeśli ma obiekt nadzorujący - {//trzeba zaktualizować mapę flag bitowych jazdy bezprądowej - if (o<0.0) - {//normalna jazda po tym torze - ctOwner->iOverheadZero&=~iOverheadMask; //zerowanie bitu - może pobierać prąd - ctOwner->iOverheadDown&=~iOverheadMask; //zerowanie bitu - może podnieść pantograf - } - else if (o>0.0) - {//opuszczenie pantografów - ctOwner->iOverheadZero|=iOverheadMask; //ustawienie bitu - ma jechać bez pobierania prądu - ctOwner->iOverheadDown|=iOverheadMask; //ustawienie bitu - ma opuścić pantograf - } - else - {//jazda bezprądowa z podniesionym pantografem - ctOwner->iOverheadZero|=iOverheadMask; //ustawienie bitu - ma jechać bez pobierania prądu - ctOwner->iOverheadDown&=~iOverheadMask; //zerowanie bitu - może podnieść pantograf - } - } +{ // ewentualne wymuszanie jazdy bezprądowej z powodu informacji w torze + if (ctOwner) // jeśli ma obiekt nadzorujący + { // trzeba zaktualizować mapę flag bitowych jazdy bezprądowej + if (o < 0.0) + { // normalna jazda po tym torze + ctOwner->iOverheadZero &= ~iOverheadMask; // zerowanie bitu - może pobierać prąd + ctOwner->iOverheadDown &= ~iOverheadMask; // zerowanie bitu - może podnieść pantograf + } + else if (o > 0.0) + { // opuszczenie pantografów + ctOwner->iOverheadZero |= + iOverheadMask; // ustawienie bitu - ma jechać bez pobierania prądu + ctOwner->iOverheadDown |= iOverheadMask; // ustawienie bitu - ma opuścić pantograf + } + else + { // jazda bezprądowa z podniesionym pantografem + ctOwner->iOverheadZero |= + iOverheadMask; // ustawienie bitu - ma jechać bez pobierania prądu + ctOwner->iOverheadDown &= ~iOverheadMask; // zerowanie bitu - może podnieść pantograf + } + } }; - diff --git a/DynObj.h b/DynObj.h index 87096d59..4063d98f 100644 --- a/DynObj.h +++ b/DynObj.h @@ -8,7 +8,7 @@ #include "QueryParserComp.hpp" #include "Mover.h" #include "TractionPower.h" -//McZapkie: +// McZapkie: #include "MdlMngr.h" #include "RealSound.h" #include "AdvSound.h" @@ -17,22 +17,22 @@ //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- -const ANIM_TYPES=7; //Ra: ilość typów animacji -const ANIM_WHEELS =0; //koła -const ANIM_DOORS =1; //drzwi -const ANIM_LEVERS =2; //elementy obracane (wycieraczki, koła skrętne, przestawiacze, klocki ham.) -const ANIM_BUFFERS=3; //elementy przesuwane (zderzaki) -const ANIM_BOOGIES=4; //wózki (są skręcane w dwóch osiach) -const ANIM_PANTS =5; //pantografy -const ANIM_STEAMS =6; //napęd parowozu +const ANIM_TYPES = 7; // Ra: ilość typów animacji +const ANIM_WHEELS = 0; // koła +const ANIM_DOORS = 1; // drzwi +const ANIM_LEVERS = 2; // elementy obracane (wycieraczki, koła skrętne, przestawiacze, klocki ham.) +const ANIM_BUFFERS = 3; // elementy przesuwane (zderzaki) +const ANIM_BOOGIES = 4; // wózki (są skręcane w dwóch osiach) +const ANIM_PANTS = 5; // pantografy +const ANIM_STEAMS = 6; // napęd parowozu class TAnim; -typedef void (__closure *TUpdate)(TAnim *pAnim); //typ funkcji aktualizującej położenie submodeli +typedef void(__closure *TUpdate)(TAnim *pAnim); // typ funkcji aktualizującej położenie submodeli -//McZapkie-250202 -const MaxAxles=16; //ABu 280105: zmienione z 8 na 16 -//const MaxAnimatedAxles=16; //i to tez. -//const MaxAnimatedDoors=16; //NBMX wrzesien 2003 +// McZapkie-250202 +const MaxAxles = 16; // ABu 280105: zmienione z 8 na 16 +// const MaxAnimatedAxles=16; //i to tez. +// const MaxAnimatedDoors=16; //NBMX wrzesien 2003 /* Ra: Utworzyć klasę wyposażenia opcjonalnego, z której będą dziedziczyć klasy drzwi, pantografów, napędu parowozu i innych ruchomych części pojazdów. Klasy powinny być @@ -45,86 +45,89 @@ szczeg modeli na stacjach na ogół przewaga jest tych nieruchomych). */ class TAnimValveGear -{//współczynniki do animacji parowozu (wartości przykładowe dla Pt47) - int iValues; //ilość liczb (wersja): - float fKorbowodR; //długość korby (pół skoku tłoka) [m]: 0.35 - float fKorbowodL; //długość korbowodu [m]: 3.8 - float fDrazekR; //promień mimośrodu (drążka) [m]: 0.18 - float fDrazekL; //dł. drążka mimośrodowego [m]: 2.55889 - float fJarzmoV; //wysokość w pionie osi jarzma od osi koła [m]: 0.751 - float fJarzmoH; //odległość w poziomie osi jarzma od osi koła [m]: 2.550 - float fJarzmoR; //promień jarzma do styku z drążkiem [m]: 0.450 - float fJarzmoA; //kąt mimośrodu względem kąta koła [°]: -96.77416667 - float fWdzidloL; //długość wodzidła [m]: 2.0 - float fWahaczH; //długość wahacza (góra) [m]: 0.14 - float fSuwakH; //wysokość osi suwaka ponad osią koła [m]: 0.62 - float fWahaczL; //długość wahacza (dół) [m]: 0.84 - float fLacznikL; //długość łącznika wahacza [m]: 0.75072 - float fRamieL; //odległość ramienia krzyżulca od osi koła [m]: 0.192 - float fSuwakL; //odległość środka tłoka/suwaka od osi koła [m]: 5.650 -//dołożyć parametry drążka nastawnicy -//albo nawet zrobić dynamiczną tablicę float[] i w nią pakować wszelkie współczynniki, potem używać indeksów -//współczynniki mogą być wspólne dla 2-4 tłoków, albo każdy tłok może mieć odrębne +{ // współczynniki do animacji parowozu (wartości przykładowe dla Pt47) + int iValues; // ilość liczb (wersja): + float fKorbowodR; // długość korby (pół skoku tłoka) [m]: 0.35 + float fKorbowodL; // długość korbowodu [m]: 3.8 + float fDrazekR; // promień mimośrodu (drążka) [m]: 0.18 + float fDrazekL; // dł. drążka mimośrodowego [m]: 2.55889 + float fJarzmoV; // wysokość w pionie osi jarzma od osi koła [m]: 0.751 + float fJarzmoH; // odległość w poziomie osi jarzma od osi koła [m]: 2.550 + float fJarzmoR; // promień jarzma do styku z drążkiem [m]: 0.450 + float fJarzmoA; // kąt mimośrodu względem kąta koła [°]: -96.77416667 + float fWdzidloL; // długość wodzidła [m]: 2.0 + float fWahaczH; // długość wahacza (góra) [m]: 0.14 + float fSuwakH; // wysokość osi suwaka ponad osią koła [m]: 0.62 + float fWahaczL; // długość wahacza (dół) [m]: 0.84 + float fLacznikL; // długość łącznika wahacza [m]: 0.75072 + float fRamieL; // odległość ramienia krzyżulca od osi koła [m]: 0.192 + float fSuwakL; // odległość środka tłoka/suwaka od osi koła [m]: 5.650 + // dołożyć parametry drążka nastawnicy + // albo nawet zrobić dynamiczną tablicę float[] i w nią pakować wszelkie współczynniki, potem + // używać indeksów + // współczynniki mogą być wspólne dla 2-4 tłoków, albo każdy tłok może mieć odrębne }; class TAnimPant -{//współczynniki do animacji pantografu -public: - vector3 vPos; //Ra: współrzędne punktu zerowego pantografu (X dodatnie dla przedniego) - double fLenL1; //długość dolnego ramienia 1, odczytana z modelu - double fLenU1; //długość górnego ramienia 1, odczytana z modelu - double fLenL2; //długość dolnego ramienia 2, odczytana z modelu - double fLenU2; //długość górnego ramienia 2, odczytana z modelu - double fHoriz; //przesunięcie ślizgu w długości pojazdu względem osi obrotu dolnego ramienia - double fHeight; //wysokość ślizgu ponad oś obrotu, odejmowana od wysokości drutu - double fWidth; //połowa szerokości roboczej ślizgu, do wykrycia ześlizgnięcia się drutu - double fAngleL0; //Ra: początkowy kąt dolnego ramienia (odejmowany przy animacji) - double fAngleU0; //Ra: początkowy kąt górnego ramienia (odejmowany przy animacji) - double PantTraction; //Winger 170204: wysokość drutu ponad punktem na wysokości vPos.y p.g.s. - double PantWys; //Ra: aktualna wysokość uniesienia ślizgu do porównania z wysokością drutu - double fAngleL; //Winger 160204: aktualny kąt ramienia dolnego - double fAngleU; //Ra: aktualny kąt ramienia górnego - double NoVoltTime; //czas od utraty kontaktu z drutem - TTraction *hvPowerWire; //aktualnie podczepione druty, na razie tu - float fWidthExtra; //dodatkowy rozmiar poziomy poza część roboczą (fWidth) - float fHeightExtra[5]; //łamana symulująca kształt nabieżnika - //double fHorizontal; //Ra 2015-01: położenie drutu względem osi pantografu - void __fastcall AKP_4E(); +{ // współczynniki do animacji pantografu + public: + vector3 vPos; // Ra: współrzędne punktu zerowego pantografu (X dodatnie dla przedniego) + double fLenL1; // długość dolnego ramienia 1, odczytana z modelu + double fLenU1; // długość górnego ramienia 1, odczytana z modelu + double fLenL2; // długość dolnego ramienia 2, odczytana z modelu + double fLenU2; // długość górnego ramienia 2, odczytana z modelu + double fHoriz; // przesunięcie ślizgu w długości pojazdu względem osi obrotu dolnego ramienia + double fHeight; // wysokość ślizgu ponad oś obrotu, odejmowana od wysokości drutu + double fWidth; // połowa szerokości roboczej ślizgu, do wykrycia ześlizgnięcia się drutu + double fAngleL0; // Ra: początkowy kąt dolnego ramienia (odejmowany przy animacji) + double fAngleU0; // Ra: początkowy kąt górnego ramienia (odejmowany przy animacji) + double PantTraction; // Winger 170204: wysokość drutu ponad punktem na wysokości vPos.y p.g.s. + double PantWys; // Ra: aktualna wysokość uniesienia ślizgu do porównania z wysokością drutu + double fAngleL; // Winger 160204: aktualny kąt ramienia dolnego + double fAngleU; // Ra: aktualny kąt ramienia górnego + double NoVoltTime; // czas od utraty kontaktu z drutem + TTraction *hvPowerWire; // aktualnie podczepione druty, na razie tu + float fWidthExtra; // dodatkowy rozmiar poziomy poza część roboczą (fWidth) + float fHeightExtra[5]; //łamana symulująca kształt nabieżnika + // double fHorizontal; //Ra 2015-01: położenie drutu względem osi pantografu + void __fastcall AKP_4E(); }; class TAnim -{//klasa animowanej części pojazdu (koła, drzwi, pantografy, burty, napęd parowozu, siłowniki itd.) -public: - union - { - TSubModel *smAnimated; //animowany submodel (jeśli tylko jeden, np. oś) - TSubModel **smElement; //jeśli animowanych elementów jest więcej (pantograf, napęd parowozu) - int iShift; //przesunięcie przed przydzieleniem wskaźnika - }; - union - {//parametry animacji - TAnimValveGear *pValveGear; //współczynniki do animacji parowozu - double *dWheelAngle; //wskaźnik na kąt obrotu osi - float *fParam; //różne parametry dla animacji - TAnimPant *fParamPants; //różne parametry dla animacji - }; - union - {//wskaźnik na obiekt odniesienia - double *fDoubleBase; //jakiś double w fizyce - float *fFloatBase; //jakiś float w fizyce - int *iIntBase; //jakiś int w fizyce - }; - //void _fastcall Update(); //wskaźnik do funkcji aktualizacji animacji - int iFlags; //flagi animacji - float fMaxDist; //do jakiej odległości wykonywana jest animacja - float fSpeed; //parametr szybkości animacji - int iNumber; //numer kolejny obiektu -public: - __fastcall TAnim(); - __fastcall ~TAnim(); - TUpdate yUpdate; //metoda TDynamicObject aktualizująca animację - int __fastcall TypeSet(int i,int fl=0); //ustawienie typu - void __fastcall Parovoz(); //wykonanie obliczeń animacji +{ // klasa animowanej części pojazdu (koła, drzwi, pantografy, burty, napęd parowozu, siłowniki + // itd.) + public: + union + { + TSubModel *smAnimated; // animowany submodel (jeśli tylko jeden, np. oś) + TSubModel **smElement; // jeśli animowanych elementów jest więcej (pantograf, napęd + // parowozu) + int iShift; // przesunięcie przed przydzieleniem wskaźnika + }; + union + { // parametry animacji + TAnimValveGear *pValveGear; // współczynniki do animacji parowozu + double *dWheelAngle; // wskaźnik na kąt obrotu osi + float *fParam; // różne parametry dla animacji + TAnimPant *fParamPants; // różne parametry dla animacji + }; + union + { // wskaźnik na obiekt odniesienia + double *fDoubleBase; // jakiś double w fizyce + float *fFloatBase; // jakiś float w fizyce + int *iIntBase; // jakiś int w fizyce + }; + // void _fastcall Update(); //wskaźnik do funkcji aktualizacji animacji + int iFlags; // flagi animacji + float fMaxDist; // do jakiej odległości wykonywana jest animacja + float fSpeed; // parametr szybkości animacji + int iNumber; // numer kolejny obiektu + public: + __fastcall TAnim(); + __fastcall ~TAnim(); + TUpdate yUpdate; // metoda TDynamicObject aktualizująca animację + int __fastcall TypeSet(int i, int fl = 0); // ustawienie typu + void __fastcall Parovoz(); // wykonanie obliczeń animacji }; //--------------------------------------------------------------------------- @@ -132,149 +135,156 @@ public: //--------------------------------------------------------------------------- class TDynamicObject -{//klasa pojazdu -private: //położenie pojazdu w świecie oraz parametry ruchu - vector3 vPosition; //Ra: pozycja pojazdu liczona zaraz po przesunięciu - vector3 vCoulpler[2]; //współrzędne sprzęgów do liczenia zderzeń czołowych - vector3 vUp,vFront,vLeft; //wektory jednostkowe ustawienia pojazdu - int iDirection; //kierunek pojazdu względem czoła składu (1=zgodny,0=przeciwny) - TTrackShape ts; //parametry toru przekazywane do fizyki - 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) - float fAxleDist; //rozstaw wózków albo osi do liczenia proporcji zacienienia - vector3 modelRot; //obrot pudła względem świata - do przeanalizowania, czy potrzebne!!! - //bool bCameraNear; //blisko kamer są potrzebne dodatkowe obliczenia szczegółów - TDynamicObject* __fastcall ABuFindNearestObject(TTrack *Track,TDynamicObject *MyPointer,int &CouplNr); -public: //parametry położenia pojazdu dostępne publicznie - AnsiString asTrack; //nazwa toru początkowego; wywalić? - AnsiString asDestination; //dokąd pojazd ma być kierowany "(stacja):(tor)" - 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 - int PrevConnectedNo; //numer sprzęgu podłączonego z przodu - double fScanDist; //odległość skanowania torów na obecność innych pojazdów +{ // klasa pojazdu + private: // położenie pojazdu w świecie oraz parametry ruchu + vector3 vPosition; // Ra: pozycja pojazdu liczona zaraz po przesunięciu + vector3 vCoulpler[2]; // współrzędne sprzęgów do liczenia zderzeń czołowych + vector3 vUp, vFront, vLeft; // wektory jednostkowe ustawienia pojazdu + int iDirection; // kierunek pojazdu względem czoła składu (1=zgodny,0=przeciwny) + TTrackShape ts; // parametry toru przekazywane do fizyki + 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) + float fAxleDist; // rozstaw wózków albo osi do liczenia proporcji zacienienia + vector3 modelRot; // obrot pudła względem świata - do przeanalizowania, czy potrzebne!!! + // bool bCameraNear; //blisko kamer są potrzebne dodatkowe obliczenia szczegółów + TDynamicObject *__fastcall ABuFindNearestObject(TTrack *Track, TDynamicObject *MyPointer, + int &CouplNr); -public: //modele składowe pojazdu - TModel3d *mdModel; //model pudła - TModel3d *mdLoad; //model zmiennego ładunku - TModel3d *mdPrzedsionek; //model przedsionków dla EZT - może użyć mdLoad zamiast? - TModel3d *mdKabina; //model kabiny dla użytkownika; McZapkie-030303: to z train.h - TModel3d *mdLowPolyInt; //ABu 010305: wnetrze lowpoly - float fShade; //zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?) + public: // parametry położenia pojazdu dostępne publicznie + AnsiString asTrack; // nazwa toru początkowego; wywalić? + AnsiString asDestination; // dokąd pojazd ma być kierowany "(stacja):(tor)" + 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 + int PrevConnectedNo; // numer sprzęgu podłączonego z przodu + double fScanDist; // odległość skanowania torów na obecność innych pojazdów -private: //zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe -public: //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: - int iAnimations; //liczba obiektów animujących - TAnim *pAnimations; //obiekty animujące (zawierają wskaźnik do funkcji wykonującej animację) - 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 - void UpdateDoorRotate(TAnim *pAnim); //animacja drzwi - obrót - void UpdateDoorFold(TAnim *pAnim); //animacja drzwi - składanie - void UpdatePant(TAnim *pAnim); //animacja pantografu - void UpdateLeverDouble(TAnim *pAnim); //animacja gałki zależna od double - void UpdateLeverFloat(TAnim *pAnim); //animacja gałki zależna od float - void UpdateLeverInt(TAnim *pAnim); //animacja gałki zależna od int (wartość) - void UpdateLeverEnum(TAnim *pAnim); //animacja gałki zależna od int (lista kątów) -private: //Ra: ciąg dalszy animacji, dopiero do ogarnięcia - //ABuWozki 060504 - vector3 bogieRot[2]; //Obroty wozkow w/m korpusu - TSubModel *smBogie[2]; //Wyszukiwanie max 2 wozkow - TSubModel *smWahacze[4]; //wahacze (np. nogi, dźwignia w drezynie) - TSubModel *smBrakeMode; //Ra 15-01: nastawa hamulca też - TSubModel *smLoadMode; //Ra 15-01: nastawa próżny/ładowny - double fWahaczeAmp; - //Winger 160204 - pantografy - double pantspeedfactor; - //animacje typu przesuw - TSubModel *smBuforLewy[2]; - TSubModel *smBuforPrawy[2]; - TAnimValveGear *pValveGear; - vector3 vFloor; //podłoga dla ładunku -public: - TAnim *pants; //indeks obiektu animującego dla pantografu 0 - double NoVoltTime; //czas od utraty zasilania - double dDoorMoveL; //NBMX - double dDoorMoveR; //NBMX - TSubModel *smBrakeSet; //nastawa hamulca (wajcha) - TSubModel *smLoadSet; //nastawa ładunku (wajcha) - TSubModel *smWiper; //wycieraczka (poniekąd też wajcha) -//Ra: koneic animacji do ogarnięcia + public: // modele składowe pojazdu + TModel3d *mdModel; // model pudła + TModel3d *mdLoad; // model zmiennego ładunku + TModel3d *mdPrzedsionek; // model przedsionków dla EZT - może użyć mdLoad zamiast? + TModel3d *mdKabina; // model kabiny dla użytkownika; McZapkie-030303: to z train.h + TModel3d *mdLowPolyInt; // ABu 010305: wnetrze lowpoly + float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?) -private: - void ABuLittleUpdate(double ObjSqrDist); - bool btnOn; //ABu: czy byly uzywane buttony, jesli tak, to po renderingu wylacz - //bo ten sam model moze byc jeszcze wykorzystany przez inny obiekt! - double __fastcall ComputeRadius(vector3 p1,vector3 p2,vector3 p3,vector3 p4); + private: // zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe + public: // 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: + int iAnimations; // liczba obiektów animujących + TAnim *pAnimations; // obiekty animujące (zawierają wskaźnik do funkcji wykonującej animację) + 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 + void UpdateDoorRotate(TAnim *pAnim); // animacja drzwi - obrót + void UpdateDoorFold(TAnim *pAnim); // animacja drzwi - składanie + void UpdatePant(TAnim *pAnim); // animacja pantografu + void UpdateLeverDouble(TAnim *pAnim); // animacja gałki zależna od double + void UpdateLeverFloat(TAnim *pAnim); // animacja gałki zależna od float + void UpdateLeverInt(TAnim *pAnim); // animacja gałki zależna od int (wartość) + void UpdateLeverEnum(TAnim *pAnim); // animacja gałki zależna od int (lista kątów) + private: // Ra: ciąg dalszy animacji, dopiero do ogarnięcia + // ABuWozki 060504 + vector3 bogieRot[2]; // Obroty wozkow w/m korpusu + TSubModel *smBogie[2]; // Wyszukiwanie max 2 wozkow + TSubModel *smWahacze[4]; // wahacze (np. nogi, dźwignia w drezynie) + TSubModel *smBrakeMode; // Ra 15-01: nastawa hamulca też + TSubModel *smLoadMode; // Ra 15-01: nastawa próżny/ładowny + double fWahaczeAmp; + // Winger 160204 - pantografy + double pantspeedfactor; + // animacje typu przesuw + TSubModel *smBuforLewy[2]; + TSubModel *smBuforPrawy[2]; + TAnimValveGear *pValveGear; + vector3 vFloor; // podłoga dla ładunku + public: + TAnim *pants; // indeks obiektu animującego dla pantografu 0 + double NoVoltTime; // czas od utraty zasilania + double dDoorMoveL; // NBMX + double dDoorMoveR; // NBMX + TSubModel *smBrakeSet; // nastawa hamulca (wajcha) + TSubModel *smLoadSet; // nastawa ładunku (wajcha) + TSubModel *smWiper; // wycieraczka (poniekąd też wajcha) + // Ra: koneic animacji do ogarnięcia - TButton btCoupler1; //sprzegi + private: + void ABuLittleUpdate(double ObjSqrDist); + bool btnOn; // ABu: czy byly uzywane buttony, jesli tak, to po renderingu wylacz + // bo ten sam model moze byc jeszcze wykorzystany przez inny obiekt! + double __fastcall ComputeRadius(vector3 p1, vector3 p2, vector3 p3, vector3 p4); + + 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 btCPneumatic1r; // ABu: to zeby nie bylo problemow przy laczeniu wagonow, TAirCoupler btCPneumatic2r; // jesli beda polaczone sprzegami 1<->1 lub 0<->0 - TAirCoupler btPneumatic1; //ABu: sprzegi powietrzne zolte + TAirCoupler btPneumatic1; // ABu: sprzegi powietrzne zolte TAirCoupler btPneumatic2; - TAirCoupler btPneumatic1r; //ABu: analogicznie jak 4 linijki wyzej + TAirCoupler btPneumatic1r; // ABu: analogicznie jak 4 linijki wyzej TAirCoupler btPneumatic2r; - TButton btCCtrl1; //sprzegi sterowania + TButton btCCtrl1; // sprzegi sterowania TButton btCCtrl2; - TButton btCPass1; //mostki przejsciowe + TButton btCPass1; // mostki przejsciowe TButton btCPass2; - char cp1, sp1, cp2, sp2; //ustawienia węży + char cp1, sp1, cp2, sp2; // ustawienia węży - TButton btEndSignals11; //sygnalu konca pociagu + TButton btEndSignals11; // sygnalu konca pociagu TButton btEndSignals13; TButton btEndSignals21; TButton btEndSignals23; - TButton btEndSignals1; //zeby bylo kompatybilne ze starymi modelami... + TButton btEndSignals1; // zeby bylo kompatybilne ze starymi modelami... TButton btEndSignals2; - TButton btEndSignalsTab1; //sygnaly konca pociagu (blachy) + TButton btEndSignalsTab1; // sygnaly konca pociagu (blachy) TButton btEndSignalsTab2; - TButton btHeadSignals11; //oswietlenie czolowe - przod + TButton btHeadSignals11; // oswietlenie czolowe - przod TButton btHeadSignals12; TButton btHeadSignals13; - TButton btHeadSignals21; //oswietlenie czolowe - tyl + TButton btHeadSignals21; // oswietlenie czolowe - tyl TButton btHeadSignals22; TButton btHeadSignals23; - 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 + 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 + int iAxles; // McZapkie: to potem mozna skasowac i zastapic iNumAxles double dRailLength; - double dRailPosition[MaxAxles]; //licznik pozycji osi w/m szyny - double dWheelsPosition[MaxAxles]; //pozycja osi w/m srodka pojazdu - TRealSound rsStukot[MaxAxles]; //dzwieki poszczegolnych osi //McZapkie-270202 - TRealSound rsSilnik; //McZapkie-010302 - silnik - TRealSound rsWentylator; //McZapkie-030302 - TRealSound rsPisk; //McZapkie-260302 - TRealSound rsDerailment; //McZapkie-051202 + double dRailPosition[MaxAxles]; // licznik pozycji osi w/m szyny + double dWheelsPosition[MaxAxles]; // pozycja osi w/m srodka pojazdu + TRealSound rsStukot[MaxAxles]; // dzwieki poszczegolnych osi //McZapkie-270202 + TRealSound rsSilnik; // McZapkie-010302 - silnik + TRealSound rsWentylator; // McZapkie-030302 + TRealSound rsPisk; // McZapkie-260302 + TRealSound rsDerailment; // McZapkie-051202 TRealSound rsPrzekladnia; TAdvancedSound sHorn1; TAdvancedSound sHorn2; - TAdvancedSound sCompressor; //NBMX wrzesien 2003 + TAdvancedSound sCompressor; // NBMX wrzesien 2003 TAdvancedSound sConverter; TAdvancedSound sSmallCompressor; TAdvancedSound sDepartureSignal; TAdvancedSound sTurbo; -//Winger 010304 -// TRealSound rsPanTup; //PSound sPantUp; + // Winger 010304 + // TRealSound rsPanTup; //PSound sPantUp; TRealSound sPantUp; TRealSound sPantDown; - TRealSound rsDoorOpen; //Ra: przeniesione z kabiny + TRealSound rsDoorOpen; // Ra: przeniesione z kabiny TRealSound rsDoorClose; double eng_vol_act; @@ -285,89 +295,90 @@ private: void __fastcall ABuModelRoll(); vector3 modelShake; - bool renderme; //yB - czy renderowac - //TRealSound sBrakeAcc; //dźwięk przyspieszacza + bool renderme; // yB - czy renderowac + // TRealSound sBrakeAcc; //dźwięk przyspieszacza PSound sBrakeAcc; bool bBrakeAcc; - TRealSound rsUnbrake; //yB - odglos luzowania + TRealSound rsUnbrake; // yB - odglos luzowania float ModCamRot; - int iInventory; //flagi bitowe posiadanych submodeli (np. świateł) - void __fastcall TurnOff(); -public: - 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: + int iInventory; // flagi bitowe posiadanych submodeli (np. świateł) + void __fastcall TurnOff(); - //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 + public: + 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 int CouplCounter; AnsiString asModel; -public: - void ABuScanObjects(int ScanDir,double ScanDist); -protected: - TDynamicObject* __fastcall ABuFindObject(TTrack *Track,int ScanDir,Byte &CouplFound,double &dist); + + public: + void ABuScanObjects(int ScanDir, double ScanDist); + + protected: + TDynamicObject *__fastcall ABuFindObject(TTrack *Track, int ScanDir, Byte &CouplFound, + double &dist); void __fastcall ABuCheckMyTrack(); -public: - int *iLights; //wskaźnik na bity zapalonych świateł (własne albo innego członu) - double fTrackBlock; //odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym pojazdem) - TDynamicObject* __fastcall PrevAny(); - TDynamicObject* __fastcall Prev(); - TDynamicObject* __fastcall Next(); - TDynamicObject* __fastcall NextC(int C); - double __fastcall NextDistance(double d=-1.0); - void __fastcall SetdMoveLen(double dMoveLen) {MoverParameters->dMoveLen=dMoveLen;} - void __fastcall ResetdMoveLen() {MoverParameters->dMoveLen=0;} - double __fastcall GetdMoveLen() {return MoverParameters->dMoveLen;} + public: + int *iLights; // wskaźnik na bity zapalonych świateł (własne albo innego członu) + double fTrackBlock; // odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym + // pojazdem) + TDynamicObject *__fastcall PrevAny(); + TDynamicObject *__fastcall Prev(); + TDynamicObject *__fastcall Next(); + TDynamicObject *__fastcall NextC(int C); + double __fastcall NextDistance(double d = -1.0); + void __fastcall SetdMoveLen(double dMoveLen) { MoverParameters->dMoveLen = dMoveLen; } + void __fastcall ResetdMoveLen() { MoverParameters->dMoveLen = 0; } + double __fastcall GetdMoveLen() { return MoverParameters->dMoveLen; } - int __fastcall GetPneumatic(bool front, bool red); - void __fastcall SetPneumatic(bool front, bool red); - AnsiString asName; - AnsiString __fastcall GetName() - { - return this?asName:AnsiString(""); - }; + int __fastcall GetPneumatic(bool front, bool red); + void __fastcall SetPneumatic(bool front, bool red); + AnsiString asName; + AnsiString __fastcall GetName() { return this ? asName : AnsiString(""); }; - TRealSound rsDiesielInc; //youBy - TRealSound rscurve; //youBy -// std::ofstream PneuLogFile; //zapis parametrow pneumatycznych -//youBy - dym - //TSmoke Smog; - //float EmR; - //vector3 smokeoffset; + TRealSound rsDiesielInc; // youBy + TRealSound rscurve; // youBy + // std::ofstream PneuLogFile; //zapis parametrow pneumatycznych + // youBy - dym + // TSmoke Smog; + // float EmR; + // vector3 smokeoffset; - TDynamicObject* __fastcall ABuScanNearestObject(TTrack *Track, double ScanDir, double ScanDist, int &CouplNr); - TDynamicObject* __fastcall GetFirstDynamic(int cpl_type); - //TDynamicObject* __fastcall GetFirstCabDynamic(int cpl_type); - void ABuSetModelShake(vector3 mShake); + TDynamicObject *__fastcall ABuScanNearestObject(TTrack *Track, double ScanDir, double ScanDist, + int &CouplNr); + TDynamicObject *__fastcall GetFirstDynamic(int cpl_type); + // TDynamicObject* __fastcall GetFirstCabDynamic(int cpl_type); + void ABuSetModelShake(vector3 mShake); - -//McZapkie-010302 + // McZapkie-010302 TController *Mechanik; - TController *ctOwner; //wskażnik na obiekt zarządzający składem + TController *ctOwner; // wskażnik na obiekt zarządzający składem bool MechInside; -//McZapkie-270202 + // McZapkie-270202 bool Controller; - bool bDisplayCab; //czy wyswietlac kabine w train.cpp - int iCabs; //maski bitowe modeli kabin - TTrack *MyTrack; //McZapkie-030303: tor na ktorym stoi, ABu + bool bDisplayCab; // czy wyswietlac kabine w train.cpp + int iCabs; // maski bitowe modeli kabin + TTrack *MyTrack; // McZapkie-030303: tor na ktorym stoi, ABu AnsiString asBaseDir; - GLuint ReplacableSkinID[5]; //McZapkie:zmienialne nadwozie - int iAlpha; //maska przezroczystości tekstur + GLuint ReplacableSkinID[5]; // McZapkie:zmienialne nadwozie + int iAlpha; // maska przezroczystości tekstur int iMultiTex; //<0 tekstury wskazane wpisem, >0 tekstury z przecinkami, =0 jedna - int iOverheadMask; //maska przydzielana przez AI pojazdom posiadającym pantograf, aby wymuszały jazdę bezprądową + int iOverheadMask; // maska przydzielana przez AI pojazdom posiadającym pantograf, aby wymuszały + // jazdę bezprądową TTractionParam tmpTraction; - double fAdjustment; //korekcja - docelowo przenieść do TrkFoll.cpp wraz z odległością od poprzedniego + double fAdjustment; // korekcja - docelowo przenieść do TrkFoll.cpp wraz z odległością od + // poprzedniego __fastcall TDynamicObject(); __fastcall ~TDynamicObject(); - double __fastcall TDynamicObject::Init - (//zwraca długość pojazdu albo 0, jeśli błąd - AnsiString Name, AnsiString BaseDir, AnsiString asReplacableSkin, AnsiString Type_Name, - TTrack *Track, double fDist, AnsiString DriverType, double fVel, AnsiString TrainName, - float Load, AnsiString LoadType,bool Reversed, AnsiString - ); - void __fastcall AttachPrev(TDynamicObject *Object, int iType= 1); + double __fastcall TDynamicObject::Init( // zwraca długość pojazdu albo 0, jeśli błąd + AnsiString Name, AnsiString BaseDir, AnsiString asReplacableSkin, AnsiString Type_Name, + TTrack *Track, double fDist, AnsiString DriverType, double fVel, AnsiString TrainName, + float Load, AnsiString LoadType, bool Reversed, AnsiString); + void __fastcall AttachPrev(TDynamicObject *Object, int iType = 1); bool __fastcall UpdateForce(double dt, double dt1, bool FullVer); void __fastcall LoadUpdate(); bool __fastcall Update(double dt, double dt1); @@ -377,64 +388,79 @@ public: void __fastcall Render(); void __fastcall RenderAlpha(); void __fastcall RenderSounds(); - inline vector3 __fastcall GetPosition() {return vPosition;}; - inline vector3 __fastcall HeadPosition() {return vCoulpler[iDirection^1];}; //pobranie współrzędnych czoła - inline vector3 __fastcall RearPosition() {return vCoulpler[iDirection];}; //pobranie współrzędnych tyłu - inline vector3 __fastcall AxlePositionGet() {return iAxleFirst?Axle1.pPosition:Axle0.pPosition;}; - inline vector3 __fastcall VectorFront() {return vFront;}; - inline vector3 __fastcall VectorUp() {return vUp;}; - inline vector3 __fastcall VectorLeft() {return vLeft;}; - inline double* __fastcall Matrix() {return mMatrix.getArray();}; + inline vector3 __fastcall GetPosition() { return vPosition; }; + inline vector3 __fastcall HeadPosition() + { + return vCoulpler[iDirection ^ 1]; + }; // pobranie współrzędnych czoła + inline vector3 __fastcall RearPosition() + { + return vCoulpler[iDirection]; + }; // pobranie współrzędnych tyłu + inline vector3 __fastcall AxlePositionGet() + { + return iAxleFirst ? Axle1.pPosition : Axle0.pPosition; + }; + inline vector3 __fastcall VectorFront() { return vFront; }; + inline vector3 __fastcall VectorUp() { return vUp; }; + inline vector3 __fastcall VectorLeft() { return vLeft; }; + inline double *__fastcall Matrix() { return mMatrix.getArray(); }; inline double __fastcall GetVelocity() { return MoverParameters->Vel; }; inline double __fastcall GetLength() { return MoverParameters->Dim.L; }; inline double __fastcall GetWidth() { return MoverParameters->Dim.W; }; - inline TTrack* __fastcall GetTrack() { return (iAxleFirst?Axle1.GetTrack():Axle0.GetTrack()); }; - //void __fastcall UpdatePos(); + inline TTrack *__fastcall GetTrack() + { + return (iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack()); + }; + // void __fastcall UpdatePos(); + // McZapkie-260202 + void __fastcall LoadMMediaFile(AnsiString BaseDir, AnsiString TypeName, + AnsiString ReplacableSkin); - //McZapkie-260202 - void __fastcall LoadMMediaFile(AnsiString BaseDir, AnsiString TypeName, AnsiString ReplacableSkin); - - inline double __fastcall ABuGetDirection() //ABu. - { - return (Axle1.GetTrack()==MyTrack?Axle1.GetDirection():Axle0.GetDirection()); - }; -// inline double __fastcall ABuGetTranslation() //ABu. -// {//zwraca przesunięcie wózka względem Point1 toru -// return (Axle1.GetTrack()==MyTrack?Axle1.GetTranslation():Axle0.GetTranslation()); -// }; - inline double __fastcall RaDirectionGet() - {//zwraca kierunek pojazdu na torze z aktywną osą - return iAxleFirst?Axle1.GetDirection():Axle0.GetDirection(); - }; - inline double __fastcall RaTranslationGet() - {//zwraca przesunięcie wózka względem Point1 toru z aktywną osią - return iAxleFirst?Axle1.GetTranslation():Axle0.GetTranslation(); - }; - inline TTrack* __fastcall RaTrackGet() - {//zwraca tor z aktywną osią - return iAxleFirst?Axle1.GetTrack():Axle0.GetTrack(); - }; - void CouplersDettach(double MinDist,int MyScanDir); - void __fastcall RadioStop(); - void __fastcall RaLightsSet(int head,int rear); - //void __fastcall RaAxleEvent(TEvent *e); - TDynamicObject* __fastcall FirstFind(int &coupler_nr); - float __fastcall GetEPP(); //wyliczanie sredniego cisnienia w PG - int __fastcall DirectionSet(int d); //ustawienie kierunku w składzie - int __fastcall DirectionGet() {return iDirection+iDirection-1;}; //odczyt kierunku w składzie - int DettachStatus(int dir); - int Dettach(int dir); - TDynamicObject* __fastcall Neightbour(int &dir); - void __fastcall CoupleDist(); - TDynamicObject* __fastcall ControlledFind(); - void __fastcall ParamSet(int what,int into); - int __fastcall RouteWish(TTrack *tr); //zapytanie do AI, po którym segmencie skrzyżowania jechać - void __fastcall DestinationSet(AnsiString to); - AnsiString __fastcall TextureTest(AnsiString &name); - void __fastcall OverheadTrack(float o); + inline double __fastcall ABuGetDirection() // ABu. + { + return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection()); + }; + // inline double __fastcall ABuGetTranslation() //ABu. + // {//zwraca przesunięcie wózka względem Point1 toru + // return (Axle1.GetTrack()==MyTrack?Axle1.GetTranslation():Axle0.GetTranslation()); + // }; + inline double __fastcall RaDirectionGet() + { // zwraca kierunek pojazdu na torze z aktywną osą + return iAxleFirst ? Axle1.GetDirection() : Axle0.GetDirection(); + }; + inline double __fastcall RaTranslationGet() + { // zwraca przesunięcie wózka względem Point1 toru z aktywną osią + return iAxleFirst ? Axle1.GetTranslation() : Axle0.GetTranslation(); + }; + inline TTrack *__fastcall RaTrackGet() + { // zwraca tor z aktywną osią + return iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack(); + }; + void CouplersDettach(double MinDist, int MyScanDir); + void __fastcall RadioStop(); + void __fastcall RaLightsSet(int head, int rear); + // void __fastcall RaAxleEvent(TEvent *e); + TDynamicObject *__fastcall FirstFind(int &coupler_nr); + float __fastcall GetEPP(); // wyliczanie sredniego cisnienia w PG + int __fastcall DirectionSet(int d); // ustawienie kierunku w składzie + int __fastcall DirectionGet() + { + return iDirection + iDirection - 1; + }; // odczyt kierunku w składzie + int DettachStatus(int dir); + int Dettach(int dir); + TDynamicObject *__fastcall Neightbour(int &dir); + void __fastcall CoupleDist(); + TDynamicObject *__fastcall ControlledFind(); + void __fastcall ParamSet(int what, int into); + int __fastcall RouteWish(TTrack *tr); // zapytanie do AI, po którym segmencie skrzyżowania + // jechać + void __fastcall DestinationSet(AnsiString to); + AnsiString __fastcall TextureTest(AnsiString &name); + void __fastcall OverheadTrack(float o); }; - //--------------------------------------------------------------------------- #endif diff --git a/EU07.cpp b/EU07.cpp index 7655e990..bc8f8fe3 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -76,96 +76,98 @@ USEUNIT("Console\LPT.cpp"); //--------------------------------------------------------------------------- #include "World.h" -HDC hDC=NULL; // Private GDI Device Context -HGLRC hRC=NULL; // Permanent Rendering Context -HWND hWnd=NULL; // Holds Our Window Handle +HDC hDC = NULL; // Private GDI Device Context +HGLRC hRC = NULL; // Permanent Rendering Context +HWND hWnd = NULL; // Holds Our Window Handle TWorld World; +// bool active=TRUE; //window active flag set to TRUE by default +bool fullscreen = TRUE; // fullscreen flag set to fullscreen mode by default +int WindowWidth = 800; +int WindowHeight = 600; +int Bpp = 32; -//bool active=TRUE; //window active flag set to TRUE by default -bool fullscreen=TRUE; //fullscreen flag set to fullscreen mode by default -int WindowWidth= 800; -int WindowHeight= 600; -int Bpp= 32; - -LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc //#include "dbgForm.h" //--------------------------------------------------------------------------- -int InitGL(GLvoid) // All Setup For OpenGL Goes Here +int InitGL(GLvoid) // All Setup For OpenGL Goes Here { - _clear87(); - _control87(MCW_EM,MCW_EM); - glewInit(); - //hunter-271211: przeniesione - //AllocConsole(); - //SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN); + _clear87(); + _control87(MCW_EM, MCW_EM); + glewInit(); + // hunter-271211: przeniesione + // AllocConsole(); + // SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN); - // ShaXbee-121209: Wlaczenie obslugi tablic wierzcholkow - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - Global::pWorld=&World; //Ra: wskaźnik potrzebny do usuwania pojazdów - return World.Init(hWnd,hDC); //true jeśli wszystko pójdzie dobrze + // ShaXbee-121209: Wlaczenie obslugi tablic wierzcholkow + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + Global::pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów + return World.Init(hWnd, hDC); // true jeśli wszystko pójdzie dobrze } //--------------------------------------------------------------------------- -GLvoid ReSizeGLScene(GLsizei width,GLsizei height) // resize and initialize the GL Window +GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // resize and initialize the GL Window { - WindowWidth=width; - WindowHeight=height; - if (height==0) // prevent a divide by zero by - height=1; // making height equal one - glViewport(0,0,width,height); // Reset The Current Viewport - glMatrixMode(GL_PROJECTION); // select the Projection Matrix - glLoadIdentity(); // reset the Projection Matrix - //calculate the aspect ratio of the window - gluPerspective(45.0f,(GLdouble)width/(GLdouble)height,0.2f,2500.0f); - glMatrixMode(GL_MODELVIEW); // select the Modelview Matrix - glLoadIdentity(); // reset the Modelview Matrix + WindowWidth = width; + WindowHeight = height; + if (height == 0) // prevent a divide by zero by + height = 1; // making height equal one + glViewport(0, 0, width, height); // Reset The Current Viewport + glMatrixMode(GL_PROJECTION); // select the Projection Matrix + glLoadIdentity(); // reset the Projection Matrix + // calculate the aspect ratio of the window + gluPerspective(45.0f, (GLdouble)width / (GLdouble)height, 0.2f, 2500.0f); + glMatrixMode(GL_MODELVIEW); // select the Modelview Matrix + glLoadIdentity(); // reset the Modelview Matrix } //--------------------------------------------------------------------------- GLvoid KillGLWindow(GLvoid) // properly kill the window { - if (hRC) // Do We Have A Rendering Context? - { - if (!wglMakeCurrent(NULL,NULL)) // are we able to release the DC and RC contexts? - { - ErrorLog("Fail: window releasing"); - MessageBox(NULL,"Release of DC and RC failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); - } + if (hRC) // Do We Have A Rendering Context? + { + if (!wglMakeCurrent(NULL, NULL)) // are we able to release the DC and RC contexts? + { + ErrorLog("Fail: window releasing"); + MessageBox(NULL, "Release of DC and RC failed.", "SHUTDOWN ERROR", + MB_OK | MB_ICONINFORMATION); + } - if (!wglDeleteContext(hRC)) // are we able to delete the RC? - { - ErrorLog("Fail: rendering context releasing"); - MessageBox(NULL,"Release rendering context failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); - } - hRC=NULL; // set RC to NULL - } + if (!wglDeleteContext(hRC)) // are we able to delete the RC? + { + ErrorLog("Fail: rendering context releasing"); + MessageBox(NULL, "Release rendering context failed.", "SHUTDOWN ERROR", + MB_OK | MB_ICONINFORMATION); + } + hRC = NULL; // set RC to NULL + } - if (hDC && !ReleaseDC(hWnd,hDC)) // are we able to release the DC? - { - ErrorLog("Fail: device context releasing"); - MessageBox(NULL,"Release device context failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); - hDC=NULL; // set DC to NULL - } + if (hDC && !ReleaseDC(hWnd, hDC)) // are we able to release the DC? + { + ErrorLog("Fail: device context releasing"); + MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", + MB_OK | MB_ICONINFORMATION); + hDC = NULL; // set DC to NULL + } - if (hWnd && !DestroyWindow(hWnd)) // are we able to destroy the window? - { - ErrorLog("Fail: window destroying"); - MessageBox(NULL,"Could not release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); - hWnd=NULL; // set hWnd to NULL - } + if (hWnd && !DestroyWindow(hWnd)) // are we able to destroy the window? + { + ErrorLog("Fail: window destroying"); + MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); + hWnd = NULL; // set hWnd to NULL + } - if (fullscreen) // Are We In Fullscreen Mode? - { - ChangeDisplaySettings(NULL,0); // if so switch back to the desktop - ShowCursor(TRUE); // show mouse pointer - } -// KillFont(); + if (fullscreen) // Are We In Fullscreen Mode? + { + ChangeDisplaySettings(NULL, 0); // if so switch back to the desktop + ShowCursor(TRUE); // show mouse pointer + } + // KillFont(); } /* This code creates our OpenGL Window. Parameters are: * @@ -175,551 +177,573 @@ GLvoid KillGLWindow(GLvoid) // properly kill the window * bits - number of bits to use for color (8/16/24/32) * * fullscreenflag - use fullscreen mode (TRUE) or windowed mode (FALSE) */ -BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) +BOOL CreateGLWindow(char *title, int width, int height, int bits, bool fullscreenflag) { - GLuint PixelFormat; // holds the results after searching for a match - HINSTANCE hInstance; // holds the instance of the application - WNDCLASS wc; // windows class structure - DWORD dwExStyle; // window extended style - DWORD dwStyle; // window style - RECT WindowRect; // grabs rectangle upper left / lower right values - WindowRect.left=(long)0; // set left value to 0 - WindowRect.right=(long)width; // set right value to requested width - WindowRect.top=(long)0; // set top value to 0 - WindowRect.bottom=(long)height; // set bottom value to requested height + GLuint PixelFormat; // holds the results after searching for a match + HINSTANCE hInstance; // holds the instance of the application + WNDCLASS wc; // windows class structure + DWORD dwExStyle; // window extended style + DWORD dwStyle; // window style + RECT WindowRect; // grabs rectangle upper left / lower right values + WindowRect.left = (long)0; // set left value to 0 + WindowRect.right = (long)width; // set right value to requested width + WindowRect.top = (long)0; // set top value to 0 + WindowRect.bottom = (long)height; // set bottom value to requested height - fullscreen=fullscreenflag; // set the global fullscreen flag + fullscreen = fullscreenflag; // set the global fullscreen flag - hInstance =GetModuleHandle(NULL); // grab an instance for our window - wc.style =CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // redraw on size, and own DC for window. - wc.lpfnWndProc =(WNDPROC) WndProc; // wndproc handles messages - wc.cbClsExtra =0; // no extra window data - wc.cbWndExtra =0; // no extra window data - wc.hInstance =hInstance; // set the instance - wc.hIcon =LoadIcon(NULL, IDI_WINLOGO); // load the default icon - wc.hCursor =LoadCursor(NULL, IDC_ARROW); // load the arrow pointer - wc.hbrBackground=NULL; // no background required for GL - wc.lpszMenuName =NULL; // we don't want a menu - wc.lpszClassName="EU07"; //nazwa okna do komunikacji zdalnej // Set The Class Name + hInstance = GetModuleHandle(NULL); // grab an instance for our window + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // redraw on size, and own DC for window. + wc.lpfnWndProc = (WNDPROC)WndProc; // wndproc handles messages + wc.cbClsExtra = 0; // no extra window data + wc.cbWndExtra = 0; // no extra window data + wc.hInstance = hInstance; // set the instance + wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // load the default icon + wc.hCursor = LoadCursor(NULL, IDC_ARROW); // load the arrow pointer + wc.hbrBackground = NULL; // no background required for GL + wc.lpszMenuName = NULL; // we don't want a menu + wc.lpszClassName = "EU07"; // nazwa okna do komunikacji zdalnej + // // Set The Class Name - if (!arbMultisampleSupported) //tylko dla pierwszego okna - if (!RegisterClass(&wc)) // Attempt To Register The Window Class - { - ErrorLog("Fail: window class registeration"); - MessageBox(NULL,"Failed to register the window class.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return FALSE; // Return FALSE - } + if (!arbMultisampleSupported) // tylko dla pierwszego okna + if (!RegisterClass(&wc)) // Attempt To Register The Window Class + { + ErrorLog("Fail: window class registeration"); + MessageBox(NULL, "Failed to register the window class.", "ERROR", + MB_OK | MB_ICONEXCLAMATION); + return FALSE; // Return FALSE + } - if (fullscreen) // Attempt Fullscreen Mode? - { - DEVMODE dmScreenSettings; // device mode - memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // makes sure memory's cleared - dmScreenSettings.dmSize=sizeof(dmScreenSettings); // size of the devmode structure + if (fullscreen) // Attempt Fullscreen Mode? + { + DEVMODE dmScreenSettings; // device mode + memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // makes sure memory's cleared + dmScreenSettings.dmSize = sizeof(dmScreenSettings); // size of the devmode structure - //tolaris-240403: poprawka na odswiezanie monitora - // locate primary monitor... - if (Global::bAdjustScreenFreq) - { - POINT point; point.x=0; point.y=0; - MONITORINFOEX monitorinfo; monitorinfo.cbSize=sizeof(MONITORINFOEX); - ::GetMonitorInfo( ::MonitorFromPoint(point,MONITOR_DEFAULTTOPRIMARY),&monitorinfo); - // ..and query for highest supported refresh rate - unsigned int refreshrate=0; - int i=0; - while (::EnumDisplaySettings(monitorinfo.szDevice,i,&dmScreenSettings)) - { - if (i>0) - if (dmScreenSettings.dmPelsWidth==(unsigned int)width) - if (dmScreenSettings.dmPelsHeight==(unsigned int)height) - if (dmScreenSettings.dmBitsPerPel==(unsigned int)bits) - if (dmScreenSettings.dmDisplayFrequency>refreshrate) - refreshrate=dmScreenSettings.dmDisplayFrequency; - ++i; - } - // fill refresh rate info for screen mode change - dmScreenSettings.dmDisplayFrequency=refreshrate; - dmScreenSettings.dmFields=DM_DISPLAYFREQUENCY; - } - dmScreenSettings.dmPelsWidth =width; // selected screen width - dmScreenSettings.dmPelsHeight=height; // selected screen height - dmScreenSettings.dmBitsPerPel=bits; // selected bits per pixel - dmScreenSettings.dmFields=dmScreenSettings.dmFields|DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; + // tolaris-240403: poprawka na odswiezanie monitora + // locate primary monitor... + if (Global::bAdjustScreenFreq) + { + POINT point; + point.x = 0; + point.y = 0; + MONITORINFOEX monitorinfo; + monitorinfo.cbSize = sizeof(MONITORINFOEX); + ::GetMonitorInfo(::MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY), &monitorinfo); + // ..and query for highest supported refresh rate + unsigned int refreshrate = 0; + int i = 0; + while (::EnumDisplaySettings(monitorinfo.szDevice, i, &dmScreenSettings)) + { + if (i > 0) + if (dmScreenSettings.dmPelsWidth == (unsigned int)width) + if (dmScreenSettings.dmPelsHeight == (unsigned int)height) + if (dmScreenSettings.dmBitsPerPel == (unsigned int)bits) + if (dmScreenSettings.dmDisplayFrequency > refreshrate) + refreshrate = dmScreenSettings.dmDisplayFrequency; + ++i; + } + // fill refresh rate info for screen mode change + dmScreenSettings.dmDisplayFrequency = refreshrate; + dmScreenSettings.dmFields = DM_DISPLAYFREQUENCY; + } + dmScreenSettings.dmPelsWidth = width; // selected screen width + dmScreenSettings.dmPelsHeight = height; // selected screen height + dmScreenSettings.dmBitsPerPel = bits; // selected bits per pixel + dmScreenSettings.dmFields = + dmScreenSettings.dmFields | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - // Try to set selected mode and get results. NOTE: CDS_FULLSCREEN gets rid of start bar. - if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) - { - // If the mode fails, offer two options. Quit or use windowed mode. - ErrorLog("Fail: full screen"); - if (MessageBox(NULL,"The requested fullscreen mode is not supported by\nyour video card. Use windowed mode instead?","EU07",MB_YESNO|MB_ICONEXCLAMATION)==IDYES) - { - fullscreen=FALSE; // Windowed Mode Selected. Fullscreen = FALSE - } - else - { - // Pop Up A Message Box Letting User Know The Program Is Closing. - Error("Program will now close."); - return FALSE; // Return FALSE - } - } - } + // Try to set selected mode and get results. NOTE: CDS_FULLSCREEN gets rid of start bar. + if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) + { + // If the mode fails, offer two options. Quit or use windowed mode. + ErrorLog("Fail: full screen"); + if (MessageBox(NULL, "The requested fullscreen mode is not supported by\nyour video " + "card. Use windowed mode instead?", + "EU07", MB_YESNO | MB_ICONEXCLAMATION) == IDYES) + { + fullscreen = FALSE; // Windowed Mode Selected. Fullscreen = FALSE + } + else + { + // Pop Up A Message Box Letting User Know The Program Is Closing. + Error("Program will now close."); + return FALSE; // Return FALSE + } + } + } - if (fullscreen) // Are We Still In Fullscreen Mode? - { - dwExStyle=WS_EX_APPWINDOW; // Window Extended Style - dwStyle=WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // Windows Style - ShowCursor(FALSE); // Hide Mouse Pointer - } - else - { - dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style - dwStyle=WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // Windows Style - } + if (fullscreen) // Are We Still In Fullscreen Mode? + { + dwExStyle = WS_EX_APPWINDOW; // Window Extended Style + dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // Windows Style + ShowCursor(FALSE); // Hide Mouse Pointer + } + else + { + dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style + dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // Windows Style + } - AdjustWindowRectEx(&WindowRect,dwStyle,FALSE,dwExStyle); // Adjust Window To True Requested Size + AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, + dwExStyle); // Adjust Window To True Requested Size - // Create The Window - if (NULL==(hWnd=CreateWindowEx(dwExStyle, // Extended Style For The Window - "EU07", // Class Name - title, // Window Title - dwStyle | // Defined Window Style - WS_CLIPSIBLINGS | // Required Window Style - WS_CLIPCHILDREN, // Required Window Style - 0, 0, // Window Position - WindowRect.right-WindowRect.left, // Calculate Window Width - WindowRect.bottom-WindowRect.top, // Calculate Window Height - NULL, // No Parent Window - NULL, // No Menu - hInstance, // Instance - NULL))) // Dont Pass Anything To WM_CREATE - { - KillGLWindow(); // Reset The Display - ErrorLog("Fail: window creation"); - MessageBox(NULL,"Window creation error.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return FALSE; // Return FALSE - } + // Create The Window + if (NULL == + (hWnd = CreateWindowEx(dwExStyle, // Extended Style For The Window + "EU07", // Class Name + title, // Window Title + dwStyle | // Defined Window Style + WS_CLIPSIBLINGS | // Required Window Style + WS_CLIPCHILDREN, // Required Window Style + 0, + 0, // Window Position + WindowRect.right - WindowRect.left, // Calculate Window Width + WindowRect.bottom - WindowRect.top, // Calculate Window Height + NULL, // No Parent Window + NULL, // No Menu + hInstance, // Instance + NULL))) // Dont Pass Anything To WM_CREATE + { + KillGLWindow(); // Reset The Display + ErrorLog("Fail: window creation"); + MessageBox(NULL, "Window creation error.", "ERROR", MB_OK | MB_ICONEXCLAMATION); + return FALSE; // Return FALSE + } - static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be - { - sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor - 1, // Version Number - PFD_DRAW_TO_WINDOW | // Format Must Support Window - PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - PFD_DOUBLEBUFFER, // Must Support Double Buffering - PFD_TYPE_RGBA, // Request An RGBA Format - bits, // Select Our Color Depth - 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // No Alpha Buffer - 0, // Shift Bit Ignored - 0, // No Accumulation Buffer - 0, 0, 0, 0, // Accumulation Bits Ignored - 24, // 32Bit Z-Buffer (Depth Buffer) - 0, // No Stencil Buffer - 0, // No Auxiliary Buffer - PFD_MAIN_PLANE, // Main Drawing Layer - 0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; + static PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be + { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + bits, // Select Our Color Depth + 0, + 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 24, // 32Bit Z-Buffer (Depth Buffer) + 0, // No Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; - if (NULL==(hDC=GetDC(hWnd))) // Did We Get A Device Context? - { - KillGLWindow(); // Reset The Display - ErrorLog("Fail: device context"); - MessageBox(NULL,"Can't create a GL device context.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return FALSE; // Return FALSE - } + if (NULL == (hDC = GetDC(hWnd))) // Did We Get A Device Context? + { + KillGLWindow(); // Reset The Display + ErrorLog("Fail: device context"); + MessageBox(NULL, "Can't create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); + return FALSE; // Return FALSE + } -/* - Our first pass, Multisampling hasn't been created yet, so we create a window normally - If it is supported, then we're on our second pass - that means we want to use our pixel format for sampling - so set PixelFormat to arbMultiSampleformat instead -*/ - if (!arbMultisampleSupported) - { - if (NULL==(PixelFormat=ChoosePixelFormat(hDC,&pfd))) // Did Windows Find A Matching Pixel Format? - { - KillGLWindow(); // Reset The Display - ErrorLog("Fail: pixelformat"); - MessageBox(NULL,"Can't find a suitable pixelformat.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return FALSE; // Return FALSE - } - } - else - PixelFormat=arbMultisampleFormat; + /* + Our first pass, Multisampling hasn't been created yet, so we create a window normally + If it is supported, then we're on our second pass + that means we want to use our pixel format for sampling + so set PixelFormat to arbMultiSampleformat instead + */ + if (!arbMultisampleSupported) + { + if (NULL == (PixelFormat = + ChoosePixelFormat(hDC, &pfd))) // Did Windows Find A Matching Pixel Format? + { + KillGLWindow(); // Reset The Display + ErrorLog("Fail: pixelformat"); + MessageBox(NULL, "Can't find a suitable pixelformat.", "ERROR", + MB_OK | MB_ICONEXCLAMATION); + return FALSE; // Return FALSE + } + } + else + PixelFormat = arbMultisampleFormat; - if (!SetPixelFormat(hDC,PixelFormat,&pfd)) // Are We Able To Set The Pixel Format? - { - KillGLWindow(); // Reset The Display - ErrorLog("Fail: pixelformat"); - MessageBox(NULL,"Can't set the pixelformat.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return FALSE; // Return FALSE - } + if (!SetPixelFormat(hDC, PixelFormat, &pfd)) // Are We Able To Set The Pixel Format? + { + KillGLWindow(); // Reset The Display + ErrorLog("Fail: pixelformat"); + MessageBox(NULL, "Can't set the pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION); + return FALSE; // Return FALSE + } - if (NULL==(hRC=wglCreateContext(hDC))) // Are We Able To Get A Rendering Context? - { - KillGLWindow(); // Reset The Display - ErrorLog("Fail: OpenGL rendering context creation"); - MessageBox(NULL,"Can't create a GL rendering context.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return FALSE; // Return FALSE - } + if (NULL == (hRC = wglCreateContext(hDC))) // Are We Able To Get A Rendering Context? + { + KillGLWindow(); // Reset The Display + ErrorLog("Fail: OpenGL rendering context creation"); + MessageBox(NULL, "Can't create a GL rendering context.", "ERROR", + MB_OK | MB_ICONEXCLAMATION); + return FALSE; // Return FALSE + } - if (!wglMakeCurrent(hDC,hRC)) // Try To Activate The Rendering Context - { - KillGLWindow(); // Reset The Display - ErrorLog("Fail: OpenGL rendering context activation"); - MessageBox(NULL,"Can't activate the GL rendering context.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return FALSE; // Return FALSE - } + if (!wglMakeCurrent(hDC, hRC)) // Try To Activate The Rendering Context + { + KillGLWindow(); // Reset The Display + ErrorLog("Fail: OpenGL rendering context activation"); + MessageBox(NULL, "Can't activate the GL rendering context.", "ERROR", + MB_OK | MB_ICONEXCLAMATION); + return FALSE; // Return FALSE + } - /* - Now that our window is created, we want to queary what samples are available - we call our InitMultiSample window - if we return a valid context, we want to destroy our current window - and create a new one using the multisample interface. - */ - if (Global::iMultisampling) - if (!arbMultisampleSupported) - if ((Global::iMultisampling=InitMultisample(hInstance,hWnd,pfd,1<dwData=='EU07') //sygnatura danych - World.OnCommandGet((DaneRozkaz*)(pDane->lpData)); - break; - case WM_ACTIVATE: //watch for window activate message - //case WM_ACTIVATEAPP: - {//Ra: uzależnienie aktywności od bycia na wierzchu - Global::bActive=(LOWORD(wParam)!=WA_INACTIVE); - if (Global::bInactivePause) //jeśli ma być pauzowanie okna w tle - if (Global::bActive) - Global::iPause&=~4; //odpauzowanie, gdy jest na pierwszym planie - else - Global::iPause|=4; //włączenie pauzy, gdy nieaktywy - if (Global::bActive) - SetCursorPos(mx,my); - ShowCursor(!Global::bActive); -/* - if (!HIWORD(wParam)) //check minimization state - active=TRUE; //program is active - else - active=FALSE; //program is no longer active -*/ - return 0; // return to the message loop - } - case WM_SYSCOMMAND: //intercept system commands - { - switch (wParam) //check system calls - { - case 61696: //F10 - World.OnKeyDown(VK_F10); - return 0; - case SC_SCREENSAVE: //screensaver trying to start? - case SC_MONITORPOWER: //monitor trying to enter powersave? - return 0; //prevent from happening - } - break; //exit - } - case WM_CLOSE: // did we receive a close message? - { - PostQuitMessage(0); //send a quit message [Alt]+[F4] - return 0; //jump back - } - case WM_MOUSEMOVE: - { - //mx= 100;//Global::iWindowWidth/2; - //my= 100;//Global::iWindowHeight/2; - //SetCursorPos(Global::iWindowWidth/2,Global::iWindowHeight/2); - //m_x= LOWORD(lParam); - //m_y= HIWORD(lParam); - GetCursorPos(&mouse); - if (Global::bActive && ((mouse.x!=mx) || (mouse.y!=my))) - { - World.OnMouseMove(double(mouse.x-mx)*0.005,double(mouse.y-my)*0.01); - SetCursorPos(mx,my); - } - return 0; // jump back - } - case WM_KEYUP : - if (Global::bActive) - { - World.OnKeyUp(wParam); - return 0; - } - case WM_KEYDOWN : - if (Global::bActive) - { - if (wParam!=17) //bo naciśnięcia [Ctrl] nie ma po co przekazywać - if (wParam!=145) //[Scroll Lock] też nie - World.OnKeyDown(wParam); - switch (wParam) + TRect rect; + switch (uMsg) // check for windows messages { - case VK_ESCAPE: //[Esc] pauzuje tylko bez Debugmode - if (DebugModeFlag) break; - case 19: //[Pause] - if (Global::iPause&1) //jeśli pauza startowa - Global::iPause&=~1; //odpauzowanie, gdy po wczytaniu miało nie startować - else if (!(Global::iMultiplayer&2)) //w multiplayerze pauza nie ma sensu - if (!Console::Pressed(VK_CONTROL)) //z [Ctrl] to radiostop jest - //Ra: poniższe nie ma sensu, bo brak komunikacji natychmiast zapauzuje ponownie - //if (Global::iPause&8) //jeśli pauza związana z brakiem komunikacji z PoKeys - // Global::iPause&=~10; //odpauzowanie pauzy PoKeys (chyba nic nie da) i ewentualnie klawiszowej również - //else - Global::iPause^=2; //zmiana stanu zapauzowania - if (Global::iPause) //jak pauza - Global::iTextMode=VK_F1; //to wyświetlić zegar i informację - break; - case VK_F7: - if (DebugModeFlag) - {//siatki wyświetlane tyko w trybie testowym - Global::bWireFrame=!Global::bWireFrame; - ++Global::iReCompile; //odświeżyć siatki - //Ra: jeszcze usunąć siatki ze skompilowanych obiektów! - } - break; + case WM_PASTE: //[Ctrl]+[V] potrzebujemy do innych celów + return 0; + case WM_COPYDATA: // obsługa danych przesłanych przez program sterujący + pDane = (PCOPYDATASTRUCT)lParam; + if (pDane->dwData == 'EU07') // sygnatura danych + World.OnCommandGet((DaneRozkaz *)(pDane->lpData)); + break; + case WM_ACTIVATE: // watch for window activate message + // case WM_ACTIVATEAPP: + { // Ra: uzależnienie aktywności od bycia na wierzchu + Global::bActive = (LOWORD(wParam) != WA_INACTIVE); + if (Global::bInactivePause) // jeśli ma być pauzowanie okna w tle + if (Global::bActive) + Global::iPause &= ~4; // odpauzowanie, gdy jest na pierwszym planie + else + Global::iPause |= 4; // włączenie pauzy, gdy nieaktywy + if (Global::bActive) + SetCursorPos(mx, my); + ShowCursor(!Global::bActive); + /* + if (!HIWORD(wParam)) //check minimization state + active=TRUE; //program is active + else + active=FALSE; //program is no longer active + */ + return 0; // return to the message loop + } + case WM_SYSCOMMAND: // intercept system commands + { + switch (wParam) // check system calls + { + case 61696: // F10 + World.OnKeyDown(VK_F10); + return 0; + case SC_SCREENSAVE: // screensaver trying to start? + case SC_MONITORPOWER: // monitor trying to enter powersave? + return 0; // prevent from happening + } + break; // exit } - } - return 0; // jump back - case WM_CHAR: - { -/* - switch ((TCHAR) wParam) - { - // case 'q': - // done= true; - // KillGLWindow(); - // PostQuitMessage(0); - // DestroyWindow( hWnd ); - // break; - }; -*/ - return 0; - } - case WM_SIZE: //resize the OpenGL window - { - ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // LoWord=Width, HiWord=Height - if (GetWindowRect(hWnd,&rect)) - {//Ra: zmiana rozmiaru okna bez przesuwania myszy - //mx=WindowWidth/2+rect.left; // horizontal position - //my=WindowHeight/2+rect.top; // vertical position - //SetCursorPos(mx,my); - } - return 0; //jump back - } - case WM_MOVE: //przesuwanie okna? - { - mx=WindowWidth/2+LOWORD(lParam); // horizontal position - my=WindowHeight/2+HIWORD(lParam); // vertical position - //SetCursorPos(mx,my); - break; - } - case WM_PAINT: - {//odrysowanie okna - break; - } - //case WM_ERASEBKGND: //Process this message to keep Windows from erasing background. - case MM_JOY1BUTTONDOWN: - { - //WriteLog("Joystick button "+AnsiString(wParam)); - break; - } - case WM_CREATE: - /* Capture the joystick. If this fails, beep and display - * error, then quit. - */ - if (joySetCapture(hWnd,JOYSTICKID1,0,FALSE)) - { - //MessageBeep(MB_ICONEXCLAMATION); - //MessageBox(hWnd,"Couldn't capture the joystick",NULL,MB_OK|MB_ICONEXCLAMATION); - //return -1; - } - break; - } - // pass all unhandled messages to DefWindowProc - return DefWindowProc(hWnd,uMsg,wParam,lParam); + case WM_CLOSE: // did we receive a close message? + { + PostQuitMessage(0); // send a quit message [Alt]+[F4] + return 0; // jump back + } + case WM_MOUSEMOVE: + { + // mx= 100;//Global::iWindowWidth/2; + // my= 100;//Global::iWindowHeight/2; + // SetCursorPos(Global::iWindowWidth/2,Global::iWindowHeight/2); + // m_x= LOWORD(lParam); + // m_y= HIWORD(lParam); + GetCursorPos(&mouse); + if (Global::bActive && ((mouse.x != mx) || (mouse.y != my))) + { + World.OnMouseMove(double(mouse.x - mx) * 0.005, double(mouse.y - my) * 0.01); + SetCursorPos(mx, my); + } + return 0; // jump back + } + case WM_KEYUP: + if (Global::bActive) + { + World.OnKeyUp(wParam); + return 0; + } + case WM_KEYDOWN: + if (Global::bActive) + { + if (wParam != 17) // bo naciśnięcia [Ctrl] nie ma po co przekazywać + if (wParam != 145) //[Scroll Lock] też nie + World.OnKeyDown(wParam); + switch (wParam) + { + case VK_ESCAPE: //[Esc] pauzuje tylko bez Debugmode + if (DebugModeFlag) + break; + case 19: //[Pause] + if (Global::iPause & 1) // jeśli pauza startowa + Global::iPause &= ~1; // odpauzowanie, gdy po wczytaniu miało nie startować + else if (!(Global::iMultiplayer & 2)) // w multiplayerze pauza nie ma sensu + if (!Console::Pressed(VK_CONTROL)) // z [Ctrl] to radiostop jest + // Ra: poniższe nie ma sensu, bo brak komunikacji natychmiast zapauzuje + // ponownie + // if (Global::iPause&8) //jeśli pauza związana z brakiem komunikacji z + // PoKeys + // Global::iPause&=~10; //odpauzowanie pauzy PoKeys (chyba nic nie da) i + // ewentualnie klawiszowej również + // else + Global::iPause ^= 2; // zmiana stanu zapauzowania + if (Global::iPause) // jak pauza + Global::iTextMode = VK_F1; // to wyświetlić zegar i informację + break; + case VK_F7: + if (DebugModeFlag) + { // siatki wyświetlane tyko w trybie testowym + Global::bWireFrame = !Global::bWireFrame; + ++Global::iReCompile; // odświeżyć siatki + // Ra: jeszcze usunąć siatki ze skompilowanych obiektów! + } + break; + } + } + return 0; // jump back + case WM_CHAR: + { + /* + switch ((TCHAR) wParam) + { + // case 'q': + // done= true; + // KillGLWindow(); + // PostQuitMessage(0); + // DestroyWindow( hWnd ); + // break; + }; + */ + return 0; + } + case WM_SIZE: // resize the OpenGL window + { + ReSizeGLScene(LOWORD(lParam), HIWORD(lParam)); // LoWord=Width, HiWord=Height + if (GetWindowRect(hWnd, &rect)) + { // Ra: zmiana rozmiaru okna bez przesuwania myszy + // mx=WindowWidth/2+rect.left; // horizontal position + // my=WindowHeight/2+rect.top; // vertical position + // SetCursorPos(mx,my); + } + return 0; // jump back + } + case WM_MOVE: // przesuwanie okna? + { + mx = WindowWidth / 2 + LOWORD(lParam); // horizontal position + my = WindowHeight / 2 + HIWORD(lParam); // vertical position + // SetCursorPos(mx,my); + break; + } + case WM_PAINT: + { // odrysowanie okna + break; + } + // case WM_ERASEBKGND: //Process this message to keep Windows from erasing background. + case MM_JOY1BUTTONDOWN: + { + // WriteLog("Joystick button "+AnsiString(wParam)); + break; + } + case WM_CREATE: + /* Capture the joystick. If this fails, beep and display + * error, then quit. + */ + if (joySetCapture(hWnd, JOYSTICKID1, 0, FALSE)) + { + // MessageBeep(MB_ICONEXCLAMATION); + // MessageBox(hWnd,"Couldn't capture the joystick",NULL,MB_OK|MB_ICONEXCLAMATION); + // return -1; + } + break; + } + // pass all unhandled messages to DefWindowProc + return DefWindowProc(hWnd, uMsg, wParam, lParam); }; - - - -int WINAPI WinMain( HINSTANCE hInstance, //instance - HINSTANCE hPrevInstance, //previous instance - LPSTR lpCmdLine, //command line parameters - int nCmdShow) //window show state +int WINAPI WinMain(HINSTANCE hInstance, // instance + HINSTANCE hPrevInstance, // previous instance + LPSTR lpCmdLine, // command line parameters + int nCmdShow) // window show state { - MSG msg; //windows message structure - BOOL done=FALSE; //bool variable to exit loop - fullscreen=true; - DecimalSeparator= '.'; -/* //Ra: tutaj to nie działa - zwraca NULL - //najpierw ustalmy wersję OpenGL - AnsiString glver=((char*)glGetString(GL_VERSION)); - while (glver.LastDelimiter(".")>glver.Pos(".")) - glver=glver.SubString(1,glver.LastDelimiter(".")-1); //obcięcie od drugiej kropki - try {Global::fOpenGL=glver.ToDouble();} catch (...) {Global::fOpenGL=0.0;} - Global::bOpenGL_1_5=(Global::fOpenGL>=1.5); -*/ - DeleteFile("errors.txt"); //usunięcie starego - Global::LoadIniFile("eu07.ini"); //teraz dopiero można przejrzeć plik z ustawieniami - Global::InitKeys("keys.ini"); //wczytanie mapowania klawiszy - jest na stałe + MSG msg; // windows message structure + BOOL done = FALSE; // bool variable to exit loop + fullscreen = true; + DecimalSeparator = '.'; + /* //Ra: tutaj to nie działa - zwraca NULL + //najpierw ustalmy wersję OpenGL + AnsiString glver=((char*)glGetString(GL_VERSION)); + while (glver.LastDelimiter(".")>glver.Pos(".")) + glver=glver.SubString(1,glver.LastDelimiter(".")-1); //obcięcie od drugiej kropki + try {Global::fOpenGL=glver.ToDouble();} catch (...) {Global::fOpenGL=0.0;} + Global::bOpenGL_1_5=(Global::fOpenGL>=1.5); + */ + DeleteFile("errors.txt"); // usunięcie starego + Global::LoadIniFile("eu07.ini"); // teraz dopiero można przejrzeć plik z ustawieniami + Global::InitKeys("keys.ini"); // wczytanie mapowania klawiszy - jest na stałe - //hunter-271211: ukrywanie konsoli - if (Global::iWriteLogEnabled&2) - { - AllocConsole(); - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN); - } - AnsiString str=lpCmdLine; //parametry uruchomienia - if (!str.IsEmpty()) - {//analizowanie parametrów - TQueryParserComp *Parser; - Parser=new TQueryParserComp(NULL); - Parser->TextToParse=lpCmdLine; - Parser->First(); - while (!Parser->EndOfFile) - { - str=Parser->GetNextSymbol().LowerCase(); - if (str==AnsiString("-s")) - {//nazwa scenerii - str=Parser->GetNextSymbol().LowerCase(); - strcpy(Global::szSceneryFile,str.c_str()); - } - else if (str==AnsiString("-v")) - {//nazwa wybranego pojazdu - str=Parser->GetNextSymbol().LowerCase(); - Global::asHumanCtrlVehicle=str; - } - else if (str==AnsiString("-modifytga")) - {//wykonanie modyfikacji wszystkich plików TGA - Global::iModifyTGA=-1; //specjalny tryb wykonania totalnej modyfikacji - } - else if (str==AnsiString("-e3d")) - {//wygenerowanie wszystkich plików E3D - if (Global::iConvertModels>0) - Global::iConvertModels=-Global::iConvertModels; //specjalny tryb - else - Global::iConvertModels=-7; //z optymalizacją, bananami i prawidłowym Opacity - } - else - Error("Program usage: EU07 [-s sceneryfilepath] [-v vehiclename] [-modifytga] [-e3d]",!Global::iWriteLogEnabled); - } - delete Parser; //ABu 050205: tego wczesniej nie bylo - } -/* MC: usunalem tymczasowo bo sie gryzlo z nowym parserem - 8.6.2003 - AnsiString csp=AnsiString(Global::szSceneryFile); - csp=csp.Delete(csp.Pos(AnsiString(strrchr(Global::szSceneryFile,'/')))+1,csp.Length()); - Global::asCurrentSceneryPath=csp; -*/ - - fullscreen=Global::bFullScreen; - WindowWidth=Global::iWindowWidth; - WindowHeight=Global::iWindowHeight; - Bpp=Global::iBpp; - if (Bpp!=32) Bpp=16; - //create our OpenGL window - if (!CreateGLWindow(Global::asHumanCtrlVehicle.c_str(),WindowWidth,WindowHeight,Bpp,fullscreen)) - return 0; //quit if window was not created - SetForegroundWindow(hWnd); - //McZapkie: proba przeplukania klawiatury - Console *pConsole=new Console(); //Ra: nie wiem, czy ma to sens, ale jakoś zainicjowac trzeba - while (Console::Pressed(VK_F10)) - Error("Keyboard buffer problem - press F10"); //na Windows 98 lubi się to pojawiać - int iOldSpeed, iOldDelay; - SystemParametersInfo(SPI_GETKEYBOARDSPEED,0,&iOldSpeed,0); - SystemParametersInfo(SPI_GETKEYBOARDDELAY,0,&iOldDelay,0); - SystemParametersInfo(SPI_SETKEYBOARDSPEED,20,NULL,0); - //SystemParametersInfo(SPI_SETKEYBOARDDELAY,10,NULL,0); - if (!joyGetNumDevs()) - WriteLog("No joystick"); - if (Global::iModifyTGA<0) - {//tylko modyfikacja TGA, bez uruchamiania symulacji - Global::iMaxTextureSize=64; //żeby nie zamulać pamięci - World.ModifyTGA(); //rekurencyjne przeglądanie katalogów - } - else - {if (Global::iConvertModels<0) - {Global::iConvertModels=-Global::iConvertModels; - World.CreateE3D("models\\"); //rekurencyjne przeglądanie katalogów - World.CreateE3D("dynamic\\",true); - } //po zrobieniu E3D odpalamy normalnie scenerię, by ją zobaczyć - //else - //{//główna pętla programu - Console::On(); //włączenie konsoli - while (!done) //loop that runs while done=FALSE - { - if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //is there a message waiting? - { - if (msg.message==WM_QUIT) //have we received a quit message? - done=TRUE; //if so - else //if not, deal with window messages + // hunter-271211: ukrywanie konsoli + if (Global::iWriteLogEnabled & 2) { - //if (msg.message==WM_CHAR) - //World.OnKeyDown(msg.wParam); - TranslateMessage(&msg); //translate the message - DispatchMessage(&msg); //dispatch the message + AllocConsole(); + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN); + } + AnsiString str = lpCmdLine; // parametry uruchomienia + if (!str.IsEmpty()) + { // analizowanie parametrów + TQueryParserComp *Parser; + Parser = new TQueryParserComp(NULL); + Parser->TextToParse = lpCmdLine; + Parser->First(); + while (!Parser->EndOfFile) + { + str = Parser->GetNextSymbol().LowerCase(); + if (str == AnsiString("-s")) + { // nazwa scenerii + str = Parser->GetNextSymbol().LowerCase(); + strcpy(Global::szSceneryFile, str.c_str()); + } + else if (str == AnsiString("-v")) + { // nazwa wybranego pojazdu + str = Parser->GetNextSymbol().LowerCase(); + Global::asHumanCtrlVehicle = str; + } + else if (str == AnsiString("-modifytga")) + { // wykonanie modyfikacji wszystkich plików TGA + Global::iModifyTGA = -1; // specjalny tryb wykonania totalnej modyfikacji + } + else if (str == AnsiString("-e3d")) + { // wygenerowanie wszystkich plików E3D + if (Global::iConvertModels > 0) + Global::iConvertModels = -Global::iConvertModels; // specjalny tryb + else + Global::iConvertModels = -7; // z optymalizacją, bananami i prawidłowym Opacity + } + else + Error( + "Program usage: EU07 [-s sceneryfilepath] [-v vehiclename] [-modifytga] [-e3d]", + !Global::iWriteLogEnabled); + } + delete Parser; // ABu 050205: tego wczesniej nie bylo + } + /* MC: usunalem tymczasowo bo sie gryzlo z nowym parserem - 8.6.2003 + AnsiString csp=AnsiString(Global::szSceneryFile); + csp=csp.Delete(csp.Pos(AnsiString(strrchr(Global::szSceneryFile,'/')))+1,csp.Length()); + Global::asCurrentSceneryPath=csp; + */ + + fullscreen = Global::bFullScreen; + WindowWidth = Global::iWindowWidth; + WindowHeight = Global::iWindowHeight; + Bpp = Global::iBpp; + if (Bpp != 32) + Bpp = 16; + // create our OpenGL window + if (!CreateGLWindow(Global::asHumanCtrlVehicle.c_str(), WindowWidth, WindowHeight, Bpp, + fullscreen)) + return 0; // quit if window was not created + SetForegroundWindow(hWnd); + // McZapkie: proba przeplukania klawiatury + Console *pConsole = new Console(); // Ra: nie wiem, czy ma to sens, ale jakoś zainicjowac trzeba + while (Console::Pressed(VK_F10)) + Error("Keyboard buffer problem - press F10"); // na Windows 98 lubi się to pojawiać + int iOldSpeed, iOldDelay; + SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &iOldSpeed, 0); + SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &iOldDelay, 0); + SystemParametersInfo(SPI_SETKEYBOARDSPEED, 20, NULL, 0); + // SystemParametersInfo(SPI_SETKEYBOARDDELAY,10,NULL,0); + if (!joyGetNumDevs()) + WriteLog("No joystick"); + if (Global::iModifyTGA < 0) + { // tylko modyfikacja TGA, bez uruchamiania symulacji + Global::iMaxTextureSize = 64; //żeby nie zamulać pamięci + World.ModifyTGA(); // rekurencyjne przeglądanie katalogów } - } - else //if there are no messages - { - //draw the scene, watch for quit messages - //DrawGLScene() - //if (!pause) - //if (Global::bInactivePause?Global::bActive:true) //tak nie, bo spada z góry - if (World.Update()) // Was There A Quit Received? - SwapBuffers(hDC); // Swap Buffers (Double Buffering) else - done=true; //[F10] or DrawGLScene signalled a quit - } - } - Console::Off(); //wyłączenie konsoli (komunikacji zwrotnej) - } - SystemParametersInfo(SPI_SETKEYBOARDSPEED,iOldSpeed,NULL,0); - SystemParametersInfo(SPI_SETKEYBOARDDELAY,iOldDelay,NULL,0); - delete pConsole; //deaktywania sterownika - //shutdown - KillGLWindow(); //kill the window - return (msg.wParam); //exit the program + { + if (Global::iConvertModels < 0) + { + Global::iConvertModels = -Global::iConvertModels; + World.CreateE3D("models\\"); // rekurencyjne przeglądanie katalogów + World.CreateE3D("dynamic\\", true); + } // po zrobieniu E3D odpalamy normalnie scenerię, by ją zobaczyć + // else + //{//główna pętla programu + Console::On(); // włączenie konsoli + while (!done) // loop that runs while done=FALSE + { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) // is there a message waiting? + { + if (msg.message == WM_QUIT) // have we received a quit message? + done = TRUE; // if so + else // if not, deal with window messages + { + // if (msg.message==WM_CHAR) + // World.OnKeyDown(msg.wParam); + TranslateMessage(&msg); // translate the message + DispatchMessage(&msg); // dispatch the message + } + } + else // if there are no messages + { + // draw the scene, watch for quit messages + // DrawGLScene() + // if (!pause) + // if (Global::bInactivePause?Global::bActive:true) //tak nie, bo spada z góry + if (World.Update()) // Was There A Quit Received? + SwapBuffers(hDC); // Swap Buffers (Double Buffering) + else + done = true; //[F10] or DrawGLScene signalled a quit + } + } + Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej) + } + SystemParametersInfo(SPI_SETKEYBOARDSPEED, iOldSpeed, NULL, 0); + SystemParametersInfo(SPI_SETKEYBOARDDELAY, iOldDelay, NULL, 0); + delete pConsole; // deaktywania sterownika + // shutdown + KillGLWindow(); // kill the window + return (msg.wParam); // exit the program } - - diff --git a/EvLaunch.cpp b/EvLaunch.cpp index 2561bd03..37d6bce4 100644 --- a/EvLaunch.cpp +++ b/EvLaunch.cpp @@ -6,7 +6,7 @@ */ -#include "system.hpp" +#include "system.hpp" #pragma hdrstop #include "mtable.hpp" @@ -20,164 +20,161 @@ #include "parser.h" #include "Console.h" - - //--------------------------------------------------------------------------- __fastcall TEventLauncher::TEventLauncher() -{//ustawienie początkowych wartości dla wszystkich zmiennych - iKey=0; - DeltaTime=-1; - UpdatedTime=0; - fVal1=fVal2=0; - szText=NULL; - iHour=iMinute=-1; //takiego czasu nigdy nie będzie - dRadius=0; - Event1=Event2=NULL; - MemCell=NULL; - iCheckMask=0; +{ // ustawienie początkowych wartości dla wszystkich zmiennych + iKey = 0; + DeltaTime = -1; + UpdatedTime = 0; + fVal1 = fVal2 = 0; + szText = NULL; + iHour = iMinute = -1; // takiego czasu nigdy nie będzie + dRadius = 0; + Event1 = Event2 = NULL; + MemCell = NULL; + iCheckMask = 0; } -__fastcall TEventLauncher::~TEventLauncher() -{ - SafeDeleteArray(szText); -} +__fastcall TEventLauncher::~TEventLauncher() { SafeDeleteArray(szText); } -void __fastcall TEventLauncher::Init() -{ -} +void __fastcall TEventLauncher::Init() {} bool __fastcall TEventLauncher::Load(cParser *parser) -{//wczytanie wyzwalacza zdarzeń - AnsiString str; - std::string token; - parser->getTokens(); - *parser >> dRadius; //promień działania - if (dRadius>0.0) - dRadius*=dRadius; //do kwadratu, pod warunkiem, że nie jest ujemne - parser->getTokens(); //klawisz sterujący - *parser >> token; - str=AnsiString(token.c_str()); - if (str!="none") - { - if (str.Length()==1) - iKey=VkKeyScan(str[1]); //jeden znak jest konwertowany na kod klawisza - else - iKey=str.ToIntDef(0); //a jak więcej, to jakby numer klawisza jest - } - parser->getTokens(); - *parser >> DeltaTime; - if (DeltaTime<0) - DeltaTime=-DeltaTime; //dla ujemnego zmieniamy na dodatni - else if (DeltaTime>0) - {//wartość dodatnia oznacza wyzwalanie o określonej godzinie - iMinute=int(DeltaTime)%100; //minuty są najmłodszymi cyframi dziesietnymi - iHour=int(DeltaTime-iMinute)/100; //godzina to setki - DeltaTime=0; //bez powtórzeń - WriteLog("EventLauncher at "+IntToStr(iHour)+":"+IntToStr(iMinute)); //wyświetlenie czasu - } - parser->getTokens(); - *parser >> token; - asEvent1Name=AnsiString(token.c_str()); //pierwszy event - parser->getTokens(); - *parser >> token; - asEvent2Name=AnsiString(token.c_str()); //drugi event - if ((asEvent2Name=="end")||(asEvent2Name=="condition")) - {//drugiego eventu może nie być, bo są z tym problemy, ale ciii... - str=asEvent2Name; //rozpoznane słowo idzie do dalszego przetwarzania - asEvent2Name="none"; //a drugiego eventu nie ma - } - else - {//gdy są dwa eventy - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - } - if (str==AnsiString("condition")) - {//obsługa wyzwalania warunkowego - parser->getTokens(); - *parser >> token; - asMemCellName=AnsiString(token.c_str()); - parser->getTokens(); - *parser >> token; - SafeDeleteArray(szText); - szText=new char[256]; - strcpy(szText,token.c_str()); - if (token.compare("*")!=0) //*=nie brać command pod uwagę - iCheckMask|=conditional_memstring; - parser->getTokens(); - *parser >> token; - if (token.compare("*")!=0) //*=nie brać wartości 1. pod uwagę - { - iCheckMask|=conditional_memval1; - str=AnsiString(token.c_str()); - fVal1=str.ToDouble(); - } - else fVal1=0; - parser->getTokens(); - *parser >> token; - if (token.compare("*")!=0) //*=nie brać wartości 2. pod uwagę - { - iCheckMask|=conditional_memval2; - str=AnsiString(token.c_str()); - fVal2=str.ToDouble(); - } - else fVal2=0; - parser->getTokens(); //słowo zamykające - *parser >> token; - } - return true; +{ // wczytanie wyzwalacza zdarzeń + AnsiString str; + std::string token; + parser->getTokens(); + *parser >> dRadius; // promień działania + if (dRadius > 0.0) + dRadius *= dRadius; // do kwadratu, pod warunkiem, że nie jest ujemne + parser->getTokens(); // klawisz sterujący + *parser >> token; + str = AnsiString(token.c_str()); + if (str != "none") + { + if (str.Length() == 1) + iKey = VkKeyScan(str[1]); // jeden znak jest konwertowany na kod klawisza + else + iKey = str.ToIntDef(0); // a jak więcej, to jakby numer klawisza jest + } + parser->getTokens(); + *parser >> DeltaTime; + if (DeltaTime < 0) + DeltaTime = -DeltaTime; // dla ujemnego zmieniamy na dodatni + else if (DeltaTime > 0) + { // wartość dodatnia oznacza wyzwalanie o określonej godzinie + iMinute = int(DeltaTime) % 100; // minuty są najmłodszymi cyframi dziesietnymi + iHour = int(DeltaTime - iMinute) / 100; // godzina to setki + DeltaTime = 0; // bez powtórzeń + WriteLog("EventLauncher at " + IntToStr(iHour) + ":" + + IntToStr(iMinute)); // wyświetlenie czasu + } + parser->getTokens(); + *parser >> token; + asEvent1Name = AnsiString(token.c_str()); // pierwszy event + parser->getTokens(); + *parser >> token; + asEvent2Name = AnsiString(token.c_str()); // drugi event + if ((asEvent2Name == "end") || (asEvent2Name == "condition")) + { // drugiego eventu może nie być, bo są z tym problemy, ale ciii... + str = asEvent2Name; // rozpoznane słowo idzie do dalszego przetwarzania + asEvent2Name = "none"; // a drugiego eventu nie ma + } + else + { // gdy są dwa eventy + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + } + if (str == AnsiString("condition")) + { // obsługa wyzwalania warunkowego + parser->getTokens(); + *parser >> token; + asMemCellName = AnsiString(token.c_str()); + parser->getTokens(); + *parser >> token; + SafeDeleteArray(szText); + szText = new char[256]; + strcpy(szText, token.c_str()); + if (token.compare("*") != 0) //*=nie brać command pod uwagę + iCheckMask |= conditional_memstring; + parser->getTokens(); + *parser >> token; + if (token.compare("*") != 0) //*=nie brać wartości 1. pod uwagę + { + iCheckMask |= conditional_memval1; + str = AnsiString(token.c_str()); + fVal1 = str.ToDouble(); + } + else + fVal1 = 0; + parser->getTokens(); + *parser >> token; + if (token.compare("*") != 0) //*=nie brać wartości 2. pod uwagę + { + iCheckMask |= conditional_memval2; + str = AnsiString(token.c_str()); + fVal2 = str.ToDouble(); + } + else + fVal2 = 0; + parser->getTokens(); // słowo zamykające + *parser >> token; + } + return true; }; bool __fastcall TEventLauncher::Render() -{//"renderowanie" wyzwalacza - bool bCond=false; - if (iKey!=0) - { - if (Global::bActive) //tylko jeśli okno jest aktywne - bCond=(Console::Pressed(iKey)); //czy klawisz wciśnięty - } - if (DeltaTime>0) - { - if (UpdatedTime>DeltaTime) - { - UpdatedTime=0; //naliczanie od nowa - bCond=true; - } - else - UpdatedTime+=Timer::GetDeltaTime(); //aktualizacja naliczania czasu - } - else - {//jeśli nie cykliczny, to sprawdzić czas - if (GlobalTime->hh==iHour) - {if (GlobalTime->mm==iMinute) - {//zgodność czasu uruchomienia - if (UpdatedTime<10) +{ //"renderowanie" wyzwalacza + bool bCond = false; + if (iKey != 0) { - UpdatedTime=20; //czas do kolejnego wyzwolenia? - bCond=true; + if (Global::bActive) // tylko jeśli okno jest aktywne + bCond = (Console::Pressed(iKey)); // czy klawisz wciśnięty } - } - } - else - UpdatedTime=1; - } - if (bCond) //jeśli spełniony został warunek - { - if ((iCheckMask!=0)&&MemCell) //sprawdzanie warunku na komórce pamięci - bCond=MemCell->Compare(szText,fVal1,fVal2,iCheckMask); - } - return bCond; //sprawdzanie dRadius w Ground.cpp + if (DeltaTime > 0) + { + if (UpdatedTime > DeltaTime) + { + UpdatedTime = 0; // naliczanie od nowa + bCond = true; + } + else + UpdatedTime += Timer::GetDeltaTime(); // aktualizacja naliczania czasu + } + else + { // jeśli nie cykliczny, to sprawdzić czas + if (GlobalTime->hh == iHour) + { + if (GlobalTime->mm == iMinute) + { // zgodność czasu uruchomienia + if (UpdatedTime < 10) + { + UpdatedTime = 20; // czas do kolejnego wyzwolenia? + bCond = true; + } + } + } + else + UpdatedTime = 1; + } + if (bCond) // jeśli spełniony został warunek + { + if ((iCheckMask != 0) && MemCell) // sprawdzanie warunku na komórce pamięci + bCond = MemCell->Compare(szText, fVal1, fVal2, iCheckMask); + } + return bCond; // sprawdzanie dRadius w Ground.cpp } bool __fastcall TEventLauncher::IsGlobal() -{//sprawdzenie, czy jest globalnym wyzwalaczem czasu - if (DeltaTime==0) - if (iHour>=0) - if (iMinute>=0) - if (dRadius<0.0) //bez ograniczenia zasięgu - return true; - return false; +{ // sprawdzenie, czy jest globalnym wyzwalaczem czasu + if (DeltaTime == 0) + if (iHour >= 0) + if (iMinute >= 0) + if (dRadius < 0.0) // bez ograniczenia zasięgu + return true; + return false; }; //--------------------------------------------------------------------------- diff --git a/EvLaunch.h b/EvLaunch.h index 04b45b49..89a2a0f4 100644 --- a/EvLaunch.h +++ b/EvLaunch.h @@ -7,29 +7,29 @@ class TEventLauncher { -private: - int iKey; - double DeltaTime; - double UpdatedTime; - double fVal1; - double fVal2; - char *szText; - int iHour,iMinute; //minuta uruchomienia -public: - double dRadius; - AnsiString asEvent1Name; - AnsiString asEvent2Name; - AnsiString asMemCellName; - TEvent *Event1; - TEvent *Event2; - TMemCell *MemCell; - int iCheckMask; - __fastcall TEventLauncher(); - __fastcall ~TEventLauncher(); - void __fastcall Init(); - bool __fastcall Load(cParser *parser); - bool __fastcall Render(); - bool __fastcall IsGlobal(); + private: + int iKey; + double DeltaTime; + double UpdatedTime; + double fVal1; + double fVal2; + char *szText; + int iHour, iMinute; // minuta uruchomienia + public: + double dRadius; + AnsiString asEvent1Name; + AnsiString asEvent2Name; + AnsiString asMemCellName; + TEvent *Event1; + TEvent *Event2; + TMemCell *MemCell; + int iCheckMask; + __fastcall TEventLauncher(); + __fastcall ~TEventLauncher(); + void __fastcall Init(); + bool __fastcall Load(cParser *parser); + bool __fastcall Render(); + bool __fastcall IsGlobal(); }; //--------------------------------------------------------------------------- diff --git a/Event.cpp b/Event.cpp index b679b080..5c86bff1 100644 --- a/Event.cpp +++ b/Event.cpp @@ -6,8 +6,8 @@ */ -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Event.h" @@ -21,606 +21,656 @@ __fastcall TEvent::TEvent(AnsiString m) { - //asName=""; //czy nazwa eventu jest niezbędna w tym przypadku? chyba nie - evNext=evNext2=NULL; - bEnabled=false; //false dla eventów używanych do skanowania sygnałów (nie dodawane do kolejki) - asNodeName=m; //nazwa obiektu powiązanego - iQueued=0; //nie został dodany do kolejki - //bIsHistory=false; - fDelay=0; - fStartTime=0; //0 nie ma sensu - Type=m.IsEmpty()?tp_Unknown:tp_GetValues; //utworzenie niejawnego odczytu komórki pamięci w torze - for (int i=0;i<13;i++) - Params[i].asPointer=NULL; - evJoined=NULL; //nie ma kolejnego z tą samą nazwą, usuwane są wg listy Next2 - Activator=NULL; - iFlags=0; - //event niejawny jest tworzony przed fazą InitEvents, która podmienia nazwę komórki pamięci na wskaźnik - //Current->Params[8].asGroundNode=m; //to się ustawi w InitEvents - //Current->Params[9].asMemCell=m->MemCell; - fRandomDelay=0.0; //standardowo nie będzie dodatkowego losowego opóźnienia + // asName=""; //czy nazwa eventu jest niezbędna w tym przypadku? chyba nie + evNext = evNext2 = NULL; + bEnabled = false; // false dla eventów używanych do skanowania sygnałów (nie dodawane do + // kolejki) + asNodeName = m; // nazwa obiektu powiązanego + iQueued = 0; // nie został dodany do kolejki + // bIsHistory=false; + fDelay = 0; + fStartTime = 0; // 0 nie ma sensu + Type = m.IsEmpty() ? tp_Unknown : + tp_GetValues; // utworzenie niejawnego odczytu komórki pamięci w torze + for (int i = 0; i < 13; i++) + Params[i].asPointer = NULL; + evJoined = NULL; // nie ma kolejnego z tą samą nazwą, usuwane są wg listy Next2 + Activator = NULL; + iFlags = 0; + // event niejawny jest tworzony przed fazą InitEvents, która podmienia nazwę komórki pamięci na + // wskaźnik + // Current->Params[8].asGroundNode=m; //to się ustawi w InitEvents + // Current->Params[9].asMemCell=m->MemCell; + fRandomDelay = 0.0; // standardowo nie będzie dodatkowego losowego opóźnienia }; __fastcall TEvent::~TEvent() { - switch (Type) - {//sprzątanie - case tp_Multiple: - //SafeDeleteArray(Params[9].asText); //nie usuwać - nazwa obiektu powiązanego zamieniana na wskaźnik - if (iFlags&conditional_memstring) //o ile jest łańcuch do porównania w memcompare - SafeDeleteArray(Params[10].asText); - break; - case tp_UpdateValues: - case tp_AddValues: - SafeDeleteArray(Params[0].asText); - if (iFlags&conditional_memstring) //o ile jest łańcuch do porównania w memcompare - SafeDeleteArray(Params[10].asText); - break; - case tp_Animation: //nic - //SafeDeleteArray(Params[9].asText); //nie usuwać - nazwa jest zamieniana na wskaźnik do submodelu - if (Params[0].asInt==4) //jeśli z pliku VMD - delete[] Params[8].asPointer; //zwolnić obszar - case tp_GetValues: //nic - break; - } - evJoined=NULL; //nie usuwać podczepionych tutaj + switch (Type) + { // sprzątanie + case tp_Multiple: + // SafeDeleteArray(Params[9].asText); //nie usuwać - nazwa obiektu powiązanego zamieniana na + // wskaźnik + if (iFlags & conditional_memstring) // o ile jest łańcuch do porównania w memcompare + SafeDeleteArray(Params[10].asText); + break; + case tp_UpdateValues: + case tp_AddValues: + SafeDeleteArray(Params[0].asText); + if (iFlags & conditional_memstring) // o ile jest łańcuch do porównania w memcompare + SafeDeleteArray(Params[10].asText); + break; + case tp_Animation: // nic + // SafeDeleteArray(Params[9].asText); //nie usuwać - nazwa jest zamieniana na wskaźnik do + // submodelu + if (Params[0].asInt == 4) // jeśli z pliku VMD + delete[] Params[8].asPointer; // zwolnić obszar + case tp_GetValues: // nic + break; + } + evJoined = NULL; // nie usuwać podczepionych tutaj }; -void __fastcall TEvent::Init() +void __fastcall TEvent::Init(){ + +}; + +void __fastcall TEvent::Conditions(cParser *parser, AnsiString s) +{ // przetwarzanie warunków, wspólne dla Multiple i UpdateValues + if (s == "condition") + { // jesli nie "endevent" + std::string token; + AnsiString str; + if (!asNodeName.IsEmpty()) + { // podczepienie łańcucha, jeśli nie jest pusty + Params[9].asText = new char[asNodeName.Length() + 1]; // usuwane i zamieniane na + // wskaźnik + strcpy(Params[9].asText, asNodeName.c_str()); + } + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + if (str == AnsiString("trackoccupied")) + iFlags |= conditional_trackoccupied; + else if (str == AnsiString("trackfree")) + iFlags |= conditional_trackfree; + else if (str == AnsiString("propability")) + { + iFlags |= conditional_propability; + parser->getTokens(); + *parser >> Params[10].asdouble; + } + else if (str == AnsiString("memcompare")) + { + iFlags |= conditional_memcompare; + parser->getTokens(1, false); // case sensitive + *parser >> token; + str = AnsiString(token.c_str()); + if (str != "*") //"*" - nie brac command pod uwage + { // zapamiętanie łańcucha do porównania + Params[10].asText = new char[255]; + strcpy(Params[10].asText, str.c_str()); + iFlags |= conditional_memstring; + } + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + if (str != "*") //"*" - nie brac val1 pod uwage + { + Params[11].asdouble = str.ToDouble(); + iFlags |= conditional_memval1; + } + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + if (str != AnsiString("*")) //"*" - nie brac val2 pod uwage + { + Params[12].asdouble = str.ToDouble(); + iFlags |= conditional_memval2; + } + } + parser->getTokens(); + *parser >> token; + s = AnsiString(token.c_str()); // ewentualnie dalej losowe opóźnienie + } + if (s == "randomdelay") + { // losowe opóźnienie + std::string token; + parser->getTokens(); + *parser >> fRandomDelay; // Ra 2014-03-11 + parser->getTokens(); + *parser >> token; // endevent + } +}; + +void __fastcall TEvent::Load(cParser *parser, vector3 *org) { + int i; + int ti; + double tf; + std::string token; + AnsiString str; + char *ptr; -}; + bEnabled = true; // zmieniane na false dla eventów używanych do skanowania sygnałów -void __fastcall TEvent::Conditions(cParser* parser,AnsiString s) -{//przetwarzanie warunków, wspólne dla Multiple i UpdateValues - if (s=="condition") - {//jesli nie "endevent" - std::string token; - AnsiString str; - if (!asNodeName.IsEmpty()) - {//podczepienie łańcucha, jeśli nie jest pusty - Params[9].asText=new char[asNodeName.Length()+1]; //usuwane i zamieniane na wskaźnik - strcpy(Params[9].asText,asNodeName.c_str()); - } - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - if (str==AnsiString("trackoccupied")) - iFlags|=conditional_trackoccupied; - else if (str==AnsiString("trackfree")) - iFlags|=conditional_trackfree; - else if (str==AnsiString("propability")) - { - iFlags|=conditional_propability; - parser->getTokens(); - *parser >> Params[10].asdouble; - } - else if (str==AnsiString("memcompare")) - { - iFlags|=conditional_memcompare; - parser->getTokens(1,false); //case sensitive - *parser >> token; - str=AnsiString(token.c_str()); - if (str!="*") //"*" - nie brac command pod uwage - {//zapamiętanie łańcucha do porównania - Params[10].asText=new char[255]; - strcpy(Params[10].asText,str.c_str()); - iFlags|=conditional_memstring; - } - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - if (str!="*") //"*" - nie brac val1 pod uwage - { - Params[11].asdouble=str.ToDouble(); - iFlags|=conditional_memval1; - } - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - if (str!=AnsiString("*")) //"*" - nie brac val2 pod uwage - { - Params[12].asdouble=str.ToDouble(); - iFlags|=conditional_memval2; - } - } - parser->getTokens(); *parser >> token; - s=AnsiString(token.c_str()); //ewentualnie dalej losowe opóźnienie - } - if (s=="randomdelay") - {//losowe opóźnienie - std::string token; - parser->getTokens(); - *parser >> fRandomDelay; //Ra 2014-03-11 - parser->getTokens(); *parser >> token; //endevent - } -}; - -void __fastcall TEvent::Load(cParser* parser,vector3 *org) -{ - int i; - int ti; - double tf; - std::string token; - AnsiString str; - char *ptr; - - bEnabled=true; //zmieniane na false dla eventów używanych do skanowania sygnałów - - parser->getTokens(); - *parser >> token; - asName=AnsiString(token.c_str()).LowerCase(); //użycie parametrów może dawać wielkie - - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - - if (str==AnsiString("exit")) - Type=tp_Exit; - else if (str==AnsiString("updatevalues")) - Type=tp_UpdateValues; - else if (str==AnsiString("getvalues")) - Type=tp_GetValues; - else if (str==AnsiString("putvalues")) - Type=tp_PutValues; - else if (str==AnsiString("disable")) - Type=tp_Disable; - else if (str==AnsiString("sound")) - Type=tp_Sound; - else if (str==AnsiString("velocity")) - Type=tp_Velocity; - else if (str==AnsiString("animation")) - Type=tp_Animation; - else if (str==AnsiString("lights")) - Type=tp_Lights; - else if (str==AnsiString("visible")) - Type=tp_Visible; //zmiana wyświetlania obiektu - else if (str==AnsiString("switch")) - Type=tp_Switch; - else if (str==AnsiString("dynvel")) - Type=tp_DynVel; - else if (str==AnsiString("trackvel")) - Type=tp_TrackVel; - else if (str==AnsiString("multiple")) - Type=tp_Multiple; - else if (str==AnsiString("addvalues")) - Type=tp_AddValues; - else if (str==AnsiString("copyvalues")) - Type=tp_CopyValues; - else if (str==AnsiString("whois")) - Type=tp_WhoIs; - else if (str==AnsiString("logvalues")) - Type=tp_LogValues; - else if (str==AnsiString("voltage")) - Type=tp_Voltage; //zmiana napięcia w zasilaczu (TractionPowerSource) - else if (str==AnsiString("message")) - Type=tp_Message; //wyświetlenie komunikatu - else if (str==AnsiString("friction")) - Type=tp_Friction; //zmiana tarcia na scenerii - else - Type=tp_Unknown; - - parser->getTokens(); - *parser >> fDelay; - - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - - if (str!="none") asNodeName=str; //nazwa obiektu powiązanego - - if (asName.SubString(1,5)=="none_") - Type=tp_Ignored; //Ra: takie są ignorowane - - switch (Type) - { - case tp_AddValues: - iFlags=update_memadd; //dodawanko - case tp_UpdateValues: - //if (Type==tp_UpdateValues) iFlags=0; //co modyfikować - parser->getTokens(1,false); //case sensitive - *parser >> token; - str=AnsiString(token.c_str()); - Params[0].asText=new char[str.Length()+1]; - strcpy(Params[0].asText,str.c_str()); - if (str!="*") //czy ma zostać bez zmian? - iFlags|=update_memstring; - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - if (str!="*") //czy ma zostać bez zmian? - { - Params[1].asdouble=str.ToDouble(); - iFlags|=update_memval1; - } - else - Params[1].asdouble=0; - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - if (str!="*") //czy ma zostać bez zmian? - { - Params[2].asdouble=str.ToDouble(); - iFlags|=update_memval2; - } - else - Params[2].asdouble=0; - parser->getTokens(); - *parser >> token; - Conditions(parser,token.c_str()); //sprawdzanie warunków - break; - case tp_CopyValues: - Params[9].asText=NULL; - iFlags=update_memstring|update_memval1|update_memval2; //normalanie trzy - i=0; - parser->getTokens(); - *parser >> token; //nazwa drugiej komórki (źródłowej) - while (token.compare("endevent")!=0) - { - switch (++i) - {//znaczenie kolejnych parametrów - case 1: //nazwa drugiej komórki (źródłowej) - Params[9].asText=new char[token.length()+1]; //usuwane i zamieniane na wskaźnik - strcpy(Params[9].asText,token.c_str()); - break; - case 2: //maska wartości - iFlags=AnsiString(token.c_str()).ToIntDef(update_memstring|update_memval1|update_memval2); - break; - } parser->getTokens(); *parser >> token; - } - break; - case tp_WhoIs: - iFlags=update_memstring|update_memval1|update_memval2; //normalanie trzy - i=0; - parser->getTokens(); - *parser >> token; //nazwa drugiej komórki (źródłowej) - while (token.compare("endevent")!=0) - { - switch (++i) - {//znaczenie kolejnych parametrów - case 1: //maska wartości - iFlags=AnsiString(token.c_str()).ToIntDef(update_memstring|update_memval1|update_memval2); - break; - } + asName = AnsiString(token.c_str()).LowerCase(); // użycie parametrów może dawać wielkie + parser->getTokens(); *parser >> token; - } - break; - case tp_GetValues: - case tp_LogValues: - parser->getTokens(); //"endevent" - *parser >> token; - break; - case tp_PutValues: - parser->getTokens(3); - *parser >> Params[3].asdouble >> Params[4].asdouble >> Params[5].asdouble; //położenie X,Y,Z - if (org) - {//przesunięcie - //tmp->pCenter.RotateY(aRotate.y/180.0*M_PI); //Ra 2014-11: uwzględnienie rotacji - Params[3].asdouble+=org->x; //współrzędne w scenerii - Params[4].asdouble+=org->y; - Params[5].asdouble+=org->z; - } - //Params[12].asInt=0; - parser->getTokens(1,false); //komendy 'case sensitive' - *parser >> token; - str=AnsiString(token.c_str()); - if (str.SubString(1,19)=="PassengerStopPoint:") - {if (str.Pos("#")) str=str.SubString(1,str.Pos("#")-1); //obcięcie unikatowości - bEnabled=false; //nie do kolejki (dla SetVelocity też, ale jak jest do toru dowiązany) - Params[6].asCommand=cm_PassengerStopPoint; - } - else if (str=="SetVelocity") - {bEnabled=false; - Params[6].asCommand=cm_SetVelocity; - } - else if (str=="ShuntVelocity") - {bEnabled=false; - Params[6].asCommand=cm_ShuntVelocity; - } - else if (str=="SetProximityVelocity") - {bEnabled=false; - Params[6].asCommand=cm_SetProximityVelocity; - } - else if (str=="OutsideStation") - {bEnabled=false; //ma być skanowny, aby AI nie przekraczało W5 - Params[6].asCommand=cm_OutsideStation; - } - else - Params[6].asCommand=cm_Unknown; - Params[0].asText=new char[str.Length()+1]; - strcpy(Params[0].asText,str.c_str()); - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - if (str=="none") - Params[1].asdouble=0.0; - else - try - {Params[1].asdouble=str.ToDouble();} - catch (...) - {Params[1].asdouble=0.0; - WriteLog("Error: number expected in PutValues event, found: "+str); - } - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - if (str=="none") - Params[2].asdouble=0.0; - else - try - {Params[2].asdouble=str.ToDouble();} - catch (...) - {Params[2].asdouble=0.0; - WriteLog("Error: number expected in PutValues event, found: "+str); - } - parser->getTokens(); - *parser >> token; - break; - case tp_Lights: - i=0; - do - { - parser->getTokens(); - *parser >> token; - if (token.compare("endevent")!=0) - { - str=AnsiString(token.c_str()); - if (i<8) - Params[i].asdouble=str.ToDouble(); //teraz może mieć ułamek - i++; - } - } - while (token.compare("endevent")!=0); - break; - case tp_Visible: //zmiana wyświetlania obiektu - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - Params[0].asInt=str.ToInt(); - parser->getTokens(); *parser >> token; - break; - case tp_Velocity: - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - Params[0].asdouble=str.ToDouble()*0.28; - parser->getTokens(); *parser >> token; - break; - case tp_Sound: - //Params[0].asRealSound->Init(asNodeName.c_str(),Parser->GetNextSymbol().ToDouble(),Parser->GetNextSymbol().ToDouble(),Parser->GetNextSymbol().ToDouble(),Parser->GetNextSymbol().ToDouble()); - //McZapkie-070502: dzwiek przestrzenny (ale do poprawy) - //Params[1].asdouble=Parser->GetNextSymbol().ToDouble(); - //Params[2].asdouble=Parser->GetNextSymbol().ToDouble(); - //Params[3].asdouble=Parser->GetNextSymbol().ToDouble(); //polozenie X,Y,Z - do poprawy! - parser->getTokens(); - *parser >> Params[0].asInt; //0: wylaczyc, 1: wlaczyc; -1: wlaczyc zapetlone - parser->getTokens(); *parser >> token; - break; - case tp_Exit: - while ((ptr=strchr(asNodeName.c_str(),'_'))!=NULL) - *ptr=' '; - parser->getTokens(); *parser >> token; - break; - case tp_Disable: - parser->getTokens(); *parser >> token; - break; - case tp_Animation: - parser->getTokens(); - *parser >> token; - Params[0].asInt=0; //na razie nieznany typ - if (token.compare("rotate")==0) - {//obrót względem osi - parser->getTokens(); - *parser >> token; - Params[9].asText=new char[255]; //nazwa submodelu - strcpy(Params[9].asText,token.c_str()); - Params[0].asInt=1; - parser->getTokens(4); - *parser >> Params[1].asdouble >> Params[2].asdouble >> Params[3].asdouble >> Params[4].asdouble; - } - else if (token.compare("translate")==0) - {//przesuw o wektor - parser->getTokens(); - *parser >> token; - Params[9].asText=new char[255]; //nazwa submodelu - strcpy(Params[9].asText,token.c_str()); - Params[0].asInt=2; - parser->getTokens(4); - *parser >> Params[1].asdouble >> Params[2].asdouble >> Params[3].asdouble >> Params[4].asdouble; - } - else if (token.compare("digital")==0) - {//licznik cyfrowy - parser->getTokens(); - *parser >> token; - Params[9].asText=new char[255]; //nazwa submodelu - strcpy(Params[9].asText,token.c_str()); - Params[0].asInt=8; - parser->getTokens(4); //jaki ma być sens tych parametrów? - *parser >> Params[1].asdouble >> Params[2].asdouble >> Params[3].asdouble >> Params[4].asdouble; - } - else if (token.substr(token.length()-4,4)==".vmd") //na razie tu, może będzie inaczej - {//animacja z pliku VMD - TFileStream *fs=new TFileStream("models\\"+AnsiString(token.c_str()),fmOpenRead); - Params[7].asInt=fs->Size; - Params[8].asPointer=new char[fs->Size]; - fs->Read(Params[8].asPointer,fs->Size); //wczytanie pliku - delete fs; - parser->getTokens(); - *parser >> token; - Params[9].asText=new char[255]; //nazwa submodelu - strcpy(Params[9].asText,token.c_str()); - Params[0].asInt=4; //rodzaj animacji - parser->getTokens(4); - *parser >> Params[1].asdouble >> Params[2].asdouble >> Params[3].asdouble >> Params[4].asdouble; - } - parser->getTokens(); *parser >> token; - break; - case tp_Switch: - parser->getTokens(); *parser >> Params[0].asInt; - parser->getTokens(); *parser >> token; - str=AnsiString(token.c_str()); - if (str!="endevent") - {Params[1].asdouble=str.ToDouble(); //prędkość liniowa ruchu iglic - parser->getTokens(); *parser >> token; - str=AnsiString(token.c_str()); - } - else - Params[1].asdouble=-1.0; //użyć domyślnej - if (str!="endevent") - {Params[2].asdouble=str.ToDouble(); //dodatkowy ruch drugiej iglicy (zamknięcie nastawnicze) - parser->getTokens(); *parser >> token; - } - else - Params[2].asdouble=-1.0; //użyć domyślnej - break; - case tp_DynVel: - parser->getTokens(); - *parser >> Params[0].asdouble; //McZapkie-090302 *0.28; - parser->getTokens(); *parser >> token; - break; - case tp_TrackVel: - parser->getTokens(); - *parser >> Params[0].asdouble; //McZapkie-090302 *0.28; - parser->getTokens(); *parser >> token; - break; - case tp_Multiple: - i=0; - ti=0; //flaga dla else - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - while (str!=AnsiString("endevent") && str!=AnsiString("condition") && str!=AnsiString("randomdelay")) - { - if ((str.SubString(1,5)!="none_")?(i<8):false) - {//eventy rozpoczynające się od "none_" są ignorowane - if (str!="else") - {Params[i].asText=new char[255]; - strcpy(Params[i].asText,str.c_str()); - if (ti) iFlags|=conditional_else<=8) - ErrorLog("Bad event: \""+str+"\" ignored in multiple \""+asName+"\"!"); + str = AnsiString(token.c_str()); + + if (str == AnsiString("exit")) + Type = tp_Exit; + else if (str == AnsiString("updatevalues")) + Type = tp_UpdateValues; + else if (str == AnsiString("getvalues")) + Type = tp_GetValues; + else if (str == AnsiString("putvalues")) + Type = tp_PutValues; + else if (str == AnsiString("disable")) + Type = tp_Disable; + else if (str == AnsiString("sound")) + Type = tp_Sound; + else if (str == AnsiString("velocity")) + Type = tp_Velocity; + else if (str == AnsiString("animation")) + Type = tp_Animation; + else if (str == AnsiString("lights")) + Type = tp_Lights; + else if (str == AnsiString("visible")) + Type = tp_Visible; // zmiana wyświetlania obiektu + else if (str == AnsiString("switch")) + Type = tp_Switch; + else if (str == AnsiString("dynvel")) + Type = tp_DynVel; + else if (str == AnsiString("trackvel")) + Type = tp_TrackVel; + else if (str == AnsiString("multiple")) + Type = tp_Multiple; + else if (str == AnsiString("addvalues")) + Type = tp_AddValues; + else if (str == AnsiString("copyvalues")) + Type = tp_CopyValues; + else if (str == AnsiString("whois")) + Type = tp_WhoIs; + else if (str == AnsiString("logvalues")) + Type = tp_LogValues; + else if (str == AnsiString("voltage")) + Type = tp_Voltage; // zmiana napięcia w zasilaczu (TractionPowerSource) + else if (str == AnsiString("message")) + Type = tp_Message; // wyświetlenie komunikatu + else if (str == AnsiString("friction")) + Type = tp_Friction; // zmiana tarcia na scenerii else - WriteLog("Event \""+str+"\" ignored in multiple \""+asName+"\"!"); + Type = tp_Unknown; + + parser->getTokens(); + *parser >> fDelay; + parser->getTokens(); *parser >> token; - str=AnsiString(token.c_str()); - } - Conditions(parser,str); //sprawdzanie warunków - break; - case tp_Voltage: //zmiana napięcia w zasilaczu (TractionPowerSource) - case tp_Friction: //zmiana przyczepnosci na scenerii - parser->getTokens(); - *parser >> Params[0].asdouble; //Ra 2014-01-27 - parser->getTokens(); *parser >> token; - break; - case tp_Message: //wyświetlenie komunikatu - do - {parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - } while (str!="endevent"); - break; - case tp_Ignored: //ignorowany - case tp_Unknown: //nieznany - do - {parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - } while (str!="endevent"); - WriteLog("Bad event: \""+asName+(Type==tp_Unknown?"\" has unknown type.":"\" is ignored.")); - break; - } + str = AnsiString(token.c_str()); + + if (str != "none") + asNodeName = str; // nazwa obiektu powiązanego + + if (asName.SubString(1, 5) == "none_") + Type = tp_Ignored; // Ra: takie są ignorowane + + switch (Type) + { + case tp_AddValues: + iFlags = update_memadd; // dodawanko + case tp_UpdateValues: + // if (Type==tp_UpdateValues) iFlags=0; //co modyfikować + parser->getTokens(1, false); // case sensitive + *parser >> token; + str = AnsiString(token.c_str()); + Params[0].asText = new char[str.Length() + 1]; + strcpy(Params[0].asText, str.c_str()); + if (str != "*") // czy ma zostać bez zmian? + iFlags |= update_memstring; + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + if (str != "*") // czy ma zostać bez zmian? + { + Params[1].asdouble = str.ToDouble(); + iFlags |= update_memval1; + } + else + Params[1].asdouble = 0; + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + if (str != "*") // czy ma zostać bez zmian? + { + Params[2].asdouble = str.ToDouble(); + iFlags |= update_memval2; + } + else + Params[2].asdouble = 0; + parser->getTokens(); + *parser >> token; + Conditions(parser, token.c_str()); // sprawdzanie warunków + break; + case tp_CopyValues: + Params[9].asText = NULL; + iFlags = update_memstring | update_memval1 | update_memval2; // normalanie trzy + i = 0; + parser->getTokens(); + *parser >> token; // nazwa drugiej komórki (źródłowej) + while (token.compare("endevent") != 0) + { + switch (++i) + { // znaczenie kolejnych parametrów + case 1: // nazwa drugiej komórki (źródłowej) + Params[9].asText = new char[token.length() + 1]; // usuwane i zamieniane na wskaźnik + strcpy(Params[9].asText, token.c_str()); + break; + case 2: // maska wartości + iFlags = AnsiString(token.c_str()) + .ToIntDef(update_memstring | update_memval1 | update_memval2); + break; + } + parser->getTokens(); + *parser >> token; + } + break; + case tp_WhoIs: + iFlags = update_memstring | update_memval1 | update_memval2; // normalanie trzy + i = 0; + parser->getTokens(); + *parser >> token; // nazwa drugiej komórki (źródłowej) + while (token.compare("endevent") != 0) + { + switch (++i) + { // znaczenie kolejnych parametrów + case 1: // maska wartości + iFlags = AnsiString(token.c_str()) + .ToIntDef(update_memstring | update_memval1 | update_memval2); + break; + } + parser->getTokens(); + *parser >> token; + } + break; + case tp_GetValues: + case tp_LogValues: + parser->getTokens(); //"endevent" + *parser >> token; + break; + case tp_PutValues: + parser->getTokens(3); + *parser >> Params[3].asdouble >> Params[4].asdouble >> Params[5].asdouble; // położenie + // X,Y,Z + if (org) + { // przesunięcie + // tmp->pCenter.RotateY(aRotate.y/180.0*M_PI); //Ra 2014-11: uwzględnienie rotacji + Params[3].asdouble += org->x; // współrzędne w scenerii + Params[4].asdouble += org->y; + Params[5].asdouble += org->z; + } + // Params[12].asInt=0; + parser->getTokens(1, false); // komendy 'case sensitive' + *parser >> token; + str = AnsiString(token.c_str()); + if (str.SubString(1, 19) == "PassengerStopPoint:") + { + if (str.Pos("#")) + str = str.SubString(1, str.Pos("#") - 1); // obcięcie unikatowości + bEnabled = false; // nie do kolejki (dla SetVelocity też, ale jak jest do toru + // dowiązany) + Params[6].asCommand = cm_PassengerStopPoint; + } + else if (str == "SetVelocity") + { + bEnabled = false; + Params[6].asCommand = cm_SetVelocity; + } + else if (str == "ShuntVelocity") + { + bEnabled = false; + Params[6].asCommand = cm_ShuntVelocity; + } + else if (str == "SetProximityVelocity") + { + bEnabled = false; + Params[6].asCommand = cm_SetProximityVelocity; + } + else if (str == "OutsideStation") + { + bEnabled = false; // ma być skanowny, aby AI nie przekraczało W5 + Params[6].asCommand = cm_OutsideStation; + } + else + Params[6].asCommand = cm_Unknown; + Params[0].asText = new char[str.Length() + 1]; + strcpy(Params[0].asText, str.c_str()); + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + if (str == "none") + Params[1].asdouble = 0.0; + else + try + { + Params[1].asdouble = str.ToDouble(); + } + catch (...) + { + Params[1].asdouble = 0.0; + WriteLog("Error: number expected in PutValues event, found: " + str); + } + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + if (str == "none") + Params[2].asdouble = 0.0; + else + try + { + Params[2].asdouble = str.ToDouble(); + } + catch (...) + { + Params[2].asdouble = 0.0; + WriteLog("Error: number expected in PutValues event, found: " + str); + } + parser->getTokens(); + *parser >> token; + break; + case tp_Lights: + i = 0; + do + { + parser->getTokens(); + *parser >> token; + if (token.compare("endevent") != 0) + { + str = AnsiString(token.c_str()); + if (i < 8) + Params[i].asdouble = str.ToDouble(); // teraz może mieć ułamek + i++; + } + } while (token.compare("endevent") != 0); + break; + case tp_Visible: // zmiana wyświetlania obiektu + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + Params[0].asInt = str.ToInt(); + parser->getTokens(); + *parser >> token; + break; + case tp_Velocity: + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + Params[0].asdouble = str.ToDouble() * 0.28; + parser->getTokens(); + *parser >> token; + break; + case tp_Sound: + // Params[0].asRealSound->Init(asNodeName.c_str(),Parser->GetNextSymbol().ToDouble(),Parser->GetNextSymbol().ToDouble(),Parser->GetNextSymbol().ToDouble(),Parser->GetNextSymbol().ToDouble()); + // McZapkie-070502: dzwiek przestrzenny (ale do poprawy) + // Params[1].asdouble=Parser->GetNextSymbol().ToDouble(); + // Params[2].asdouble=Parser->GetNextSymbol().ToDouble(); + // Params[3].asdouble=Parser->GetNextSymbol().ToDouble(); //polozenie X,Y,Z - do poprawy! + parser->getTokens(); + *parser >> Params[0].asInt; // 0: wylaczyc, 1: wlaczyc; -1: wlaczyc zapetlone + parser->getTokens(); + *parser >> token; + break; + case tp_Exit: + while ((ptr = strchr(asNodeName.c_str(), '_')) != NULL) + *ptr = ' '; + parser->getTokens(); + *parser >> token; + break; + case tp_Disable: + parser->getTokens(); + *parser >> token; + break; + case tp_Animation: + parser->getTokens(); + *parser >> token; + Params[0].asInt = 0; // na razie nieznany typ + if (token.compare("rotate") == 0) + { // obrót względem osi + parser->getTokens(); + *parser >> token; + Params[9].asText = new char[255]; // nazwa submodelu + strcpy(Params[9].asText, token.c_str()); + Params[0].asInt = 1; + parser->getTokens(4); + *parser >> Params[1].asdouble >> Params[2].asdouble >> Params[3].asdouble >> + Params[4].asdouble; + } + else if (token.compare("translate") == 0) + { // przesuw o wektor + parser->getTokens(); + *parser >> token; + Params[9].asText = new char[255]; // nazwa submodelu + strcpy(Params[9].asText, token.c_str()); + Params[0].asInt = 2; + parser->getTokens(4); + *parser >> Params[1].asdouble >> Params[2].asdouble >> Params[3].asdouble >> + Params[4].asdouble; + } + else if (token.compare("digital") == 0) + { // licznik cyfrowy + parser->getTokens(); + *parser >> token; + Params[9].asText = new char[255]; // nazwa submodelu + strcpy(Params[9].asText, token.c_str()); + Params[0].asInt = 8; + parser->getTokens(4); // jaki ma być sens tych parametrów? + *parser >> Params[1].asdouble >> Params[2].asdouble >> Params[3].asdouble >> + Params[4].asdouble; + } + else if (token.substr(token.length() - 4, 4) == ".vmd") // na razie tu, może będzie inaczej + { // animacja z pliku VMD + TFileStream *fs = new TFileStream("models\\" + AnsiString(token.c_str()), fmOpenRead); + Params[7].asInt = fs->Size; + Params[8].asPointer = new char[fs->Size]; + fs->Read(Params[8].asPointer, fs->Size); // wczytanie pliku + delete fs; + parser->getTokens(); + *parser >> token; + Params[9].asText = new char[255]; // nazwa submodelu + strcpy(Params[9].asText, token.c_str()); + Params[0].asInt = 4; // rodzaj animacji + parser->getTokens(4); + *parser >> Params[1].asdouble >> Params[2].asdouble >> Params[3].asdouble >> + Params[4].asdouble; + } + parser->getTokens(); + *parser >> token; + break; + case tp_Switch: + parser->getTokens(); + *parser >> Params[0].asInt; + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + if (str != "endevent") + { + Params[1].asdouble = str.ToDouble(); // prędkość liniowa ruchu iglic + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + } + else + Params[1].asdouble = -1.0; // użyć domyślnej + if (str != "endevent") + { + Params[2].asdouble = + str.ToDouble(); // dodatkowy ruch drugiej iglicy (zamknięcie nastawnicze) + parser->getTokens(); + *parser >> token; + } + else + Params[2].asdouble = -1.0; // użyć domyślnej + break; + case tp_DynVel: + parser->getTokens(); + *parser >> Params[0].asdouble; // McZapkie-090302 *0.28; + parser->getTokens(); + *parser >> token; + break; + case tp_TrackVel: + parser->getTokens(); + *parser >> Params[0].asdouble; // McZapkie-090302 *0.28; + parser->getTokens(); + *parser >> token; + break; + case tp_Multiple: + i = 0; + ti = 0; // flaga dla else + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + while (str != AnsiString("endevent") && str != AnsiString("condition") && + str != AnsiString("randomdelay")) + { + if ((str.SubString(1, 5) != "none_") ? (i < 8) : false) + { // eventy rozpoczynające się od "none_" są ignorowane + if (str != "else") + { + Params[i].asText = new char[255]; + strcpy(Params[i].asText, str.c_str()); + if (ti) + iFlags |= conditional_else << i; // oflagowanie dla eventów "else" + i++; + } + else + ti = !ti; // zmiana flagi dla słowa "else" + } + else if (i >= 8) + ErrorLog("Bad event: \"" + str + "\" ignored in multiple \"" + asName + "\"!"); + else + WriteLog("Event \"" + str + "\" ignored in multiple \"" + asName + "\"!"); + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + } + Conditions(parser, str); // sprawdzanie warunków + break; + case tp_Voltage: // zmiana napięcia w zasilaczu (TractionPowerSource) + case tp_Friction: // zmiana przyczepnosci na scenerii + parser->getTokens(); + *parser >> Params[0].asdouble; // Ra 2014-01-27 + parser->getTokens(); + *parser >> token; + break; + case tp_Message: // wyświetlenie komunikatu + do + { + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + } while (str != "endevent"); + break; + case tp_Ignored: // ignorowany + case tp_Unknown: // nieznany + do + { + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + } while (str != "endevent"); + WriteLog("Bad event: \"" + asName + + (Type == tp_Unknown ? "\" has unknown type." : "\" is ignored.")); + break; + } }; void __fastcall TEvent::AddToQuery(TEvent *e) -{//dodanie eventu do kolejki - if (evNext?(e->fStartTime>=evNext->fStartTime):false) - evNext->AddToQuery(e); //sortowanie wg czasu - else - {//dodanie z przodu - e->evNext=evNext; - evNext=e; - } +{ // dodanie eventu do kolejki + if (evNext ? (e->fStartTime >= evNext->fStartTime) : false) + evNext->AddToQuery(e); // sortowanie wg czasu + else + { // dodanie z przodu + e->evNext = evNext; + evNext = e; + } } //--------------------------------------------------------------------------- AnsiString __fastcall TEvent::CommandGet() -{//odczytanie komendy z eventu - switch (Type) - {//to się wykonuje również składu jadącego bez obsługi - case tp_GetValues: - return String(Params[9].asMemCell->Text()); - case tp_PutValues: - return String(Params[0].asText); - } - return ""; //inne eventy się nie liczą +{ // odczytanie komendy z eventu + switch (Type) + { // to się wykonuje również składu jadącego bez obsługi + case tp_GetValues: + return String(Params[9].asMemCell->Text()); + case tp_PutValues: + return String(Params[0].asText); + } + return ""; // inne eventy się nie liczą }; TCommandType __fastcall TEvent::Command() -{//odczytanie komendy z eventu - switch (Type) - {//to się wykonuje również dla składu jadącego bez obsługi - case tp_GetValues: - return Params[9].asMemCell->Command(); - case tp_PutValues: - return Params[6].asCommand; //komenda zakodowana binarnie - } - return cm_Unknown; //inne eventy się nie liczą +{ // odczytanie komendy z eventu + switch (Type) + { // to się wykonuje również dla składu jadącego bez obsługi + case tp_GetValues: + return Params[9].asMemCell->Command(); + case tp_PutValues: + return Params[6].asCommand; // komenda zakodowana binarnie + } + return cm_Unknown; // inne eventy się nie liczą }; double __fastcall TEvent::ValueGet(int n) -{//odczytanie komendy z eventu - n&=1; //tylko 1 albo 2 jest prawidłowy - switch (Type) - {//to się wykonuje również składu jadącego bez obsługi - case tp_GetValues: - return n?Params[9].asMemCell->Value1():Params[9].asMemCell->Value2(); - case tp_PutValues: - return Params[2-n].asdouble; - } - return 0.0; //inne eventy się nie liczą +{ // odczytanie komendy z eventu + n &= 1; // tylko 1 albo 2 jest prawidłowy + switch (Type) + { // to się wykonuje również składu jadącego bez obsługi + case tp_GetValues: + return n ? Params[9].asMemCell->Value1() : Params[9].asMemCell->Value2(); + case tp_PutValues: + return Params[2 - n].asdouble; + } + return 0.0; // inne eventy się nie liczą }; vector3 __fastcall TEvent::PositionGet() -{//pobranie współrzędnych eventu - switch (Type) - {// - case tp_GetValues: - return Params[9].asMemCell->Position(); //współrzędne podłączonej komórki pamięci - case tp_PutValues: - return vector3(Params[3].asdouble,Params[4].asdouble,Params[5].asdouble); - } - return vector3(0,0,0); //inne eventy się nie liczą +{ // pobranie współrzędnych eventu + switch (Type) + { // + case tp_GetValues: + return Params[9].asMemCell->Position(); // współrzędne podłączonej komórki pamięci + case tp_PutValues: + return vector3(Params[3].asdouble, Params[4].asdouble, Params[5].asdouble); + } + return vector3(0, 0, 0); // inne eventy się nie liczą }; bool __fastcall TEvent::StopCommand() -{// - if (Type==tp_GetValues) - return Params[9].asMemCell->StopCommand(); //info o komendzie z komórki - return false; +{ // + if (Type == tp_GetValues) + return Params[9].asMemCell->StopCommand(); // info o komendzie z komórki + return false; }; void __fastcall TEvent::StopCommandSent() { - if (Type==tp_GetValues) - Params[9].asMemCell->StopCommandSent(); //komenda z komórki została wysłana + if (Type == tp_GetValues) + Params[9].asMemCell->StopCommandSent(); // komenda z komórki została wysłana }; void __fastcall TEvent::Append(TEvent *e) -{//doczepienie kolejnych z tą samą nazwą - if (evJoined) - evJoined->Append(e); //rekurencja! - góra kilkanaście eventów będzie potrzebne - else - {evJoined=e; - e->bEnabled=true; //ten doczepiony może być tylko kolejkowany - } +{ // doczepienie kolejnych z tą samą nazwą + if (evJoined) + evJoined->Append(e); // rekurencja! - góra kilkanaście eventów będzie potrzebne + else + { + evJoined = e; + e->bEnabled = true; // ten doczepiony może być tylko kolejkowany + } }; diff --git a/Event.h b/Event.h index f89bf13f..d8ef806b 100644 --- a/Event.h +++ b/Event.h @@ -7,30 +7,49 @@ #include "dumb3d.h" using namespace Math3D; -typedef enum { tp_Unknown, tp_Sound, tp_SoundPos, tp_Exit, - tp_Disable, tp_Velocity, tp_Animation, tp_Lights, - tp_UpdateValues, tp_GetValues, tp_PutValues, - tp_Switch, tp_DynVel, tp_TrackVel, tp_Multiple, - tp_AddValues, tp_Ignored, tp_CopyValues, tp_WhoIs, - tp_LogValues, tp_Visible, - tp_Voltage, tp_Message, tp_Friction - } TEventType; +typedef enum +{ + tp_Unknown, + tp_Sound, + tp_SoundPos, + tp_Exit, + tp_Disable, + tp_Velocity, + tp_Animation, + tp_Lights, + tp_UpdateValues, + tp_GetValues, + tp_PutValues, + tp_Switch, + tp_DynVel, + tp_TrackVel, + tp_Multiple, + tp_AddValues, + tp_Ignored, + tp_CopyValues, + tp_WhoIs, + tp_LogValues, + tp_Visible, + tp_Voltage, + tp_Message, + tp_Friction +} TEventType; -const int update_memstring =0x0000001; //zmodyfikować tekst (UpdateValues) -const int update_memval1 =0x0000002; //zmodyfikować pierwszą wartosć -const int update_memval2 =0x0000004; //zmodyfikować drugą wartosć -const int update_memadd =0x0000008; //dodać do poprzedniej zawartości -const int update_load =0x0000010; //odczytać ładunek -const int update_only =0x00000FF; //wartość graniczna -const int conditional_memstring =0x0000100; //porównanie tekstu -const int conditional_memval1 =0x0000200; //porównanie pierwszej wartości liczbowej -const int conditional_memval2 =0x0000400; //porównanie drugiej wartości -const int conditional_else =0x0010000; //flaga odwrócenia warunku (przesuwana bitowo) -const int conditional_anyelse =0x0FF0000; //do sprawdzania, czy są odwrócone warunki -const int conditional_trackoccupied =0x1000000; //jeśli tor zajęty -const int conditional_trackfree =0x2000000; //jeśli tor wolny -const int conditional_propability =0x4000000; //zależnie od generatora lizcb losowych -const int conditional_memcompare =0x8000000; //porównanie zawartości +const int update_memstring = 0x0000001; // zmodyfikować tekst (UpdateValues) +const int update_memval1 = 0x0000002; // zmodyfikować pierwszą wartosć +const int update_memval2 = 0x0000004; // zmodyfikować drugą wartosć +const int update_memadd = 0x0000008; // dodać do poprzedniej zawartości +const int update_load = 0x0000010; // odczytać ładunek +const int update_only = 0x00000FF; // wartość graniczna +const int conditional_memstring = 0x0000100; // porównanie tekstu +const int conditional_memval1 = 0x0000200; // porównanie pierwszej wartości liczbowej +const int conditional_memval2 = 0x0000400; // porównanie drugiej wartości +const int conditional_else = 0x0010000; // flaga odwrócenia warunku (przesuwana bitowo) +const int conditional_anyelse = 0x0FF0000; // do sprawdzania, czy są odwrócone warunki +const int conditional_trackoccupied = 0x1000000; // jeśli tor zajęty +const int conditional_trackfree = 0x2000000; // jeśli tor wolny +const int conditional_propability = 0x4000000; // zależnie od generatora lizcb losowych +const int conditional_memcompare = 0x8000000; // porównanie zawartości union TParam { @@ -52,39 +71,40 @@ union TParam TTractionPowerSource *psPower; }; -class TEvent //zmienne: ev* -{//zdarzenie -private: - void __fastcall Conditions(cParser* parser,AnsiString s); -public: - AnsiString asName; - bool bEnabled; //false gdy ma nie być dodawany do kolejki (skanowanie sygnałów) - int iQueued; //ile razy dodany do kolejki - //bool bIsHistory; - TEvent *evNext; //następny w kolejce - TEvent *evNext2; - TEventType Type; - double fStartTime; - double fDelay; - TDynamicObject *Activator; - TParam Params[13]; //McZapkie-070502 //Ra: zamienić to na union/struct - unsigned int iFlags; //zamiast Params[8] z flagami warunku - AnsiString asNodeName; //McZapkie-100302 - dodalem zeby zapamietac nazwe toru - TEvent *evJoined; //kolejny event z tą samą nazwą - od wersji 378 - double fRandomDelay; //zakres dodatkowego opóźnienia -public: //metody - __fastcall TEvent(AnsiString m=""); - __fastcall ~TEvent(); - void __fastcall Init(); - void __fastcall Load(cParser* parser,vector3 *org); - void __fastcall AddToQuery(TEvent *e); - AnsiString __fastcall CommandGet(); - TCommandType __fastcall Command(); - double __fastcall ValueGet(int n); - vector3 __fastcall PositionGet(); - bool __fastcall StopCommand(); - void __fastcall StopCommandSent(); - void __fastcall Append(TEvent *e); +class TEvent // zmienne: ev* +{ // zdarzenie + private: + void __fastcall Conditions(cParser *parser, AnsiString s); + + public: + AnsiString asName; + bool bEnabled; // false gdy ma nie być dodawany do kolejki (skanowanie sygnałów) + int iQueued; // ile razy dodany do kolejki + // bool bIsHistory; + TEvent *evNext; // następny w kolejce + TEvent *evNext2; + TEventType Type; + double fStartTime; + double fDelay; + TDynamicObject *Activator; + TParam Params[13]; // McZapkie-070502 //Ra: zamienić to na union/struct + unsigned int iFlags; // zamiast Params[8] z flagami warunku + AnsiString asNodeName; // McZapkie-100302 - dodalem zeby zapamietac nazwe toru + TEvent *evJoined; // kolejny event z tą samą nazwą - od wersji 378 + double fRandomDelay; // zakres dodatkowego opóźnienia + public: // metody + __fastcall TEvent(AnsiString m = ""); + __fastcall ~TEvent(); + void __fastcall Init(); + void __fastcall Load(cParser *parser, vector3 *org); + void __fastcall AddToQuery(TEvent *e); + AnsiString __fastcall CommandGet(); + TCommandType __fastcall Command(); + double __fastcall ValueGet(int n); + vector3 __fastcall PositionGet(); + bool __fastcall StopCommand(); + void __fastcall StopCommandSent(); + void __fastcall Append(TEvent *e); }; //--------------------------------------------------------------------------- diff --git a/FadeSound.cpp b/FadeSound.cpp index 7eb6b8ef..e10458d4 100644 --- a/FadeSound.cpp +++ b/FadeSound.cpp @@ -5,101 +5,86 @@ */ -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Timer.h" #include "FadeSound.h" - __fastcall TFadeSound::TFadeSound() { - Sound= NULL; - fFade= 0; - dt= 0; - fTime= 0; + Sound = NULL; + fFade = 0; + dt = 0; + fTime = 0; } +__fastcall TFadeSound::~TFadeSound() { Free(); } -__fastcall TFadeSound::~TFadeSound() -{ - Free(); -} - -void __fastcall TFadeSound::Free() -{ -} +void __fastcall TFadeSound::Free() {} void __fastcall TFadeSound::Init(char *Name, float fNewFade) { - Sound= TSoundsManager::GetFromName(Name,false); + Sound = TSoundsManager::GetFromName(Name, false); if (Sound) Sound->SetVolume(0); - fFade= fNewFade; - fTime= 0; + fFade = fNewFade; + fTime = 0; } void __fastcall TFadeSound::TurnOn() { - State= ss_Starting; - Sound->Play(0,0,DSBPLAY_LOOPING); - fTime= fFade; - + State = ss_Starting; + Sound->Play(0, 0, DSBPLAY_LOOPING); + fTime = fFade; } -void __fastcall TFadeSound::TurnOff() -{ - State= ss_ShuttingDown; -} +void __fastcall TFadeSound::TurnOff() { State = ss_ShuttingDown; } void __fastcall TFadeSound::Update() { - if (State==ss_Starting) + if (State == ss_Starting) { - fTime+= Timer::GetDeltaTime(); -// SoundStart->SetVolume(-1000*(4-fTime)/4); - if (fTime>=fFade) + fTime += Timer::GetDeltaTime(); + // SoundStart->SetVolume(-1000*(4-fTime)/4); + if (fTime >= fFade) { - fTime= fFade; - State= ss_Commencing; - Sound->SetVolume(-2000*(fFade-fTime)/fFade); - Sound->SetFrequency(44100-500+500*(fTime)/fFade); + fTime = fFade; + State = ss_Commencing; + Sound->SetVolume(-2000 * (fFade - fTime) / fFade); + Sound->SetFrequency(44100 - 500 + 500 * (fTime) / fFade); } - else - if (Timer::GetSoundTimer()) + else if (Timer::GetSoundTimer()) { - Sound->SetVolume(-2000*(fFade-fTime)/fFade); - Sound->SetFrequency(44100-500+500*(fTime)/fFade); + Sound->SetVolume(-2000 * (fFade - fTime) / fFade); + Sound->SetFrequency(44100 - 500 + 500 * (fTime) / fFade); } } - else - if (State==ss_ShuttingDown) + else if (State == ss_ShuttingDown) { - fTime-= Timer::GetDeltaTime(); + fTime -= Timer::GetDeltaTime(); - if (fTime<=0) + if (fTime <= 0) { - State= ss_Off; - fTime= 0; + State = ss_Off; + fTime = 0; Sound->Stop(); } if (Timer::GetSoundTimer()) - { //DSBVOLUME_MIN - Sound->SetVolume(-2000*(fFade-fTime)/fFade); - Sound->SetFrequency(44100-500+500*fTime/fFade); + { // DSBVOLUME_MIN + Sound->SetVolume(-2000 * (fFade - fTime) / fFade); + Sound->SetFrequency(44100 - 500 + 500 * fTime / fFade); } } } void __fastcall TFadeSound::Volume(long vol) { - float glos= 1; - Sound->SetVolume(vol*glos); + float glos = 1; + Sound->SetVolume(vol * glos); } //--------------------------------------------------------------------------- #pragma package(smart_init) - - diff --git a/FadeSound.h b/FadeSound.h index 6c9f8d45..cc55e194 100644 --- a/FadeSound.h +++ b/FadeSound.h @@ -10,19 +10,19 @@ class TFadeSound { PSound Sound; float fFade; - float dt,fTime; + float dt, fTime; TSoundState State; -public: + + public: __fastcall TFadeSound(); __fastcall ~TFadeSound(); void __fastcall Init(char *Name, float fNewFade); void __fastcall TurnOn(); void __fastcall TurnOff(); - bool __fastcall Playing() {return (State==ss_Commencing || State==ss_Starting); }; + bool __fastcall Playing() { return (State == ss_Commencing || State == ss_Starting); }; void __fastcall Free(); void __fastcall Update(); void __fastcall Volume(long vol); - }; //--------------------------------------------------------------------------- diff --git a/Float3d.cpp b/Float3d.cpp index 26253a85..54bbbc35 100644 --- a/Float3d.cpp +++ b/Float3d.cpp @@ -10,18 +10,18 @@ #pragma package(smart_init) void __fastcall float4x4::Quaternion(float4 *q) -{//konwersja kwaternionu obrotu na macierz obrotu - float xx=q->x*q->x,yy=q->y*q->y,zz=q->z*q->z; - float xy=q->x*q->y,xz=q->x*q->z,yz=q->y*q->z; - float wx=q->w*q->x,wy=q->w*q->y,wz=q->w*q->z; - e[ 0]=1.0f-yy-yy-zz-zz; - e[ 1]=xy+xy+wz+wz; - e[ 2]=xz+xz-wy-wy; - e[ 4]=xy+xy-wz-wz; - e[ 5]=1.0f-xx-xx-zz-zz; - e[ 6]=yz+yz+wx+wx; - e[ 8]=xz+xz+wy+wy; - e[ 9]=yz+yz-wx-wx; - e[10]=1.0f-xx-xx-yy-yy; - //czwartej kolumny i czwartego wiersza nie ruszamy +{ // konwersja kwaternionu obrotu na macierz obrotu + float xx = q->x * q->x, yy = q->y * q->y, zz = q->z * q->z; + float xy = q->x * q->y, xz = q->x * q->z, yz = q->y * q->z; + float wx = q->w * q->x, wy = q->w * q->y, wz = q->w * q->z; + e[0] = 1.0f - yy - yy - zz - zz; + e[1] = xy + xy + wz + wz; + e[2] = xz + xz - wy - wy; + e[4] = xy + xy - wz - wz; + e[5] = 1.0f - xx - xx - zz - zz; + e[6] = yz + yz + wx + wx; + e[8] = xz + xz + wy + wy; + e[9] = yz + yz - wx - wx; + e[10] = 1.0f - xx - xx - yy - yy; + // czwartej kolumny i czwartego wiersza nie ruszamy }; diff --git a/Float3d.h b/Float3d.h index 388f8f6f..5120fdb8 100644 --- a/Float3d.h +++ b/Float3d.h @@ -6,264 +6,274 @@ //--------------------------------------------------------------------------- class float3 -{//wapółrzędne wierchołka 3D o pojedynczej precyzji -public: - float x,y,z; - float3(void) {}; - __fastcall float3(float a,float b,float c) {x=a;y=b;z=c;}; - double inline __fastcall Length() const; +{ // wapółrzędne wierchołka 3D o pojedynczej precyzji + public: + float x, y, z; + float3(void){}; + __fastcall float3(float a, float b, float c) + { + x = a; + y = b; + z = c; + }; + double inline __fastcall Length() const; }; -inline bool operator==(const float3& v1,const float3& v2) -{return (v1.x==v2.x&&v1.y==v2.y&&v1.z==v2.z); +inline bool operator==(const float3 &v1, const float3 &v2) +{ + return (v1.x == v2.x && v1.y == v2.y && v1.z == v2.z); }; -inline float3& operator+=(float3& v1,const float3& v2) -{v1.x+=v2.x; v1.y+=v2.y; v1.z+=v2.z; - return v1; +inline float3 &operator+=(float3 &v1, const float3 &v2) +{ + v1.x += v2.x; + v1.y += v2.y; + v1.z += v2.z; + return v1; }; -inline float3 operator-(const float3& v) -{return float3(-v.x,-v.y,-v.z); +inline float3 operator-(const float3 &v) { return float3(-v.x, -v.y, -v.z); }; +inline float3 operator-(const float3 &v1, const float3 &v2) +{ + return float3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); }; -inline float3 operator-(const float3 &v1,const float3 &v2) -{return float3(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z); -}; -inline float3 operator+(const float3 &v1,const float3 &v2) -{return float3(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z); -}; -double inline __fastcall float3::Length() const -{return sqrt(x*x+y*y+z*z); -}; -inline float3 operator/(const float3& v, double k) -{return float3(v.x/k,v.y/k,v.z/k); +inline float3 operator+(const float3 &v1, const float3 &v2) +{ + return float3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); }; +double inline __fastcall float3::Length() const { return sqrt(x * x + y * y + z * z); }; +inline float3 operator/(const float3 &v, double k) { return float3(v.x / k, v.y / k, v.z / k); }; inline float3 SafeNormalize(const float3 &v) -{//bezpieczna normalizacja (wektor długości 1.0) - double l=v.Length(); - float3 retVal; - if (l==0) - retVal.x=retVal.y=retVal.z=0; - else - retVal=v/l; - return retVal; +{ // bezpieczna normalizacja (wektor długości 1.0) + double l = v.Length(); + float3 retVal; + if (l == 0) + retVal.x = retVal.y = retVal.z = 0; + else + retVal = v / l; + return retVal; }; -inline float3 CrossProduct(const float3& v1,const float3& v2) -{return float3(v1.y*v2.z-v1.z*v2.y,v2.x*v1.z-v2.z*v1.x,v1.x*v2.y-v1.y*v2.x); +inline float3 CrossProduct(const float3 &v1, const float3 &v2) +{ + return float3(v1.y * v2.z - v1.z * v2.y, v2.x * v1.z - v2.z * v1.x, v1.x * v2.y - v1.y * v2.x); } class float4 -{//kwaternion obrotu -public: - float x,y,z,w; - __fastcall float4() {x=y=z=0.f;w=1.f;}; - __fastcall float4(float a,float b,float c,float d) {x=a;y=b;z=c;w=d;}; - double inline float4::LengthSquared() const - {return x*x+y*y+z*z+w*w;}; - double inline float4::Length() const - {return sqrt(x*x+y*y+z*z+w*w);}; +{ // kwaternion obrotu + public: + float x, y, z, w; + __fastcall float4() + { + x = y = z = 0.f; + w = 1.f; + }; + __fastcall float4(float a, float b, float c, float d) + { + x = a; + y = b; + z = c; + w = d; + }; + double inline float4::LengthSquared() const { return x * x + y * y + z * z + w * w; }; + double inline float4::Length() const { return sqrt(x * x + y * y + z * z + w * w); }; }; -inline float4 operator*(const float4 &q1,const float4 &q2) -{//mnożenie to prawie jak mnożenie macierzy - return float4 - (q1.w*q2.x+q1.x*q2.w+q1.y*q2.z-q1.z*q2.y, - q1.w*q2.y+q1.y*q2.w+q1.z*q2.x-q1.x*q2.z, - q1.w*q2.z+q1.z*q2.w+q1.x*q2.y-q1.y*q2.x, - q1.w*q2.w-q1.x*q2.x-q1.y*q2.y-q1.z*q2.z - ); +inline float4 operator*(const float4 &q1, const float4 &q2) +{ // mnożenie to prawie jak mnożenie macierzy + return float4(q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y, + q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z, + q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x, + q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z); } -inline float4 operator-(const float4& q) -{//sprzężony; odwrotny tylko dla znormalizowanych! - return float4(-q.x,-q.y,-q.z,q.w); +inline float4 operator-(const float4 &q) { // sprzężony; odwrotny tylko dla znormalizowanych! return float4(-q.x, -q.y, -q.z, q.w); }; +inline float4 operator-(const float4 &q1, const float4 &q2) +{ // z odejmowaniem nie ma lekko + return (-q1) * q2; // inwersja tylko dla znormalizowanych! }; -inline float4 operator-(const float4 &q1,const float4 &q2) -{//z odejmowaniem nie ma lekko - return (-q1)*q2; //inwersja tylko dla znormalizowanych! +inline float4 operator+(const float4 &v1, const float4 &v2) +{ + return float4(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.w + v2.w); +}; +inline float4 operator/(const float4 &v, double k) +{ + return float4(v.x / k, v.y / k, v.z / k, v.w / k); }; -inline float4 operator+(const float4 &v1,const float4 &v2) -{return float4(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z,v1.w+v2.w);}; -inline float4 operator/(const float4& v, double k) -{return float4(v.x/k,v.y/k,v.z/k,v.w/k);}; inline float4 Normalize(const float4 &v) -{//bezpieczna normalizacja (wektor długości 1.0) - double l=v.LengthSquared(); - if (l==1.0) - return v; - if (l==0.0) - return float4(); //wektor zerowy, w=1 - else - return v/sqrt(l); //pierwiastek liczony tylko jeśli trzeba wykonać dzielenia +{ // bezpieczna normalizacja (wektor długości 1.0) + double l = v.LengthSquared(); + if (l == 1.0) + return v; + if (l == 0.0) + return float4(); // wektor zerowy, w=1 + else + return v / sqrt(l); // pierwiastek liczony tylko jeśli trzeba wykonać dzielenia }; -float Dot(const float4 &q1,const float4 &q2) -{//iloczyn skalarny - return q1.x*q2.x+q1.y*q2.y+q1.z*q2.z+q1.w*q2.w; +float Dot(const float4 &q1, const float4 &q2) +{ // iloczyn skalarny + return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; } -inline float4& operator*=(float4& v1,double d) -{//mnożenie przez skalar, jaki ma sens? - v1.x*=d; v1.y*=d; v1.z*=d; v1.w*=d; - return v1; +inline float4 &operator*=(float4 &v1, double d) +{ // mnożenie przez skalar, jaki ma sens? + v1.x *= d; + v1.y *= d; + v1.z *= d; + v1.w *= d; + return v1; }; -inline float4 Slerp(const float4 &q0,const float4 &q1,float t) -//void Slerp(QUATERNION *Out, const QUATERNION &q0, const QUATERNION &q1, float t) -{//interpolacja sweryczna - float cosOmega=Dot(q0,q1); - float4 new_q1(q1); - if (cosOmega<0.0f) - {//jeżeli są niezgodne kierunki, jeden z nich trzeba zanegować - new_q1.x=-new_q1.x; - new_q1.y=-new_q1.y; - new_q1.z=-new_q1.z; - new_q1.w=-new_q1.w; - cosOmega=-cosOmega; - } - double k0,k1; - if (cosOmega>0.9999f) - {//jeśli jesteśmy z (t) na maksimum kosinusa, to tam prawie liniowo jest - k0=1.0f-t; - k1=t; - } - else - {//a w ogólnym przypadku trzeba liczyć na trygonometrię - double sinOmega=sqrt(1.0f-cosOmega*cosOmega); //sinus z jedynki tryg. - double omega=atan2(sinOmega,cosOmega); //wyznaczenie kąta - double oneOverSinOmega=1.0f/sinOmega; //odwrotność sinusa, bo sinus w mianowniku - k0=sin((1.0f-t)*omega)*oneOverSinOmega; - k1=sin(t*omega)*oneOverSinOmega; - } - return float4 - (q0.x*k0+new_q1.x*k1, - q0.y*k0+new_q1.y*k1, - q0.z*k0+new_q1.z*k1, - q0.w*k0+new_q1.w*k1 - ); +inline float4 Slerp(const float4 &q0, const float4 &q1, float t) +// void Slerp(QUATERNION *Out, const QUATERNION &q0, const QUATERNION &q1, float t) +{ // interpolacja sweryczna + float cosOmega = Dot(q0, q1); + float4 new_q1(q1); + if (cosOmega < 0.0f) + { // jeżeli są niezgodne kierunki, jeden z nich trzeba zanegować + new_q1.x = -new_q1.x; + new_q1.y = -new_q1.y; + new_q1.z = -new_q1.z; + new_q1.w = -new_q1.w; + cosOmega = -cosOmega; + } + double k0, k1; + if (cosOmega > 0.9999f) + { // jeśli jesteśmy z (t) na maksimum kosinusa, to tam prawie liniowo jest + k0 = 1.0f - t; + k1 = t; + } + else + { // a w ogólnym przypadku trzeba liczyć na trygonometrię + double sinOmega = sqrt(1.0f - cosOmega * cosOmega); // sinus z jedynki tryg. + double omega = atan2(sinOmega, cosOmega); // wyznaczenie kąta + double oneOverSinOmega = 1.0f / sinOmega; // odwrotność sinusa, bo sinus w mianowniku + k0 = sin((1.0f - t) * omega) * oneOverSinOmega; + k1 = sin(t * omega) * oneOverSinOmega; + } + return float4(q0.x * k0 + new_q1.x * k1, q0.y * k0 + new_q1.y * k1, q0.z * k0 + new_q1.z * k1, + q0.w * k0 + new_q1.w * k1); } - struct float8 -{//wierchołek 3D z wektorem normalnym i mapowaniem, pojedyncza precyzja -public: - float3 Point; - float3 Normal; - float tu,tv; +{ // wierchołek 3D z wektorem normalnym i mapowaniem, pojedyncza precyzja + public: + float3 Point; + float3 Normal; + float tu, tv; }; class float4x4 -{//macierz transformacji pojedynczej precyzji - float e[16]; -public: - float4x4(void) {}; - float4x4(float f[16]) {for (int i=0;i<16;++i) e[i]=f[i];}; - float* __fastcall operator() (int i) { return &e[i<<2]; } - const float* __fastcall readArray(void) { return e; } - void __fastcall Identity() - {for (int i=0;i<16;++i) - e[i]=0; - e[0]=e[5]=e[10]=e[15]=1.0f; - } - const float* operator[](int i) const {return &e[i<<2];}; - void __fastcall InitialRotate() - {//taka specjalna rotacja, nie ma co ciągać trygonometrii - float f; - for (int i=0;i<16;i+=4) - {e[i]=-e[i]; //zmiana znaku X - f=e[i+1]; e[i+1]=e[i+2]; e[i+2]=f; //zamiana Y i Z - } - }; - inline float4x4& Rotation(double angle,float3 axis); - inline bool IdentityIs() - {//sprawdzenie jednostkowości - for (int i=0;i<16;++i) - if (e[i]!=((i%5)?0.0:1.0)) //jedynki tylko na 0, 5, 10 i 15 - return false; - return true; - } - void __fastcall Quaternion(float4 *q); - inline float3* TranslationGet() - {return (float3*)(e+12);} +{ // macierz transformacji pojedynczej precyzji + float e[16]; + + public: + float4x4(void){}; + float4x4(float f[16]) + { + for (int i = 0; i < 16; ++i) + e[i] = f[i]; + }; + float *__fastcall operator()(int i) { return &e[i << 2]; } + const float *__fastcall readArray(void) { return e; } + void __fastcall Identity() + { + for (int i = 0; i < 16; ++i) + e[i] = 0; + e[0] = e[5] = e[10] = e[15] = 1.0f; + } + const float *operator[](int i) const { return &e[i << 2]; }; + void __fastcall InitialRotate() + { // taka specjalna rotacja, nie ma co ciągać trygonometrii + float f; + for (int i = 0; i < 16; i += 4) + { + e[i] = -e[i]; // zmiana znaku X + f = e[i + 1]; + e[i + 1] = e[i + 2]; + e[i + 2] = f; // zamiana Y i Z + } + }; + inline float4x4 &Rotation(double angle, float3 axis); + inline bool IdentityIs() + { // sprawdzenie jednostkowości + for (int i = 0; i < 16; ++i) + if (e[i] != ((i % 5) ? 0.0 : 1.0)) // jedynki tylko na 0, 5, 10 i 15 + return false; + return true; + } + void __fastcall Quaternion(float4 *q); + inline float3 *TranslationGet() { return (float3 *)(e + 12); } }; -inline float3 operator*(const float4x4& m,const float3& v) -{//mnożenie wektora przez macierz - return float3( - v.x*m[0][0]+v.y*m[1][0]+v.z*m[2][0]+m[3][0], - v.x*m[0][1]+v.y*m[1][1]+v.z*m[2][1]+m[3][1], - v.x*m[0][2]+v.y*m[1][2]+v.z*m[2][2]+m[3][2] - ); +inline float3 operator*(const float4x4 &m, const float3 &v) +{ // mnożenie wektora przez macierz + return float3(v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0] + m[3][0], + v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1] + m[3][1], + v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2] + m[3][2]); } -inline float4x4& float4x4::Rotation(double angle,float3 axis) +inline float4x4 &float4x4::Rotation(double angle, float3 axis) { - double c=cos(angle); - double s=sin(angle); - // One minus c (short name for legibility of formulai) - double omc=(1-c); - if (axis.Length()!=1.0f) axis=SafeNormalize(axis); - double x = axis.x; - double y = axis.y; - double z = axis.z; - double xs = x * s; - double ys = y * s; - double zs = z * s; - double xyomc = x * y * omc; - double xzomc = x * z * omc; - double yzomc = y * z * omc; - e[0] =x*x*omc+c; - e[1] =xyomc+zs; - e[2] =xzomc-ys; - e[3] =0; - e[4] =xyomc-zs; - e[5] =y*y*omc+c; - e[6] =yzomc+xs; - e[7] =0; - e[8] =xzomc+ys; - e[9] =yzomc-xs; - e[10]=z*z*omc+c; - e[11]=0; - e[12]=0; - e[13]=0; - e[14]=0; - e[15]=1; - return *this; + double c = cos(angle); + double s = sin(angle); + // One minus c (short name for legibility of formulai) + double omc = (1 - c); + if (axis.Length() != 1.0f) + axis = SafeNormalize(axis); + double x = axis.x; + double y = axis.y; + double z = axis.z; + double xs = x * s; + double ys = y * s; + double zs = z * s; + double xyomc = x * y * omc; + double xzomc = x * z * omc; + double yzomc = y * z * omc; + e[0] = x * x * omc + c; + e[1] = xyomc + zs; + e[2] = xzomc - ys; + e[3] = 0; + e[4] = xyomc - zs; + e[5] = y * y * omc + c; + e[6] = yzomc + xs; + e[7] = 0; + e[8] = xzomc + ys; + e[9] = yzomc - xs; + e[10] = z * z * omc + c; + e[11] = 0; + e[12] = 0; + e[13] = 0; + e[14] = 0; + e[15] = 1; + return *this; }; -inline float4x4 operator*(const float4x4& m1, const float4x4& m2) -{//iloczyn macierzy - float4x4 retVal; - for (int x=0;x<4;++x) - for (int y=0;y<4;++y) - { - retVal(x)[y]=0; - for (int i=0;i<4;++i) - retVal(x)[y]+=m1[i][y]*m2[x][i]; - } - return retVal; +inline float4x4 operator*(const float4x4 &m1, const float4x4 &m2) +{ // iloczyn macierzy + float4x4 retVal; + for (int x = 0; x < 4; ++x) + for (int y = 0; y < 4; ++y) + { + retVal(x)[y] = 0; + for (int i = 0; i < 4; ++i) + retVal(x)[y] += m1[i][y] * m2[x][i]; + } + return retVal; }; // From code in Graphics Gems; p. 766 -inline float Det2x2(float a,float b,float c,float d) -{//obliczenie wyznacznika macierzy 2×2 - return a*d-b*c; -}; +inline float Det2x2(float a, float b, float c, float d) { // obliczenie wyznacznika macierzy 2×2 return a * d - b * c; }; -inline float Det3x3(float a1,float a2,float a3, - float b1,float b2,float b3, - float c1,float c2,float c3) -{//obliczenie wyznacznika macierzy 3×3 - return - +a1*Det2x2(b2,b3,c2,c3) - -b1*Det2x2(a2,a3,c2,c3) - +c1*Det2x2(a2,a3,b2,b3); +inline float Det3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, + float c3) +{ // obliczenie wyznacznika macierzy 3×3 + return +a1 * Det2x2(b2, b3, c2, c3) - b1 * Det2x2(a2, a3, c2, c3) + c1 * Det2x2(a2, a3, b2, b3); }; float Det(const float4x4 &m) -{//obliczenie wyznacznika macierzy 4×4 - float a1=m[0][0],a2=m[1][0],a3=m[2][0],a4=m[3][0]; - float b1=m[0][1],b2=m[1][1],b3=m[2][1],b4=m[3][1]; - float c1=m[0][2],c2=m[1][2],c3=m[2][2],c4=m[3][2]; - float d1=m[0][3],d2=m[1][3],d3=m[2][3],d4=m[3][3]; - return - +a1*Det3x3(b2,b3,b4,c2,c3,c4,d2,d3,d4) - -b1*Det3x3(a2,a3,a4,c2,c3,c4,d2,d3,d4) - +c1*Det3x3(a2,a3,a4,b2,b3,b4,d2,d3,d4) - -d1*Det3x3(a2,a3,a4,b2,b3,b4,c2,c3,c4); +{ // obliczenie wyznacznika macierzy 4×4 + float a1 = m[0][0], a2 = m[1][0], a3 = m[2][0], a4 = m[3][0]; + float b1 = m[0][1], b2 = m[1][1], b3 = m[2][1], b4 = m[3][1]; + float c1 = m[0][2], c2 = m[1][2], c3 = m[2][2], c4 = m[3][2]; + float d1 = m[0][3], d2 = m[1][3], d3 = m[2][3], d4 = m[3][3]; + return +a1 * Det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) - + b1 * Det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) + + c1 * Det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) - + d1 * Det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); }; #endif diff --git a/Forth.h b/Forth.h index 93a8d3e2..da579e72 100644 --- a/Forth.h +++ b/Forth.h @@ -5,6 +5,6 @@ //--------------------------------------------------------------------------- class Forth -{//klasa obsługi języka +{ // klasa obsługi języka }; #endif diff --git a/Gauge.cpp b/Gauge.cpp index 2358264d..78493629 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -6,8 +6,8 @@ */ -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Timer.h" @@ -18,200 +18,199 @@ __fastcall TGauge::TGauge() { - eType=gt_Unknown; - fFriction=0.0; - fDesiredValue=0.0; - fValue=0.0; - fOffset=0.0; - fScale=1.0; - fStepSize=5; - //iChannel=-1; //kanał analogowej komunikacji zwrotnej - SubModel=NULL; + eType = gt_Unknown; + fFriction = 0.0; + fDesiredValue = 0.0; + fValue = 0.0; + fOffset = 0.0; + fScale = 1.0; + fStepSize = 5; + // iChannel=-1; //kanał analogowej komunikacji zwrotnej + SubModel = NULL; }; -__fastcall TGauge::~TGauge() -{ -}; +__fastcall TGauge::~TGauge(){}; void __fastcall TGauge::Clear() { - SubModel=NULL; - eType=gt_Unknown; - fValue=0; - fDesiredValue=0; + SubModel = NULL; + eType = gt_Unknown; + fValue = 0; + fDesiredValue = 0; }; -void __fastcall TGauge::Init(TSubModel *NewSubModel,TGaugeType eNewType,double fNewScale,double fNewOffset,double fNewFriction,double fNewValue) -{//ustawienie parametrów animacji submodelu - if (NewSubModel) - {//warunek na wszelki wypadek, gdyby się submodel nie podłączył - fFriction=fNewFriction; - fValue=fNewValue; - fOffset=fNewOffset; - fScale=fNewScale; - SubModel=NewSubModel; - eType=eNewType; - if (eType==gt_Digital) - { - TSubModel *sm=SubModel->ChildGet(); - do - {//pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue) - if (sm->pName) - {//musi mieć niepustą nazwę - if ((*sm->pName)>='0') - if ((*sm->pName)<='9') - sm->WillBeAnimated(); //wyłączenie optymalizacji +void __fastcall TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale, + double fNewOffset, double fNewFriction, double fNewValue) +{ // ustawienie parametrów animacji submodelu + if (NewSubModel) + { // warunek na wszelki wypadek, gdyby się submodel nie podłączył + fFriction = fNewFriction; + fValue = fNewValue; + fOffset = fNewOffset; + fScale = fNewScale; + SubModel = NewSubModel; + eType = eNewType; + if (eType == gt_Digital) + { + TSubModel *sm = SubModel->ChildGet(); + do + { // pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue) + if (sm->pName) + { // musi mieć niepustą nazwę + if ((*sm->pName) >= '0') + if ((*sm->pName) <= '9') + sm->WillBeAnimated(); // wyłączenie optymalizacji + } + sm = sm->NextGet(); + } while (sm); + } + else // a banan może być z optymalizacją? + NewSubModel->WillBeAnimated(); // wyłączenie ignowania jedynkowego transformu } - sm=sm->NextGet(); - } while (sm); - } - else //a banan może być z optymalizacją? - NewSubModel->WillBeAnimated(); //wyłączenie ignowania jedynkowego transformu - } }; -bool __fastcall TGauge::Load(TQueryParserComp *Parser,TModel3d *md1,TModel3d *md2,double mul) +bool __fastcall TGauge::Load(TQueryParserComp *Parser, TModel3d *md1, TModel3d *md2, double mul) { - AnsiString str1=Parser->GetNextSymbol(); - AnsiString str2=Parser->GetNextSymbol().LowerCase(); - double val3=Parser->GetNextSymbol().ToDouble()*mul; - double val4=Parser->GetNextSymbol().ToDouble(); - double val5=Parser->GetNextSymbol().ToDouble(); - TSubModel *sm=md1->GetFromName(str1.c_str()); - if (sm) //jeśli nie znaleziony - md2=NULL; //informacja, że znaleziony - else - if (md2) //a jest podany drugi model (np. zewnętrzny) - sm=md2->GetFromName(str1.c_str()); //to może tam będzie, co za różnica gdzie - if (str2=="mov") - Init(sm,gt_Move,val3,val4,val5); - else if (str2=="wip") - Init(sm,gt_Wiper,val3,val4,val5); - else if (str2=="dgt") - Init(sm,gt_Digital,val3,val4,val5); - else - Init(sm,gt_Rotate,val3,val4,val5); - return (md2); //true, gdy podany model zewnętrzny, a w kabinie nie było + AnsiString str1 = Parser->GetNextSymbol(); + AnsiString str2 = Parser->GetNextSymbol().LowerCase(); + double val3 = Parser->GetNextSymbol().ToDouble() * mul; + double val4 = Parser->GetNextSymbol().ToDouble(); + double val5 = Parser->GetNextSymbol().ToDouble(); + TSubModel *sm = md1->GetFromName(str1.c_str()); + if (sm) // jeśli nie znaleziony + md2 = NULL; // informacja, że znaleziony + else if (md2) // a jest podany drugi model (np. zewnętrzny) + sm = md2->GetFromName(str1.c_str()); // to może tam będzie, co za różnica gdzie + if (str2 == "mov") + Init(sm, gt_Move, val3, val4, val5); + else if (str2 == "wip") + Init(sm, gt_Wiper, val3, val4, val5); + else if (str2 == "dgt") + Init(sm, gt_Digital, val3, val4, val5); + else + Init(sm, gt_Rotate, val3, val4, val5); + return (md2); // true, gdy podany model zewnętrzny, a w kabinie nie było }; - void __fastcall TGauge::PermIncValue(double fNewDesired) { - fDesiredValue=fDesiredValue+fNewDesired*fScale+fOffset; - if (fDesiredValue-fOffset>360/fScale) - { - fDesiredValue=fDesiredValue-(360/fScale); - fValue=fValue-(360/fScale); - } + fDesiredValue = fDesiredValue + fNewDesired * fScale + fOffset; + if (fDesiredValue - fOffset > 360 / fScale) + { + fDesiredValue = fDesiredValue - (360 / fScale); + fValue = fValue - (360 / fScale); + } }; void __fastcall TGauge::IncValue(double fNewDesired) -{//używane tylko dla uniwersali - fDesiredValue=fDesiredValue+fNewDesired*fScale+fOffset; - if (fDesiredValue>fScale+fOffset) - fDesiredValue=fScale+fOffset; +{ // używane tylko dla uniwersali + fDesiredValue = fDesiredValue + fNewDesired * fScale + fOffset; + if (fDesiredValue > fScale + fOffset) + fDesiredValue = fScale + fOffset; }; void __fastcall TGauge::DecValue(double fNewDesired) -{//używane tylko dla uniwersali - fDesiredValue=fDesiredValue-fNewDesired*fScale+fOffset; - if (fDesiredValue<0) fDesiredValue=0; +{ // używane tylko dla uniwersali + fDesiredValue = fDesiredValue - fNewDesired * fScale + fOffset; + if (fDesiredValue < 0) + fDesiredValue = 0; }; void __fastcall TGauge::UpdateValue(double fNewDesired) -{//ustawienie wartości docelowej - fDesiredValue=fNewDesired*fScale+fOffset; +{ // ustawienie wartości docelowej + fDesiredValue = fNewDesired * fScale + fOffset; }; void __fastcall TGauge::PutValue(double fNewDesired) -{//McZapkie-281102: natychmiastowe wpisanie wartosci - fDesiredValue=fNewDesired*fScale+fOffset; - fValue=fDesiredValue; +{ // McZapkie-281102: natychmiastowe wpisanie wartosci + fDesiredValue = fNewDesired * fScale + fOffset; + fValue = fDesiredValue; }; void __fastcall TGauge::Update() { - float dt=Timer::GetDeltaTime(); - if ((fFriction>0)&&(dt<0.5*fFriction)) //McZapkie-281102: zabezpieczenie przed oscylacjami dla dlugich czasow - fValue+=dt*(fDesiredValue-fValue)/fFriction; - else - fValue=fDesiredValue; - if (SubModel) - {//warunek na wszelki wypadek, gdyby się submodel nie podłączył - TSubModel *sm; - switch (eType) - { - case gt_Rotate: - SubModel->SetRotate(float3(0,1,0),fValue*360.0); - break; - case gt_Move: - SubModel->SetTranslate(float3(0,0,fValue)); - break; - case gt_Wiper: - SubModel->SetRotate(float3(0,1,0),fValue*360.0); - sm=SubModel->ChildGet(); - if (sm) - {sm->SetRotate(float3(0,1,0),fValue*360.0); - sm=sm->ChildGet(); - if (sm) - sm->SetRotate(float3(0,1,0),fValue*360.0); + float dt = Timer::GetDeltaTime(); + if ((fFriction > 0) && + (dt < + 0.5 * fFriction)) // McZapkie-281102: zabezpieczenie przed oscylacjami dla dlugich czasow + fValue += dt * (fDesiredValue - fValue) / fFriction; + else + fValue = fDesiredValue; + if (SubModel) + { // warunek na wszelki wypadek, gdyby się submodel nie podłączył + TSubModel *sm; + switch (eType) + { + case gt_Rotate: + SubModel->SetRotate(float3(0, 1, 0), fValue * 360.0); + break; + case gt_Move: + SubModel->SetTranslate(float3(0, 0, fValue)); + break; + case gt_Wiper: + SubModel->SetRotate(float3(0, 1, 0), fValue * 360.0); + sm = SubModel->ChildGet(); + if (sm) + { + sm->SetRotate(float3(0, 1, 0), fValue * 360.0); + sm = sm->ChildGet(); + if (sm) + sm->SetRotate(float3(0, 1, 0), fValue * 360.0); + } + break; + case gt_Digital: // Ra 2014-07: licznik cyfrowy + sm = SubModel->ChildGet(); + AnsiString n = FormatFloat("0000000000", floor(fValue)); // na razie tak trochę bez + // sensu + do + { // pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue) + if (sm->pName) + { // musi mieć niepustą nazwę + if ((*sm->pName) >= '0') + if ((*sm->pName) <= '9') + sm->SetRotate(float3(0, 1, 0), + -36.0 * (n['0' + 10 - (*sm->pName)] - '0')); + } + sm = sm->NextGet(); + } while (sm); + break; + } } - break; - case gt_Digital: //Ra 2014-07: licznik cyfrowy - sm=SubModel->ChildGet(); - AnsiString n=FormatFloat("0000000000",floor(fValue)); //na razie tak trochę bez sensu - do - {//pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue) - if (sm->pName) - {//musi mieć niepustą nazwę - if ((*sm->pName)>='0') - if ((*sm->pName)<='9') - sm->SetRotate(float3(0,1,0),-36.0*(n['0'+10-(*sm->pName)]-'0')); - } - sm=sm->NextGet(); - } while (sm); - break; - } - } }; -void __fastcall TGauge::Render() -{ -}; +void __fastcall TGauge::Render(){}; -void __fastcall TGauge::AssignFloat(float* fValue) +void __fastcall TGauge::AssignFloat(float *fValue) { - cDataType='f'; - fData=fValue; + cDataType = 'f'; + fData = fValue; }; -void __fastcall TGauge::AssignDouble(double* dValue) +void __fastcall TGauge::AssignDouble(double *dValue) { - cDataType='d'; - dData=dValue; + cDataType = 'd'; + dData = dValue; }; -void __fastcall TGauge::AssignInt(int* iValue) +void __fastcall TGauge::AssignInt(int *iValue) { - cDataType='i'; - iData=iValue; + cDataType = 'i'; + iData = iValue; }; void __fastcall TGauge::UpdateValue() -{//ustawienie wartości docelowej z parametru - switch (cDataType) - {//to nie jest zbyt optymalne, można by zrobić osobne funkcje - case 'f': - fDesiredValue=(*fData)*fScale+fOffset; - break; - case 'd': - fDesiredValue=(*dData)*fScale+fOffset; - break; - case 'i': - fDesiredValue=(*iData)*fScale+fOffset; - break; - } +{ // ustawienie wartości docelowej z parametru + switch (cDataType) + { // to nie jest zbyt optymalne, można by zrobić osobne funkcje + case 'f': + fDesiredValue = (*fData) * fScale + fOffset; + break; + case 'd': + fDesiredValue = (*dData) * fScale + fOffset; + break; + case 'i': + fDesiredValue = (*iData) * fScale + fOffset; + break; + } }; - - //--------------------------------------------------------------------------- #pragma package(smart_init) diff --git a/Gauge.h b/Gauge.h index 69cd8924..5ab60cfe 100644 --- a/Gauge.h +++ b/Gauge.h @@ -5,57 +5,60 @@ //#include "Classes.h" #include "QueryParserComp.hpp" -//class Queryparsercomp::TQueryParserComp; +// class Queryparsercomp::TQueryParserComp; class TSubModel; class TModel3d; - + typedef enum -{//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_Digital //licznik cyfrowy, np. kilometrów +{ // 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_Digital // licznik cyfrowy, np. kilometrów } TGaugeType; -class TGauge //zmienne "gg" -{//animowany wskaźnik, mogący przyjmować wiele stanów pośrednich -private: - TGaugeType eType; //typ ruchu - double fFriction; //hamowanie przy zliżaniu się do zadanej wartości - double fDesiredValue; //wartość docelowa - double fValue; //wartość obecna - double fOffset; //wartość początkowa ("0") - double fScale; //wartość końcowa ("1") - double fStepSize; //nie używane - char cDataType; //typ zmiennej parametru: f-float, d-double, i-int - union - {//wskaźnik na parametr pokazywany przez animację - float* fData; - double* dData; - int* iData; - }; -public: - __fastcall TGauge(); - __fastcall ~TGauge(); - void __fastcall Clear(); - void __fastcall Init(TSubModel *NewSubModel,TGaugeType eNewTyp,double fNewScale=1,double fNewOffset=0,double fNewFriction=0,double fNewValue=0); - bool __fastcall Load(TQueryParserComp *Parser,TModel3d *md1,TModel3d *md2=NULL,double mul=1.0); - void __fastcall PermIncValue(double fNewDesired); - void __fastcall IncValue(double fNewDesired); - void __fastcall DecValue(double fNewDesired); - void __fastcall UpdateValue(double fNewDesired); - void __fastcall PutValue(double fNewDesired); - float GetValue() {return fValue;}; - void __fastcall Update(); - void __fastcall Render(); - void __fastcall AssignFloat(float* fValue); - void __fastcall AssignDouble(double* dValue); - void __fastcall AssignInt(int* iValue); - void __fastcall UpdateValue(); - TSubModel *SubModel; //McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie +class TGauge // zmienne "gg" +{ // animowany wskaźnik, mogący przyjmować wiele stanów pośrednich + private: + TGaugeType eType; // typ ruchu + double fFriction; // hamowanie przy zliżaniu się do zadanej wartości + double fDesiredValue; // wartość docelowa + double fValue; // wartość obecna + double fOffset; // wartość początkowa ("0") + double fScale; // wartość końcowa ("1") + double fStepSize; // nie używane + char cDataType; // typ zmiennej parametru: f-float, d-double, i-int + union + { // wskaźnik na parametr pokazywany przez animację + float *fData; + double *dData; + int *iData; + }; + + public: + __fastcall TGauge(); + __fastcall ~TGauge(); + void __fastcall Clear(); + void __fastcall Init(TSubModel *NewSubModel, TGaugeType eNewTyp, double fNewScale = 1, + double fNewOffset = 0, double fNewFriction = 0, double fNewValue = 0); + bool __fastcall Load(TQueryParserComp *Parser, TModel3d *md1, TModel3d *md2 = NULL, + double mul = 1.0); + void __fastcall PermIncValue(double fNewDesired); + void __fastcall IncValue(double fNewDesired); + void __fastcall DecValue(double fNewDesired); + void __fastcall UpdateValue(double fNewDesired); + void __fastcall PutValue(double fNewDesired); + float GetValue() { return fValue; }; + void __fastcall Update(); + void __fastcall Render(); + void __fastcall AssignFloat(float *fValue); + void __fastcall AssignDouble(double *dValue); + void __fastcall AssignInt(int *iValue); + void __fastcall UpdateValue(); + TSubModel *SubModel; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie }; //--------------------------------------------------------------------------- #endif - diff --git a/Geom.cpp b/Geom.cpp index 90926d31..e709290d 100644 --- a/Geom.cpp +++ b/Geom.cpp @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------- -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #include #include #include "opengl/glut.h" @@ -12,108 +12,101 @@ #include "Globals.h" #include "Geom.h" +__fastcall TGeometry::TGeometry() {} -__fastcall TGeometry::TGeometry() -{ -} - -__fastcall TGeometry::~TGeometry() -{ -} - -bool __fastcall TGeometry::Init() -{ -} +__fastcall TGeometry::~TGeometry() {} +bool __fastcall TGeometry::Init() {} vector3 __fastcall TGeometry::Load(TQueryParserComp *Parser) { - str= Parser->GetNextSymbol().LowerCase(); - tmp->TextureID= TTexturesManager::GetTextureID(str.c_str()); + str = Parser->GetNextSymbol().LowerCase(); + tmp->TextureID = TTexturesManager::GetTextureID(str.c_str()); - i=0; - do - { - tf= Parser->GetNextSymbol().ToDouble(); - TempVerts[i].Point.x= tf; - tf= Parser->GetNextSymbol().ToDouble(); - TempVerts[i].Point.y= tf; - tf= Parser->GetNextSymbol().ToDouble(); - TempVerts[i].Point.z= tf; - tf= Parser->GetNextSymbol().ToDouble(); - TempVerts[i].Normal.x= tf; - tf= Parser->GetNextSymbol().ToDouble(); - TempVerts[i].Normal.y= tf; - tf= Parser->GetNextSymbol().ToDouble(); - TempVerts[i].Normal.z= tf; + i = 0; + do + { + tf = Parser->GetNextSymbol().ToDouble(); + TempVerts[i].Point.x = tf; + tf = Parser->GetNextSymbol().ToDouble(); + TempVerts[i].Point.y = tf; + tf = Parser->GetNextSymbol().ToDouble(); + TempVerts[i].Point.z = tf; + tf = Parser->GetNextSymbol().ToDouble(); + TempVerts[i].Normal.x = tf; + tf = Parser->GetNextSymbol().ToDouble(); + TempVerts[i].Normal.y = tf; + tf = Parser->GetNextSymbol().ToDouble(); + TempVerts[i].Normal.z = tf; - str= Parser->GetNextSymbol().LowerCase(); - if (str=="x") - TempVerts[i].tu= (TempVerts[i].Point.x+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str=="y") - TempVerts[i].tu= (TempVerts[i].Point.y+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str=="z") - TempVerts[i].tu= (TempVerts[i].Point.z+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - TempVerts[i].tu= str.ToDouble();; + str = Parser->GetNextSymbol().LowerCase(); + if (str == "x") + TempVerts[i].tu = (TempVerts[i].Point.x + Parser->GetNextSymbol().ToDouble()) / + Parser->GetNextSymbol().ToDouble(); + else if (str == "y") + TempVerts[i].tu = (TempVerts[i].Point.y + Parser->GetNextSymbol().ToDouble()) / + Parser->GetNextSymbol().ToDouble(); + else if (str == "z") + TempVerts[i].tu = (TempVerts[i].Point.z + Parser->GetNextSymbol().ToDouble()) / + Parser->GetNextSymbol().ToDouble(); + else + TempVerts[i].tu = str.ToDouble(); + ; - str= Parser->GetNextSymbol().LowerCase(); - if (str=="x") - TempVerts[i].tv= (TempVerts[i].Point.x+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str=="y") - TempVerts[i].tv= (TempVerts[i].Point.y+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str=="z") - TempVerts[i].tv= (TempVerts[i].Point.z+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - TempVerts[i].tv= str.ToDouble();; + str = Parser->GetNextSymbol().LowerCase(); + if (str == "x") + TempVerts[i].tv = (TempVerts[i].Point.x + Parser->GetNextSymbol().ToDouble()) / + Parser->GetNextSymbol().ToDouble(); + else if (str == "y") + TempVerts[i].tv = (TempVerts[i].Point.y + Parser->GetNextSymbol().ToDouble()) / + Parser->GetNextSymbol().ToDouble(); + else if (str == "z") + TempVerts[i].tv = (TempVerts[i].Point.z + Parser->GetNextSymbol().ToDouble()) / + Parser->GetNextSymbol().ToDouble(); + else + TempVerts[i].tv = str.ToDouble(); + ; -// tf= Parser->GetNextSymbol().ToDouble(); - // TempVerts[i].tu= tf; - // tf= Parser->GetNextSymbol().ToDouble(); - // TempVerts[i].tv= tf; + // tf= Parser->GetNextSymbol().ToDouble(); + // TempVerts[i].tu= tf; + // tf= Parser->GetNextSymbol().ToDouble(); + // TempVerts[i].tv= tf; - TempVerts[i].Point.RotateZ(aRotate.z/180*M_PI); - TempVerts[i].Point.RotateX(aRotate.x/180*M_PI); - TempVerts[i].Point.RotateY(aRotate.y/180*M_PI); - TempVerts[i].Normal.RotateZ(aRotate.z/180*M_PI); - TempVerts[i].Normal.RotateX(aRotate.x/180*M_PI); - TempVerts[i].Normal.RotateY(aRotate.y/180*M_PI); + TempVerts[i].Point.RotateZ(aRotate.z / 180 * M_PI); + TempVerts[i].Point.RotateX(aRotate.x / 180 * M_PI); + TempVerts[i].Point.RotateY(aRotate.y / 180 * M_PI); + TempVerts[i].Normal.RotateZ(aRotate.z / 180 * M_PI); + TempVerts[i].Normal.RotateX(aRotate.x / 180 * M_PI); + TempVerts[i].Normal.RotateY(aRotate.y / 180 * M_PI); - TempVerts[i].Point+= pOrigin; - tmp->pCenter+= TempVerts[i].Point; + TempVerts[i].Point += pOrigin; + tmp->pCenter += TempVerts[i].Point; - i++; + i++; -// } - } while ( Parser->GetNextSymbol().LowerCase()!="endtri" ); + // } + } while (Parser->GetNextSymbol().LowerCase() != "endtri"); - nv= i; - tmp->Init(nv); - tmp->pCenter/= (nv>0?nv:1); + nv = i; + tmp->Init(nv); + tmp->pCenter /= (nv > 0 ? nv : 1); -// memcpy(tmp->Vertices,TempVerts,nv*sizeof(TGroundVertex)); + // memcpy(tmp->Vertices,TempVerts,nv*sizeof(TGroundVertex)); - r= 0; - for (int i=0; iVertices[i]= TempVerts[i]; - tf= SquareMagnitude(tmp->Vertices[i].Point-tmp->pCenter); - if (tf>r) - r= tf; - } - -// tmp->fSquareRadius= 2000*2000+r; - tmp->fSquareRadius+= r; + r = 0; + for (int i = 0; i < nv; i++) + { + tmp->Vertices[i] = TempVerts[i]; + tf = SquareMagnitude(tmp->Vertices[i].Point - tmp->pCenter); + if (tf > r) + r = tf; + } + // tmp->fSquareRadius= 2000*2000+r; + tmp->fSquareRadius += r; } -bool __fastcall TGeometry::Render() -{ -} +bool __fastcall TGeometry::Render() {} //--------------------------------------------------------------------------- #pragma package(smart_init) diff --git a/Geom.h b/Geom.h index 24398462..12382468 100644 --- a/Geom.h +++ b/Geom.h @@ -10,12 +10,12 @@ struct TGeomVertex { vector3 Point; vector3 Normal; - double tu,tv; + double tu, tv; }; class TGeometry { -private: + private: GLuint iType; union { @@ -26,7 +26,8 @@ private: TMaterialColor Ambient; TMaterialColor Diffuse; TMaterialColor Specular; -public: + + public: __fastcall TGeometry(); __fastcall ~TGeometry(); bool __fastcall Init(); diff --git a/Globals.cpp b/Globals.cpp index bd001006..b613a6f2 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -8,7 +8,6 @@ #include "system.hpp" #pragma hdrstop - #include "Globals.h" #include "QueryParserComp.hpp" #include "usefull.h" @@ -18,564 +17,614 @@ #include //do odczytu daty #include "World.h" +// namespace Global { +// parametry do użytku wewnętrznego +// double Global::tSinceStart=0; +TGround *Global::pGround = NULL; +// char Global::CreatorName1[30]="2001-2004 Maciej Czapkiewicz "; +// char Global::CreatorName2[30]="2001-2003 Marcin Woźniak "; +// char Global::CreatorName3[20]="2004-2005 Adam Bugiel "; +// char Global::CreatorName4[30]="2004 Arkadiusz Ślusarczyk "; +// char Global::CreatorName5[30]="2003-2009 Łukasz Kirchner "; +AnsiString Global::asCurrentSceneryPath = "scenery/"; +AnsiString Global::asCurrentTexturePath = AnsiString(szTexturePath); +AnsiString Global::asCurrentDynamicPath = ""; +int Global::iSlowMotion = + 0; // info o malym FPS: 0-OK, 1-wyłączyć multisampling, 3-promień 1.5km, 7-1km +TDynamicObject *Global::changeDynObj = NULL; // info o zmianie pojazdu +bool Global::detonatoryOK; // info o nowych detonatorach +double Global::ABuDebug = 0; +AnsiString Global::asSky = "1"; +double Global::fOpenGL = 0.0; // wersja OpenGL - do sprawdzania obecności rozszerzeń +bool Global::bOpenGL_1_5 = false; // czy są dostępne funkcje OpenGL 1.5 +double Global::fLuminance = 1.0; // jasność światła do automatycznego zapalania +int Global::iReCompile = 0; // zwiększany, gdy trzeba odświeżyć siatki +HWND Global::hWnd = NULL; // uchwyt okna +int Global::iCameraLast = -1; +AnsiString Global::asRelease = "15.3.1166.469"; +AnsiString Global::asVersion = + "Compilation 2015-03-25, release " + Global::asRelease + "."; // tutaj, bo wysyłany +int Global::iViewMode = 0; // co aktualnie widać: 0-kabina, 1-latanie, 2-sprzęgi, 3-dokumenty +int Global::iTextMode = 0; // tryb pracy wyświetlacza tekstowego +int Global::iScreenMode[12] = {0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0}; // numer ekranu wyświetlacza tekstowego +double Global::fSunDeclination = 0.0; // deklinacja Słońca +double Global::fTimeAngleDeg = 0.0; // godzina w postaci kąta +float Global::fClockAngleDeg[6]; // kąty obrotu cylindrów dla zegara cyfrowego +char *Global::szTexturesTGA[4] = {"tga", "dds", "tex", "bmp"}; // lista tekstur od TGA +char *Global::szTexturesDDS[4] = {"dds", "tga", "tex", "bmp"}; // lista tekstur od DDS +int Global::iKeyLast = 0; // ostatnio naciśnięty klawisz w celu logowania +GLuint Global::iTextureId = 0; // ostatnio użyta tekstura 2D +int Global::iPause = 0x10; // globalna pauza ruchu +bool Global::bActive = true; // czy jest aktywnym oknem +int Global::iErorrCounter = 0; // licznik sprawdzań do śledzenia błędów OpenGL +int Global::iTextures = 0; // licznik użytych tekstur +TWorld *Global::pWorld = NULL; +Queryparsercomp::TQueryParserComp *Global::qParser = NULL; +cParser *Global::pParser = NULL; +int Global::iSegmentsRendered = 90; // ilość segmentów do regulacji wydajności +TCamera *Global::pCamera = NULL; // parametry kamery +TDynamicObject *Global::pUserDynamic = NULL; // pojazd użytkownika, renderowany bez trzęsienia +bool Global::bSmudge = false; // czy wyświetlać smugę, a pojazd użytkownika na końcu +AnsiString Global::asTranscript[5]; // napisy na ekranie (widoczne) +TTranscripts Global::tranTexts; // obiekt obsługujący stenogramy dźwięków na ekranie -//namespace Global { - -//parametry do użytku wewnętrznego -//double Global::tSinceStart=0; -TGround *Global::pGround=NULL; -//char Global::CreatorName1[30]="2001-2004 Maciej Czapkiewicz "; -//char Global::CreatorName2[30]="2001-2003 Marcin Woźniak "; -//char Global::CreatorName3[20]="2004-2005 Adam Bugiel "; -//char Global::CreatorName4[30]="2004 Arkadiusz Ślusarczyk "; -//char Global::CreatorName5[30]="2003-2009 Łukasz Kirchner "; -AnsiString Global::asCurrentSceneryPath="scenery/"; -AnsiString Global::asCurrentTexturePath=AnsiString(szTexturePath); -AnsiString Global::asCurrentDynamicPath=""; -int Global::iSlowMotion=0; //info o malym FPS: 0-OK, 1-wyłączyć multisampling, 3-promień 1.5km, 7-1km -TDynamicObject *Global::changeDynObj=NULL; //info o zmianie pojazdu -bool Global::detonatoryOK; //info o nowych detonatorach -double Global::ABuDebug=0; -AnsiString Global::asSky="1"; -double Global::fOpenGL=0.0; //wersja OpenGL - do sprawdzania obecności rozszerzeń -bool Global::bOpenGL_1_5=false; //czy są dostępne funkcje OpenGL 1.5 -double Global::fLuminance=1.0; //jasność światła do automatycznego zapalania -int Global::iReCompile=0; //zwiększany, gdy trzeba odświeżyć siatki -HWND Global::hWnd=NULL; //uchwyt okna -int Global::iCameraLast=-1; -AnsiString Global::asRelease="15.3.1166.469"; -AnsiString Global::asVersion="Compilation 2015-03-25, release "+Global::asRelease+"."; //tutaj, bo wysyłany -int Global::iViewMode=0; //co aktualnie widać: 0-kabina, 1-latanie, 2-sprzęgi, 3-dokumenty -int Global::iTextMode=0; //tryb pracy wyświetlacza tekstowego -int Global::iScreenMode[12]={0,0,0,0,0,0,0,0,0,0,0,0}; //numer ekranu wyświetlacza tekstowego -double Global::fSunDeclination=0.0; //deklinacja Słońca -double Global::fTimeAngleDeg=0.0; //godzina w postaci kąta -float Global::fClockAngleDeg[6]; //kąty obrotu cylindrów dla zegara cyfrowego -char* Global::szTexturesTGA[4]={"tga","dds","tex","bmp"}; //lista tekstur od TGA -char* Global::szTexturesDDS[4]={"dds","tga","tex","bmp"}; //lista tekstur od DDS -int Global::iKeyLast=0; //ostatnio naciśnięty klawisz w celu logowania -GLuint Global::iTextureId=0; //ostatnio użyta tekstura 2D -int Global::iPause=0x10; //globalna pauza ruchu -bool Global::bActive=true; //czy jest aktywnym oknem -int Global::iErorrCounter=0; //licznik sprawdzań do śledzenia błędów OpenGL -int Global::iTextures=0; //licznik użytych tekstur -TWorld* Global::pWorld=NULL; -Queryparsercomp::TQueryParserComp *Global::qParser=NULL; -cParser *Global::pParser=NULL; -int Global::iSegmentsRendered=90; //ilość segmentów do regulacji wydajności -TCamera* Global::pCamera=NULL; //parametry kamery -TDynamicObject *Global::pUserDynamic=NULL; //pojazd użytkownika, renderowany bez trzęsienia -bool Global::bSmudge=false; //czy wyświetlać smugę, a pojazd użytkownika na końcu -AnsiString Global::asTranscript[5]; //napisy na ekranie (widoczne) -TTranscripts Global::tranTexts; //obiekt obsługujący stenogramy dźwięków na ekranie - -//parametry scenerii +// parametry scenerii vector3 Global::pCameraPosition; double Global::pCameraRotation; double Global::pCameraRotationDeg; vector3 Global::pFreeCameraInit[10]; vector3 Global::pFreeCameraInitAngle[10]; -double Global::fFogStart=1700; -double Global::fFogEnd=2000; -GLfloat Global::AtmoColor[]={0.423f,0.702f,1.0f}; -GLfloat Global::FogColor[]={0.6f,0.7f,0.8f}; -GLfloat Global::ambientDayLight[] ={0.40f,0.40f,0.45f,1.0f}; //robocze -GLfloat Global::diffuseDayLight[] ={0.55f,0.54f,0.50f,1.0f}; -GLfloat Global::specularDayLight[]={0.95f,0.94f,0.90f,1.0f}; -GLfloat Global::ambientLight[] ={0.80f,0.80f,0.85f,1.0f}; //stałe -GLfloat Global::diffuseLight[] ={0.85f,0.85f,0.80f,1.0f}; -GLfloat Global::specularLight[] ={0.95f,0.94f,0.90f,1.0f}; -GLfloat Global::whiteLight[] ={1.00f,1.00f,1.00f,1.0f}; -GLfloat Global::noLight[] ={0.00f,0.00f,0.00f,1.0f}; -GLfloat Global::darkLight[] ={0.03f,0.03f,0.03f,1.0f}; //śladowe +double Global::fFogStart = 1700; +double Global::fFogEnd = 2000; +GLfloat Global::AtmoColor[] = {0.423f, 0.702f, 1.0f}; +GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f}; +GLfloat Global::ambientDayLight[] = {0.40f, 0.40f, 0.45f, 1.0f}; // robocze +GLfloat Global::diffuseDayLight[] = {0.55f, 0.54f, 0.50f, 1.0f}; +GLfloat Global::specularDayLight[] = {0.95f, 0.94f, 0.90f, 1.0f}; +GLfloat Global::ambientLight[] = {0.80f, 0.80f, 0.85f, 1.0f}; // stałe +GLfloat Global::diffuseLight[] = {0.85f, 0.85f, 0.80f, 1.0f}; +GLfloat Global::specularLight[] = {0.95f, 0.94f, 0.90f, 1.0f}; +GLfloat Global::whiteLight[] = {1.00f, 1.00f, 1.00f, 1.0f}; +GLfloat Global::noLight[] = {0.00f, 0.00f, 0.00f, 1.0f}; +GLfloat Global::darkLight[] = {0.03f, 0.03f, 0.03f, 1.0f}; //śladowe GLfloat Global::lightPos[4]; -bool Global::bRollFix=true; //czy wykonać przeliczanie przechyłki -bool Global::bJoinEvents=false; //czy grupować eventy o tych samych nazwach -int Global::iHiddenEvents=0; //czy łączyć eventy z torami poprzez nazwę toru +bool Global::bRollFix = true; // czy wykonać przeliczanie przechyłki +bool Global::bJoinEvents = false; // czy grupować eventy o tych samych nazwach +int Global::iHiddenEvents = 0; // czy łączyć eventy z torami poprzez nazwę toru -//parametry użytkowe (jak komu pasuje) +// parametry użytkowe (jak komu pasuje) int Global::Keys[MaxKeys]; -int Global::iWindowWidth=800; -int Global::iWindowHeight=600; -float Global::fDistanceFactor=768.0; //baza do przeliczania odległości dla LoD -int Global::iFeedbackMode=1; //tryb pracy informacji zwrotnej -int Global::iFeedbackPort=0; //dodatkowy adres dla informacji zwrotnych -bool Global::bFreeFly=false; -bool Global::bFullScreen=false; -bool Global::bInactivePause=true; //automatyczna pauza, gdy okno nieaktywne -float Global::fMouseXScale=1.5; -float Global::fMouseYScale=0.2; -char Global::szSceneryFile[256]="td.scn"; -AnsiString Global::asHumanCtrlVehicle="EU07-424"; -int Global::iMultiplayer=0; //blokada działania niektórych funkcji na rzecz komunikacji -double Global::fMoveLight=-1; //ruchome światło -double Global::fLatitudeDeg=52.0; //szerokość geograficzna -float Global::fFriction=1.0; //mnożnik tarcia - KURS90 -double Global::fBrakeStep=1.0; //krok zmiany hamulca dla klawiszy [Num3] i [Num9] -AnsiString Global::asLang="pl"; //domyślny język - http://tools.ietf.org/html/bcp47 +int Global::iWindowWidth = 800; +int Global::iWindowHeight = 600; +float Global::fDistanceFactor = 768.0; // baza do przeliczania odległości dla LoD +int Global::iFeedbackMode = 1; // tryb pracy informacji zwrotnej +int Global::iFeedbackPort = 0; // dodatkowy adres dla informacji zwrotnych +bool Global::bFreeFly = false; +bool Global::bFullScreen = false; +bool Global::bInactivePause = true; // automatyczna pauza, gdy okno nieaktywne +float Global::fMouseXScale = 1.5; +float Global::fMouseYScale = 0.2; +char Global::szSceneryFile[256] = "td.scn"; +AnsiString Global::asHumanCtrlVehicle = "EU07-424"; +int Global::iMultiplayer = 0; // blokada działania niektórych funkcji na rzecz komunikacji +double Global::fMoveLight = -1; // ruchome światło +double Global::fLatitudeDeg = 52.0; // szerokość geograficzna +float Global::fFriction = 1.0; // mnożnik tarcia - KURS90 +double Global::fBrakeStep = 1.0; // krok zmiany hamulca dla klawiszy [Num3] i [Num9] +AnsiString Global::asLang = "pl"; // domyślny język - http://tools.ietf.org/html/bcp47 +// parametry wydajnościowe (np. regulacja FPS, szybkość wczytywania) +bool Global::bAdjustScreenFreq = true; +bool Global::bEnableTraction = true; +bool Global::bLoadTraction = true; +bool Global::bLiveTraction = true; +int Global::iDefaultFiltering = 9; // domyślne rozmywanie tekstur TGA bez alfa +int Global::iBallastFiltering = 9; // domyślne rozmywanie tekstur podsypki +int Global::iRailProFiltering = 5; // domyślne rozmywanie tekstur szyn +int Global::iDynamicFiltering = 5; // domyślne rozmywanie tekstur pojazdów +bool Global::bUseVBO = false; // czy jest VBO w karcie graficznej (czy użyć) +GLint Global::iMaxTextureSize = 16384; // maksymalny rozmiar tekstury +bool Global::bSmoothTraction = false; // wygładzanie drutów starym sposobem +char **Global::szDefaultExt = Global::szTexturesDDS; // domyślnie od DDS +int Global::iMultisampling = 2; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px +bool Global::bGlutFont = false; // czy tekst generowany przez GLUT32.DLL +int Global::iConvertModels = 7; // tworzenie plików binarnych, +2-optymalizacja transformów +int Global::iSlowMotionMask = -1; // maska wyłączanych właściwości dla zwiększenia FPS +int Global::iModifyTGA = 7; // czy korygować pliki TGA dla szybszego wczytywania +// bool Global::bTerrainCompact=true; //czy zapisać teren w pliku +TAnimModel *Global::pTerrainCompact = NULL; // do zapisania terenu w pliku +AnsiString Global::asTerrainModel = ""; // nazwa obiektu terenu do zapisania w pliku +double Global::fFpsAverage = 20.0; // oczekiwana wartosć FPS +double Global::fFpsDeviation = 5.0; // odchylenie standardowe FPS +double Global::fFpsMin = 0.0; // dolna granica FPS, przy której promień scenerii będzie zmniejszany +double Global::fFpsMax = 0.0; // górna granica FPS, przy której promień scenerii będzie zwiększany +double Global::fFpsRadiusMax = 3000.0; // maksymalny promień renderowania +int Global::iFpsRadiusMax = 225; // maksymalny promień renderowania +double Global::fRadiusFactor = 1.1; // współczynnik jednorazowej zmiany promienia scenerii -//parametry wydajnościowe (np. regulacja FPS, szybkość wczytywania) -bool Global::bAdjustScreenFreq=true; -bool Global::bEnableTraction=true; -bool Global::bLoadTraction=true; -bool Global::bLiveTraction=true; -int Global::iDefaultFiltering=9; //domyślne rozmywanie tekstur TGA bez alfa -int Global::iBallastFiltering=9; //domyślne rozmywanie tekstur podsypki -int Global::iRailProFiltering=5; //domyślne rozmywanie tekstur szyn -int Global::iDynamicFiltering=5; //domyślne rozmywanie tekstur pojazdów -bool Global::bUseVBO=false; //czy jest VBO w karcie graficznej (czy użyć) -GLint Global::iMaxTextureSize=16384; //maksymalny rozmiar tekstury -bool Global::bSmoothTraction=false; //wygładzanie drutów starym sposobem -char** Global::szDefaultExt=Global::szTexturesDDS; //domyślnie od DDS -int Global::iMultisampling=2; //tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px -bool Global::bGlutFont=false; //czy tekst generowany przez GLUT32.DLL -int Global::iConvertModels=7; //tworzenie plików binarnych, +2-optymalizacja transformów -int Global::iSlowMotionMask=-1; //maska wyłączanych właściwości dla zwiększenia FPS -int Global::iModifyTGA=7; //czy korygować pliki TGA dla szybszego wczytywania -//bool Global::bTerrainCompact=true; //czy zapisać teren w pliku -TAnimModel *Global::pTerrainCompact=NULL; //do zapisania terenu w pliku -AnsiString Global::asTerrainModel=""; //nazwa obiektu terenu do zapisania w pliku -double Global::fFpsAverage=20.0; //oczekiwana wartosć FPS -double Global::fFpsDeviation=5.0; //odchylenie standardowe FPS -double Global::fFpsMin=0.0; //dolna granica FPS, przy której promień scenerii będzie zmniejszany -double Global::fFpsMax=0.0; //górna granica FPS, przy której promień scenerii będzie zwiększany -double Global::fFpsRadiusMax=3000.0; //maksymalny promień renderowania -int Global::iFpsRadiusMax=225; //maksymalny promień renderowania -double Global::fRadiusFactor=1.1; //współczynnik jednorazowej zmiany promienia scenerii +// parametry testowe (do testowania scenerii i obiektów) +bool Global::bWireFrame = false; +bool Global::bSoundEnabled = true; +int Global::iWriteLogEnabled = 3; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów +bool Global::bManageNodes = true; +bool Global::bDecompressDDS = false; // czy programowa dekompresja DDS -//parametry testowe (do testowania scenerii i obiektów) -bool Global::bWireFrame=false; -bool Global::bSoundEnabled=true; -int Global::iWriteLogEnabled=3; //maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów -bool Global::bManageNodes=true; -bool Global::bDecompressDDS=false; //czy programowa dekompresja DDS +// parametry do kalibracji +// kolejno współczynniki dla potęg 0, 1, 2, 3 wartości odczytanej z urządzenia +double Global::fCalibrateIn[6][4] = { + {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}}; +double Global::fCalibrateOut[7][4] = {{0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}}; -//parametry do kalibracji -//kolejno współczynniki dla potęg 0, 1, 2, 3 wartości odczytanej z urządzenia -double Global::fCalibrateIn[6][4]={{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0}}; -double Global::fCalibrateOut[7][4]={{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0}}; - -//parametry przejściowe (do usunięcia) -//bool Global::bTimeChange=false; //Ra: ZiomalCl wyłączył starą wersję nocy -//bool Global::bRenderAlpha=true; //Ra: wywaliłam tę flagę -bool Global::bnewAirCouplers=true; -bool Global::bDoubleAmbient=false; //podwójna jasność ambient -double Global::fTimeSpeed=1.0; //przyspieszenie czasu, zmienna do testów -bool Global::bHideConsole=false; //hunter-271211: ukrywanie konsoli -int Global::iBpp=32; //chyba już nie używa się kart, na których 16bpp coś poprawi +// parametry przejściowe (do usunięcia) +// bool Global::bTimeChange=false; //Ra: ZiomalCl wyłączył starą wersję nocy +// bool Global::bRenderAlpha=true; //Ra: wywaliłam tę flagę +bool Global::bnewAirCouplers = true; +bool Global::bDoubleAmbient = false; // podwójna jasność ambient +double Global::fTimeSpeed = 1.0; // przyspieszenie czasu, zmienna do testów +bool Global::bHideConsole = false; // hunter-271211: ukrywanie konsoli +int Global::iBpp = 32; // chyba już nie używa się kart, na których 16bpp coś poprawi //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- AnsiString __fastcall Global::GetNextSymbol() -{//pobranie tokenu z aktualnego parsera - if (qParser) return qParser->EndOfFile?AnsiString("endconfig"):qParser->GetNextSymbol(); - if (pParser) - {std::string token; - pParser->getTokens(); - *pParser >> token; - return AnsiString(token.c_str()); - }; - return ""; +{ // pobranie tokenu z aktualnego parsera + if (qParser) + return qParser->EndOfFile ? AnsiString("endconfig") : qParser->GetNextSymbol(); + if (pParser) + { + std::string token; + pParser->getTokens(); + *pParser >> token; + return AnsiString(token.c_str()); + }; + return ""; }; void __fastcall Global::LoadIniFile(AnsiString asFileName) { - int i; - for (i=0;i<10;++i) - {//zerowanie pozycji kamer - pFreeCameraInit[i]=vector3(0,0,0); //współrzędne w scenerii - pFreeCameraInitAngle[i]=vector3(0,0,0); //kąty obrotu w radianach - } - TFileStream *fs; - fs=new TFileStream(asFileName,fmOpenRead|fmShareCompat); - if (!fs) return; - AnsiString str=""; - int size=fs->Size; - str.SetLength(size); - fs->Read(str.c_str(),size); - //str+=""; - delete fs; - TQueryParserComp *Parser; - Parser=new TQueryParserComp(NULL); - Parser->TextToParse=str; - //Parser->LoadStringToParse(asFile); - Parser->First(); - ConfigParse(Parser); - delete Parser; //Ra: tego jak zwykle nie było wcześniej :] + int i; + for (i = 0; i < 10; ++i) + { // zerowanie pozycji kamer + pFreeCameraInit[i] = vector3(0, 0, 0); // współrzędne w scenerii + pFreeCameraInitAngle[i] = vector3(0, 0, 0); // kąty obrotu w radianach + } + TFileStream *fs; + fs = new TFileStream(asFileName, fmOpenRead | fmShareCompat); + if (!fs) + return; + AnsiString str = ""; + int size = fs->Size; + str.SetLength(size); + fs->Read(str.c_str(), size); + // str+=""; + delete fs; + TQueryParserComp *Parser; + Parser = new TQueryParserComp(NULL); + Parser->TextToParse = str; + // Parser->LoadStringToParse(asFile); + Parser->First(); + ConfigParse(Parser); + delete Parser; // Ra: tego jak zwykle nie było wcześniej :] }; -void __fastcall Global::ConfigParse(TQueryParserComp *qp,cParser *cp) -{//Ra: trzeba by przerobić na cParser, żeby to działało w scenerii - pParser=cp; - qParser=qp; - AnsiString str; - int i; - do - { - str=GetNextSymbol().LowerCase(); - if (str==AnsiString("sceneryfile")) - { - str=GetNextSymbol().LowerCase(); - strcpy(szSceneryFile,str.c_str()); - } - else - if (str==AnsiString("humanctrlvehicle")) - { - str=GetNextSymbol().LowerCase(); - asHumanCtrlVehicle=str; - } - else if (str==AnsiString("width")) - iWindowWidth=GetNextSymbol().ToInt(); - else if (str==AnsiString("height")) - iWindowHeight=GetNextSymbol().ToInt(); - else if (str==AnsiString("heightbase")) - fDistanceFactor=GetNextSymbol().ToInt(); - else if (str==AnsiString("bpp")) - iBpp=((GetNextSymbol().LowerCase()==AnsiString("32")) ? 32 : 16 ); - else if (str==AnsiString("fullscreen")) - bFullScreen=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("freefly")) //Mczapkie-130302 - { - bFreeFly=(GetNextSymbol().LowerCase()==AnsiString("yes")); - pFreeCameraInit[0].x=GetNextSymbol().ToDouble(); - pFreeCameraInit[0].y=GetNextSymbol().ToDouble(); - pFreeCameraInit[0].z=GetNextSymbol().ToDouble(); - } - else if (str==AnsiString("wireframe")) - bWireFrame=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("debugmode")) //McZapkie! - DebugModeFlag uzywana w mover.pas, warto tez blokowac cheaty gdy false - DebugModeFlag=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("soundenabled")) //McZapkie-040302 - blokada dzwieku - przyda sie do debugowania oraz na komp. bez karty dzw. - bSoundEnabled=(GetNextSymbol().LowerCase()==AnsiString("yes")); - //else if (str==AnsiString("renderalpha")) //McZapkie-1312302 - dwuprzebiegowe renderowanie - // bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("physicslog")) //McZapkie-030402 - logowanie parametrow fizycznych dla kazdego pojazdu z maszynista - WriteLogFlag=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("physicsdeactivation")) //McZapkie-291103 - usypianie fizyki - PhysicActivationFlag=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("debuglog")) - {//McZapkie-300402 - wylaczanie log.txt - str=GetNextSymbol().LowerCase(); - if (str=="yes") iWriteLogEnabled=3; - else if (str=="no") iWriteLogEnabled=0; - else iWriteLogEnabled=str.ToIntDef(3); - } - else if (str==AnsiString("adjustscreenfreq")) - {//McZapkie-240403 - czestotliwosc odswiezania ekranu - str=GetNextSymbol(); - bAdjustScreenFreq=(str.LowerCase()==AnsiString("yes")); - } - else if (str==AnsiString("mousescale")) - {//McZapkie-060503 - czulosc ruchu myszy (krecenia glowa) - str=GetNextSymbol(); - fMouseXScale=str.ToDouble(); - str=GetNextSymbol(); - fMouseYScale=str.ToDouble(); - } - else if (str==AnsiString("enabletraction")) - {//Winger 040204 - 'zywe' patyki dostosowujace sie do trakcji; Ra 2014-03: teraz łamanie - bEnableTraction=(GetNextSymbol().LowerCase()==AnsiString("yes")); - } - else if (str==AnsiString("loadtraction")) - {//Winger 140404 - ladowanie sie trakcji - bLoadTraction=(GetNextSymbol().LowerCase()==AnsiString("yes")); - } - else if (str==AnsiString("friction")) //mnożnik tarcia - KURS90 - fFriction=GetNextSymbol().ToDouble(); - else if (str==AnsiString("livetraction")) - {//Winger 160404 - zaleznosc napiecia loka od trakcji; Ra 2014-03: teraz prąd przy braku sieci - bLiveTraction=(GetNextSymbol().LowerCase()==AnsiString("yes")); - } - else if (str==AnsiString("skyenabled")) - {//youBy - niebo - if (GetNextSymbol().LowerCase()==AnsiString("yes")) - asSky="1"; else asSky="0"; - } - else if (str==AnsiString("managenodes")) - { - bManageNodes=(GetNextSymbol().LowerCase()==AnsiString("yes")); - } - else if (str==AnsiString("decompressdds")) - { - bDecompressDDS=(GetNextSymbol().LowerCase()==AnsiString("yes")); - } -// ShaXbee - domyslne rozszerzenie tekstur - else if (str==AnsiString("defaultext")) - {str=GetNextSymbol().LowerCase(); //rozszerzenie - if (str=="tga") - szDefaultExt=szTexturesTGA; //domyślnie od TGA - //szDefaultExt=std::string(Parser->GetNextSymbol().LowerCase().c_str()); - } - else if (str==AnsiString("newaircouplers")) - bnewAirCouplers=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("defaultfiltering")) - iDefaultFiltering=GetNextSymbol().ToIntDef(-1); - else if (str==AnsiString("ballastfiltering")) - iBallastFiltering=GetNextSymbol().ToIntDef(-1); - else if (str==AnsiString("railprofiltering")) - iRailProFiltering=GetNextSymbol().ToIntDef(-1); - else if (str==AnsiString("dynamicfiltering")) - iDynamicFiltering=GetNextSymbol().ToIntDef(-1); - else if (str==AnsiString("usevbo")) - bUseVBO=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("feedbackmode")) - iFeedbackMode=GetNextSymbol().ToIntDef(1); //domyślnie 1 - else if (str==AnsiString("feedbackport")) - iFeedbackPort=GetNextSymbol().ToIntDef(0); //domyślnie 0 - else if (str==AnsiString("multiplayer")) - iMultiplayer=GetNextSymbol().ToIntDef(0); //domyślnie 0 - else if (str==AnsiString("maxtexturesize")) - {//wymuszenie przeskalowania tekstur - i=GetNextSymbol().ToIntDef(16384); //domyślnie duże - if (i<= 64) iMaxTextureSize= 64; else - if (i<= 128) iMaxTextureSize= 128; else - if (i<= 256) iMaxTextureSize= 256; else - if (i<= 512) iMaxTextureSize= 512; else - if (i<=1024) iMaxTextureSize=1024; else - if (i<=2048) iMaxTextureSize=2048; else - if (i<=4096) iMaxTextureSize=4096; else - if (i<=8192) iMaxTextureSize=8192; else - iMaxTextureSize=16384; - } - else if (str==AnsiString("doubleambient")) //podwójna jasność ambient - bDoubleAmbient=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("movelight")) //numer dnia w roku albo -1 - {fMoveLight=GetNextSymbol().ToIntDef(-1); //numer dnia 1..365 - if (fMoveLight==0.0) - {//pobranie daty z systemu - unsigned short y,m,d; - TDate date=Now(); - date.DecodeDate(&y,&m,&d); - fMoveLight=(double)date-(double)TDate(y,1,1)+1; //numer bieżącego dnia w roku - } - if (fMoveLight>0.0) //tu jest nadal zwiększone o 1 - {//obliczenie deklinacji wg: - //http://naturalfrequency.com/Tregenza_Sharples/Daylight_Algorithms/algorithm_1_11.htm - //Spencer J W Fourier series representation of the position of the sun Search 2 (5) 172 (1971) - fMoveLight=M_PI/182.5*(Global::fMoveLight-1.0); //numer dnia w postaci kąta - fSunDeclination=0.006918-0.3999120*cos( fMoveLight)+0.0702570*sin( fMoveLight) - -0.0067580*cos(2*fMoveLight)+0.0009070*sin(2*fMoveLight) - -0.0026970*cos(3*fMoveLight)+0.0014800*sin(3*fMoveLight); - } - } - else if (str==AnsiString("smoothtraction")) //podwójna jasność ambient - bSmoothTraction=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("timespeed")) //przyspieszenie czasu, zmienna do testów - fTimeSpeed=GetNextSymbol().ToIntDef(1); - else if (str==AnsiString("multisampling")) //tryb antyaliasingu: 0=brak,1=2px,2=4px - iMultisampling=GetNextSymbol().ToIntDef(2); //domyślnie 2 - else if (str==AnsiString("glutfont")) //tekst generowany przez GLUT - bGlutFont=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("latitude")) //szerokość geograficzna - fLatitudeDeg=GetNextSymbol().ToDouble(); - else if (str==AnsiString("convertmodels")) //tworzenie plików binarnych - iConvertModels=GetNextSymbol().ToIntDef(7); //domyślnie 7 - else if (str==AnsiString("inactivepause")) //automatyczna pauza, gdy okno nieaktywne - bInactivePause=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("slowmotion")) //tworzenie plików binarnych - iSlowMotionMask=GetNextSymbol().ToIntDef(-1); //domyślnie -1 - else if (str==AnsiString("modifytga")) //czy korygować pliki TGA dla szybszego wczytywania - iModifyTGA=GetNextSymbol().ToIntDef(0); //domyślnie 0 - else if (str==AnsiString("hideconsole")) //hunter-271211: ukrywanie konsoli - bHideConsole=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("rollfix")) //Ra: poprawianie przechyłki, aby wewnętrzna szyna była "pozioma" - bRollFix=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("fpsaverage")) //oczekiwana wartosć FPS - fFpsAverage=GetNextSymbol().ToDouble(); - else if (str==AnsiString("fpsdeviation")) //odchylenie standardowe FPS - fFpsDeviation=GetNextSymbol().ToDouble(); - else if (str==AnsiString("fpsradiusmax")) //maksymalny promień renderowania - fFpsRadiusMax=GetNextSymbol().ToDouble(); - else if (str==AnsiString("calibratein")) //parametry kalibracji wejść - {// - i=GetNextSymbol().ToIntDef(-1); //numer wejścia - if ((i<0)||(i>5)) i=5; //na ostatni, bo i tak trzeba pominąć wartości - fCalibrateIn[i][0]=GetNextSymbol().ToDouble(); //wyraz wolny - fCalibrateIn[i][1]=GetNextSymbol().ToDouble(); //mnożnik - fCalibrateIn[i][2]=GetNextSymbol().ToDouble(); //mnożnik dla kwadratu - fCalibrateIn[i][3]=GetNextSymbol().ToDouble(); //mnożnik dla sześcianu - } - else if (str==AnsiString("calibrateout")) //parametry kalibracji wyjść - {// - i=GetNextSymbol().ToIntDef(-1); //numer wejścia - if ((i<0)||(i>6)) i=6; //na ostatni, bo i tak trzeba pominąć wartości - fCalibrateOut[i][0]=GetNextSymbol().ToDouble(); //wyraz wolny - fCalibrateOut[i][1]=GetNextSymbol().ToDouble(); //mnożnik liniowy - fCalibrateOut[i][2]=GetNextSymbol().ToDouble(); //mnożnik dla kwadratu - fCalibrateOut[i][3]=GetNextSymbol().ToDouble(); //mnożnik dla sześcianu - } - else if (str==AnsiString("brakestep")) //krok zmiany hamulca dla klawiszy [Num3] i [Num9] - fBrakeStep=GetNextSymbol().ToDouble(); - else if (str==AnsiString("joinduplicatedevents")) //czy grupować eventy o tych samych nazwach - bJoinEvents=(GetNextSymbol().LowerCase()==AnsiString("yes")); - else if (str==AnsiString("hiddenevents")) //czy łączyć eventy z torami poprzez nazwę toru - iHiddenEvents=GetNextSymbol().ToIntDef(0); - else if (str==AnsiString("pause")) //czy po wczytaniu ma być pauza? - iPause|=(GetNextSymbol().LowerCase()==AnsiString("yes"))?1:0; - else if (str==AnsiString("lang")) - asLang=GetNextSymbol(); //domyślny język - http://tools.ietf.org/html/bcp47 - else if (str==AnsiString("opengl")) //deklarowana wersja OpenGL, żeby powstrzymać błędy - fOpenGL=GetNextSymbol().ToDouble(); //wymuszenie wersji OpenGL - } - while (str!="endconfig"); //(!Parser->EndOfFile) - //na koniec trochę zależności - if (!bLoadTraction) //wczytywanie drutów i słupów - {//tutaj wyłączenie, bo mogą nie być zdefiniowane w INI - bEnableTraction=false; //false = pantograf się nie połamie - bLiveTraction=false; //false = pantografy zawsze zbierają 95% MaxVoltage - } - //if (fMoveLight>0) bDoubleAmbient=false; //wtedy tylko jedno światło ruchome - //if (fOpenGL<1.3) iMultisampling=0; //można by z góry wyłączyć, ale nie mamy jeszcze fOpenGL - if (iMultisampling) - {//antyaliasing całoekranowy wyłącza rozmywanie drutów - bSmoothTraction=false; - } - if (iMultiplayer>0) - {bInactivePause=false; //okno "w tle" nie może pauzować, jeśli włączona komunikacja - //pauzowanie jest zablokowane dla (iMultiplayer&2)>0, więc iMultiplayer=1 da się zapauzować (tryb instruktora) - } - fFpsMin=fFpsAverage-fFpsDeviation; //dolna granica FPS, przy której promień scenerii będzie zmniejszany - fFpsMax=fFpsAverage+fFpsDeviation; //górna granica FPS, przy której promień scenerii będzie zwiększany - if (iPause) iTextMode=VK_F1; //jak pauza, to pokazać zegar - if (qp) - {//to poniżej wykonywane tylko raz, jedynie po wczytaniu eu07.ini - Console::ModeSet(iFeedbackMode,iFeedbackPort); //tryb pracy konsoli sterowniczej - iFpsRadiusMax=0.000025*fFpsRadiusMax*fFpsRadiusMax; //maksymalny promień renderowania 3000.0 -> 225 - if (iFpsRadiusMax>400) iFpsRadiusMax=400; - if (fDistanceFactor>1.0) - {//dla 1.0 specjalny tryb bez przeliczania - fDistanceFactor=iWindowHeight/fDistanceFactor; //fDistanceFactor>1.0 dla rozdzielczości większych niż bazowa - fDistanceFactor*=(iMultisampling+1.0)*fDistanceFactor; //do kwadratu, bo większość odległości to ich kwadraty - } - } +void __fastcall Global::ConfigParse(TQueryParserComp *qp, cParser *cp) +{ // Ra: trzeba by przerobić na cParser, żeby to działało w scenerii + pParser = cp; + qParser = qp; + AnsiString str; + int i; + do + { + str = GetNextSymbol().LowerCase(); + if (str == AnsiString("sceneryfile")) + { + str = GetNextSymbol().LowerCase(); + strcpy(szSceneryFile, str.c_str()); + } + else if (str == AnsiString("humanctrlvehicle")) + { + str = GetNextSymbol().LowerCase(); + asHumanCtrlVehicle = str; + } + else if (str == AnsiString("width")) + iWindowWidth = GetNextSymbol().ToInt(); + else if (str == AnsiString("height")) + iWindowHeight = GetNextSymbol().ToInt(); + else if (str == AnsiString("heightbase")) + fDistanceFactor = GetNextSymbol().ToInt(); + else if (str == AnsiString("bpp")) + iBpp = ((GetNextSymbol().LowerCase() == AnsiString("32")) ? 32 : 16); + else if (str == AnsiString("fullscreen")) + bFullScreen = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("freefly")) // Mczapkie-130302 + { + bFreeFly = (GetNextSymbol().LowerCase() == AnsiString("yes")); + pFreeCameraInit[0].x = GetNextSymbol().ToDouble(); + pFreeCameraInit[0].y = GetNextSymbol().ToDouble(); + pFreeCameraInit[0].z = GetNextSymbol().ToDouble(); + } + else if (str == AnsiString("wireframe")) + bWireFrame = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("debugmode")) // McZapkie! - DebugModeFlag uzywana w mover.pas, + // warto tez blokowac cheaty gdy false + DebugModeFlag = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("soundenabled")) // McZapkie-040302 - blokada dzwieku - przyda + // sie do debugowania oraz na komp. bez karty + // dzw. + bSoundEnabled = (GetNextSymbol().LowerCase() == AnsiString("yes")); + // else if (str==AnsiString("renderalpha")) //McZapkie-1312302 - dwuprzebiegowe renderowanie + // bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes")); + else if (str == AnsiString("physicslog")) // McZapkie-030402 - logowanie parametrow + // fizycznych dla kazdego pojazdu z maszynista + WriteLogFlag = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("physicsdeactivation")) // McZapkie-291103 - usypianie fizyki + PhysicActivationFlag = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("debuglog")) + { // McZapkie-300402 - wylaczanie log.txt + str = GetNextSymbol().LowerCase(); + if (str == "yes") + iWriteLogEnabled = 3; + else if (str == "no") + iWriteLogEnabled = 0; + else + iWriteLogEnabled = str.ToIntDef(3); + } + else if (str == AnsiString("adjustscreenfreq")) + { // McZapkie-240403 - czestotliwosc odswiezania ekranu + str = GetNextSymbol(); + bAdjustScreenFreq = (str.LowerCase() == AnsiString("yes")); + } + else if (str == AnsiString("mousescale")) + { // McZapkie-060503 - czulosc ruchu myszy (krecenia glowa) + str = GetNextSymbol(); + fMouseXScale = str.ToDouble(); + str = GetNextSymbol(); + fMouseYScale = str.ToDouble(); + } + else if (str == AnsiString("enabletraction")) + { // Winger 040204 - 'zywe' patyki dostosowujace sie do trakcji; Ra 2014-03: teraz łamanie + bEnableTraction = (GetNextSymbol().LowerCase() == AnsiString("yes")); + } + else if (str == AnsiString("loadtraction")) + { // Winger 140404 - ladowanie sie trakcji + bLoadTraction = (GetNextSymbol().LowerCase() == AnsiString("yes")); + } + else if (str == AnsiString("friction")) // mnożnik tarcia - KURS90 + fFriction = GetNextSymbol().ToDouble(); + else if (str == AnsiString("livetraction")) + { // Winger 160404 - zaleznosc napiecia loka od trakcji; Ra 2014-03: teraz prąd przy braku + // sieci + bLiveTraction = (GetNextSymbol().LowerCase() == AnsiString("yes")); + } + else if (str == AnsiString("skyenabled")) + { // youBy - niebo + if (GetNextSymbol().LowerCase() == AnsiString("yes")) + asSky = "1"; + else + asSky = "0"; + } + else if (str == AnsiString("managenodes")) + { + bManageNodes = (GetNextSymbol().LowerCase() == AnsiString("yes")); + } + else if (str == AnsiString("decompressdds")) + { + bDecompressDDS = (GetNextSymbol().LowerCase() == AnsiString("yes")); + } + // ShaXbee - domyslne rozszerzenie tekstur + else if (str == AnsiString("defaultext")) + { + str = GetNextSymbol().LowerCase(); // rozszerzenie + if (str == "tga") + szDefaultExt = szTexturesTGA; // domyślnie od TGA + // szDefaultExt=std::string(Parser->GetNextSymbol().LowerCase().c_str()); + } + else if (str == AnsiString("newaircouplers")) + bnewAirCouplers = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("defaultfiltering")) + iDefaultFiltering = GetNextSymbol().ToIntDef(-1); + else if (str == AnsiString("ballastfiltering")) + iBallastFiltering = GetNextSymbol().ToIntDef(-1); + else if (str == AnsiString("railprofiltering")) + iRailProFiltering = GetNextSymbol().ToIntDef(-1); + else if (str == AnsiString("dynamicfiltering")) + iDynamicFiltering = GetNextSymbol().ToIntDef(-1); + else if (str == AnsiString("usevbo")) + bUseVBO = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("feedbackmode")) + iFeedbackMode = GetNextSymbol().ToIntDef(1); // domyślnie 1 + else if (str == AnsiString("feedbackport")) + iFeedbackPort = GetNextSymbol().ToIntDef(0); // domyślnie 0 + else if (str == AnsiString("multiplayer")) + iMultiplayer = GetNextSymbol().ToIntDef(0); // domyślnie 0 + else if (str == AnsiString("maxtexturesize")) + { // wymuszenie przeskalowania tekstur + i = GetNextSymbol().ToIntDef(16384); // domyślnie duże + if (i <= 64) + iMaxTextureSize = 64; + else if (i <= 128) + iMaxTextureSize = 128; + else if (i <= 256) + iMaxTextureSize = 256; + else if (i <= 512) + iMaxTextureSize = 512; + else if (i <= 1024) + iMaxTextureSize = 1024; + else if (i <= 2048) + iMaxTextureSize = 2048; + else if (i <= 4096) + iMaxTextureSize = 4096; + else if (i <= 8192) + iMaxTextureSize = 8192; + else + iMaxTextureSize = 16384; + } + else if (str == AnsiString("doubleambient")) // podwójna jasność ambient + bDoubleAmbient = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("movelight")) // numer dnia w roku albo -1 + { + fMoveLight = GetNextSymbol().ToIntDef(-1); // numer dnia 1..365 + if (fMoveLight == 0.0) + { // pobranie daty z systemu + unsigned short y, m, d; + TDate date = Now(); + date.DecodeDate(&y, &m, &d); + fMoveLight = + (double)date - (double)TDate(y, 1, 1) + 1; // numer bieżącego dnia w roku + } + if (fMoveLight > 0.0) // tu jest nadal zwiększone o 1 + { // obliczenie deklinacji wg: + // http://naturalfrequency.com/Tregenza_Sharples/Daylight_Algorithms/algorithm_1_11.htm + // Spencer J W Fourier series representation of the position of the sun Search 2 (5) + // 172 (1971) + fMoveLight = M_PI / 182.5 * (Global::fMoveLight - 1.0); // numer dnia w postaci kąta + fSunDeclination = 0.006918 - 0.3999120 * cos(fMoveLight) + + 0.0702570 * sin(fMoveLight) - 0.0067580 * cos(2 * fMoveLight) + + 0.0009070 * sin(2 * fMoveLight) - + 0.0026970 * cos(3 * fMoveLight) + 0.0014800 * sin(3 * fMoveLight); + } + } + else if (str == AnsiString("smoothtraction")) // podwójna jasność ambient + bSmoothTraction = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("timespeed")) // przyspieszenie czasu, zmienna do testów + fTimeSpeed = GetNextSymbol().ToIntDef(1); + else if (str == AnsiString("multisampling")) // tryb antyaliasingu: 0=brak,1=2px,2=4px + iMultisampling = GetNextSymbol().ToIntDef(2); // domyślnie 2 + else if (str == AnsiString("glutfont")) // tekst generowany przez GLUT + bGlutFont = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("latitude")) // szerokość geograficzna + fLatitudeDeg = GetNextSymbol().ToDouble(); + else if (str == AnsiString("convertmodels")) // tworzenie plików binarnych + iConvertModels = GetNextSymbol().ToIntDef(7); // domyślnie 7 + else if (str == AnsiString("inactivepause")) // automatyczna pauza, gdy okno nieaktywne + bInactivePause = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("slowmotion")) // tworzenie plików binarnych + iSlowMotionMask = GetNextSymbol().ToIntDef(-1); // domyślnie -1 + else if (str == AnsiString("modifytga")) // czy korygować pliki TGA dla szybszego + // wczytywania + iModifyTGA = GetNextSymbol().ToIntDef(0); // domyślnie 0 + else if (str == AnsiString("hideconsole")) // hunter-271211: ukrywanie konsoli + bHideConsole = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == + AnsiString( + "rollfix")) // Ra: poprawianie przechyłki, aby wewnętrzna szyna była "pozioma" + bRollFix = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("fpsaverage")) // oczekiwana wartosć FPS + fFpsAverage = GetNextSymbol().ToDouble(); + else if (str == AnsiString("fpsdeviation")) // odchylenie standardowe FPS + fFpsDeviation = GetNextSymbol().ToDouble(); + else if (str == AnsiString("fpsradiusmax")) // maksymalny promień renderowania + fFpsRadiusMax = GetNextSymbol().ToDouble(); + else if (str == AnsiString("calibratein")) // parametry kalibracji wejść + { // + i = GetNextSymbol().ToIntDef(-1); // numer wejścia + if ((i < 0) || (i > 5)) + i = 5; // na ostatni, bo i tak trzeba pominąć wartości + fCalibrateIn[i][0] = GetNextSymbol().ToDouble(); // wyraz wolny + fCalibrateIn[i][1] = GetNextSymbol().ToDouble(); // mnożnik + fCalibrateIn[i][2] = GetNextSymbol().ToDouble(); // mnożnik dla kwadratu + fCalibrateIn[i][3] = GetNextSymbol().ToDouble(); // mnożnik dla sześcianu + } + else if (str == AnsiString("calibrateout")) // parametry kalibracji wyjść + { // + i = GetNextSymbol().ToIntDef(-1); // numer wejścia + if ((i < 0) || (i > 6)) + i = 6; // na ostatni, bo i tak trzeba pominąć wartości + fCalibrateOut[i][0] = GetNextSymbol().ToDouble(); // wyraz wolny + fCalibrateOut[i][1] = GetNextSymbol().ToDouble(); // mnożnik liniowy + fCalibrateOut[i][2] = GetNextSymbol().ToDouble(); // mnożnik dla kwadratu + fCalibrateOut[i][3] = GetNextSymbol().ToDouble(); // mnożnik dla sześcianu + } + else if (str == AnsiString("brakestep")) // krok zmiany hamulca dla klawiszy [Num3] i [Num9] + fBrakeStep = GetNextSymbol().ToDouble(); + else if (str == + AnsiString("joinduplicatedevents")) // czy grupować eventy o tych samych nazwach + bJoinEvents = (GetNextSymbol().LowerCase() == AnsiString("yes")); + else if (str == AnsiString("hiddenevents")) // czy łączyć eventy z torami poprzez nazwę toru + iHiddenEvents = GetNextSymbol().ToIntDef(0); + else if (str == AnsiString("pause")) // czy po wczytaniu ma być pauza? + iPause |= (GetNextSymbol().LowerCase() == AnsiString("yes")) ? 1 : 0; + else if (str == AnsiString("lang")) + asLang = GetNextSymbol(); // domyślny język - http://tools.ietf.org/html/bcp47 + else if (str == AnsiString("opengl")) // deklarowana wersja OpenGL, żeby powstrzymać błędy + fOpenGL = GetNextSymbol().ToDouble(); // wymuszenie wersji OpenGL + } while (str != "endconfig"); //(!Parser->EndOfFile) + // na koniec trochę zależności + if (!bLoadTraction) // wczytywanie drutów i słupów + { // tutaj wyłączenie, bo mogą nie być zdefiniowane w INI + bEnableTraction = false; // false = pantograf się nie połamie + bLiveTraction = false; // false = pantografy zawsze zbierają 95% MaxVoltage + } + // if (fMoveLight>0) bDoubleAmbient=false; //wtedy tylko jedno światło ruchome + // if (fOpenGL<1.3) iMultisampling=0; //można by z góry wyłączyć, ale nie mamy jeszcze fOpenGL + if (iMultisampling) + { // antyaliasing całoekranowy wyłącza rozmywanie drutów + bSmoothTraction = false; + } + if (iMultiplayer > 0) + { + bInactivePause = false; // okno "w tle" nie może pauzować, jeśli włączona komunikacja + // pauzowanie jest zablokowane dla (iMultiplayer&2)>0, więc iMultiplayer=1 da się zapauzować + // (tryb instruktora) + } + fFpsMin = fFpsAverage - + fFpsDeviation; // dolna granica FPS, przy której promień scenerii będzie zmniejszany + fFpsMax = fFpsAverage + + fFpsDeviation; // górna granica FPS, przy której promień scenerii będzie zwiększany + if (iPause) + iTextMode = VK_F1; // jak pauza, to pokazać zegar + if (qp) + { // to poniżej wykonywane tylko raz, jedynie po wczytaniu eu07.ini + Console::ModeSet(iFeedbackMode, iFeedbackPort); // tryb pracy konsoli sterowniczej + iFpsRadiusMax = 0.000025 * fFpsRadiusMax * + fFpsRadiusMax; // maksymalny promień renderowania 3000.0 -> 225 + if (iFpsRadiusMax > 400) + iFpsRadiusMax = 400; + if (fDistanceFactor > 1.0) + { // dla 1.0 specjalny tryb bez przeliczania + fDistanceFactor = + iWindowHeight / + fDistanceFactor; // fDistanceFactor>1.0 dla rozdzielczości większych niż bazowa + fDistanceFactor *= + (iMultisampling + 1.0) * + fDistanceFactor; // do kwadratu, bo większość odległości to ich kwadraty + } + } } void __fastcall Global::InitKeys(AnsiString asFileName) { -// if (FileExists(asFileName)) -// { -// Error("Chwilowo plik keys.ini nie jest obsługiwany. Ładuję standardowe ustawienia.\nKeys.ini file is temporarily not functional, loading default keymap..."); -/* TQueryParserComp *Parser; - Parser=new TQueryParserComp(NULL); - Parser->LoadStringToParse(asFileName); + // if (FileExists(asFileName)) + // { + // Error("Chwilowo plik keys.ini nie jest obsługiwany. Ładuję standardowe + // ustawienia.\nKeys.ini file is temporarily not functional, loading default keymap..."); + /* TQueryParserComp *Parser; + Parser=new TQueryParserComp(NULL); + Parser->LoadStringToParse(asFileName); - for (int keycount=0; keycountGetNextSymbol().ToInt(); - } + for (int keycount=0; keycountGetNextSymbol().ToInt(); + } - delete Parser; -*/ -// } -// else + delete Parser; + */ + // } + // else { - Keys[k_IncMainCtrl]=VK_ADD; - Keys[k_IncMainCtrlFAST]=VK_ADD; - Keys[k_DecMainCtrl]=VK_SUBTRACT; - Keys[k_DecMainCtrlFAST]=VK_SUBTRACT; - Keys[k_IncScndCtrl]=VK_DIVIDE; - Keys[k_IncScndCtrlFAST]=VK_DIVIDE; - Keys[k_DecScndCtrl]=VK_MULTIPLY; - Keys[k_DecScndCtrlFAST]=VK_MULTIPLY; -///*NORMALNE - Keys[k_IncLocalBrakeLevel]=VK_NUMPAD1; //VK_NUMPAD7; - //Keys[k_IncLocalBrakeLevelFAST]=VK_END; //VK_HOME; - Keys[k_DecLocalBrakeLevel]=VK_NUMPAD7; //VK_NUMPAD1; - //Keys[k_DecLocalBrakeLevelFAST]=VK_HOME; //VK_END; - Keys[k_IncBrakeLevel]=VK_NUMPAD3; //VK_NUMPAD9; - Keys[k_DecBrakeLevel]=VK_NUMPAD9; //VK_NUMPAD3; - Keys[k_Releaser]=VK_NUMPAD6; - Keys[k_EmergencyBrake]=VK_NUMPAD0; - Keys[k_Brake3]=VK_NUMPAD8; - Keys[k_Brake2]=VK_NUMPAD5; - Keys[k_Brake1]=VK_NUMPAD2; - Keys[k_Brake0]=VK_NUMPAD4; - Keys[k_WaveBrake]=VK_DECIMAL; -//*/ -/*MOJE - Keys[k_IncLocalBrakeLevel]=VK_NUMPAD3; //VK_NUMPAD7; - Keys[k_IncLocalBrakeLevelFAST]=VK_NUMPAD3; //VK_HOME; - Keys[k_DecLocalBrakeLevel]=VK_DECIMAL; //VK_NUMPAD1; - Keys[k_DecLocalBrakeLevelFAST]=VK_DECIMAL; //VK_END; - Keys[k_IncBrakeLevel]=VK_NUMPAD6; //VK_NUMPAD9; - Keys[k_DecBrakeLevel]=VK_NUMPAD9; //VK_NUMPAD3; - Keys[k_Releaser]=VK_NUMPAD5; - Keys[k_EmergencyBrake]=VK_NUMPAD0; - Keys[k_Brake3]=VK_NUMPAD2; - Keys[k_Brake2]=VK_NUMPAD1; - Keys[k_Brake1]=VK_NUMPAD4; - Keys[k_Brake0]=VK_NUMPAD7; - Keys[k_WaveBrake]=VK_NUMPAD8; -*/ - Keys[k_AntiSlipping]=VK_RETURN; - Keys[k_Sand]=VkKeyScan('s'); - Keys[k_Main]=VkKeyScan('m'); - Keys[k_Active]=VkKeyScan('w'); - Keys[k_Battery]=VkKeyScan('j'); - Keys[k_DirectionForward]=VkKeyScan('d'); - Keys[k_DirectionBackward]=VkKeyScan('r'); - Keys[k_Fuse]=VkKeyScan('n'); - Keys[k_Compressor]=VkKeyScan('c'); - Keys[k_Converter]=VkKeyScan('x'); - Keys[k_MaxCurrent]=VkKeyScan('f'); - Keys[k_CurrentAutoRelay]=VkKeyScan('g'); - Keys[k_BrakeProfile]=VkKeyScan('b'); - Keys[k_CurrentNext]=VkKeyScan('z'); + Keys[k_IncMainCtrl] = VK_ADD; + Keys[k_IncMainCtrlFAST] = VK_ADD; + Keys[k_DecMainCtrl] = VK_SUBTRACT; + Keys[k_DecMainCtrlFAST] = VK_SUBTRACT; + Keys[k_IncScndCtrl] = VK_DIVIDE; + Keys[k_IncScndCtrlFAST] = VK_DIVIDE; + Keys[k_DecScndCtrl] = VK_MULTIPLY; + Keys[k_DecScndCtrlFAST] = VK_MULTIPLY; + ///*NORMALNE + Keys[k_IncLocalBrakeLevel] = VK_NUMPAD1; // VK_NUMPAD7; + // Keys[k_IncLocalBrakeLevelFAST]=VK_END; //VK_HOME; + Keys[k_DecLocalBrakeLevel] = VK_NUMPAD7; // VK_NUMPAD1; + // Keys[k_DecLocalBrakeLevelFAST]=VK_HOME; //VK_END; + Keys[k_IncBrakeLevel] = VK_NUMPAD3; // VK_NUMPAD9; + Keys[k_DecBrakeLevel] = VK_NUMPAD9; // VK_NUMPAD3; + Keys[k_Releaser] = VK_NUMPAD6; + Keys[k_EmergencyBrake] = VK_NUMPAD0; + Keys[k_Brake3] = VK_NUMPAD8; + Keys[k_Brake2] = VK_NUMPAD5; + Keys[k_Brake1] = VK_NUMPAD2; + Keys[k_Brake0] = VK_NUMPAD4; + Keys[k_WaveBrake] = VK_DECIMAL; + //*/ + /*MOJE + Keys[k_IncLocalBrakeLevel]=VK_NUMPAD3; //VK_NUMPAD7; + Keys[k_IncLocalBrakeLevelFAST]=VK_NUMPAD3; //VK_HOME; + Keys[k_DecLocalBrakeLevel]=VK_DECIMAL; //VK_NUMPAD1; + Keys[k_DecLocalBrakeLevelFAST]=VK_DECIMAL; //VK_END; + Keys[k_IncBrakeLevel]=VK_NUMPAD6; //VK_NUMPAD9; + Keys[k_DecBrakeLevel]=VK_NUMPAD9; //VK_NUMPAD3; + Keys[k_Releaser]=VK_NUMPAD5; + Keys[k_EmergencyBrake]=VK_NUMPAD0; + Keys[k_Brake3]=VK_NUMPAD2; + Keys[k_Brake2]=VK_NUMPAD1; + Keys[k_Brake1]=VK_NUMPAD4; + Keys[k_Brake0]=VK_NUMPAD7; + Keys[k_WaveBrake]=VK_NUMPAD8; + */ + Keys[k_AntiSlipping] = VK_RETURN; + Keys[k_Sand] = VkKeyScan('s'); + Keys[k_Main] = VkKeyScan('m'); + Keys[k_Active] = VkKeyScan('w'); + Keys[k_Battery] = VkKeyScan('j'); + Keys[k_DirectionForward] = VkKeyScan('d'); + Keys[k_DirectionBackward] = VkKeyScan('r'); + Keys[k_Fuse] = VkKeyScan('n'); + Keys[k_Compressor] = VkKeyScan('c'); + Keys[k_Converter] = VkKeyScan('x'); + Keys[k_MaxCurrent] = VkKeyScan('f'); + Keys[k_CurrentAutoRelay] = VkKeyScan('g'); + Keys[k_BrakeProfile] = VkKeyScan('b'); + Keys[k_CurrentNext] = VkKeyScan('z'); - Keys[k_Czuwak]=VkKeyScan(' '); - Keys[k_Horn]=VkKeyScan('a'); - Keys[k_Horn2]=VkKeyScan('a'); + Keys[k_Czuwak] = VkKeyScan(' '); + Keys[k_Horn] = VkKeyScan('a'); + Keys[k_Horn2] = VkKeyScan('a'); - Keys[k_FailedEngineCutOff]=VkKeyScan('e'); + Keys[k_FailedEngineCutOff] = VkKeyScan('e'); - Keys[k_MechUp]=VK_PRIOR; - Keys[k_MechDown]=VK_NEXT ; - Keys[k_MechLeft]=VK_LEFT ; - Keys[k_MechRight]=VK_RIGHT; - Keys[k_MechForward]=VK_UP; - Keys[k_MechBackward]=VK_DOWN; + Keys[k_MechUp] = VK_PRIOR; + Keys[k_MechDown] = VK_NEXT; + Keys[k_MechLeft] = VK_LEFT; + Keys[k_MechRight] = VK_RIGHT; + Keys[k_MechForward] = VK_UP; + Keys[k_MechBackward] = VK_DOWN; - Keys[k_CabForward]=VK_HOME; - Keys[k_CabBackward]=VK_END; + Keys[k_CabForward] = VK_HOME; + Keys[k_CabBackward] = VK_END; - Keys[k_Couple]=VK_INSERT; - Keys[k_DeCouple]=VK_DELETE; + Keys[k_Couple] = VK_INSERT; + Keys[k_DeCouple] = VK_DELETE; - Keys[k_ProgramQuit]=VK_F10; - //Keys[k_ProgramPause]=VK_F3; - Keys[k_ProgramHelp]=VK_F1; - //Keys[k_FreeFlyMode]=VK_F4; - Keys[k_WalkMode]=VK_F5; + Keys[k_ProgramQuit] = VK_F10; + // Keys[k_ProgramPause]=VK_F3; + Keys[k_ProgramHelp] = VK_F1; + // Keys[k_FreeFlyMode]=VK_F4; + Keys[k_WalkMode] = VK_F5; - Keys[k_OpenLeft]=VkKeyScan(','); - Keys[k_OpenRight]=VkKeyScan('.'); - Keys[k_CloseLeft]=VkKeyScan(','); - Keys[k_CloseRight]=VkKeyScan('.'); - Keys[k_DepartureSignal]=VkKeyScan('/'); + Keys[k_OpenLeft] = VkKeyScan(','); + Keys[k_OpenRight] = VkKeyScan('.'); + Keys[k_CloseLeft] = VkKeyScan(','); + Keys[k_CloseRight] = VkKeyScan('.'); + Keys[k_DepartureSignal] = VkKeyScan('/'); -//Winger 160204 - obsluga pantografow - Keys[k_PantFrontUp]=VkKeyScan('p'); //Ra: zamieniony przedni z tylnym - Keys[k_PantFrontDown]=VkKeyScan('p'); - Keys[k_PantRearUp]=VkKeyScan('o'); - Keys[k_PantRearDown]=VkKeyScan('o'); -//Winger 020304 - ogrzewanie - Keys[k_Heating]=VkKeyScan('h'); - Keys[k_LeftSign]=VkKeyScan('y'); - Keys[k_UpperSign]=VkKeyScan('u'); - Keys[k_RightSign]=VkKeyScan('i'); - Keys[k_EndSign]=VkKeyScan('t'); + // Winger 160204 - obsluga pantografow + Keys[k_PantFrontUp] = VkKeyScan('p'); // Ra: zamieniony przedni z tylnym + Keys[k_PantFrontDown] = VkKeyScan('p'); + Keys[k_PantRearUp] = VkKeyScan('o'); + Keys[k_PantRearDown] = VkKeyScan('o'); + // Winger 020304 - ogrzewanie + Keys[k_Heating] = VkKeyScan('h'); + Keys[k_LeftSign] = VkKeyScan('y'); + Keys[k_UpperSign] = VkKeyScan('u'); + Keys[k_RightSign] = VkKeyScan('i'); + Keys[k_EndSign] = VkKeyScan('t'); - Keys[k_SmallCompressor]=VkKeyScan('v'); - Keys[k_StLinOff]=VkKeyScan('l'); -//ABu 090305 - przyciski uniwersalne, do roznych bajerow :) - Keys[k_Univ1]=VkKeyScan('['); - Keys[k_Univ2]=VkKeyScan(']'); - Keys[k_Univ3]=VkKeyScan(';'); - Keys[k_Univ4]=VkKeyScan('\''); + Keys[k_SmallCompressor] = VkKeyScan('v'); + Keys[k_StLinOff] = VkKeyScan('l'); + // ABu 090305 - przyciski uniwersalne, do roznych bajerow :) + Keys[k_Univ1] = VkKeyScan('['); + Keys[k_Univ2] = VkKeyScan(']'); + Keys[k_Univ3] = VkKeyScan(';'); + Keys[k_Univ4] = VkKeyScan('\''); } } /* @@ -586,193 +635,201 @@ vector3 __fastcall Global::GetCameraPosition() */ void __fastcall Global::SetCameraPosition(vector3 pNewCameraPosition) { - pCameraPosition=pNewCameraPosition; + pCameraPosition = pNewCameraPosition; } void __fastcall Global::SetCameraRotation(double Yaw) -{//ustawienie bezwzględnego kierunku kamery z korekcją do przedziału <-M_PI,M_PI> - pCameraRotation=Yaw; - while (pCameraRotation<-M_PI) pCameraRotation+=2*M_PI; - while (pCameraRotation> M_PI) pCameraRotation-=2*M_PI; - pCameraRotationDeg=pCameraRotation*180.0/M_PI; +{ // ustawienie bezwzględnego kierunku kamery z korekcją do przedziału <-M_PI,M_PI> + pCameraRotation = Yaw; + while (pCameraRotation < -M_PI) + pCameraRotation += 2 * M_PI; + while (pCameraRotation > M_PI) + pCameraRotation -= 2 * M_PI; + pCameraRotationDeg = pCameraRotation * 180.0 / M_PI; } void __fastcall Global::BindTexture(GLuint t) -{//ustawienie aktualnej tekstury, tylko gdy się zmienia - if (t!=iTextureId) - {iTextureId=t; - } +{ // ustawienie aktualnej tekstury, tylko gdy się zmienia + if (t != iTextureId) + { + iTextureId = t; + } }; void __fastcall Global::TrainDelete(TDynamicObject *d) -{//usunięcie pojazdu prowadzonego przez użytkownika - if (pWorld) pWorld->TrainDelete(d); +{ // usunięcie pojazdu prowadzonego przez użytkownika + if (pWorld) + pWorld->TrainDelete(d); }; -TDynamicObject* __fastcall Global::DynamicNearest() -{//ustalenie pojazdu najbliższego kamerze - return pGround->DynamicNearest(pCamera->Pos); +TDynamicObject *__fastcall Global::DynamicNearest() +{ // ustalenie pojazdu najbliższego kamerze + return pGround->DynamicNearest(pCamera->Pos); }; -TDynamicObject* __fastcall Global::CouplerNearest() -{//ustalenie pojazdu najbliższego kamerze - return pGround->CouplerNearest(pCamera->Pos); +TDynamicObject *__fastcall Global::CouplerNearest() +{ // ustalenie pojazdu najbliższego kamerze + return pGround->CouplerNearest(pCamera->Pos); }; -bool __fastcall Global::AddToQuery(TEvent *event,TDynamicObject *who) +bool __fastcall Global::AddToQuery(TEvent *event, TDynamicObject *who) { - return pGround->AddToQuery(event,who); + return pGround->AddToQuery(event, who); }; //--------------------------------------------------------------------------- bool __fastcall Global::DoEvents() -{//wywoływać czasem, żeby nie robił wrażenia zawieszonego - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message==WM_QUIT) - return FALSE; - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return TRUE; +{ // wywoływać czasem, żeby nie robił wrażenia zawieszonego + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + return FALSE; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return TRUE; } //--------------------------------------------------------------------------- __fastcall TTranscripts::TTranscripts() { - iCount=0; //brak linijek do wyświetlenia - iStart=0; //wypełniać od linijki 0 - for (int i=0;i=0)?(aLines[aLines[i].iNext].fShow<=show):false) //póki nie koniec i wcześniej puszczane - i=aLines[i].iNext; //przejście do kolejnej linijki - //(i) wskazuje na linię, po której należy wstawić dany tekst, chyba że - while (txt?*txt:false) - for (j=0;j0) - {//jak jest podział linijki na wiersze - aLines[j].asText=aLines[j].asText.SubString(1,k-1); - txt+=k; - i=j; //kolejna linijka dopisywana będzie na koniec właśnie dodanej + iCount = 0; // brak linijek do wyświetlenia + iStart = 0; // wypełniać od linijki 0 + for (int i = 0; i < MAX_TRANSCRIPTS; ++i) + { // to do konstruktora można by dać + aLines[i].fHide = -1.0; // wolna pozycja (czas symulacji, 360.0 to doba) + aLines[i].iNext = -1; // nie ma kolejnej } - else - txt=NULL; //koniec dodawania - if (fRefreshTime>show) //jeśli odświeżacz ustawiony jest na później - fRefreshTime=show; //to odświeżyć wcześniej - break; //więcej już nic - } + fRefreshTime = 360.0; // wartośc zaporowa }; -void __fastcall TTranscripts::Add(char *txt,float len,bool backgorund) -{//dodanie tekstów, długość dźwięku, czy istotne - if (!txt) return; //pusty tekst - int i=0,j=int(0.5+10.0*len); //[0.1s] - if (*txt=='[') - {//powinny być dwa nawiasy - while (*++txt?*txt!=']':false) - if ((*txt>='0')&&(*txt<='9')) - i=10*i+int(*txt-'0'); //pierwsza liczba aż do ] - if (*txt?*++txt=='[':false) - {j=0; //drugi nawias określa czas zakończenia wyświetlania - while (*++txt?*txt!=']':false) - if ((*txt>='0')&&(*txt<='9')) - j=10*j+int(*txt-'0'); //druga liczba aż do ] - if (*txt) ++txt; //pominięcie drugiego ] - } - } - AddLine(txt,0.1*i,0.1*j,false); +__fastcall TTranscripts::~TTranscripts(){}; +void __fastcall TTranscripts::AddLine(char *txt, float show, float hide, bool it) +{ // dodanie linii do tabeli, (show) i (hide) w [s] od aktualnego czasu + if (show == hide) + return; // komentarz jest ignorowany + show = Global::fTimeAngleDeg + show / 240.0; // jeśli doba to 360, to 1s będzie równe 1/240 + hide = Global::fTimeAngleDeg + hide / 240.0; + int i = iStart, j, k; // od czegoś trzeba zacząć + while ((aLines[i].iNext >= 0) ? (aLines[aLines[i].iNext].fShow <= show) : + false) // póki nie koniec i wcześniej puszczane + i = aLines[i].iNext; // przejście do kolejnej linijki + //(i) wskazuje na linię, po której należy wstawić dany tekst, chyba że + while (txt ? *txt : false) + for (j = 0; j < MAX_TRANSCRIPTS; ++j) + if (aLines[j].fHide < 0.0) + { // znaleziony pierwszy wolny + aLines[j].iNext = aLines[i].iNext; // dotychczasowy następny będzie za nowym + if (aLines[iStart].fHide < 0.0) // jeśli tablica jest pusta + iStart = j; // fHide trzeba sprawdzić przed ewentualnym nadpisaniem, gdy i=j=0 + else + aLines[i].iNext = j; // a nowy będzie za tamtym wcześniejszym + aLines[j].fShow = show; // wyświetlać od + aLines[j].fHide = hide; // wyświetlać do + aLines[j].bItalic = it; + aLines[j].asText = AnsiString(txt); // bez sensu, wystarczyłby wskaźnik + if ((k = aLines[j].asText.Pos("|")) > 0) + { // jak jest podział linijki na wiersze + aLines[j].asText = aLines[j].asText.SubString(1, k - 1); + txt += k; + i = j; // kolejna linijka dopisywana będzie na koniec właśnie dodanej + } + else + txt = NULL; // koniec dodawania + if (fRefreshTime > show) // jeśli odświeżacz ustawiony jest na później + fRefreshTime = show; // to odświeżyć wcześniej + break; // więcej już nic + } +}; +void __fastcall TTranscripts::Add(char *txt, float len, bool backgorund) +{ // dodanie tekstów, długość dźwięku, czy istotne + if (!txt) + return; // pusty tekst + int i = 0, j = int(0.5 + 10.0 * len); //[0.1s] + if (*txt == '[') + { // powinny być dwa nawiasy + while (*++txt ? *txt != ']' : false) + if ((*txt >= '0') && (*txt <= '9')) + i = 10 * i + int(*txt - '0'); // pierwsza liczba aż do ] + if (*txt ? *++txt == '[' : false) + { + j = 0; // drugi nawias określa czas zakończenia wyświetlania + while (*++txt ? *txt != ']' : false) + if ((*txt >= '0') && (*txt <= '9')) + j = 10 * j + int(*txt - '0'); // druga liczba aż do ] + if (*txt) + ++txt; // pominięcie drugiego ] + } + } + AddLine(txt, 0.1 * i, 0.1 * j, false); }; void __fastcall TTranscripts::Update() -{//usuwanie niepotrzebnych (nie częściej niż 10 razy na sekundę) - if (fRefreshTime>Global::fTimeAngleDeg) - return; //nie czas jeszcze na zmiany - //czas odświeżenia można ustalić wg tabelki, kiedy coś się w niej zmienia - fRefreshTime=Global::fTimeAngleDeg+360.0; //wartość zaporowa - int i=iStart,j=-1; //od czegoś trzeba zacząć - bool change=false; //czy zmieniać napisy? - do - { - if (aLines[i].fHide>=0.0) //o ile aktywne - if (aLines[i].fHide=0?aLines[i].iNext:0; //przestawienie pierwszego - else if (j>=0) - aLines[j].iNext=aLines[i].iNext; //usunięcie ze środka - change=true; - } - else - {//gdy ma być pokazane - if (aLines[i].fShow>Global::fTimeAngleDeg) //będzie pokazane w przyszłości - if (fRefreshTime>aLines[i].fShow) //a nie ma nic wcześniej - fRefreshTime=aLines[i].fShow; - if (fRefreshTime>aLines[i].fHide) - fRefreshTime=aLines[i].fHide; - } - //można by jeszcze wykrywać, które nowe mają być pokazane - j=i; - i=aLines[i].iNext; //kolejna linijka - } while (i>=0); //póki po tablicy - change=true; //bo na razie nie ma warunku, że coś się dodało - if (change) - {//aktualizacja linijek ekranowych - i=iStart; j=-1; - do - { - if (aLines[i].fHide>0.0) //jeśli nie ukryte - if (aLines[i].fShow=0); //póki po tablicy - for (++j;j<5;++j) - Global::asTranscript[j]=""; //i czyszczenie nieużywanych linijek - } +{ // usuwanie niepotrzebnych (nie częściej niż 10 razy na sekundę) + if (fRefreshTime > Global::fTimeAngleDeg) + return; // nie czas jeszcze na zmiany + // czas odświeżenia można ustalić wg tabelki, kiedy coś się w niej zmienia + fRefreshTime = Global::fTimeAngleDeg + 360.0; // wartość zaporowa + int i = iStart, j = -1; // od czegoś trzeba zacząć + bool change = false; // czy zmieniać napisy? + do + { + if (aLines[i].fHide >= 0.0) // o ile aktywne + if (aLines[i].fHide < Global::fTimeAngleDeg) + { // gdy czas wyświetlania upłynął + aLines[i].fHide = -1.0; // teraz będzie wolną pozycją + if (i == iStart) + iStart = aLines[i].iNext >= 0 ? aLines[i].iNext : 0; // przestawienie pierwszego + else if (j >= 0) + aLines[j].iNext = aLines[i].iNext; // usunięcie ze środka + change = true; + } + else + { // gdy ma być pokazane + if (aLines[i].fShow > Global::fTimeAngleDeg) // będzie pokazane w przyszłości + if (fRefreshTime > aLines[i].fShow) // a nie ma nic wcześniej + fRefreshTime = aLines[i].fShow; + if (fRefreshTime > aLines[i].fHide) + fRefreshTime = aLines[i].fHide; + } + // można by jeszcze wykrywać, które nowe mają być pokazane + j = i; + i = aLines[i].iNext; // kolejna linijka + } while (i >= 0); // póki po tablicy + change = true; // bo na razie nie ma warunku, że coś się dodało + if (change) + { // aktualizacja linijek ekranowych + i = iStart; + j = -1; + do + { + if (aLines[i].fHide > 0.0) // jeśli nie ukryte + if (aLines[i].fShow < Global::fTimeAngleDeg) // to dodanie linijki do wyświetlania + if (j < 5 - 1) // ograniczona liczba linijek + Global::asTranscript[++j] = aLines[i].asText; // skopiowanie tekstu + i = aLines[i].iNext; // kolejna linijka + } while (i >= 0); // póki po tablicy + for (++j; j < 5; ++j) + Global::asTranscript[j] = ""; // i czyszczenie nieużywanych linijek + } }; -//Ra: tymczasowe rozwiązanie kwestii zagranicznych (czeskich) napisów -char bezogonkowo[128]= - "E?,?\"_++?%Sstzz" - " ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz" - "RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB" - "raaaalccceeeeiiddnnoooo-ruuuuyt?"; +// Ra: tymczasowe rozwiązanie kwestii zagranicznych (czeskich) napisów +char bezogonkowo[128] = "E?,?\"_++?%Sstzz" + " ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz" + "RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB" + "raaaalccceeeeiiddnnoooo-ruuuuyt?"; AnsiString __fastcall Global::Bezogonkow(AnsiString str, bool _) -{//wycięcie liter z ogonkami, bo OpenGL nie umie wyświetlić - for (int i=1;i<=str.Length();++i) - if (str[i]&0x80) - str[i]=bezogonkowo[str[i]&0x7F]; - else if (str[i]<' ') //znaki sterujące nie są obsługiwane - str[i]=' '; - else if (_) if (str[i]=='_') //nazwy stacji nie mogą zawierać spacji - str[i]=' '; //więc trzeba wyświetlać inaczej - return str; +{ // wycięcie liter z ogonkami, bo OpenGL nie umie wyświetlić + for (int i = 1; i <= str.Length(); ++i) + if (str[i] & 0x80) + str[i] = bezogonkowo[str[i] & 0x7F]; + else if (str[i] < ' ') // znaki sterujące nie są obsługiwane + str[i] = ' '; + else if (_) + if (str[i] == '_') // nazwy stacji nie mogą zawierać spacji + str[i] = ' '; // więc trzeba wyświetlać inaczej + return str; } #pragma package(smart_init) diff --git a/Globals.h b/Globals.h index 58096103..b9767912 100644 --- a/Globals.h +++ b/Globals.h @@ -11,295 +11,298 @@ using namespace Math3D; -//definicje klawiszy -const int k_IncMainCtrl= 0; //[Num+] -const int k_IncMainCtrlFAST= 1; //[Num+] [Shift] -const int k_DecMainCtrl= 2; //[Num-] -const int k_DecMainCtrlFAST= 3; //[Num-] [Shift] -const int k_IncScndCtrl= 4; //[Num/] -const int k_IncScndCtrlFAST= 5; -const int k_DecScndCtrl= 6; -const int k_DecScndCtrlFAST= 7; -const int k_IncLocalBrakeLevel= 8; -const int k_IncLocalBrakeLevelFAST= 9; -const int k_DecLocalBrakeLevel=10 ; -const int k_DecLocalBrakeLevelFAST= 11; -const int k_IncBrakeLevel= 12; -const int k_DecBrakeLevel= 13; -const int k_Releaser= 14; -const int k_EmergencyBrake= 15; -const int k_Brake3= 16; -const int k_Brake2= 17; -const int k_Brake1= 18; -const int k_Brake0= 19; -const int k_WaveBrake= 20; -const int k_AntiSlipping= 21; -const int k_Sand= 22; +// definicje klawiszy +const int k_IncMainCtrl = 0; //[Num+] +const int k_IncMainCtrlFAST = 1; //[Num+] [Shift] +const int k_DecMainCtrl = 2; //[Num-] +const int k_DecMainCtrlFAST = 3; //[Num-] [Shift] +const int k_IncScndCtrl = 4; //[Num/] +const int k_IncScndCtrlFAST = 5; +const int k_DecScndCtrl = 6; +const int k_DecScndCtrlFAST = 7; +const int k_IncLocalBrakeLevel = 8; +const int k_IncLocalBrakeLevelFAST = 9; +const int k_DecLocalBrakeLevel = 10; +const int k_DecLocalBrakeLevelFAST = 11; +const int k_IncBrakeLevel = 12; +const int k_DecBrakeLevel = 13; +const int k_Releaser = 14; +const int k_EmergencyBrake = 15; +const int k_Brake3 = 16; +const int k_Brake2 = 17; +const int k_Brake1 = 18; +const int k_Brake0 = 19; +const int k_WaveBrake = 20; +const int k_AntiSlipping = 21; +const int k_Sand = 22; -const int k_Main= 23; -const int k_DirectionForward= 24; -const int k_DirectionBackward= 25; +const int k_Main = 23; +const int k_DirectionForward = 24; +const int k_DirectionBackward = 25; -const int k_Fuse= 26; -const int k_Compressor= 27; -const int k_Converter= 28; -const int k_MaxCurrent= 29; -const int k_CurrentAutoRelay= 30; -const int k_BrakeProfile= 31; +const int k_Fuse = 26; +const int k_Compressor = 27; +const int k_Converter = 28; +const int k_MaxCurrent = 29; +const int k_CurrentAutoRelay = 30; +const int k_BrakeProfile = 31; -const int k_Czuwak= 32; -const int k_Horn= 33; -const int k_Horn2= 34; +const int k_Czuwak = 32; +const int k_Horn = 33; +const int k_Horn2 = 34; -const int k_FailedEngineCutOff= 35; +const int k_FailedEngineCutOff = 35; -const int k_MechUp= 36; -const int k_MechDown= 37; -const int k_MechLeft= 38; -const int k_MechRight= 39; -const int k_MechForward= 40; -const int k_MechBackward= 41; +const int k_MechUp = 36; +const int k_MechDown = 37; +const int k_MechLeft = 38; +const int k_MechRight = 39; +const int k_MechForward = 40; +const int k_MechBackward = 41; -const int k_CabForward= 42; -const int k_CabBackward= 43; +const int k_CabForward = 42; +const int k_CabBackward = 43; -const int k_Couple= 44; -const int k_DeCouple= 45; +const int k_Couple = 44; +const int k_DeCouple = 45; -const int k_ProgramQuit= 46; -//const int k_ProgramPause= 47; -const int k_ProgramHelp= 48; - //NBMX -const int k_OpenLeft= 49; -const int k_OpenRight= 50; -const int k_CloseLeft= 51; -const int k_CloseRight= 52; -const int k_DepartureSignal= 53; - //NBMX -const int k_PantFrontUp= 54; -const int k_PantRearUp= 55; -const int k_PantFrontDown= 56; -const int k_PantRearDown= 57; +const int k_ProgramQuit = 46; +// const int k_ProgramPause= 47; +const int k_ProgramHelp = 48; +// NBMX +const int k_OpenLeft = 49; +const int k_OpenRight = 50; +const int k_CloseLeft = 51; +const int k_CloseRight = 52; +const int k_DepartureSignal = 53; +// NBMX +const int k_PantFrontUp = 54; +const int k_PantRearUp = 55; +const int k_PantFrontDown = 56; +const int k_PantRearDown = 57; -const int k_Heating= 58; +const int k_Heating = 58; -//const int k_FreeFlyMode= 59; +// const int k_FreeFlyMode= 59; const int k_LeftSign = 60; -const int k_UpperSign= 61; -const int k_RightSign= 62; +const int k_UpperSign = 61; +const int k_RightSign = 62; -const int k_SmallCompressor= 63; +const int k_SmallCompressor = 63; -const int k_StLinOff= 64; +const int k_StLinOff = 64; -const int k_CurrentNext=65; +const int k_CurrentNext = 65; -const int k_Univ1=66; -const int k_Univ2=67; -const int k_Univ3=68; -const int k_Univ4=69; -const int k_EndSign=70; +const int k_Univ1 = 66; +const int k_Univ2 = 67; +const int k_Univ3 = 68; +const int k_Univ4 = 69; +const int k_EndSign = 70; -const int k_Active=71; - //Winger 020304 -const int k_Battery=72; -const int k_WalkMode=73; -const int MaxKeys= 74; +const int k_Active = 71; +// Winger 020304 +const int k_Battery = 72; +const int k_WalkMode = 73; +const int MaxKeys = 74; -//klasy dla wskaźników globalnych +// klasy dla wskaźników globalnych class TGround; class TWorld; class TCamera; class TDynamicObject; -class TAnimModel; //obiekt terenu +class TAnimModel; // obiekt terenu namespace Queryparsercomp { -class TQueryParserComp; //stary(?) parser +class TQueryParserComp; // stary(?) parser } -class cParser; //nowy (powolny!) parser +class cParser; // nowy (powolny!) parser class TEvent; class TTextSound; class TTranscript -{//klasa obsługująca linijkę napisu do dźwięku -public: - float fShow; //czas pokazania - float fHide; //czas ukrycia/usunięcia - AnsiString asText; //tekst gotowy do wyświetlenia (usunięte znaczniki czasu) - bool bItalic; //czy kursywa (dźwięk nieistotny dla prowadzącego) - int iNext; //następna używana linijka, żeby nie przestawiać fizycznie tabeli +{ // klasa obsługująca linijkę napisu do dźwięku + public: + float fShow; // czas pokazania + float fHide; // czas ukrycia/usunięcia + AnsiString asText; // tekst gotowy do wyświetlenia (usunięte znaczniki czasu) + bool bItalic; // czy kursywa (dźwięk nieistotny dla prowadzącego) + int iNext; // następna używana linijka, żeby nie przestawiać fizycznie tabeli }; #define MAX_TRANSCRIPTS 30 class TTranscripts -{//klasa obsługująca napisy do dźwięków - TTranscript aLines[MAX_TRANSCRIPTS]; //pozycje na napisy do wyświetlenia - int iCount; //liczba zajętych pozycji - int iStart; //pierwsza istotna pozycja w tabeli, żeby sortować przestawiając numerki - float fRefreshTime; -public: - __fastcall TTranscripts(); - __fastcall ~TTranscripts(); - void __fastcall AddLine(char *txt,float show,float hide,bool it); - void __fastcall Add(char *txt,float len,bool backgorund=false); //dodanie tekstów, długość dźwięku, czy istotne - void __fastcall Update(); //usuwanie niepotrzebnych (ok. 10 razy na sekundę) +{ // klasa obsługująca napisy do dźwięków + TTranscript aLines[MAX_TRANSCRIPTS]; // pozycje na napisy do wyświetlenia + int iCount; // liczba zajętych pozycji + int iStart; // pierwsza istotna pozycja w tabeli, żeby sortować przestawiając numerki + float fRefreshTime; + + public: + __fastcall TTranscripts(); + __fastcall ~TTranscripts(); + void __fastcall AddLine(char *txt, float show, float hide, bool it); + void __fastcall Add(char *txt, float len, + bool backgorund = false); // dodanie tekstów, długość dźwięku, czy istotne + void __fastcall Update(); // usuwanie niepotrzebnych (ok. 10 razy na sekundę) }; class Global { -private: - static GLuint iTextureId; //ostatnio użyta tekstura 2D -public: - //double Global::tSinceStart; - static int Keys[MaxKeys]; - static vector3 pCameraPosition; //pozycja kamery w świecie - static double pCameraRotation; //kierunek bezwzględny kamery w świecie: 0=północ, 90°=zachód (-azymut) - static double pCameraRotationDeg; //w stopniach, dla animacji billboard - static vector3 pFreeCameraInit[10]; //pozycje kamery - static vector3 pFreeCameraInitAngle[10]; - static int iWindowWidth; - static int iWindowHeight; - static float fDistanceFactor; - static int iBpp; - static bool bFullScreen; - static bool bFreeFly; - //float RunningTime; - static bool bWireFrame; - static bool bSoundEnabled; - //McZapkie-131202 - //static bool bRenderAlpha; - static bool bAdjustScreenFreq; - static bool bEnableTraction; - static bool bLoadTraction; - static float fFriction; - static bool bLiveTraction; - static bool bManageNodes; - static bool bDecompressDDS; - // bool WFreeFly; - static float Global::fMouseXScale; - static float Global::fMouseYScale; - static double fFogStart; - static double fFogEnd; - static TGround *pGround; - static char** szDefaultExt; - static char szSceneryFile[256]; - static char CreatorName1[20]; - static char CreatorName2[20]; - static char CreatorName3[20]; - static char CreatorName4[30]; - static char CreatorName5[30]; - static AnsiString asCurrentSceneryPath; - static AnsiString asCurrentTexturePath; - static AnsiString asCurrentDynamicPath; - //McZapkie-170602: zewnetrzna definicja pojazdu uzytkownika - static AnsiString asHumanCtrlVehicle; - static void __fastcall LoadIniFile(AnsiString asFileName); - static void __fastcall InitKeys(AnsiString asFileName); - inline static vector3 __fastcall GetCameraPosition() - {return pCameraPosition;}; - static void __fastcall SetCameraPosition(vector3 pNewCameraPosition); - static void __fastcall SetCameraRotation(double Yaw); - static int iWriteLogEnabled; //maska bitowa: 1-zapis do pliku, 2-okienko - //McZapkie-221002: definicja swiatla dziennego - static GLfloat AtmoColor[]; - static GLfloat FogColor[]; - //static bool bTimeChange; - static GLfloat ambientDayLight[]; - static GLfloat diffuseDayLight[]; - static GLfloat specularDayLight[]; - static GLfloat ambientLight[]; - static GLfloat diffuseLight[]; - static GLfloat specularLight[]; - static GLfloat whiteLight[]; - static GLfloat noLight[]; - static GLfloat darkLight[]; - static GLfloat lightPos[4]; - static int iSlowMotion; - static TDynamicObject *changeDynObj; - static double ABuDebug; - static bool detonatoryOK; - static AnsiString asSky; - static bool bnewAirCouplers; - //Ra: nowe zmienne globalne - static int iDefaultFiltering; //domyślne rozmywanie tekstur TGA - static int iBallastFiltering; //domyślne rozmywanie tekstury podsypki - static int iRailProFiltering; //domyślne rozmywanie tekstury szyn - static int iDynamicFiltering; //domyślne rozmywanie tekstur pojazdów - static int iReCompile; //zwiększany, gdy trzeba odświeżyć siatki - static bool bUseVBO; //czy jest VBO w karcie graficznej - static int iFeedbackMode; //tryb pracy informacji zwrotnej - static int iFeedbackPort; //dodatkowy adres dla informacji zwrotnych - static double fOpenGL; //wersja OpenGL - przyda się - static bool bOpenGL_1_5; //czy są dostępne funkcje OpenGL 1.5 - static double fLuminance; //jasność światła do automatycznego zapalania - static int iMultiplayer; //blokada działania niektórych eventów na rzecz kominikacji - static HWND hWnd; //uchwyt okna - static int iCameraLast; - static AnsiString asRelease; //numer - static AnsiString asVersion; //z opisem - static int iViewMode; //co aktualnie widać: 0-kabina, 1-latanie, 2-sprzęgi, 3-dokumenty, 4-obwody - static GLint iMaxTextureSize; //maksymalny rozmiar tekstury - static int iTextMode; //tryb pracy wyświetlacza tekstowego - static int iScreenMode[12]; //numer ekranu wyświetlacza tekstowego - static bool bDoubleAmbient; //podwójna jasność ambient - static double fMoveLight; //numer dnia w roku albo -1 - static bool bSmoothTraction; //wygładzanie drutów - static double fSunDeclination; //deklinacja Słońca - static double fTimeSpeed; //przyspieszenie czasu, zmienna do testów - static double fTimeAngleDeg; //godzina w postaci kąta - static float fClockAngleDeg[6]; //kąty obrotu cylindrów dla zegara cyfrowego - static double fLatitudeDeg; //szerokość geograficzna - static char* szTexturesTGA[4]; //lista tekstur od TGA - static char* szTexturesDDS[4]; //lista tekstur od DDS - static int iMultisampling; //tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px - static bool bGlutFont; //tekst generowany przez GLUT - static int iKeyLast; //ostatnio naciśnięty klawisz w celu logowania - static int iPause; //globalna pauza ruchu: b0=start,b1=klawisz,b2=tło,b3=lagi,b4=wczytywanie - static bool bActive; //czy jest aktywnym oknem - static void __fastcall BindTexture(GLuint t); - static int iConvertModels; //tworzenie plików binarnych - static int iErorrCounter; //licznik sprawdzań do śledzenia błędów OpenGL - static bool bInactivePause; //automatyczna pauza, gdy okno nieaktywne - static int iTextures; //licznik użytych tekstur - static int iSlowMotionMask; //maska wyłączanych właściwości - static int iModifyTGA; //czy korygować pliki TGA dla szybszego wczytywania - static bool bHideConsole; //hunter-271211: ukrywanie konsoli - static TWorld *pWorld; //wskaźnik na świat do usuwania pojazdów - static TAnimModel *pTerrainCompact; //obiekt terenu do ewentualnego zapisania w pliku - static AnsiString asTerrainModel; //nazwa obiektu terenu do zapisania w pliku - static bool bRollFix; //czy wykonać przeliczanie przechyłki - static Queryparsercomp::TQueryParserComp *qParser; - static cParser *pParser; - static int iSegmentsRendered; //ilość segmentów do regulacji wydajności - static double fFpsAverage; //oczekiwana wartosć FPS - static double fFpsDeviation; //odchylenie standardowe FPS - static double fFpsMin; //dolna granica FPS, przy której promień scenerii będzie zmniejszany - static double fFpsMax; //górna granica FPS, przy której promień scenerii będzie zwiększany - static double fFpsRadiusMax; //maksymalny promień renderowania - static int iFpsRadiusMax; //maksymalny promień renderowania w rozmiarze tabeli sektorów - static double fRadiusFactor; //współczynnik zmiany promienia - static TCamera *pCamera; //parametry kamery - static TDynamicObject *pUserDynamic; //pojazd użytkownika, renderowany bez trzęsienia - static double fCalibrateIn[6][4]; //parametry kalibracyjne wejść z pulpitu - static double fCalibrateOut[7][4]; //parametry kalibracyjne wyjść dla pulpitu - static double fBrakeStep; //krok zmiany hamulca dla klawiszy [Num3] i [Num9] - static bool bJoinEvents; //czy grupować eventy o tych samych nazwach - static bool bSmudge; //czy wyświetlać smugę, a pojazd użytkownika na końcu - static AnsiString asTranscript[5]; //napisy na ekranie (widoczne) - static TTranscripts tranTexts; //obiekt obsługujący stenogramy dźwięków na ekranie - static AnsiString asLang; //domyślny język - http://tools.ietf.org/html/bcp47 - static int iHiddenEvents; //czy łączyć eventy z torami poprzez nazwę toru - static TTextSound *tsRadioBusy[10]; //zajętość kanałów radiowych (wskaźnik na odgrywany dźwięk) - //metody - static void __fastcall TrainDelete(TDynamicObject *d); - static void __fastcall ConfigParse(Queryparsercomp::TQueryParserComp *qp,cParser *cp=NULL); - static AnsiString __fastcall GetNextSymbol(); - static TDynamicObject* __fastcall DynamicNearest(); - static TDynamicObject* __fastcall CouplerNearest(); - static bool __fastcall AddToQuery(TEvent *event,TDynamicObject *who); - static bool __fastcall DoEvents(); - static AnsiString __fastcall Bezogonkow(AnsiString str, bool _=false); + private: + static GLuint iTextureId; // ostatnio użyta tekstura 2D + public: + // double Global::tSinceStart; + static int Keys[MaxKeys]; + static vector3 pCameraPosition; // pozycja kamery w świecie + static double + pCameraRotation; // kierunek bezwzględny kamery w świecie: 0=północ, 90°=zachód (-azymut) + static double pCameraRotationDeg; // w stopniach, dla animacji billboard + static vector3 pFreeCameraInit[10]; // pozycje kamery + static vector3 pFreeCameraInitAngle[10]; + static int iWindowWidth; + static int iWindowHeight; + static float fDistanceFactor; + static int iBpp; + static bool bFullScreen; + static bool bFreeFly; + // float RunningTime; + static bool bWireFrame; + static bool bSoundEnabled; + // McZapkie-131202 + // static bool bRenderAlpha; + static bool bAdjustScreenFreq; + static bool bEnableTraction; + static bool bLoadTraction; + static float fFriction; + static bool bLiveTraction; + static bool bManageNodes; + static bool bDecompressDDS; + // bool WFreeFly; + static float Global::fMouseXScale; + static float Global::fMouseYScale; + static double fFogStart; + static double fFogEnd; + static TGround *pGround; + static char **szDefaultExt; + static char szSceneryFile[256]; + static char CreatorName1[20]; + static char CreatorName2[20]; + static char CreatorName3[20]; + static char CreatorName4[30]; + static char CreatorName5[30]; + static AnsiString asCurrentSceneryPath; + static AnsiString asCurrentTexturePath; + static AnsiString asCurrentDynamicPath; + // McZapkie-170602: zewnetrzna definicja pojazdu uzytkownika + static AnsiString asHumanCtrlVehicle; + static void __fastcall LoadIniFile(AnsiString asFileName); + static void __fastcall InitKeys(AnsiString asFileName); + inline static vector3 __fastcall GetCameraPosition() { return pCameraPosition; }; + static void __fastcall SetCameraPosition(vector3 pNewCameraPosition); + static void __fastcall SetCameraRotation(double Yaw); + static int iWriteLogEnabled; // maska bitowa: 1-zapis do pliku, 2-okienko + // McZapkie-221002: definicja swiatla dziennego + static GLfloat AtmoColor[]; + static GLfloat FogColor[]; + // static bool bTimeChange; + static GLfloat ambientDayLight[]; + static GLfloat diffuseDayLight[]; + static GLfloat specularDayLight[]; + static GLfloat ambientLight[]; + static GLfloat diffuseLight[]; + static GLfloat specularLight[]; + static GLfloat whiteLight[]; + static GLfloat noLight[]; + static GLfloat darkLight[]; + static GLfloat lightPos[4]; + static int iSlowMotion; + static TDynamicObject *changeDynObj; + static double ABuDebug; + static bool detonatoryOK; + static AnsiString asSky; + static bool bnewAirCouplers; + // Ra: nowe zmienne globalne + static int iDefaultFiltering; // domyślne rozmywanie tekstur TGA + static int iBallastFiltering; // domyślne rozmywanie tekstury podsypki + static int iRailProFiltering; // domyślne rozmywanie tekstury szyn + static int iDynamicFiltering; // domyślne rozmywanie tekstur pojazdów + static int iReCompile; // zwiększany, gdy trzeba odświeżyć siatki + static bool bUseVBO; // czy jest VBO w karcie graficznej + static int iFeedbackMode; // tryb pracy informacji zwrotnej + static int iFeedbackPort; // dodatkowy adres dla informacji zwrotnych + static double fOpenGL; // wersja OpenGL - przyda się + static bool bOpenGL_1_5; // czy są dostępne funkcje OpenGL 1.5 + static double fLuminance; // jasność światła do automatycznego zapalania + static int iMultiplayer; // blokada działania niektórych eventów na rzecz kominikacji + static HWND hWnd; // uchwyt okna + static int iCameraLast; + static AnsiString asRelease; // numer + static AnsiString asVersion; // z opisem + static int + iViewMode; // co aktualnie widać: 0-kabina, 1-latanie, 2-sprzęgi, 3-dokumenty, 4-obwody + static GLint iMaxTextureSize; // maksymalny rozmiar tekstury + static int iTextMode; // tryb pracy wyświetlacza tekstowego + static int iScreenMode[12]; // numer ekranu wyświetlacza tekstowego + static bool bDoubleAmbient; // podwójna jasność ambient + static double fMoveLight; // numer dnia w roku albo -1 + static bool bSmoothTraction; // wygładzanie drutów + static double fSunDeclination; // deklinacja Słońca + static double fTimeSpeed; // przyspieszenie czasu, zmienna do testów + static double fTimeAngleDeg; // godzina w postaci kąta + static float fClockAngleDeg[6]; // kąty obrotu cylindrów dla zegara cyfrowego + static double fLatitudeDeg; // szerokość geograficzna + static char *szTexturesTGA[4]; // lista tekstur od TGA + static char *szTexturesDDS[4]; // lista tekstur od DDS + static int iMultisampling; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px + static bool bGlutFont; // tekst generowany przez GLUT + static int iKeyLast; // ostatnio naciśnięty klawisz w celu logowania + static int iPause; // globalna pauza ruchu: b0=start,b1=klawisz,b2=tło,b3=lagi,b4=wczytywanie + static bool bActive; // czy jest aktywnym oknem + static void __fastcall BindTexture(GLuint t); + static int iConvertModels; // tworzenie plików binarnych + static int iErorrCounter; // licznik sprawdzań do śledzenia błędów OpenGL + static bool bInactivePause; // automatyczna pauza, gdy okno nieaktywne + static int iTextures; // licznik użytych tekstur + static int iSlowMotionMask; // maska wyłączanych właściwości + static int iModifyTGA; // czy korygować pliki TGA dla szybszego wczytywania + static bool bHideConsole; // hunter-271211: ukrywanie konsoli + static TWorld *pWorld; // wskaźnik na świat do usuwania pojazdów + static TAnimModel *pTerrainCompact; // obiekt terenu do ewentualnego zapisania w pliku + static AnsiString asTerrainModel; // nazwa obiektu terenu do zapisania w pliku + static bool bRollFix; // czy wykonać przeliczanie przechyłki + static Queryparsercomp::TQueryParserComp *qParser; + static cParser *pParser; + static int iSegmentsRendered; // ilość segmentów do regulacji wydajności + static double fFpsAverage; // oczekiwana wartosć FPS + static double fFpsDeviation; // odchylenie standardowe FPS + static double fFpsMin; // dolna granica FPS, przy której promień scenerii będzie zmniejszany + static double fFpsMax; // górna granica FPS, przy której promień scenerii będzie zwiększany + static double fFpsRadiusMax; // maksymalny promień renderowania + static int iFpsRadiusMax; // maksymalny promień renderowania w rozmiarze tabeli sektorów + static double fRadiusFactor; // współczynnik zmiany promienia + static TCamera *pCamera; // parametry kamery + static TDynamicObject *pUserDynamic; // pojazd użytkownika, renderowany bez trzęsienia + static double fCalibrateIn[6][4]; // parametry kalibracyjne wejść z pulpitu + static double fCalibrateOut[7][4]; // parametry kalibracyjne wyjść dla pulpitu + static double fBrakeStep; // krok zmiany hamulca dla klawiszy [Num3] i [Num9] + static bool bJoinEvents; // czy grupować eventy o tych samych nazwach + static bool bSmudge; // czy wyświetlać smugę, a pojazd użytkownika na końcu + static AnsiString asTranscript[5]; // napisy na ekranie (widoczne) + static TTranscripts tranTexts; // obiekt obsługujący stenogramy dźwięków na ekranie + static AnsiString asLang; // domyślny język - http://tools.ietf.org/html/bcp47 + static int iHiddenEvents; // czy łączyć eventy z torami poprzez nazwę toru + static TTextSound *tsRadioBusy[10]; // zajętość kanałów radiowych (wskaźnik na odgrywany dźwięk) + // metody + static void __fastcall TrainDelete(TDynamicObject *d); + static void __fastcall ConfigParse(Queryparsercomp::TQueryParserComp *qp, cParser *cp = NULL); + static AnsiString __fastcall GetNextSymbol(); + static TDynamicObject *__fastcall DynamicNearest(); + static TDynamicObject *__fastcall CouplerNearest(); + static bool __fastcall AddToQuery(TEvent *event, TDynamicObject *who); + static bool __fastcall DoEvents(); + static AnsiString __fastcall Bezogonkow(AnsiString str, bool _ = false); }; //--------------------------------------------------------------------------- diff --git a/Ground.cpp b/Ground.cpp index e35864a3..0d9e887b 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -34,13 +34,11 @@ #include "Console.h" #include "Names.h" - #define _PROBLEND 1 //--------------------------------------------------------------------------- #pragma package(smart_init) - -bool bCondition; //McZapkie: do testowania warunku na event multiple +bool bCondition; // McZapkie: do testowania warunku na event multiple AnsiString LogComment; //--------------------------------------------------------------------------- @@ -56,587 +54,621 @@ AnsiString LogComment; // tylko jedna (np. zwrotnice), nie jest używany TP_DUMMYTRACK. //--------------------------------------------------------------------------- __fastcall TGroundNode::TGroundNode() -{//nowy obiekt terenu - pusty - iType=GL_POINTS; - Vertices=NULL; - nNext=nNext2=NULL; - pCenter=vector3(0,0,0); - iCount=0; //wierzchołków w trójkącie - //iNumPts=0; //punktów w linii - TextureID=0; - iFlags=0; //tryb przezroczystości nie zbadany - DisplayListID=0; - Pointer=NULL; //zerowanie wskaźnika kontekstowego - bVisible=false; //czy widoczny - fSquareRadius=10000*10000; - fSquareMinRadius=0; - asName=""; - //Color= TMaterialColor(1); - //fAngle=0; //obrót dla modelu - //fLineThickness=1.0; //mm dla linii - for (int i=0;i<3;i++) - { - Ambient[i]=Global::whiteLight[i]*255; - Diffuse[i]=Global::whiteLight[i]*255; - Specular[i]=Global::noLight[i]*255; - } - nNext3=NULL; //nie wyświetla innych - iVboPtr=-1; //indeks w VBO sektora (-1: nie używa VBO) - iVersion=0; //wersja siatki +{ // nowy obiekt terenu - pusty + iType = GL_POINTS; + Vertices = NULL; + nNext = nNext2 = NULL; + pCenter = vector3(0, 0, 0); + iCount = 0; // wierzchołków w trójkącie + // iNumPts=0; //punktów w linii + TextureID = 0; + iFlags = 0; // tryb przezroczystości nie zbadany + DisplayListID = 0; + Pointer = NULL; // zerowanie wskaźnika kontekstowego + bVisible = false; // czy widoczny + fSquareRadius = 10000 * 10000; + fSquareMinRadius = 0; + asName = ""; + // Color= TMaterialColor(1); + // fAngle=0; //obrót dla modelu + // fLineThickness=1.0; //mm dla linii + for (int i = 0; i < 3; i++) + { + Ambient[i] = Global::whiteLight[i] * 255; + Diffuse[i] = Global::whiteLight[i] * 255; + Specular[i] = Global::noLight[i] * 255; + } + nNext3 = NULL; // nie wyświetla innych + iVboPtr = -1; // indeks w VBO sektora (-1: nie używa VBO) + iVersion = 0; // wersja siatki } __fastcall TGroundNode::~TGroundNode() { - //if (iFlags&0x200) //czy obiekt został utworzony? - switch (iType) - {case TP_MEMCELL: SafeDelete(MemCell); break; - case TP_EVLAUNCH: SafeDelete(EvLaunch); break; - case TP_TRACTION: SafeDelete(hvTraction); break; - case TP_TRACTIONPOWERSOURCE: - SafeDelete(psTractionPowerSource); break; - case TP_TRACK: SafeDelete(pTrack); break; - case TP_DYNAMIC: SafeDelete(DynamicObject); break; - case TP_MODEL: - if (iFlags&0x200) //czy model został utworzony? - delete Model; - Model=NULL; - break; - case TP_TERRAIN: - {//pierwsze nNode zawiera model E3D, reszta to trójkąty - for (int i=1;iVertices=NULL; //zerowanie wskaźników w kolejnych elementach, bo nie są do usuwania - delete[] nNode; //usunięcie tablicy i pierwszego elementu - } - case TP_SUBMODEL: //dla formalności, nie wymaga usuwania - break; - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - SafeDeleteArray(Points); - break; - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_TRIANGLES: - SafeDeleteArray(Vertices); - break; - } + // if (iFlags&0x200) //czy obiekt został utworzony? + switch (iType) + { + case TP_MEMCELL: + SafeDelete(MemCell); + break; + case TP_EVLAUNCH: + SafeDelete(EvLaunch); + break; + case TP_TRACTION: + SafeDelete(hvTraction); + break; + case TP_TRACTIONPOWERSOURCE: + SafeDelete(psTractionPowerSource); + break; + case TP_TRACK: + SafeDelete(pTrack); + break; + case TP_DYNAMIC: + SafeDelete(DynamicObject); + break; + case TP_MODEL: + if (iFlags & 0x200) // czy model został utworzony? + delete Model; + Model = NULL; + break; + case TP_TERRAIN: + { // pierwsze nNode zawiera model E3D, reszta to trójkąty + for (int i = 1; i < iCount; ++i) + nNode->Vertices = + NULL; // zerowanie wskaźników w kolejnych elementach, bo nie są do usuwania + delete[] nNode; // usunięcie tablicy i pierwszego elementu + } + case TP_SUBMODEL: // dla formalności, nie wymaga usuwania + break; + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + SafeDeleteArray(Points); + break; + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_TRIANGLES: + SafeDeleteArray(Vertices); + break; + } } void __fastcall TGroundNode::Init(int n) -{//utworzenie tablicy wierzchołków - bVisible=false; - iNumVerts=n; - Vertices=new TGroundVertex[iNumVerts]; +{ // utworzenie tablicy wierzchołków + bVisible = false; + iNumVerts = n; + Vertices = new TGroundVertex[iNumVerts]; } -__fastcall TGroundNode::TGroundNode(TGroundNodeType t,int n) -{//utworzenie obiektu - TGroundNode(); //domyślne ustawienia - iNumVerts=n; - if (iNumVerts) Vertices=new TGroundVertex[iNumVerts]; - iType=t; - switch (iType) - {//zależnie od typu - case TP_TRACK: - pTrack=new TTrack(this); - break; - } +__fastcall TGroundNode::TGroundNode(TGroundNodeType t, int n) +{ // utworzenie obiektu + TGroundNode(); // domyślne ustawienia + iNumVerts = n; + if (iNumVerts) + Vertices = new TGroundVertex[iNumVerts]; + iType = t; + switch (iType) + { // zależnie od typu + case TP_TRACK: + pTrack = new TTrack(this); + break; + } } void __fastcall TGroundNode::InitCenter() -{//obliczenie środka ciężkości obiektu - for (int i=0;ipPoint1+=pPosition; - hvTraction->pPoint2+=pPosition; - hvTraction->pPoint3+=pPosition; - hvTraction->pPoint4+=pPosition; - hvTraction->Optimize(); - break; - case TP_MODEL: - case TP_DYNAMIC: - case TP_MEMCELL: - case TP_EVLAUNCH: - break; - case TP_TRACK: - pTrack->MoveMe(pPosition); - break; - case TP_SOUND: //McZapkie - dzwiek zapetlony w zaleznosci od odleglosci - tsStaticSound->vSoundPosition+=pPosition; - break; - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - for (int i=0; ipPoint1 += pPosition; + hvTraction->pPoint2 += pPosition; + hvTraction->pPoint3 += pPosition; + hvTraction->pPoint4 += pPosition; + hvTraction->Optimize(); + break; + case TP_MODEL: + case TP_DYNAMIC: + case TP_MEMCELL: + case TP_EVLAUNCH: + break; + case TP_TRACK: + pTrack->MoveMe(pPosition); + break; + case TP_SOUND: // McZapkie - dzwiek zapetlony w zaleznosci od odleglosci + tsStaticSound->vSoundPosition += pPosition; + break; + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + for (int i = 0; i < iNumPts; i++) + Points[i] += pPosition; + ResourceManager::Unregister(this); + break; + default: + for (int i = 0; i < iNumVerts; i++) + Vertices[i].Point += pPosition; + ResourceManager::Unregister(this); + } } void __fastcall TGroundNode::RaRenderVBO() -{//renderowanie z domyslnego bufora VBO - glColor3ub(Diffuse[0],Diffuse[1],Diffuse[2]); - if (TextureID) - glBindTexture(GL_TEXTURE_2D,TextureID); // Ustaw aktywną teksturę - glDrawArrays(iType,iVboPtr,iNumVerts); // Narysuj naraz wszystkie trójkąty +{ // renderowanie z domyslnego bufora VBO + glColor3ub(Diffuse[0], Diffuse[1], Diffuse[2]); + if (TextureID) + glBindTexture(GL_TEXTURE_2D, TextureID); // Ustaw aktywną teksturę + glDrawArrays(iType, iVboPtr, iNumVerts); // Narysuj naraz wszystkie trójkąty } void __fastcall TGroundNode::RenderVBO() -{//renderowanie obiektu z VBO - faza nieprzezroczystych - double mgn=SquareMagnitude(pCenter-Global::pCameraPosition); - if ((mgn>fSquareRadius || (mgnRaRenderVBO(iVboPtr); return; - case TP_MODEL: Model->RenderVBO(&pCenter); return; - //case TP_SOUND: //McZapkie - dzwiek zapetlony w zaleznosci od odleglosci - // if ((pStaticSound->GetStatus()&DSBSTATUS_PLAYING)==DSBPLAY_LOOPING) - // { - // pStaticSound->Play(1,DSBPLAY_LOOPING,true,pStaticSound->vSoundPosition); - // pStaticSound->AdjFreq(1.0,Timer::GetDeltaTime()); - // } - // return; //Ra: TODO sprawdzić, czy dźwięki nie są tylko w RenderHidden - case TP_MEMCELL: return; - case TP_EVLAUNCH: - if (EvLaunch->Render()) - if ((EvLaunch->dRadius<0)||(mgndRadius)) +{ // renderowanie obiektu z VBO - faza nieprzezroczystych + double mgn = SquareMagnitude(pCenter - Global::pCameraPosition); + if ((mgn > fSquareRadius || (mgn < fSquareMinRadius)) && + (iType != TP_EVLAUNCH)) // McZapkie-070602: nie rysuj odleglych obiektow ale sprawdzaj + // wyzwalacz zdarzen + return; + int i, a; + switch (iType) { - if (Console::Pressed(VK_SHIFT) && EvLaunch->Event2!=NULL) - Global::AddToQuery(EvLaunch->Event2,NULL); - else - if (EvLaunch->Event1!=NULL) - Global::AddToQuery(EvLaunch->Event1,NULL); - } - return; - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - if (iNumPts) - {float linealpha=255000*fLineThickness/(mgn+1.0); - if (linealpha>255) linealpha=255; - float r,g,b; - r=floor(Diffuse[0]*Global::ambientDayLight[0]); //w zaleznosci od koloru swiatla - g=floor(Diffuse[1]*Global::ambientDayLight[1]); - b=floor(Diffuse[2]*Global::ambientDayLight[2]); - glColor4ub(r,g,b,linealpha); //przezroczystosc dalekiej linii - //glDisable(GL_LIGHTING); //nie powinny świecić - glDrawArrays(iType,iVboPtr,iNumPts); //rysowanie linii - //glEnable(GL_LIGHTING); - } - return; - default: - if (iVboPtr>=0) - RaRenderVBO(); - }; - return; + case TP_TRACTION: + return; + case TP_TRACK: + if (iNumVerts) + pTrack->RaRenderVBO(iVboPtr); + return; + case TP_MODEL: + Model->RenderVBO(&pCenter); + return; + // case TP_SOUND: //McZapkie - dzwiek zapetlony w zaleznosci od odleglosci + // if ((pStaticSound->GetStatus()&DSBSTATUS_PLAYING)==DSBPLAY_LOOPING) + // { + // pStaticSound->Play(1,DSBPLAY_LOOPING,true,pStaticSound->vSoundPosition); + // pStaticSound->AdjFreq(1.0,Timer::GetDeltaTime()); + // } + // return; //Ra: TODO sprawdzić, czy dźwięki nie są tylko w RenderHidden + case TP_MEMCELL: + return; + case TP_EVLAUNCH: + if (EvLaunch->Render()) + if ((EvLaunch->dRadius < 0) || (mgn < EvLaunch->dRadius)) + { + if (Console::Pressed(VK_SHIFT) && EvLaunch->Event2 != NULL) + Global::AddToQuery(EvLaunch->Event2, NULL); + else if (EvLaunch->Event1 != NULL) + Global::AddToQuery(EvLaunch->Event1, NULL); + } + return; + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + if (iNumPts) + { + float linealpha = 255000 * fLineThickness / (mgn + 1.0); + if (linealpha > 255) + linealpha = 255; + float r, g, b; + r = floor(Diffuse[0] * Global::ambientDayLight[0]); // w zaleznosci od koloru swiatla + g = floor(Diffuse[1] * Global::ambientDayLight[1]); + b = floor(Diffuse[2] * Global::ambientDayLight[2]); + glColor4ub(r, g, b, linealpha); // przezroczystosc dalekiej linii + // glDisable(GL_LIGHTING); //nie powinny świecić + glDrawArrays(iType, iVboPtr, iNumPts); // rysowanie linii + // glEnable(GL_LIGHTING); + } + return; + default: + if (iVboPtr >= 0) + RaRenderVBO(); + }; + return; }; void __fastcall TGroundNode::RenderAlphaVBO() -{//renderowanie obiektu z VBO - faza przezroczystych - double mgn=SquareMagnitude(pCenter-Global::pCameraPosition); - float r,g,b; - if (mgnfSquareRadius) return; - int i,a; +{ // renderowanie obiektu z VBO - faza przezroczystych + double mgn = SquareMagnitude(pCenter - Global::pCameraPosition); + float r, g, b; + if (mgn < fSquareMinRadius) + return; + if (mgn > fSquareRadius) + return; + int i, a; #ifdef _PROBLEND - if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - { - glDisable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.45); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - }; + if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 + { + glDisable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.45); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + }; #endif - switch (iType) - { - case TP_TRACTION: - if (bVisible) - { + switch (iType) + { + case TP_TRACTION: + if (bVisible) + { +#ifdef _PROBLEND + glEnable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.04); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#endif + hvTraction->RenderVBO(mgn, iVboPtr); + } + return; + case TP_MODEL: +#ifdef _PROBLEND + glEnable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.04); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#endif + Model->RenderAlphaVBO(&pCenter); + return; + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + if (iNumPts) + { + float linealpha = 255000 * fLineThickness / (mgn + 1.0); + if (linealpha > 255) + linealpha = 255; + r = Diffuse[0] * Global::ambientDayLight[0]; // w zaleznosci od koloru swiatla + g = Diffuse[1] * Global::ambientDayLight[1]; + b = Diffuse[2] * Global::ambientDayLight[2]; + glColor4ub(r, g, b, linealpha); // przezroczystosc dalekiej linii + // glDisable(GL_LIGHTING); //nie powinny świecić + glDrawArrays(iType, iVboPtr, iNumPts); // rysowanie linii +// glEnable(GL_LIGHTING); +#ifdef _PROBLEND + glEnable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.04); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#endif + } +#ifdef _PROBLEND + glEnable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.04); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#endif + return; + default: + if (iVboPtr >= 0) + { + RaRenderVBO(); +#ifdef _PROBLEND + glEnable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.04); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#endif + return; + } + } #ifdef _PROBLEND glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.04); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -#endif - hvTraction->RenderVBO(mgn,iVboPtr); - } - return; - case TP_MODEL: -#ifdef _PROBLEND - glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.04); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -#endif - Model->RenderAlphaVBO(&pCenter); - return; - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - if (iNumPts) - {float linealpha=255000*fLineThickness/(mgn+1.0); - if (linealpha>255) linealpha=255; - r=Diffuse[0]*Global::ambientDayLight[0]; //w zaleznosci od koloru swiatla - g=Diffuse[1]*Global::ambientDayLight[1]; - b=Diffuse[2]*Global::ambientDayLight[2]; - glColor4ub(r,g,b,linealpha); //przezroczystosc dalekiej linii - //glDisable(GL_LIGHTING); //nie powinny świecić - glDrawArrays(iType,iVboPtr,iNumPts); //rysowanie linii - //glEnable(GL_LIGHTING); -#ifdef _PROBLEND - glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.04); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -#endif - } -#ifdef _PROBLEND - glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.04); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -#endif - return; - default: - if (iVboPtr>=0) - {RaRenderVBO(); -#ifdef _PROBLEND - glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.04); + glAlphaFunc(GL_GREATER, 0.04); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #endif return; - } - } -#ifdef _PROBLEND - glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.04); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -#endif - return; } void __fastcall TGroundNode::Compile(bool many) -{//tworzenie skompilowanej listy w wyświetlaniu DL - if (!many) - {//obsługa pojedynczej listy - if (DisplayListID) Release(); - if (Global::bManageNodes) - { - DisplayListID=glGenLists(1); - glNewList(DisplayListID,GL_COMPILE); - iVersion=Global::iReCompile; //aktualna wersja siatek (do WireFrame) - } - } - if ((iType==GL_LINES)||(iType==GL_LINE_STRIP)||(iType==GL_LINE_LOOP)) - { +{ // tworzenie skompilowanej listy w wyświetlaniu DL + if (!many) + { // obsługa pojedynczej listy + if (DisplayListID) + Release(); + if (Global::bManageNodes) + { + DisplayListID = glGenLists(1); + glNewList(DisplayListID, GL_COMPILE); + iVersion = Global::iReCompile; // aktualna wersja siatek (do WireFrame) + } + } + if ((iType == GL_LINES) || (iType == GL_LINE_STRIP) || (iType == GL_LINE_LOOP)) + { #ifdef USE_VERTEX_ARRAYS - glVertexPointer(3,GL_DOUBLE,sizeof(vector3),&Points[0].x); + glVertexPointer(3, GL_DOUBLE, sizeof(vector3), &Points[0].x); #endif - glBindTexture(GL_TEXTURE_2D,0); + glBindTexture(GL_TEXTURE_2D, 0); #ifdef USE_VERTEX_ARRAYS - glDrawArrays(iType,0,iNumPts); + glDrawArrays(iType, 0, iNumPts); #else - glBegin(iType); - for (int i=0;iVertices[0].Point.x); - glNormalPointer(GL_DOUBLE, sizeof(TGroundVertex), &tri->Vertices[0].Normal.x); - glTexCoordPointer(2, GL_FLOAT, sizeof(TGroundVertex), &tri->Vertices[0].tu); + glVertexPointer(3, GL_DOUBLE, sizeof(TGroundVertex), &tri->Vertices[0].Point.x); + glNormalPointer(GL_DOUBLE, sizeof(TGroundVertex), &tri->Vertices[0].Normal.x); + glTexCoordPointer(2, GL_FLOAT, sizeof(TGroundVertex), &tri->Vertices[0].tu); #endif - glColor3ub(tri->Diffuse[0],tri->Diffuse[1],tri->Diffuse[2]); - glBindTexture(GL_TEXTURE_2D,Global::bWireFrame?0:tri->TextureID); + glColor3ub(tri->Diffuse[0], tri->Diffuse[1], tri->Diffuse[2]); + glBindTexture(GL_TEXTURE_2D, Global::bWireFrame ? 0 : tri->TextureID); #ifdef USE_VERTEX_ARRAYS - glDrawArrays(Global::bWireFrame?GL_LINE_LOOP:tri->iType,0,tri->iNumVerts); + glDrawArrays(Global::bWireFrame ? GL_LINE_LOOP : tri->iType, 0, tri->iNumVerts); #else - glBegin(Global::bWireFrame?GL_LINE_LOOP:tri->iType); - for (int i=0;iiNumVerts;i++) - { - glNormal3d(tri->Vertices[i].Normal.x,tri->Vertices[i].Normal.y,tri->Vertices[i].Normal.z); - glTexCoord2f(tri->Vertices[i].tu,tri->Vertices[i].tv); - glVertex3dv(&tri->Vertices[i].Point.x); - }; - glEnd(); + glBegin(Global::bWireFrame ? GL_LINE_LOOP : tri->iType); + for (int i = 0; i < tri->iNumVerts; i++) + { + glNormal3d(tri->Vertices[i].Normal.x, tri->Vertices[i].Normal.y, + tri->Vertices[i].Normal.z); + glTexCoord2f(tri->Vertices[i].tu, tri->Vertices[i].tv); + glVertex3dv(&tri->Vertices[i].Point.x); + }; + glEnd(); #endif -/* - if (tri->pTriGroup) //jeśli z grupy - {tri=tri->pNext2; //następny w sektorze - while (tri?!tri->pTriGroup:false) tri=tri->pNext2; //szukamy kolejnego należącego do grupy - } - else -*/ - tri=NULL; //a jak nie, to koniec - } while (tri); - } - else if (iType==TP_MESH) - {//grupa ze wspólną teksturą - wrzucanie do wspólnego Display List - if (TextureID) - glBindTexture(GL_TEXTURE_2D,TextureID); // Ustaw aktywną teksturę - TGroundNode *n=nNode; - while (n?n->TextureID==TextureID:false) - {//wszystkie obiekty o tej samej testurze - switch (n->iType) - {//poszczególne typy różnie się tworzy - case TP_TRACK: - case TP_DUMMYTRACK: - n->pTrack->Compile(TextureID); //dodanie trójkątów dla podanej tekstury - break; - } - n=n->nNext3; //następny z listy - } - } - if (!many) - if (Global::bManageNodes) - glEndList(); + /* + if (tri->pTriGroup) //jeśli z grupy + {tri=tri->pNext2; //następny w sektorze + while (tri?!tri->pTriGroup:false) tri=tri->pNext2; //szukamy kolejnego należącego do + grupy + } + else + */ + tri = NULL; // a jak nie, to koniec + } while (tri); + } + else if (iType == TP_MESH) + { // grupa ze wspólną teksturą - wrzucanie do wspólnego Display List + if (TextureID) + glBindTexture(GL_TEXTURE_2D, TextureID); // Ustaw aktywną teksturę + TGroundNode *n = nNode; + while (n ? n->TextureID == TextureID : false) + { // wszystkie obiekty o tej samej testurze + switch (n->iType) + { // poszczególne typy różnie się tworzy + case TP_TRACK: + case TP_DUMMYTRACK: + n->pTrack->Compile(TextureID); // dodanie trójkątów dla podanej tekstury + break; + } + n = n->nNext3; // następny z listy + } + } + if (!many) + if (Global::bManageNodes) + glEndList(); }; void TGroundNode::Release() { - if (DisplayListID) - glDeleteLists(DisplayListID,1); - DisplayListID=0; + if (DisplayListID) + glDeleteLists(DisplayListID, 1); + DisplayListID = 0; }; void __fastcall TGroundNode::RenderHidden() -{//renderowanie obiektów niewidocznych - double mgn=SquareMagnitude(pCenter-Global::pCameraPosition); - switch (iType) - { - case TP_SOUND: //McZapkie - dzwiek zapetlony w zaleznosci od odleglosci - if ((tsStaticSound->GetStatus()&DSBSTATUS_PLAYING)==DSBPLAY_LOOPING) - { - tsStaticSound->Play(1,DSBPLAY_LOOPING,true,tsStaticSound->vSoundPosition); - tsStaticSound->AdjFreq(1.0,Timer::GetDeltaTime()); - } - return; - case TP_EVLAUNCH: - if (EvLaunch->Render()) - if ((EvLaunch->dRadius<0)||(mgndRadius)) +{ // renderowanie obiektów niewidocznych + double mgn = SquareMagnitude(pCenter - Global::pCameraPosition); + switch (iType) { - WriteLog("Eventlauncher "+asName); - if (Console::Pressed(VK_SHIFT)&&(EvLaunch->Event2)) - Global::AddToQuery(EvLaunch->Event2,NULL); - else - if (EvLaunch->Event1) - Global::AddToQuery(EvLaunch->Event1,NULL); + case TP_SOUND: // McZapkie - dzwiek zapetlony w zaleznosci od odleglosci + if ((tsStaticSound->GetStatus() & DSBSTATUS_PLAYING) == DSBPLAY_LOOPING) + { + tsStaticSound->Play(1, DSBPLAY_LOOPING, true, tsStaticSound->vSoundPosition); + tsStaticSound->AdjFreq(1.0, Timer::GetDeltaTime()); + } + return; + case TP_EVLAUNCH: + if (EvLaunch->Render()) + if ((EvLaunch->dRadius < 0) || (mgn < EvLaunch->dRadius)) + { + WriteLog("Eventlauncher " + asName); + if (Console::Pressed(VK_SHIFT) && (EvLaunch->Event2)) + Global::AddToQuery(EvLaunch->Event2, NULL); + else if (EvLaunch->Event1) + Global::AddToQuery(EvLaunch->Event1, NULL); + } + return; } - return; - } }; void __fastcall TGroundNode::RenderDL() -{//wyświetlanie obiektu przez Display List - switch (iType) - {//obiekty renderowane niezależnie od odległości - case TP_SUBMODEL: - TSubModel::fSquareDist=0; - return smTerrain->RenderDL(); - } - //if (pTriGroup) if (pTriGroup!=this) return; //wyświetla go inny obiekt - double mgn=SquareMagnitude(pCenter-Global::pCameraPosition); - if ((mgn>fSquareRadius)||(mgnRender(); - case TP_MODEL: - return Model->RenderDL(&pCenter); - } - // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 - //if ((iNumVerts&&(iFlags&0x10))||(iNumPts&&(fLineThickness<0))) - if ((iFlags&0x10)||(fLineThickness<0)) - { - if (!DisplayListID||(iVersion!=Global::iReCompile)) //Ra: wymuszenie rekompilacji - { - Compile(); - if (Global::bManageNodes) - ResourceManager::Register(this); - }; +{ // wyświetlanie obiektu przez Display List + switch (iType) + { // obiekty renderowane niezależnie od odległości + case TP_SUBMODEL: + TSubModel::fSquareDist = 0; + return smTerrain->RenderDL(); + } + // if (pTriGroup) if (pTriGroup!=this) return; //wyświetla go inny obiekt + double mgn = SquareMagnitude(pCenter - Global::pCameraPosition); + if ((mgn > fSquareRadius) || (mgn < fSquareMinRadius)) // McZapkie-070602: nie rysuj odleglych + // obiektow ale sprawdzaj wyzwalacz + // zdarzen + return; + int i, a; + switch (iType) + { + case TP_TRACK: + return pTrack->Render(); + case TP_MODEL: + return Model->RenderDL(&pCenter); + } + // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 + // if ((iNumVerts&&(iFlags&0x10))||(iNumPts&&(fLineThickness<0))) + if ((iFlags & 0x10) || (fLineThickness < 0)) + { + if (!DisplayListID || (iVersion != Global::iReCompile)) // Ra: wymuszenie rekompilacji + { + Compile(); + if (Global::bManageNodes) + ResourceManager::Register(this); + }; - if ((iType==GL_LINES)||(iType==GL_LINE_STRIP)||(iType==GL_LINE_LOOP)) - //if (iNumPts) - {//wszelkie linie są rysowane na samym końcu - float r,g,b; - r=Diffuse[0]*Global::ambientDayLight[0]; //w zaleznosci od koloru swiatla - g=Diffuse[1]*Global::ambientDayLight[1]; - b=Diffuse[2]*Global::ambientDayLight[2]; - glColor4ub(r,g,b,1.0); - glCallList(DisplayListID); - //glColor4fv(Diffuse); //przywrócenie koloru - //glColor3ub(Diffuse[0],Diffuse[1],Diffuse[2]); - } - // GL_TRIANGLE etc - else - glCallList(DisplayListID); - SetLastUsage(Timer::GetSimulationTime()); - }; + if ((iType == GL_LINES) || (iType == GL_LINE_STRIP) || (iType == GL_LINE_LOOP)) + // if (iNumPts) + { // wszelkie linie są rysowane na samym końcu + float r, g, b; + r = Diffuse[0] * Global::ambientDayLight[0]; // w zaleznosci od koloru swiatla + g = Diffuse[1] * Global::ambientDayLight[1]; + b = Diffuse[2] * Global::ambientDayLight[2]; + glColor4ub(r, g, b, 1.0); + glCallList(DisplayListID); + // glColor4fv(Diffuse); //przywrócenie koloru + // glColor3ub(Diffuse[0],Diffuse[1],Diffuse[2]); + } + // GL_TRIANGLE etc + else + glCallList(DisplayListID); + SetLastUsage(Timer::GetSimulationTime()); + }; }; void __fastcall TGroundNode::RenderAlphaDL() { -// SPOSOB NA POZBYCIE SIE RAMKI DOOKOLA TEXTURY ALPHA DLA OBIEKTOW ZAGNIEZDZONYCH W SCN JAKO NODE + // SPOSOB NA POZBYCIE SIE RAMKI DOOKOLA TEXTURY ALPHA DLA OBIEKTOW ZAGNIEZDZONYCH W SCN JAKO + // NODE -//W GROUND.H dajemy do klasy TGroundNode zmienna bool PROBLEND to samo robimy w klasie TGround -//nastepnie podczas wczytywania textury dla TRIANGLES w TGround::AddGroundNode -//sprawdzamy czy w nazwie jest @ i wg tego -//ustawiamy PROBLEND na true dla wlasnie wczytywanego trojkata (kazdy trojkat jest osobnym nodem) -//nastepnie podczas renderowania w bool __fastcall TGroundNode::RenderAlpha() -//na poczatku ustawiamy standardowe GL_GREATER = 0.04 -//pozniej sprawdzamy czy jest wlaczony PROBLEND dla aktualnie renderowanego noda TRIANGLE, wlasciwie dla kazdego node'a -//i jezeli tak to odpowiedni GL_GREATER w przeciwnym wypadku standardowy 0.04 + // W GROUND.H dajemy do klasy TGroundNode zmienna bool PROBLEND to samo robimy w klasie TGround + // nastepnie podczas wczytywania textury dla TRIANGLES w TGround::AddGroundNode + // sprawdzamy czy w nazwie jest @ i wg tego + // ustawiamy PROBLEND na true dla wlasnie wczytywanego trojkata (kazdy trojkat jest osobnym + // nodem) + // nastepnie podczas renderowania w bool __fastcall TGroundNode::RenderAlpha() + // na poczatku ustawiamy standardowe GL_GREATER = 0.04 + // pozniej sprawdzamy czy jest wlaczony PROBLEND dla aktualnie renderowanego noda TRIANGLE, + // wlasciwie dla kazdego node'a + // i jezeli tak to odpowiedni GL_GREATER w przeciwnym wypadku standardowy 0.04 + // if (pTriGroup) if (pTriGroup!=this) return; //wyświetla go inny obiekt + double mgn = SquareMagnitude(pCenter - Global::pCameraPosition); + float r, g, b; + if (mgn < fSquareMinRadius) + return; + if (mgn > fSquareRadius) + return; + int i, a; + switch (iType) + { + case TP_TRACTION: + if (bVisible) + hvTraction->RenderDL(mgn); + return; + case TP_MODEL: + Model->RenderAlphaDL(&pCenter); + return; + case TP_TRACK: + // pTrack->RenderAlpha(); + return; + }; - //if (pTriGroup) if (pTriGroup!=this) return; //wyświetla go inny obiekt - double mgn=SquareMagnitude(pCenter-Global::pCameraPosition); - float r,g,b; - if (mgnfSquareRadius) - return; - int i,a; - switch (iType) - { - case TP_TRACTION: - if (bVisible) - hvTraction->RenderDL(mgn); - return; - case TP_MODEL: - Model->RenderAlphaDL(&pCenter); - return; - case TP_TRACK: - //pTrack->RenderAlpha(); - return; - }; - - // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 - if ( - (iNumVerts && (iFlags&0x20)) || - (iNumPts && (fLineThickness > 0))) - { + // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 + if ((iNumVerts && (iFlags & 0x20)) || (iNumPts && (fLineThickness > 0))) + { #ifdef _PROBLEND - if ((PROBLEND) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - { - glDisable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.45); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - }; + if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 + { + glDisable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.45); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + }; #endif - if (!DisplayListID) //||Global::bReCompile) //Ra: wymuszenie rekompilacji - { - Compile(); - if (Global::bManageNodes) - ResourceManager::Register(this); - }; + if (!DisplayListID) //||Global::bReCompile) //Ra: wymuszenie rekompilacji + { + Compile(); + if (Global::bManageNodes) + ResourceManager::Register(this); + }; - // GL_LINE, GL_LINE_STRIP, GL_LINE_LOOP - if (iNumPts) - { - float linealpha=255000*fLineThickness/(mgn+1.0); - if (linealpha>255) - linealpha= 255; - r=Diffuse[0]*Global::ambientDayLight[0]; //w zaleznosci od koloru swiatla - g=Diffuse[1]*Global::ambientDayLight[1]; - b=Diffuse[2]*Global::ambientDayLight[2]; - glColor4ub(r,g,b,linealpha); //przezroczystosc dalekiej linii - glCallList(DisplayListID); - } - // GL_TRIANGLE etc - else - glCallList(DisplayListID); - SetLastUsage(Timer::GetSimulationTime()); - }; + // GL_LINE, GL_LINE_STRIP, GL_LINE_LOOP + if (iNumPts) + { + float linealpha = 255000 * fLineThickness / (mgn + 1.0); + if (linealpha > 255) + linealpha = 255; + r = Diffuse[0] * Global::ambientDayLight[0]; // w zaleznosci od koloru swiatla + g = Diffuse[1] * Global::ambientDayLight[1]; + b = Diffuse[2] * Global::ambientDayLight[2]; + glColor4ub(r, g, b, linealpha); // przezroczystosc dalekiej linii + glCallList(DisplayListID); + } + // GL_TRIANGLE etc + else + glCallList(DisplayListID); + SetLastUsage(Timer::GetSimulationTime()); + }; #ifdef _PROBLEND - if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - {glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.04); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - }; + if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 + { + glEnable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.04); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + }; #endif } @@ -645,507 +677,581 @@ void __fastcall TGroundNode::RenderAlphaDL() //------------------------------------------------------------------------------ __fastcall TSubRect::TSubRect() { - nRootNode=NULL; //lista wszystkich obiektów jest pusta - nRenderHidden=nRenderRect=nRenderRectAlpha=nRender=nRenderMixed=nRenderAlpha=nRenderWires=NULL; - tTrackAnim=NULL; //nic nie animujemy - tTracks=NULL; //nie ma jeszcze torów - nRootMesh=nMeshed=NULL; //te listy też są puste - iNodeCount=0; //licznik obiektów - iTracks=0; //licznik torów + nRootNode = NULL; // lista wszystkich obiektów jest pusta + nRenderHidden = nRenderRect = nRenderRectAlpha = nRender = nRenderMixed = nRenderAlpha = + nRenderWires = NULL; + tTrackAnim = NULL; // nic nie animujemy + tTracks = NULL; // nie ma jeszcze torów + nRootMesh = nMeshed = NULL; // te listy też są puste + iNodeCount = 0; // licznik obiektów + iTracks = 0; // licznik torów } __fastcall TSubRect::~TSubRect() { - if (Global::bManageNodes) //Ra: tu się coś sypie - ResourceManager::Unregister(this); //wyrejestrowanie ze sprzątacza - //TODO: usunąć obiekty z listy (nRootMesh), bo są one tworzone dla sektora + if (Global::bManageNodes) // Ra: tu się coś sypie + ResourceManager::Unregister(this); // wyrejestrowanie ze sprzątacza + // TODO: usunąć obiekty z listy (nRootMesh), bo są one tworzone dla sektora } void __fastcall TSubRect::NodeAdd(TGroundNode *Node) -{//przyczepienie obiektu do sektora, wstępna kwalifikacja na listy renderowania - if (!this) return; //zabezpiecznie przed obiektami przekraczającymi obszar roboczy - //Ra: sortowanie obiektów na listy renderowania: - //nRenderHidden - lista obiektów niewidocznych, "renderowanych" również z tyłu - //nRenderRect - lista grup renderowanych z sektora - //nRenderRectAlpha - lista grup renderowanych z sektora z przezroczystością - //nRender - lista grup renderowanych z własnych VBO albo DL - //nRenderAlpha - lista grup renderowanych z własnych VBO albo DL z przezroczystością - //nRenderWires - lista grup renderowanych z własnych VBO albo DL - druty i linie - //nMeshed - obiekty do pogrupowania wg tekstur - GLuint t; //pomocniczy kod tekstury - switch (Node->iType) - {case TP_SOUND: //te obiekty są sprawdzanie niezależnie od kierunku patrzenia - case TP_EVLAUNCH: - Node->nNext3=nRenderHidden; nRenderHidden=Node; //do listy koniecznych - break; - case TP_TRACK: //TODO: tory z cieniem (tunel, canyon) też dać bez łączenia? - ++iTracks; //jeden tor więcej - Node->pTrack->RaOwnerSet(this); //do którego sektora ma zgłaszać animację - //if (Global::bUseVBO?false:!Node->pTrack->IsGroupable()) - if (Global::bUseVBO?true:!Node->pTrack->IsGroupable()) //TODO: tymczasowo dla VBO wyłączone - RaNodeAdd(Node); //tory ruchome nie są grupowane przy Display Lists (wymagają odświeżania DL) - else - {//tory nieruchome mogą być pogrupowane wg tekstury, przy VBO wszystkie - Node->TextureID=Node->pTrack->TextureGet(0); //pobranie tekstury do sortowania - t=Node->pTrack->TextureGet(1); - if (Node->TextureID) //jeżeli jest pierwsza - {if (t&&(Node->TextureID!=t)) - {//jeśli są dwie różne tekstury, dodajemy drugi obiekt dla danego toru - TGroundNode *n=new TGroundNode(); - n->iType=TP_DUMMYTRACK; //obiekt renderujący siatki dla tekstury - n->TextureID=t; - n->pTrack=Node->pTrack; //wskazuje na ten sam tor - n->pCenter=Node->pCenter; - n->fSquareRadius=Node->fSquareRadius; - n->fSquareMinRadius=Node->fSquareMinRadius; - n->iFlags=Node->iFlags; - n->nNext2=nRootMesh; nRootMesh=n; //podczepienie do listy, żeby usunąć na końcu - n->nNext3=nMeshed; nMeshed=n; - } +{ // przyczepienie obiektu do sektora, wstępna kwalifikacja na listy renderowania + if (!this) + return; // zabezpiecznie przed obiektami przekraczającymi obszar roboczy + // Ra: sortowanie obiektów na listy renderowania: + // nRenderHidden - lista obiektów niewidocznych, "renderowanych" również z tyłu + // nRenderRect - lista grup renderowanych z sektora + // nRenderRectAlpha - lista grup renderowanych z sektora z przezroczystością + // nRender - lista grup renderowanych z własnych VBO albo DL + // nRenderAlpha - lista grup renderowanych z własnych VBO albo DL z przezroczystością + // nRenderWires - lista grup renderowanych z własnych VBO albo DL - druty i linie + // nMeshed - obiekty do pogrupowania wg tekstur + GLuint t; // pomocniczy kod tekstury + switch (Node->iType) + { + case TP_SOUND: // te obiekty są sprawdzanie niezależnie od kierunku patrzenia + case TP_EVLAUNCH: + Node->nNext3 = nRenderHidden; + nRenderHidden = Node; // do listy koniecznych + break; + case TP_TRACK: // TODO: tory z cieniem (tunel, canyon) też dać bez łączenia? + ++iTracks; // jeden tor więcej + Node->pTrack->RaOwnerSet(this); // do którego sektora ma zgłaszać animację + // if (Global::bUseVBO?false:!Node->pTrack->IsGroupable()) + if (Global::bUseVBO ? true : + !Node->pTrack->IsGroupable()) // TODO: tymczasowo dla VBO wyłączone + RaNodeAdd( + Node); // tory ruchome nie są grupowane przy Display Lists (wymagają odświeżania DL) + else + { // tory nieruchome mogą być pogrupowane wg tekstury, przy VBO wszystkie + Node->TextureID = Node->pTrack->TextureGet(0); // pobranie tekstury do sortowania + t = Node->pTrack->TextureGet(1); + if (Node->TextureID) // jeżeli jest pierwsza + { + if (t && (Node->TextureID != t)) + { // jeśli są dwie różne tekstury, dodajemy drugi obiekt dla danego toru + TGroundNode *n = new TGroundNode(); + n->iType = TP_DUMMYTRACK; // obiekt renderujący siatki dla tekstury + n->TextureID = t; + n->pTrack = Node->pTrack; // wskazuje na ten sam tor + n->pCenter = Node->pCenter; + n->fSquareRadius = Node->fSquareRadius; + n->fSquareMinRadius = Node->fSquareMinRadius; + n->iFlags = Node->iFlags; + n->nNext2 = nRootMesh; + nRootMesh = n; // podczepienie do listy, żeby usunąć na końcu + n->nNext3 = nMeshed; + nMeshed = n; + } + } + else + Node->TextureID = t; // jest tylko druga tekstura + if (Node->TextureID) + { + Node->nNext3 = nMeshed; + nMeshed = Node; + } // do podzielenia potem + } + break; + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_TRIANGLES: + // Node->nNext3=nMeshed; nMeshed=Node; //do podzielenia potem + if (Node->iFlags & 0x20) // czy jest przezroczyste? + { + Node->nNext3 = nRenderRectAlpha; + nRenderRectAlpha = Node; + } // DL: do przezroczystych z sektora + else if (Global::bUseVBO) + { + Node->nNext3 = nRenderRect; + nRenderRect = Node; + } // VBO: do nieprzezroczystych z sektora + else + { + Node->nNext3 = nRender; + nRender = Node; + } // DL: do nieprzezroczystych wszelakich + /* + //Ra: na razie wyłączone do testów VBO + //if + ((Node->iType==GL_TRIANGLE_STRIP)||(Node->iType==GL_TRIANGLE_FAN)||(Node->iType==GL_TRIANGLES)) + if (Node->fSquareMinRadius==0.0) //znikające z bliska nie mogą być optymalizowane + if (Node->fSquareRadius>=160000.0) //tak od 400m to już normalne trójkąty muszą być + //if (Node->iFlags&0x10) //i nieprzezroczysty + {if (pTriGroup) //jeżeli był już jakiś grupujący + {if (pTriGroup->fSquareRadius>Node->fSquareRadius) //i miał większy zasięg + Node->fSquareRadius=pTriGroup->fSquareRadius; //zwiększenie zakresu widoczności + grupującego + pTriGroup->pTriGroup=Node; //poprzedniemu doczepiamy nowy + } + Node->pTriGroup=Node; //nowy lider ma się sam wyświetlać - wskaźnik na siebie + pTriGroup=Node; //zapamiętanie lidera + } + */ + break; + case TP_TRACTION: + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: // te renderowane na końcu, żeby nie łapały koloru nieba + Node->nNext3 = nRenderWires; + nRenderWires = Node; // lista drutów + break; + case TP_MODEL: // modele zawsze wyświetlane z własnego VBO + // jeśli model jest prosty, można próbować zrobić wspólną siatkę (słupy) + if ((Node->iFlags & 0x20200020) == 0) // czy brak przezroczystości? + { + Node->nNext3 = nRender; + nRender = Node; + } // do nieprzezroczystych + else if ((Node->iFlags & 0x10100010) == 0) // czy brak nieprzezroczystości? + { + Node->nNext3 = nRenderAlpha; + nRenderAlpha = Node; + } // do przezroczystych + else // jak i take i takie, to będzie dwa razy renderowane... + { + Node->nNext3 = nRenderMixed; + nRenderMixed = Node; + } // do mieszanych + // Node->nNext3=nMeshed; //dopisanie do listy sortowania + // nMeshed=Node; + break; + case TP_MEMCELL: + case TP_TRACTIONPOWERSOURCE: // a te w ogóle pomijamy + // case TP_ISOLATED: //lista torów w obwodzie izolowanym - na razie ignorowana + break; + case TP_DYNAMIC: + return; // tych nie dopisujemy wcale } - else - Node->TextureID=t; //jest tylko druga tekstura - if (Node->TextureID) - {Node->nNext3=nMeshed; nMeshed=Node;} //do podzielenia potem - } - break; - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_TRIANGLES: - //Node->nNext3=nMeshed; nMeshed=Node; //do podzielenia potem - if (Node->iFlags&0x20) //czy jest przezroczyste? - {Node->nNext3=nRenderRectAlpha; nRenderRectAlpha=Node;} //DL: do przezroczystych z sektora - else - if (Global::bUseVBO) - {Node->nNext3=nRenderRect; nRenderRect=Node;} //VBO: do nieprzezroczystych z sektora - else - {Node->nNext3=nRender; nRender=Node;} //DL: do nieprzezroczystych wszelakich -/* - //Ra: na razie wyłączone do testów VBO - //if ((Node->iType==GL_TRIANGLE_STRIP)||(Node->iType==GL_TRIANGLE_FAN)||(Node->iType==GL_TRIANGLES)) - if (Node->fSquareMinRadius==0.0) //znikające z bliska nie mogą być optymalizowane - if (Node->fSquareRadius>=160000.0) //tak od 400m to już normalne trójkąty muszą być - //if (Node->iFlags&0x10) //i nieprzezroczysty - {if (pTriGroup) //jeżeli był już jakiś grupujący - {if (pTriGroup->fSquareRadius>Node->fSquareRadius) //i miał większy zasięg - Node->fSquareRadius=pTriGroup->fSquareRadius; //zwiększenie zakresu widoczności grupującego - pTriGroup->pTriGroup=Node; //poprzedniemu doczepiamy nowy - } - Node->pTriGroup=Node; //nowy lider ma się sam wyświetlać - wskaźnik na siebie - pTriGroup=Node; //zapamiętanie lidera - } -*/ - break; - case TP_TRACTION: - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: //te renderowane na końcu, żeby nie łapały koloru nieba - Node->nNext3=nRenderWires; nRenderWires=Node; //lista drutów - break; - case TP_MODEL: //modele zawsze wyświetlane z własnego VBO - //jeśli model jest prosty, można próbować zrobić wspólną siatkę (słupy) - if ((Node->iFlags&0x20200020)==0) //czy brak przezroczystości? - {Node->nNext3=nRender; nRender=Node;} //do nieprzezroczystych - else if ((Node->iFlags&0x10100010)==0) //czy brak nieprzezroczystości? - {Node->nNext3=nRenderAlpha; nRenderAlpha=Node;} //do przezroczystych - else //jak i take i takie, to będzie dwa razy renderowane... - {Node->nNext3=nRenderMixed; nRenderMixed=Node;} //do mieszanych - //Node->nNext3=nMeshed; //dopisanie do listy sortowania - //nMeshed=Node; - break; - case TP_MEMCELL: - case TP_TRACTIONPOWERSOURCE: //a te w ogóle pomijamy -// case TP_ISOLATED: //lista torów w obwodzie izolowanym - na razie ignorowana - break; - case TP_DYNAMIC: - return; //tych nie dopisujemy wcale - } - Node->nNext2=nRootNode; //dopisanie do ogólnej listy - nRootNode=Node; - ++iNodeCount; //licznik obiektów + Node->nNext2 = nRootNode; // dopisanie do ogólnej listy + nRootNode = Node; + ++iNodeCount; // licznik obiektów } void __fastcall TSubRect::RaNodeAdd(TGroundNode *Node) -{//finalna kwalifikacja na listy renderowania, jeśli nie obsługiwane grupowo - switch (Node->iType) - {case TP_TRACK: - if (Global::bUseVBO) - {Node->nNext3=nRenderRect; nRenderRect=Node;} //VBO: do nieprzezroczystych z sektora - else - {Node->nNext3=nRender; nRender=Node;} //DL: do nieprzezroczystych - break; - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_TRIANGLES: - if (Node->iFlags&0x20) //czy jest przezroczyste? - {Node->nNext3=nRenderRectAlpha; nRenderRectAlpha=Node;} //DL: do przezroczystych z sektora - else - if (Global::bUseVBO) - {Node->nNext3=nRenderRect; nRenderRect=Node;} //VBO: do nieprzezroczystych z sektora - else - {Node->nNext3=nRender; nRender=Node;} //DL: do nieprzezroczystych wszelakich - break; - case TP_MODEL: //modele zawsze wyświetlane z własnego VBO - if ((Node->iFlags&0x20200020)==0) //czy brak przezroczystości? - {Node->nNext3=nRender; nRender=Node;} //do nieprzezroczystych - else if ((Node->iFlags&0x10100010)==0) //czy brak nieprzezroczystości? - {Node->nNext3=nRenderAlpha; nRenderAlpha=Node;} //do przezroczystych - else //jak i take i takie, to będzie dwa razy renderowane... - {Node->nNext3=nRenderMixed; nRenderMixed=Node;} //do mieszanych - break; - case TP_MESH: //grupa ze wspólną teksturą - //{Node->nNext3=nRenderRect; nRenderRect=Node;} //do nieprzezroczystych z sektora - {Node->nNext3=nRender; nRender=Node;} //do nieprzezroczystych - break; - case TP_SUBMODEL: //submodele terenu w kwadracie kilometrowym idą do nRootMesh - //WriteLog("nRootMesh was "+AnsiString(nRootMesh?"not null ":"null ")+IntToHex(int(this),8)); - Node->nNext3=nRootMesh; //przy VBO musi być inaczej - nRootMesh=Node; - break; - } +{ // finalna kwalifikacja na listy renderowania, jeśli nie obsługiwane grupowo + switch (Node->iType) + { + case TP_TRACK: + if (Global::bUseVBO) + { + Node->nNext3 = nRenderRect; + nRenderRect = Node; + } // VBO: do nieprzezroczystych z sektora + else + { + Node->nNext3 = nRender; + nRender = Node; + } // DL: do nieprzezroczystych + break; + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_TRIANGLES: + if (Node->iFlags & 0x20) // czy jest przezroczyste? + { + Node->nNext3 = nRenderRectAlpha; + nRenderRectAlpha = Node; + } // DL: do przezroczystych z sektora + else if (Global::bUseVBO) + { + Node->nNext3 = nRenderRect; + nRenderRect = Node; + } // VBO: do nieprzezroczystych z sektora + else + { + Node->nNext3 = nRender; + nRender = Node; + } // DL: do nieprzezroczystych wszelakich + break; + case TP_MODEL: // modele zawsze wyświetlane z własnego VBO + if ((Node->iFlags & 0x20200020) == 0) // czy brak przezroczystości? + { + Node->nNext3 = nRender; + nRender = Node; + } // do nieprzezroczystych + else if ((Node->iFlags & 0x10100010) == 0) // czy brak nieprzezroczystości? + { + Node->nNext3 = nRenderAlpha; + nRenderAlpha = Node; + } // do przezroczystych + else // jak i take i takie, to będzie dwa razy renderowane... + { + Node->nNext3 = nRenderMixed; + nRenderMixed = Node; + } // do mieszanych + break; + case TP_MESH: // grupa ze wspólną teksturą + //{Node->nNext3=nRenderRect; nRenderRect=Node;} //do nieprzezroczystych z sektora + { + Node->nNext3 = nRender; + nRender = Node; + } // do nieprzezroczystych + break; + case TP_SUBMODEL: // submodele terenu w kwadracie kilometrowym idą do nRootMesh + // WriteLog("nRootMesh was "+AnsiString(nRootMesh?"not null ":"null + // ")+IntToHex(int(this),8)); + Node->nNext3 = nRootMesh; // przy VBO musi być inaczej + nRootMesh = Node; + break; + } } void __fastcall TSubRect::Sort() -{//przygotowanie sektora do renderowania - TGroundNode **n0,*n1,*n2; //wskaźniki robocze - delete[] tTracks; //usunięcie listy - tTracks=iTracks?new TTrack*[iTracks]:NULL; //tworzenie tabeli torów do renderowania pojazdów - if (tTracks) - {//wypełnianie tabeli torów - int i=0; - for (n1=nRootNode;n1;n1=n1->nNext2) //kolejne obiekty z sektora - if (n1->iType==TP_TRACK) - tTracks[i++]=n1->pTrack; - } - //sortowanie obiektów w sektorze na listy renderowania - if (!nMeshed) return; //nie ma nic do sortowania - bool sorted=false; - while (!sorted) - {//sortowanie bąbelkowe obiektów wg tekstury - sorted=true; //zakładamy posortowanie - n0=&nMeshed; //wskaźnik niezbędny do zamieniania obiektów - n1=nMeshed; //lista obiektów przetwarzanych na statyczne siatki - while (n1) - {//sprawdzanie stanu posortowania obiektów i ewentualne zamiany - n2=n1->nNext3; //kolejny z tej listy - if (n2) //jeśli istnieje - if (n1->TextureID>n2->TextureID) - {//zamiana elementów miejscami - *n0=n2; //drugi będzie na początku - n1->nNext3=n2->nNext3; //ten zza drugiego będzie za pierwszym - n2->nNext3=n1; //a za drugim będzie pierwszy - sorted=false; //potrzebny kolejny przebieg +{ // przygotowanie sektora do renderowania + TGroundNode **n0, *n1, *n2; // wskaźniki robocze + delete[] tTracks; // usunięcie listy + tTracks = + iTracks ? new TTrack *[iTracks] : NULL; // tworzenie tabeli torów do renderowania pojazdów + if (tTracks) + { // wypełnianie tabeli torów + int i = 0; + for (n1 = nRootNode; n1; n1 = n1->nNext2) // kolejne obiekty z sektora + if (n1->iType == TP_TRACK) + tTracks[i++] = n1->pTrack; } - n0=&(n1->nNext3); - n1=n2; - }; - } - //wyrzucenie z listy obiektów pojedynczych (nie ma z czym ich grupować) - //nawet jak są pojedyncze, to i tak lepiej, aby były w jednym Display List -/* - else - {//dodanie do zwykłej listy renderowania i usunięcie z grupowego - *n0=n2; //drugi będzie na początku - RaNodeAdd(n1); //nie ma go z czym zgrupować; (n1->nNext3) zostanie nadpisane - n1=n2; //potrzebne do ustawienia (n0) + // sortowanie obiektów w sektorze na listy renderowania + if (!nMeshed) + return; // nie ma nic do sortowania + bool sorted = false; + while (!sorted) + { // sortowanie bąbelkowe obiektów wg tekstury + sorted = true; // zakładamy posortowanie + n0 = &nMeshed; // wskaźnik niezbędny do zamieniania obiektów + n1 = nMeshed; // lista obiektów przetwarzanych na statyczne siatki + while (n1) + { // sprawdzanie stanu posortowania obiektów i ewentualne zamiany + n2 = n1->nNext3; // kolejny z tej listy + if (n2) // jeśli istnieje + if (n1->TextureID > n2->TextureID) + { // zamiana elementów miejscami + *n0 = n2; // drugi będzie na początku + n1->nNext3 = n2->nNext3; // ten zza drugiego będzie za pierwszym + n2->nNext3 = n1; // a za drugim będzie pierwszy + sorted = false; // potrzebny kolejny przebieg + } + n0 = &(n1->nNext3); + n1 = n2; + }; } -*/ - //... - //przeglądanie listy i tworzenie obiektów renderujących dla danej tekstury - GLuint t=0; //pomocniczy kod tekstury - n1=nMeshed; //lista obiektów przetwarzanych na statyczne siatki - while (n1) - {//dla każdej tekstury powinny istnieć co najmniej dwa obiekty, ale dla DL nie ma to znaczenia - if (tTextureID) //jeśli (n1) ma inną teksturę niż poprzednie - {//można zrobić obiekt renderujący - t=n1->TextureID; - n2=new TGroundNode(); - n2->nNext2=nRootMesh; nRootMesh=n2; //podczepienie na początku listy - nRootMesh->iType=TP_MESH; //obiekt renderujący siatki dla tekstury - nRootMesh->TextureID=t; - nRootMesh->nNode=n1; //pierwszy element z listy - nRootMesh->pCenter=n1->pCenter; - nRootMesh->fSquareRadius=1e8; //widać bez ograniczeń - nRootMesh->fSquareMinRadius=0.0; - nRootMesh->iFlags=0x10; - RaNodeAdd(nRootMesh); //dodanie do odpowiedniej listy renderowania - } - n1=n1->nNext3; //kolejny z tej listy - }; + // wyrzucenie z listy obiektów pojedynczych (nie ma z czym ich grupować) + // nawet jak są pojedyncze, to i tak lepiej, aby były w jednym Display List + /* + else + {//dodanie do zwykłej listy renderowania i usunięcie z grupowego + *n0=n2; //drugi będzie na początku + RaNodeAdd(n1); //nie ma go z czym zgrupować; (n1->nNext3) zostanie nadpisane + n1=n2; //potrzebne do ustawienia (n0) + } + */ + //... + // przeglądanie listy i tworzenie obiektów renderujących dla danej tekstury + GLuint t = 0; // pomocniczy kod tekstury + n1 = nMeshed; // lista obiektów przetwarzanych na statyczne siatki + while (n1) + { // dla każdej tekstury powinny istnieć co najmniej dwa obiekty, ale dla DL nie ma to znaczenia + if (t < n1->TextureID) // jeśli (n1) ma inną teksturę niż poprzednie + { // można zrobić obiekt renderujący + t = n1->TextureID; + n2 = new TGroundNode(); + n2->nNext2 = nRootMesh; + nRootMesh = n2; // podczepienie na początku listy + nRootMesh->iType = TP_MESH; // obiekt renderujący siatki dla tekstury + nRootMesh->TextureID = t; + nRootMesh->nNode = n1; // pierwszy element z listy + nRootMesh->pCenter = n1->pCenter; + nRootMesh->fSquareRadius = 1e8; // widać bez ograniczeń + nRootMesh->fSquareMinRadius = 0.0; + nRootMesh->iFlags = 0x10; + RaNodeAdd(nRootMesh); // dodanie do odpowiedniej listy renderowania + } + n1 = n1->nNext3; // kolejny z tej listy + }; } -TTrack* __fastcall TSubRect::FindTrack(vector3 *Point,int &iConnection,TTrack *Exclude) -{//szukanie toru, którego koniec jest najbliższy (*Point) - TTrack *Track; - for (int i=0;iTestPoint(Point); - if (iConnection>=0) return tTracks[i]; //szukanie TGroundNode nie jest potrzebne - } -/* - TGroundNode *Current; - for (Current=nRootNode;Current;Current=Current->Next) - if ((Current->iType==TP_TRACK)&&(Current->pTrack!=Exclude)) //można użyć tabelę torów - { - iConnection=Current->pTrack->TestPoint(Point); - if (iConnection>=0) return Current; - } -*/ - return NULL; +TTrack *__fastcall TSubRect::FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude) +{ // szukanie toru, którego koniec jest najbliższy (*Point) + TTrack *Track; + for (int i = 0; i < iTracks; ++i) + if (tTracks[i] != Exclude) // można użyć tabelę torów, bo jest mniejsza + { + iConnection = tTracks[i]->TestPoint(Point); + if (iConnection >= 0) + return tTracks[i]; // szukanie TGroundNode nie jest potrzebne + } + /* + TGroundNode *Current; + for (Current=nRootNode;Current;Current=Current->Next) + if ((Current->iType==TP_TRACK)&&(Current->pTrack!=Exclude)) //można użyć tabelę torów + { + iConnection=Current->pTrack->TestPoint(Point); + if (iConnection>=0) return Current; + } + */ + return NULL; }; bool __fastcall TSubRect::RaTrackAnimAdd(TTrack *t) -{//aktywacja animacji torów w VBO (zwrotnica, obrotnica) - if (m_nVertexCount<0) return true; //nie ma animacji, gdy nie widać - if (tTrackAnim) - tTrackAnim->RaAnimListAdd(t); - else - tTrackAnim=t; - return false; //będzie animowane... +{ // aktywacja animacji torów w VBO (zwrotnica, obrotnica) + if (m_nVertexCount < 0) + return true; // nie ma animacji, gdy nie widać + if (tTrackAnim) + tTrackAnim->RaAnimListAdd(t); + else + tTrackAnim = t; + return false; // będzie animowane... } void __fastcall TSubRect::RaAnimate() -{//wykonanie animacji - if (!tTrackAnim) return; //nie ma nic do animowania - if (Global::bUseVBO) - {//odświeżenie VBO sektora - if (Global::bOpenGL_1_5) //modyfikacje VBO są dostępne od OpenGL 1.5 - glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_nVBOVertices); - else //dla OpenGL 1.4 z GL_ARB_vertex_buffer_object odświeżenie całego sektora - Release(); //opróżnienie VBO sektora, aby się odświeżył z nowymi ustawieniami - } - tTrackAnim=tTrackAnim->RaAnimate(); //przeliczenie animacji kolejnego +{ // wykonanie animacji + if (!tTrackAnim) + return; // nie ma nic do animowania + if (Global::bUseVBO) + { // odświeżenie VBO sektora + if (Global::bOpenGL_1_5) // modyfikacje VBO są dostępne od OpenGL 1.5 + glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_nVBOVertices); + else // dla OpenGL 1.4 z GL_ARB_vertex_buffer_object odświeżenie całego sektora + Release(); // opróżnienie VBO sektora, aby się odświeżył z nowymi ustawieniami + } + tTrackAnim = tTrackAnim->RaAnimate(); // przeliczenie animacji kolejnego }; -TTraction* __fastcall TSubRect::FindTraction(vector3 *Point,int &iConnection,TTraction *Exclude) -{//szukanie przęsła w sektorze, którego koniec jest najbliższy (*Point) - TGroundNode *Current; - for (Current=nRenderWires;Current;Current=Current->nNext3) - if ((Current->iType==TP_TRACTION)&&(Current->hvTraction!=Exclude)) - { - iConnection=Current->hvTraction->TestPoint(Point); - if (iConnection>=0) return Current->hvTraction; - } - return NULL; +TTraction *__fastcall TSubRect::FindTraction(vector3 *Point, int &iConnection, TTraction *Exclude) +{ // szukanie przęsła w sektorze, którego koniec jest najbliższy (*Point) + TGroundNode *Current; + for (Current = nRenderWires; Current; Current = Current->nNext3) + if ((Current->iType == TP_TRACTION) && (Current->hvTraction != Exclude)) + { + iConnection = Current->hvTraction->TestPoint(Point); + if (iConnection >= 0) + return Current->hvTraction; + } + return NULL; }; void __fastcall TSubRect::LoadNodes() -{//utworzenie siatek VBO dla wszystkich node w sektorze - if (m_nVertexCount>=0) return; //obiekty były już sprawdzone - m_nVertexCount=0; //-1 oznacza, że nie sprawdzono listy obiektów - if (!nRootNode) return; - TGroundNode *n=nRootNode; - while (n) - {switch (n->iType) - {case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_TRIANGLES: - n->iVboPtr=m_nVertexCount; //nowy początek - m_nVertexCount+=n->iNumVerts; - break; - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - n->iVboPtr=m_nVertexCount; //nowy początek - m_nVertexCount+=n->iNumPts; //miejsce w tablicach normalnych i teksturowania się zmarnuje... - break; - case TP_TRACK: - n->iVboPtr=m_nVertexCount; //nowy początek - n->iNumVerts=n->pTrack->RaArrayPrepare(); //zliczenie wierzchołków - m_nVertexCount+=n->iNumVerts; - break; - case TP_TRACTION: - n->iVboPtr=m_nVertexCount; //nowy początek - n->iNumVerts=n->hvTraction->RaArrayPrepare(); //zliczenie wierzchołków - m_nVertexCount+=n->iNumVerts; - break; - } - n=n->nNext2; //następny z sektora - } - if (!m_nVertexCount) return; //jeśli nie ma obiektów do wyświetlenia z VBO, to koniec - if (Global::bUseVBO) - {//tylko liczenie wierzchołów, gdy nie ma VBO - MakeArray(m_nVertexCount); - n=nRootNode; - int i; - while (n) - {if (n->iVboPtr>=0) - switch (n->iType) - {case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_TRIANGLES: - for (i=0;iiNumVerts;++i) - {//Ra: trójkąty można od razu wczytywać do takich tablic... to może poczekać - m_pVNT[n->iVboPtr+i].x=n->Vertices[i].Point.x; - m_pVNT[n->iVboPtr+i].y=n->Vertices[i].Point.y; - m_pVNT[n->iVboPtr+i].z=n->Vertices[i].Point.z; - m_pVNT[n->iVboPtr+i].nx=n->Vertices[i].Normal.x; - m_pVNT[n->iVboPtr+i].ny=n->Vertices[i].Normal.y; - m_pVNT[n->iVboPtr+i].nz=n->Vertices[i].Normal.z; - m_pVNT[n->iVboPtr+i].u=n->Vertices[i].tu; - m_pVNT[n->iVboPtr+i].v=n->Vertices[i].tv; - } - break; - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - for (i=0;iiNumPts;++i) - { - m_pVNT[n->iVboPtr+i].x=n->Points[i].x; - m_pVNT[n->iVboPtr+i].y=n->Points[i].y; - m_pVNT[n->iVboPtr+i].z=n->Points[i].z; - //miejsce w tablicach normalnych i teksturowania się marnuje... - } - break; - case TP_TRACK: - if (n->iNumVerts) //bo tory zabezpieczające są niewidoczne - n->pTrack->RaArrayFill(m_pVNT+n->iVboPtr,m_pVNT); - break; - case TP_TRACTION: - if (n->iNumVerts) //druty mogą być niewidoczne...? - n->hvTraction->RaArrayFill(m_pVNT+n->iVboPtr); - break; +{ // utworzenie siatek VBO dla wszystkich node w sektorze + if (m_nVertexCount >= 0) + return; // obiekty były już sprawdzone + m_nVertexCount = 0; //-1 oznacza, że nie sprawdzono listy obiektów + if (!nRootNode) + return; + TGroundNode *n = nRootNode; + while (n) + { + switch (n->iType) + { + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_TRIANGLES: + n->iVboPtr = m_nVertexCount; // nowy początek + m_nVertexCount += n->iNumVerts; + break; + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + n->iVboPtr = m_nVertexCount; // nowy początek + m_nVertexCount += + n->iNumPts; // miejsce w tablicach normalnych i teksturowania się zmarnuje... + break; + case TP_TRACK: + n->iVboPtr = m_nVertexCount; // nowy początek + n->iNumVerts = n->pTrack->RaArrayPrepare(); // zliczenie wierzchołków + m_nVertexCount += n->iNumVerts; + break; + case TP_TRACTION: + n->iVboPtr = m_nVertexCount; // nowy początek + n->iNumVerts = n->hvTraction->RaArrayPrepare(); // zliczenie wierzchołków + m_nVertexCount += n->iNumVerts; + break; + } + n = n->nNext2; // następny z sektora } - n=n->nNext2; //następny z sektora - } - BuildVBOs(); - } - if (Global::bManageNodes) - ResourceManager::Register(this); //dodanie do automatu zwalniającego pamięć + if (!m_nVertexCount) + return; // jeśli nie ma obiektów do wyświetlenia z VBO, to koniec + if (Global::bUseVBO) + { // tylko liczenie wierzchołów, gdy nie ma VBO + MakeArray(m_nVertexCount); + n = nRootNode; + int i; + while (n) + { + if (n->iVboPtr >= 0) + switch (n->iType) + { + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_TRIANGLES: + for (i = 0; i < n->iNumVerts; ++i) + { // Ra: trójkąty można od razu wczytywać do takich tablic... to może poczekać + m_pVNT[n->iVboPtr + i].x = n->Vertices[i].Point.x; + m_pVNT[n->iVboPtr + i].y = n->Vertices[i].Point.y; + m_pVNT[n->iVboPtr + i].z = n->Vertices[i].Point.z; + m_pVNT[n->iVboPtr + i].nx = n->Vertices[i].Normal.x; + m_pVNT[n->iVboPtr + i].ny = n->Vertices[i].Normal.y; + m_pVNT[n->iVboPtr + i].nz = n->Vertices[i].Normal.z; + m_pVNT[n->iVboPtr + i].u = n->Vertices[i].tu; + m_pVNT[n->iVboPtr + i].v = n->Vertices[i].tv; + } + break; + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + for (i = 0; i < n->iNumPts; ++i) + { + m_pVNT[n->iVboPtr + i].x = n->Points[i].x; + m_pVNT[n->iVboPtr + i].y = n->Points[i].y; + m_pVNT[n->iVboPtr + i].z = n->Points[i].z; + // miejsce w tablicach normalnych i teksturowania się marnuje... + } + break; + case TP_TRACK: + if (n->iNumVerts) // bo tory zabezpieczające są niewidoczne + n->pTrack->RaArrayFill(m_pVNT + n->iVboPtr, m_pVNT); + break; + case TP_TRACTION: + if (n->iNumVerts) // druty mogą być niewidoczne...? + n->hvTraction->RaArrayFill(m_pVNT + n->iVboPtr); + break; + } + n = n->nNext2; // następny z sektora + } + BuildVBOs(); + } + if (Global::bManageNodes) + ResourceManager::Register(this); // dodanie do automatu zwalniającego pamięć } bool __fastcall TSubRect::StartVBO() -{//początek rysowania elementów z VBO w sektorze - SetLastUsage(Timer::GetSimulationTime()); //te z tyłu będą niepotrzebnie zwalniane - return CMesh::StartVBO(); +{ // początek rysowania elementów z VBO w sektorze + SetLastUsage(Timer::GetSimulationTime()); // te z tyłu będą niepotrzebnie zwalniane + return CMesh::StartVBO(); }; void TSubRect::Release() -{//wirtualne zwolnienie zasobów przez sprzątacz albo destruktor - if (Global::bUseVBO) - CMesh::Clear(); //usuwanie buforów +{ // wirtualne zwolnienie zasobów przez sprzątacz albo destruktor + if (Global::bUseVBO) + CMesh::Clear(); // usuwanie buforów }; void __fastcall TSubRect::RenderDL() -{//renderowanie nieprzezroczystych (DL) - TGroundNode *node; - RaAnimate(); //przeliczenia animacji torów w sektorze - for (node=nRender;node;node=node->nNext3) - node->RenderDL(); //nieprzezroczyste obiekty (oprócz pojazdów) - for (node=nRenderMixed;node;node=node->nNext3) - node->RenderDL(); //nieprzezroczyste z mieszanych modeli - for (int j=0;jRenderDyn(); //nieprzezroczyste fragmenty pojazdów na torach +{ // renderowanie nieprzezroczystych (DL) + TGroundNode *node; + RaAnimate(); // przeliczenia animacji torów w sektorze + for (node = nRender; node; node = node->nNext3) + node->RenderDL(); // nieprzezroczyste obiekty (oprócz pojazdów) + for (node = nRenderMixed; node; node = node->nNext3) + node->RenderDL(); // nieprzezroczyste z mieszanych modeli + for (int j = 0; j < iTracks; ++j) + tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach }; void __fastcall TSubRect::RenderAlphaDL() -{//renderowanie przezroczystych modeli oraz pojazdów (DL) - TGroundNode *node; - for (node=nRenderMixed;node;node=node->nNext3) - node->RenderAlphaDL(); //przezroczyste z mieszanych modeli - for (node=nRenderAlpha;node;node=node->nNext3) - node->RenderAlphaDL(); //przezroczyste modele - //for (node=tmp->nRender;node;node=node->nNext3) - // if (node->iType==TP_TRACK) - // node->pTrack->RenderAlpha(); //przezroczyste fragmenty pojazdów na torach - for (int j=0;jRenderDynAlpha(); //przezroczyste fragmenty pojazdów na torach +{ // renderowanie przezroczystych modeli oraz pojazdów (DL) + TGroundNode *node; + for (node = nRenderMixed; node; node = node->nNext3) + node->RenderAlphaDL(); // przezroczyste z mieszanych modeli + for (node = nRenderAlpha; node; node = node->nNext3) + node->RenderAlphaDL(); // przezroczyste modele + // for (node=tmp->nRender;node;node=node->nNext3) + // if (node->iType==TP_TRACK) + // node->pTrack->RenderAlpha(); //przezroczyste fragmenty pojazdów na torach + for (int j = 0; j < iTracks; ++j) + tTracks[j]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach }; void __fastcall TSubRect::RenderVBO() -{//renderowanie nieprzezroczystych (VBO) - TGroundNode *node; - RaAnimate(); //przeliczenia animacji torów w sektorze - LoadNodes(); //czemu tutaj? - if (StartVBO()) - {for (node=nRenderRect;node;node=node->nNext3) - if (node->iVboPtr>=0) - node->RenderVBO(); //nieprzezroczyste obiekty terenu - EndVBO(); - } - for (node=nRender;node;node=node->nNext3) - node->RenderVBO(); //nieprzezroczyste obiekty (oprócz pojazdów) - for (node=nRenderMixed;node;node=node->nNext3) - node->RenderVBO(); //nieprzezroczyste z mieszanych modeli - for (int j=0;jRenderDyn(); //nieprzezroczyste fragmenty pojazdów na torach +{ // renderowanie nieprzezroczystych (VBO) + TGroundNode *node; + RaAnimate(); // przeliczenia animacji torów w sektorze + LoadNodes(); // czemu tutaj? + if (StartVBO()) + { + for (node = nRenderRect; node; node = node->nNext3) + if (node->iVboPtr >= 0) + node->RenderVBO(); // nieprzezroczyste obiekty terenu + EndVBO(); + } + for (node = nRender; node; node = node->nNext3) + node->RenderVBO(); // nieprzezroczyste obiekty (oprócz pojazdów) + for (node = nRenderMixed; node; node = node->nNext3) + node->RenderVBO(); // nieprzezroczyste z mieszanych modeli + for (int j = 0; j < iTracks; ++j) + tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach }; void __fastcall TSubRect::RenderAlphaVBO() -{//renderowanie przezroczystych modeli oraz pojazdów (VBO) - TGroundNode *node; - for (node=nRenderMixed;node;node=node->nNext3) - node->RenderAlphaVBO(); //przezroczyste z mieszanych modeli - for (node=nRenderAlpha;node;node=node->nNext3) - node->RenderAlphaVBO(); //przezroczyste modele - //for (node=tmp->nRender;node;node=node->nNext3) - // if (node->iType==TP_TRACK) - // node->pTrack->RenderAlpha(); //przezroczyste fragmenty pojazdów na torach - for (int j=0;jRenderDynAlpha(); //przezroczyste fragmenty pojazdów na torach +{ // renderowanie przezroczystych modeli oraz pojazdów (VBO) + TGroundNode *node; + for (node = nRenderMixed; node; node = node->nNext3) + node->RenderAlphaVBO(); // przezroczyste z mieszanych modeli + for (node = nRenderAlpha; node; node = node->nNext3) + node->RenderAlphaVBO(); // przezroczyste modele + // for (node=tmp->nRender;node;node=node->nNext3) + // if (node->iType==TP_TRACK) + // node->pTrack->RenderAlpha(); //przezroczyste fragmenty pojazdów na torach + for (int j = 0; j < iTracks; ++j) + tTracks[j]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach }; void __fastcall TSubRect::RenderSounds() -{//aktualizacja dźwięków w pojazdach sektora (sektor może nie być wyświetlany) - for (int j=0;jRenderDynSounds(); //dźwięki pojazdów idą niezależnie od wyświetlania +{ // aktualizacja dźwięków w pojazdach sektora (sektor może nie być wyświetlany) + for (int j = 0; j < iTracks; ++j) + tTracks[j]->RenderDynSounds(); // dźwięki pojazdów idą niezależnie od wyświetlania }; //--------------------------------------------------------------------------- //------------------ Kwadrat kilometrowy ------------------------------------ //--------------------------------------------------------------------------- -int TGroundRect::iFrameNumber=0; //licznik wyświetlanych klatek +int TGroundRect::iFrameNumber = 0; // licznik wyświetlanych klatek __fastcall TGroundRect::TGroundRect() { - pSubRects=NULL; - nTerrain=NULL; + pSubRects = NULL; + nTerrain = NULL; }; -__fastcall TGroundRect::~TGroundRect() -{ - SafeDeleteArray(pSubRects); -}; +__fastcall TGroundRect::~TGroundRect() { SafeDeleteArray(pSubRects); }; void __fastcall TGroundRect::RenderDL() -{//renderowanie kwadratu kilometrowego (DL), jeśli jeszcze nie zrobione - if (iLastDisplay!=iFrameNumber) - {//tylko jezeli dany kwadrat nie był jeszcze renderowany - //for (TGroundNode* node=pRender;node;node=node->pNext3) - // node->Render(); //nieprzezroczyste trójkąty kwadratu kilometrowego - if (nRender) - {//łączenie trójkątów w jedną listę - trochę wioska - if (!nRender->DisplayListID||(nRender->iVersion!=Global::iReCompile)) - {//jeżeli nie skompilowany, kompilujemy wszystkie trójkąty w jeden - nRender->fSquareRadius=5000.0*5000.0; //aby agregat nigdy nie znikał - nRender->DisplayListID=glGenLists(1); - glNewList(nRender->DisplayListID,GL_COMPILE); - nRender->iVersion=Global::iReCompile; //aktualna wersja siatek - for (TGroundNode* node=nRender;node;node=node->nNext3) //następny tej grupy - node->Compile(true); - glEndList(); - } - nRender->RenderDL(); //nieprzezroczyste trójkąty kwadratu kilometrowego - } - if (nRootMesh) - nRootMesh->RenderDL(); - iLastDisplay=iFrameNumber; //drugi raz nie potrzeba - } +{ // renderowanie kwadratu kilometrowego (DL), jeśli jeszcze nie zrobione + if (iLastDisplay != iFrameNumber) + { // tylko jezeli dany kwadrat nie był jeszcze renderowany + // for (TGroundNode* node=pRender;node;node=node->pNext3) + // node->Render(); //nieprzezroczyste trójkąty kwadratu kilometrowego + if (nRender) + { //łączenie trójkątów w jedną listę - trochę wioska + if (!nRender->DisplayListID || (nRender->iVersion != Global::iReCompile)) + { // jeżeli nie skompilowany, kompilujemy wszystkie trójkąty w jeden + nRender->fSquareRadius = 5000.0 * 5000.0; // aby agregat nigdy nie znikał + nRender->DisplayListID = glGenLists(1); + glNewList(nRender->DisplayListID, GL_COMPILE); + nRender->iVersion = Global::iReCompile; // aktualna wersja siatek + for (TGroundNode *node = nRender; node; node = node->nNext3) // następny tej grupy + node->Compile(true); + glEndList(); + } + nRender->RenderDL(); // nieprzezroczyste trójkąty kwadratu kilometrowego + } + if (nRootMesh) + nRootMesh->RenderDL(); + iLastDisplay = iFrameNumber; // drugi raz nie potrzeba + } }; void __fastcall TGroundRect::RenderVBO() -{//renderowanie kwadratu kilometrowego (VBO), jeśli jeszcze nie zrobione - if (iLastDisplay!=iFrameNumber) - {//tylko jezeli dany kwadrat nie był jeszcze renderowany - LoadNodes(); //ewentualne tworzenie siatek - if (StartVBO()) - {for (TGroundNode* node=nRenderRect;node;node=node->nNext3) //następny tej grupy - node->RaRenderVBO(); //nieprzezroczyste trójkąty kwadratu kilometrowego - EndVBO(); - iLastDisplay=iFrameNumber; - } - if (nTerrain) - nTerrain->smTerrain->iVisible=iFrameNumber; //ma się wyświetlić w tej ramce - } +{ // renderowanie kwadratu kilometrowego (VBO), jeśli jeszcze nie zrobione + if (iLastDisplay != iFrameNumber) + { // tylko jezeli dany kwadrat nie był jeszcze renderowany + LoadNodes(); // ewentualne tworzenie siatek + if (StartVBO()) + { + for (TGroundNode *node = nRenderRect; node; node = node->nNext3) // następny tej grupy + node->RaRenderVBO(); // nieprzezroczyste trójkąty kwadratu kilometrowego + EndVBO(); + iLastDisplay = iFrameNumber; + } + if (nTerrain) + nTerrain->smTerrain->iVisible = iFrameNumber; // ma się wyświetlić w tej ramce + } }; //--------------------------------------------------------------------------- @@ -1153,2078 +1259,2377 @@ void __fastcall TGroundRect::RenderVBO() //--------------------------------------------------------------------------- void __fastcall TGround::MoveGroundNode(vector3 pPosition) -{//Ra: to wymaga gruntownej reformy -/* - TGroundNode *Current; - for (Current=RootNode;Current!=NULL;Current=Current->Next) - Current->MoveMe(pPosition); +{ // Ra: to wymaga gruntownej reformy + /* + TGroundNode *Current; + for (Current=RootNode;Current!=NULL;Current=Current->Next) + Current->MoveMe(pPosition); - TGroundRect *Rectx=new TGroundRect; //kwadrat kilometrowy - for(int i=0;iNext) - {//rozłożenie obiektów na mapie - if (Current->iType!=TP_DYNAMIC) - {//pojazdów to w ogóle nie dotyczy - if ((Current->iType!=GL_TRIANGLES)&&(Current->iType!=GL_TRIANGLE_STRIP)?true //~czy trójkąt? - :(Current->iFlags&0x20)?true //~czy teksturę ma nieprzezroczystą? - //:(Current->iNumVerts!=3)?true //~czy tylko jeden trójkąt? - :(Current->fSquareMinRadius!=0.0)?true //~czy widoczny z bliska? - :(Current->fSquareRadius<=90000.0)) //~czy widoczny z daleka? - GetSubRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current); - else //dodajemy do kwadratu kilometrowego - GetRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current); - } - } - for (Current=RootDynamic;Current!=NULL;Current=Current->Next) - { - Current->pCenter+=pPosition; - Current->DynamicObject->UpdatePos(); - } - for (Current=RootDynamic;Current!=NULL;Current=Current->Next) - Current->DynamicObject->MoverParameters->Physic_ReActivation(); -*/ + TGroundRect *Rectx=new TGroundRect; //kwadrat kilometrowy + for(int i=0;iNext) + {//rozłożenie obiektów na mapie + if (Current->iType!=TP_DYNAMIC) + {//pojazdów to w ogóle nie dotyczy + if ((Current->iType!=GL_TRIANGLES)&&(Current->iType!=GL_TRIANGLE_STRIP)?true //~czy trójkąt? + :(Current->iFlags&0x20)?true //~czy teksturę ma nieprzezroczystą? + //:(Current->iNumVerts!=3)?true //~czy tylko jeden trójkąt? + :(Current->fSquareMinRadius!=0.0)?true //~czy widoczny z bliska? + :(Current->fSquareRadius<=90000.0)) //~czy widoczny z daleka? + GetSubRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current); + else //dodajemy do kwadratu kilometrowego + GetRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current); + } + } + for (Current=RootDynamic;Current!=NULL;Current=Current->Next) + { + Current->pCenter+=pPosition; + Current->DynamicObject->UpdatePos(); + } + for (Current=RootDynamic;Current!=NULL;Current=Current->Next) + Current->DynamicObject->MoverParameters->Physic_ReActivation(); + */ } __fastcall TGround::TGround() { - //RootNode=NULL; - nRootDynamic=NULL; - QueryRootEvent=NULL; - tmpEvent=NULL; - tmp2Event=NULL; - OldQRE=NULL; - RootEvent=NULL; - iNumNodes=0; - //pTrain=NULL; - Global::pGround=this; - bInitDone=false; //Ra: żeby nie robiło dwa razy FirstInit - for (int i=0;ievNext2; - delete tmp; - } - TGroundNode *tmpn; - for (int i=0;inNext; - delete tmpn; - } - nRootOfType[i]=NULL; - } - for (TGroundNode *Current=nRootDynamic;Current;) - { - tmpn=Current; - Current=Current->nNext; - delete tmpn; - } - iNumNodes=0; - //RootNode=NULL; - nRootDynamic=NULL; - delete sTracks; + TEvent *tmp; + for (TEvent *Current = RootEvent; Current;) + { + tmp = Current; + Current = Current->evNext2; + delete tmp; + } + TGroundNode *tmpn; + for (int i = 0; i < TP_LAST; ++i) + { + for (TGroundNode *Current = nRootOfType[i]; Current;) + { + tmpn = Current; + Current = Current->nNext; + delete tmpn; + } + nRootOfType[i] = NULL; + } + for (TGroundNode *Current = nRootDynamic; Current;) + { + tmpn = Current; + Current = Current->nNext; + delete tmpn; + } + iNumNodes = 0; + // RootNode=NULL; + nRootDynamic = NULL; + delete sTracks; } -TGroundNode* __fastcall TGround::DynamicFindAny(AnsiString asNameToFind) -{//wyszukanie pojazdu o podanej nazwie, szukanie po wszystkich (użyć drzewa!) - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - if ((Current->asName==asNameToFind)) - return Current; - return NULL; +TGroundNode *__fastcall TGround::DynamicFindAny(AnsiString asNameToFind) +{ // wyszukanie pojazdu o podanej nazwie, szukanie po wszystkich (użyć drzewa!) + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + if ((Current->asName == asNameToFind)) + return Current; + return NULL; }; -TGroundNode* __fastcall TGround::DynamicFind(AnsiString asNameToFind) -{//wyszukanie pojazdu z obsadą o podanej nazwie (użyć drzewa!) - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - if (Current->DynamicObject->Mechanik) - if ((Current->asName==asNameToFind)) - return Current; - return NULL; +TGroundNode *__fastcall TGround::DynamicFind(AnsiString asNameToFind) +{ // wyszukanie pojazdu z obsadą o podanej nazwie (użyć drzewa!) + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + if (Current->DynamicObject->Mechanik) + if ((Current->asName == asNameToFind)) + return Current; + return NULL; }; void __fastcall TGround::DynamicList(bool all) -{//odesłanie nazw pojazdów dostępnych na scenerii (nazwy, szczególnie wagonów, mogą się powtarzać!) - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - if (all||Current->DynamicObject->Mechanik) - WyslijString(Current->asName,6); //same nazwy pojazdów - WyslijString("none",6); //informacja o końcu listy +{ // odesłanie nazw pojazdów dostępnych na scenerii (nazwy, szczególnie wagonów, mogą się + // powtarzać!) + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + if (all || Current->DynamicObject->Mechanik) + WyslijString(Current->asName, 6); // same nazwy pojazdów + WyslijString("none", 6); // informacja o końcu listy }; -TGroundNode* __fastcall TGround::FindGroundNode(AnsiString asNameToFind,TGroundNodeType iNodeType) -{//wyszukiwanie obiektu o podanej nazwie i konkretnym typie - if ((iNodeType==TP_TRACK)||(iNodeType==TP_MEMCELL)||(iNodeType==TP_MODEL)) - {//wyszukiwanie w drzewie binarnym - return (TGroundNode*)sTracks->Find(iNodeType,asNameToFind.c_str()); - } - //standardowe wyszukiwanie liniowe - TGroundNode *Current; - for (Current=nRootOfType[iNodeType];Current;Current=Current->nNext) - if (Current->asName==asNameToFind) - return Current; - return NULL; +TGroundNode *__fastcall TGround::FindGroundNode(AnsiString asNameToFind, TGroundNodeType iNodeType) +{ // wyszukiwanie obiektu o podanej nazwie i konkretnym typie + if ((iNodeType == TP_TRACK) || (iNodeType == TP_MEMCELL) || (iNodeType == TP_MODEL)) + { // wyszukiwanie w drzewie binarnym + return (TGroundNode *)sTracks->Find(iNodeType, asNameToFind.c_str()); + } + // standardowe wyszukiwanie liniowe + TGroundNode *Current; + for (Current = nRootOfType[iNodeType]; Current; Current = Current->nNext) + if (Current->asName == asNameToFind) + return Current; + return NULL; } +double fTrainSetVel = 0; +double fTrainSetDir = 0; +double fTrainSetDist = 0; // odległość składu od punktu 1 w stronę punktu 2 +AnsiString asTrainSetTrack = ""; +int iTrainSetConnection = 0; +bool bTrainSet = false; +AnsiString asTrainName = ""; +int iTrainSetWehicleNumber = 0; +TGroundNode *nTrainSetNode = NULL; // poprzedni pojazd do łączenia +TGroundNode *nTrainSetDriver = NULL; // pojazd, któremu zostanie wysłany rozkład -double fTrainSetVel=0; -double fTrainSetDir=0; -double fTrainSetDist=0; //odległość składu od punktu 1 w stronę punktu 2 -AnsiString asTrainSetTrack=""; -int iTrainSetConnection=0; -bool bTrainSet=false; -AnsiString asTrainName=""; -int iTrainSetWehicleNumber=0; -TGroundNode *nTrainSetNode=NULL; //poprzedni pojazd do łączenia -TGroundNode *nTrainSetDriver=NULL; //pojazd, któremu zostanie wysłany rozkład +TGroundVertex TempVerts[10000]; // tu wczytywane są trójkąty +Byte TempConnectionType[200]; // Ra: sprzęgi w składzie; ujemne, gdy odwrotnie -TGroundVertex TempVerts[10000]; //tu wczytywane są trójkąty -Byte TempConnectionType[200]; //Ra: sprzęgi w składzie; ujemne, gdy odwrotnie - -void __fastcall TGround::RaTriangleDivider(TGroundNode* node) -{//tworzy dodatkowe trójkąty i zmiejsza podany - //to jest wywoływane przy wczytywaniu trójkątów - //dodatkowe trójkąty są dodawane do głównej listy trójkątów - //podział trójkątów na sektory i kwadraty jest dokonywany później w FirstInit - if (node->iType!=GL_TRIANGLES) return; //tylko pojedyncze trójkąty - if (node->iNumVerts!=3) return; //tylko gdy jeden trójkąt - double x0=1000.0*floor(0.001*node->pCenter.x)-200.0; double x1=x0+1400.0; - double z0=1000.0*floor(0.001*node->pCenter.z)-200.0; double z1=z0+1400.0; - if ( - (node->Vertices[0].Point.x>=x0) && (node->Vertices[0].Point.x<=x1) && - (node->Vertices[0].Point.z>=z0) && (node->Vertices[0].Point.z<=z1) && - (node->Vertices[1].Point.x>=x0) && (node->Vertices[1].Point.x<=x1) && - (node->Vertices[1].Point.z>=z0) && (node->Vertices[1].Point.z<=z1) && - (node->Vertices[2].Point.x>=x0) && (node->Vertices[2].Point.x<=x1) && - (node->Vertices[2].Point.z>=z0) && (node->Vertices[2].Point.z<=z1)) - return; //trójkąt wystający mniej niż 200m z kw. kilometrowego jest do przyjęcia - //Ra: przerobić na dzielenie na 2 trójkąty, podział w przecięciu z siatką kilometrową - //Ra: i z rekurencją będzie dzielić trzy trójkąty, jeśli będzie taka potrzeba - int divide=-1; //bok do podzielenia: 0=AB, 1=BC, 2=CA; +4=podział po OZ; +8 na x1/z1 - double min=0,mul; //jeśli przechodzi przez oś, iloczyn będzie ujemny - x0+=200.0; x1-=200.0; //przestawienie na siatkę - z0+=200.0; z1-=200.0; - mul=(node->Vertices[0].Point.x-x0)*(node->Vertices[1].Point.x-x0); //AB na wschodzie - if (mulVertices[1].Point.x-x0)*(node->Vertices[2].Point.x-x0); //BC na wschodzie - if (mulVertices[2].Point.x-x0)*(node->Vertices[0].Point.x-x0); //CA na wschodzie - if (mulVertices[0].Point.x-x1)*(node->Vertices[1].Point.x-x1); //AB na zachodzie - if (mulVertices[1].Point.x-x1)*(node->Vertices[2].Point.x-x1); //BC na zachodzie - if (mulVertices[2].Point.x-x1)*(node->Vertices[0].Point.x-x1); //CA na zachodzie - if (mulVertices[0].Point.z-z0)*(node->Vertices[1].Point.z-z0); //AB na południu - if (mulVertices[1].Point.z-z0)*(node->Vertices[2].Point.z-z0); //BC na południu - if (mulVertices[2].Point.z-z0)*(node->Vertices[0].Point.z-z0); //CA na południu - if (mulVertices[0].Point.z-z1)*(node->Vertices[1].Point.z-z1); //AB na północy - if (mulVertices[1].Point.z-z1)*(node->Vertices[2].Point.z-z1); //BC na północy - if (mulVertices[2].Point.z-z1)*(node->Vertices[0].Point.z-z1); //CA na północy - if (muliType=GL_TRIANGLES; //kopiowanie parametrów, przydałby się konstruktor kopiujący - ntri->Init(3); - ntri->TextureID=node->TextureID; - ntri->iFlags=node->iFlags; - for (int j=0;j<4;++j) - {ntri->Ambient[j]=node->Ambient[j]; - ntri->Diffuse[j]=node->Diffuse[j]; - ntri->Specular[j]=node->Specular[j]; - } - ntri->asName=node->asName; - ntri->fSquareRadius=node->fSquareRadius; - ntri->fSquareMinRadius=node->fSquareMinRadius; - ntri->bVisible=node->bVisible; //a są jakieś niewidoczne? - ntri->nNext=nRootOfType[GL_TRIANGLES]; - nRootOfType[GL_TRIANGLES]=ntri; //dopisanie z przodu do listy - iNumNodes++; - switch (divide&3) - {//podzielenie jednego z boków, powstaje wierzchołek D - case 0: //podział AB (0-1) -> ADC i DBC - ntri->Vertices[2]=node->Vertices[2]; //wierzchołek C jest wspólny - ntri->Vertices[1]=node->Vertices[1]; //wierzchołek B przechodzi do nowego - //node->Vertices[1].HalfSet(node->Vertices[0],node->Vertices[1]); //na razie D tak - if (divide&4) - node->Vertices[1].SetByZ(node->Vertices[0],node->Vertices[1],divide&8?z1:z0); - else - node->Vertices[1].SetByX(node->Vertices[0],node->Vertices[1],divide&8?x1:x0); - ntri->Vertices[0]=node->Vertices[1]; //wierzchołek D jest wspólny - break; - case 1: //podział BC (1-2) -> ABD i ADC - ntri->Vertices[0]=node->Vertices[0]; //wierzchołek A jest wspólny - ntri->Vertices[2]=node->Vertices[2]; //wierzchołek C przechodzi do nowego - //node->Vertices[2].HalfSet(node->Vertices[1],node->Vertices[2]); //na razie D tak - if (divide&4) - node->Vertices[2].SetByZ(node->Vertices[1],node->Vertices[2],divide&8?z1:z0); - else - node->Vertices[2].SetByX(node->Vertices[1],node->Vertices[2],divide&8?x1:x0); - ntri->Vertices[1]=node->Vertices[2]; //wierzchołek D jest wspólny - break; - case 2: //podział CA (2-0) -> ABD i DBC - ntri->Vertices[1]=node->Vertices[1]; //wierzchołek B jest wspólny - ntri->Vertices[2]=node->Vertices[2]; //wierzchołek C przechodzi do nowego - //node->Vertices[2].HalfSet(node->Vertices[2],node->Vertices[0]); //na razie D tak - if (divide&4) - node->Vertices[2].SetByZ(node->Vertices[2],node->Vertices[0],divide&8?z1:z0); - else - node->Vertices[2].SetByX(node->Vertices[2],node->Vertices[0],divide&8?x1:x0); - ntri->Vertices[0]=node->Vertices[2]; //wierzchołek D jest wspólny - break; - } - //przeliczenie środków ciężkości obu - node->pCenter=(node->Vertices[0].Point+node->Vertices[1].Point+node->Vertices[2].Point)/3.0; - ntri->pCenter=(ntri->Vertices[0].Point+ntri->Vertices[1].Point+ntri->Vertices[2].Point)/3.0; - RaTriangleDivider(node); //rekurencja, bo nawet na TD raz nie wystarczy - RaTriangleDivider(ntri); +void __fastcall TGround::RaTriangleDivider(TGroundNode *node) +{ // tworzy dodatkowe trójkąty i zmiejsza podany + // to jest wywoływane przy wczytywaniu trójkątów + // dodatkowe trójkąty są dodawane do głównej listy trójkątów + // podział trójkątów na sektory i kwadraty jest dokonywany później w FirstInit + if (node->iType != GL_TRIANGLES) + return; // tylko pojedyncze trójkąty + if (node->iNumVerts != 3) + return; // tylko gdy jeden trójkąt + double x0 = 1000.0 * floor(0.001 * node->pCenter.x) - 200.0; + double x1 = x0 + 1400.0; + double z0 = 1000.0 * floor(0.001 * node->pCenter.z) - 200.0; + double z1 = z0 + 1400.0; + if ((node->Vertices[0].Point.x >= x0) && (node->Vertices[0].Point.x <= x1) && + (node->Vertices[0].Point.z >= z0) && (node->Vertices[0].Point.z <= z1) && + (node->Vertices[1].Point.x >= x0) && (node->Vertices[1].Point.x <= x1) && + (node->Vertices[1].Point.z >= z0) && (node->Vertices[1].Point.z <= z1) && + (node->Vertices[2].Point.x >= x0) && (node->Vertices[2].Point.x <= x1) && + (node->Vertices[2].Point.z >= z0) && (node->Vertices[2].Point.z <= z1)) + return; // trójkąt wystający mniej niż 200m z kw. kilometrowego jest do przyjęcia + // Ra: przerobić na dzielenie na 2 trójkąty, podział w przecięciu z siatką kilometrową + // Ra: i z rekurencją będzie dzielić trzy trójkąty, jeśli będzie taka potrzeba + int divide = -1; // bok do podzielenia: 0=AB, 1=BC, 2=CA; +4=podział po OZ; +8 na x1/z1 + double min = 0, mul; // jeśli przechodzi przez oś, iloczyn będzie ujemny + x0 += 200.0; + x1 -= 200.0; // przestawienie na siatkę + z0 += 200.0; + z1 -= 200.0; + mul = (node->Vertices[0].Point.x - x0) * (node->Vertices[1].Point.x - x0); // AB na wschodzie + if (mul < min) + min = mul, divide = 0; + mul = (node->Vertices[1].Point.x - x0) * (node->Vertices[2].Point.x - x0); // BC na wschodzie + if (mul < min) + min = mul, divide = 1; + mul = (node->Vertices[2].Point.x - x0) * (node->Vertices[0].Point.x - x0); // CA na wschodzie + if (mul < min) + min = mul, divide = 2; + mul = (node->Vertices[0].Point.x - x1) * (node->Vertices[1].Point.x - x1); // AB na zachodzie + if (mul < min) + min = mul, divide = 8; + mul = (node->Vertices[1].Point.x - x1) * (node->Vertices[2].Point.x - x1); // BC na zachodzie + if (mul < min) + min = mul, divide = 9; + mul = (node->Vertices[2].Point.x - x1) * (node->Vertices[0].Point.x - x1); // CA na zachodzie + if (mul < min) + min = mul, divide = 10; + mul = (node->Vertices[0].Point.z - z0) * (node->Vertices[1].Point.z - z0); // AB na południu + if (mul < min) + min = mul, divide = 4; + mul = (node->Vertices[1].Point.z - z0) * (node->Vertices[2].Point.z - z0); // BC na południu + if (mul < min) + min = mul, divide = 5; + mul = (node->Vertices[2].Point.z - z0) * (node->Vertices[0].Point.z - z0); // CA na południu + if (mul < min) + min = mul, divide = 6; + mul = (node->Vertices[0].Point.z - z1) * (node->Vertices[1].Point.z - z1); // AB na północy + if (mul < min) + min = mul, divide = 12; + mul = (node->Vertices[1].Point.z - z1) * (node->Vertices[2].Point.z - z1); // BC na północy + if (mul < min) + min = mul, divide = 13; + mul = (node->Vertices[2].Point.z - z1) * (node->Vertices[0].Point.z - z1); // CA na północy + if (mul < min) + divide = 14; + // tworzymy jeden dodatkowy trójkąt, dzieląc jeden bok na przecięciu siatki kilometrowej + TGroundNode *ntri; // wskaźnik na nowy trójkąt + ntri = new TGroundNode(); // a ten jest nowy + ntri->iType = GL_TRIANGLES; // kopiowanie parametrów, przydałby się konstruktor kopiujący + ntri->Init(3); + ntri->TextureID = node->TextureID; + ntri->iFlags = node->iFlags; + for (int j = 0; j < 4; ++j) + { + ntri->Ambient[j] = node->Ambient[j]; + ntri->Diffuse[j] = node->Diffuse[j]; + ntri->Specular[j] = node->Specular[j]; + } + ntri->asName = node->asName; + ntri->fSquareRadius = node->fSquareRadius; + ntri->fSquareMinRadius = node->fSquareMinRadius; + ntri->bVisible = node->bVisible; // a są jakieś niewidoczne? + ntri->nNext = nRootOfType[GL_TRIANGLES]; + nRootOfType[GL_TRIANGLES] = ntri; // dopisanie z przodu do listy + iNumNodes++; + switch (divide & 3) + { // podzielenie jednego z boków, powstaje wierzchołek D + case 0: // podział AB (0-1) -> ADC i DBC + ntri->Vertices[2] = node->Vertices[2]; // wierzchołek C jest wspólny + ntri->Vertices[1] = node->Vertices[1]; // wierzchołek B przechodzi do nowego + // node->Vertices[1].HalfSet(node->Vertices[0],node->Vertices[1]); //na razie D tak + if (divide & 4) + node->Vertices[1].SetByZ(node->Vertices[0], node->Vertices[1], divide & 8 ? z1 : z0); + else + node->Vertices[1].SetByX(node->Vertices[0], node->Vertices[1], divide & 8 ? x1 : x0); + ntri->Vertices[0] = node->Vertices[1]; // wierzchołek D jest wspólny + break; + case 1: // podział BC (1-2) -> ABD i ADC + ntri->Vertices[0] = node->Vertices[0]; // wierzchołek A jest wspólny + ntri->Vertices[2] = node->Vertices[2]; // wierzchołek C przechodzi do nowego + // node->Vertices[2].HalfSet(node->Vertices[1],node->Vertices[2]); //na razie D tak + if (divide & 4) + node->Vertices[2].SetByZ(node->Vertices[1], node->Vertices[2], divide & 8 ? z1 : z0); + else + node->Vertices[2].SetByX(node->Vertices[1], node->Vertices[2], divide & 8 ? x1 : x0); + ntri->Vertices[1] = node->Vertices[2]; // wierzchołek D jest wspólny + break; + case 2: // podział CA (2-0) -> ABD i DBC + ntri->Vertices[1] = node->Vertices[1]; // wierzchołek B jest wspólny + ntri->Vertices[2] = node->Vertices[2]; // wierzchołek C przechodzi do nowego + // node->Vertices[2].HalfSet(node->Vertices[2],node->Vertices[0]); //na razie D tak + if (divide & 4) + node->Vertices[2].SetByZ(node->Vertices[2], node->Vertices[0], divide & 8 ? z1 : z0); + else + node->Vertices[2].SetByX(node->Vertices[2], node->Vertices[0], divide & 8 ? x1 : x0); + ntri->Vertices[0] = node->Vertices[2]; // wierzchołek D jest wspólny + break; + } + // przeliczenie środków ciężkości obu + node->pCenter = + (node->Vertices[0].Point + node->Vertices[1].Point + node->Vertices[2].Point) / 3.0; + ntri->pCenter = + (ntri->Vertices[0].Point + ntri->Vertices[1].Point + ntri->Vertices[2].Point) / 3.0; + RaTriangleDivider(node); // rekurencja, bo nawet na TD raz nie wystarczy + RaTriangleDivider(ntri); }; -TGroundNode* __fastcall TGround::AddGroundNode(cParser* parser) -{//wczytanie wpisu typu "node" - //parser->LoadTraction=Global::bLoadTraction; //Ra: tu nie potrzeba powtarzać - AnsiString str,str1,str2,str3,str4,Skin,DriverType,asNodeName; - int nv,ti,i,n; - double tf,r,rmin,tf1,tf2,tf3,tf4,l,dist,mgn; - int int1,int2; - bool bError=false,curve; - vector3 pt,front,up,left,pos,tv; - matrix4x4 mat2,mat1,mat; - GLuint TexID; - TGroundNode *tmp1; - TTrack *Track; - TTextSound *tmpsound; - std::string token; - parser->getTokens(2); - *parser >> r >> rmin; - parser->getTokens(); - *parser >> token; - asNodeName=AnsiString(token.c_str()); - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - TGroundNode *tmp,*tmp2; - tmp=new TGroundNode(); - tmp->asName=(asNodeName==AnsiString("none")?AnsiString(""):asNodeName); - if (r>=0) tmp->fSquareRadius=r*r; - tmp->fSquareMinRadius=rmin*rmin; - if (str=="triangles") tmp->iType=GL_TRIANGLES; - else if (str=="triangle_strip") tmp->iType=GL_TRIANGLE_STRIP; - else if (str=="triangle_fan") tmp->iType=GL_TRIANGLE_FAN; - else if (str=="lines") tmp->iType=GL_LINES; - else if (str=="line_strip") tmp->iType=GL_LINE_STRIP; - else if (str=="line_loop") tmp->iType=GL_LINE_LOOP; - else if (str=="model") tmp->iType=TP_MODEL; - //else if (str=="terrain") tmp->iType=TP_TERRAIN; //tymczasowo do odwołania - else if (str=="dynamic") tmp->iType=TP_DYNAMIC; - else if (str=="sound") tmp->iType=TP_SOUND; - else if (str=="track") tmp->iType=TP_TRACK; - else if (str=="memcell") tmp->iType=TP_MEMCELL; - else if (str=="eventlauncher") tmp->iType=TP_EVLAUNCH; - else if (str=="traction") tmp->iType=TP_TRACTION; - else if (str=="tractionpowersource") tmp->iType=TP_TRACTIONPOWERSOURCE; -// else if (str=="isolated") tmp->iType=TP_ISOLATED; - else bError=true; - //WriteLog("-> node "+str+" "+tmp->asName); - if (bError) - { - Error(AnsiString("Scene parse error near "+str).c_str()); - for (int i=0;i<60;++i) - {//Ra: skopiowanie dalszej części do logu - taka prowizorka, lepsza niż nic - parser->getTokens(); //pobranie linijki tekstu nie działa - *parser >> token; - WriteLog(token.c_str()); - } - //if (tmp==RootNode) RootNode=NULL; - delete tmp; - return NULL; - } - switch (tmp->iType) - { - case TP_TRACTION : - tmp->hvTraction=new TTraction(); - parser->getTokens(); - *parser >> token; - tmp->hvTraction->asPowerSupplyName=AnsiString(token.c_str()); //nazwa zasilacza - parser->getTokens(3); - *parser >> tmp->hvTraction->NominalVoltage >> tmp->hvTraction->MaxCurrent >> tmp->hvTraction->fResistivity; - if (tmp->hvTraction->fResistivity==0.01) //tyle jest w sceneriach [om/km] - tmp->hvTraction->fResistivity=0.075; //taka sensowniejsza wartość za http://www.ikolej.pl/fileadmin/user_upload/Seminaria_IK/13_05_07_Prezentacja_Kruczek.pdf - tmp->hvTraction->fResistivity*=0.001; //teraz [om/m] - parser->getTokens(); - *parser >> token; - //Ra 2014-02: a tutaj damy symbol sieci i jej budowę, np.: - // SKB70-C, CuCd70-2C, KB95-2C, C95-C, C95-2C, YC95-2C, YpC95-2C, YC120-2C - // YpC120-2C, YzC120-2C, YwsC120-2C, YC150-C150, YC150-2C150, C150-C150 - // C120-2C, 2C120-2C, 2C120-2C-1, 2C120-2C-2, 2C120-2C-3, 2C120-2C-4 - if (token.compare("none")==0) - tmp->hvTraction->Material=0; - else if (token.compare("al")==0) - tmp->hvTraction->Material=2; //1=aluminiowa, rysuje się na czarno - else - tmp->hvTraction->Material=1; //1=miedziana, rysuje się na zielono albo czerwono - parser->getTokens(); - *parser >> tmp->hvTraction->WireThickness; - parser->getTokens(); - *parser >> tmp->hvTraction->DamageFlag; - parser->getTokens(3); - *parser >> tmp->hvTraction->pPoint1.x >> tmp->hvTraction->pPoint1.y >> tmp->hvTraction->pPoint1.z; - tmp->hvTraction->pPoint1+=pOrigin; - parser->getTokens(3); - *parser >> tmp->hvTraction->pPoint2.x >> tmp->hvTraction->pPoint2.y >> tmp->hvTraction->pPoint2.z; - tmp->hvTraction->pPoint2+=pOrigin; - parser->getTokens(3); - *parser >> tmp->hvTraction->pPoint3.x >> tmp->hvTraction->pPoint3.y >> tmp->hvTraction->pPoint3.z; - tmp->hvTraction->pPoint3+=pOrigin; - parser->getTokens(3); - *parser >> tmp->hvTraction->pPoint4.x >> tmp->hvTraction->pPoint4.y >> tmp->hvTraction->pPoint4.z; - tmp->hvTraction->pPoint4+=pOrigin; - parser->getTokens(); - *parser >> tf1; - tmp->hvTraction->fHeightDifference= - (tmp->hvTraction->pPoint3.y-tmp->hvTraction->pPoint1.y+ - tmp->hvTraction->pPoint4.y-tmp->hvTraction->pPoint2.y)*0.5f-tf1; - parser->getTokens(); - *parser >> tf1; - if (tf1>0) - tmp->hvTraction->iNumSections=(tmp->hvTraction->pPoint1-tmp->hvTraction->pPoint2).Length()/tf1; - else tmp->hvTraction->iNumSections=0; - parser->getTokens(); - *parser >> tmp->hvTraction->Wires; - parser->getTokens(); - *parser >> tmp->hvTraction->WireOffset; - parser->getTokens(); - *parser >> token; - tmp->bVisible=(token.compare("vis")==0); - parser->getTokens(); - *parser >> token; - if (token.compare("parallel")==0) - {//jawne wskazanie innego przęsła, na które może przestawić się pantograf - parser->getTokens(); - *parser >> token; //wypadało by to zapamiętać... - tmp->hvTraction->asParallel=AnsiString(token.c_str()); - parser->getTokens(); - *parser >> token; //a tu już powinien być koniec - } - if (token.compare("endtraction")!=0) - Error("ENDTRACTION delimiter missing! "+str2+" found instead."); - tmp->hvTraction->Init(); //przeliczenie parametrów - //if (Global::bLoadTraction) - // tmp->hvTraction->Optimize(); //generowanie DL dla wszystkiego przy wczytywaniu? - tmp->pCenter=(tmp->hvTraction->pPoint2+tmp->hvTraction->pPoint1)*0.5f; - //if (!Global::bLoadTraction) SafeDelete(tmp); //Ra: tak być nie może, bo NULL to błąd - break; - case TP_TRACTIONPOWERSOURCE: - parser->getTokens(3); - *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; - tmp->pCenter+=pOrigin; - tmp->psTractionPowerSource=new TTractionPowerSource(); - tmp->psTractionPowerSource->gMyNode=tmp; //Ra 2015-03: znowu prowizorka, aby mieć nazwę do logowania - tmp->psTractionPowerSource->Load(parser); - break; - case TP_MEMCELL: - parser->getTokens(3); - *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; - tmp->pCenter.RotateY(aRotate.y/180.0*M_PI); //Ra 2014-11: uwzględnienie rotacji - tmp->pCenter+=pOrigin; - tmp->MemCell=new TMemCell(&tmp->pCenter); - tmp->MemCell->Load(parser); - if (!tmp->asName.IsEmpty()) //jest pusta gdy "none" - {//dodanie do wyszukiwarki - if (sTracks->Update(TP_MEMCELL,tmp->asName.c_str(),tmp)) //najpierw sprawdzić, czy już jest - {//przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność wsteczna) - ErrorLog("Duplicated memcell: "+tmp->asName); //to zgłaszać duplikat - } - else - sTracks->Add(TP_MEMCELL,tmp->asName.c_str(),tmp); //nazwa jest unikalna - } - break; - case TP_EVLAUNCH: - parser->getTokens(3); - *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; - tmp->pCenter.RotateY(aRotate.y/180.0*M_PI); //Ra 2014-11: uwzględnienie rotacji - tmp->pCenter+=pOrigin; - tmp->EvLaunch=new TEventLauncher(); - tmp->EvLaunch->Load(parser); - break; - case TP_TRACK : - tmp->pTrack=new TTrack(tmp); - if (Global::iWriteLogEnabled&4) - if (!tmp->asName.IsEmpty()) - WriteLog(tmp->asName.c_str()); - tmp->pTrack->Load(parser,pOrigin,tmp->asName); //w nazwie może być nazwa odcinka izolowanego - if (!tmp->asName.IsEmpty()) //jest pusta gdy "none" - {//dodanie do wyszukiwarki - if (sTracks->Update(TP_TRACK,tmp->asName.c_str(),tmp)) //najpierw sprawdzić, czy już jest - {//przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność wsteczna) - if (tmp->pTrack->iCategoryFlag&1) //jeśli jest zdublowany tor kolejowy - ErrorLog("Duplicated track: "+tmp->asName); //to zgłaszać duplikat - } - else - sTracks->Add(TP_TRACK,tmp->asName.c_str(),tmp); //nazwa jest unikalna - } - tmp->pCenter=(tmp->pTrack->CurrentSegment()->FastGetPoint_0()+ - tmp->pTrack->CurrentSegment()->FastGetPoint(0.5)+ - tmp->pTrack->CurrentSegment()->FastGetPoint_1() )/3.0; - break; - case TP_SOUND : - tmp->tsStaticSound=new TTextSound; - parser->getTokens(3); - *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; - tmp->pCenter.RotateY(aRotate.y/180.0*M_PI); //Ra 2014-11: uwzględnienie rotacji - tmp->pCenter+=pOrigin; - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - tmp->tsStaticSound->Init(str.c_str(),sqrt(tmp->fSquareRadius),tmp->pCenter.x,tmp->pCenter.y,tmp->pCenter.z,false,rmin); - if (rmin<0.0) rmin=0.0; //przywrócenie poprawnej wartości, jeśli służyła do wyłączenia efektu Dopplera - -// tmp->pDirectSoundBuffer=TSoundsManager::GetFromName(str.c_str()); -// tmp->iState=(Parser->GetNextSymbol().LowerCase()=="loop"?DSBPLAY_LOOPING:0); - parser->getTokens(); *parser >> token; - break; - case TP_DYNAMIC: - tmp->DynamicObject=new TDynamicObject(); - //tmp->DynamicObject->Load(Parser); - parser->getTokens(); - *parser >> token; - str1=AnsiString(token.c_str()); //katalog - //McZapkie: doszedl parametr ze zmienialna skora - parser->getTokens(); - *parser >> token; - Skin=AnsiString(token.c_str()); //tekstura wymienna - parser->getTokens(); - *parser >> token; - str3=AnsiString(token.c_str()); //McZapkie-131102: model w MMD - if (bTrainSet) - {//jeśli pojazd jest umieszczony w składzie - str=asTrainSetTrack; - parser->getTokens(); - *parser >> tf1; //Ra: -1 oznacza odwrotne wstawienie, normalnie w składzie 0 - parser->getTokens(); - *parser >> token; - DriverType=AnsiString(token.c_str()); //McZapkie:010303 - w przyszlosci rozne konfiguracje mechanik/pomocnik itp - tf3=fTrainSetVel; //prędkość - parser->getTokens(); - *parser >> token; - str4=AnsiString(token.c_str()); - int2=str4.Pos("."); //yB: wykorzystuje tutaj zmienna, ktora potem bedzie ladunkiem - if (int2>0) //yB: jesli znalazl kropke, to ja przetwarza jako parametry - { - int dlugosc= str4.Length(); - int1=str4.SubString(1, int2-1).ToInt(); //niech sprzegiem bedzie do kropki cos - str4=str4.SubString(int2+1, dlugosc-int2); - } - else - { - int1=str4.ToInt(); - str4=""; - } - int2=0; //zeruje po wykorzystaniu -// *parser >> int1; //yB: nastawy i takie tam TUTAJ!!!!! - if (int1<0) int1=(-int1)|ctrain_depot; //sprzęg zablokowany (pojazdy nierozłączalne przy manewrach) - if (tf1!=-1.0) - if (fabs(tf1)>0.5) //maksymalna odległość między sprzęgami - do przemyślenia - int1=0; //likwidacja sprzęgu, jeśli odległość zbyt duża - to powinno być uwzględniane w fizyce sprzęgów... - TempConnectionType[iTrainSetWehicleNumber]=int1; //wartość dodatnia - } - else - {//pojazd wstawiony luzem - fTrainSetDist=0; //zerowanie dodatkowego przesunięcia - asTrainName=""; //puste oznacza jazdę pojedynczego bez rozkładu, "none" jest dla składu (trainset) - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); //track - parser->getTokens(); - *parser >> tf1; //Ra: -1 oznacza odwrotne wstawienie - parser->getTokens(); - *parser >> token; - DriverType=AnsiString(token.c_str()); //McZapkie:010303: obsada - parser->getTokens(); - *parser >> tf3; //prędkość, niektórzy wpisują tu "3" jako sprzęg, żeby nie było tabliczki - iTrainSetWehicleNumber=0; - TempConnectionType[iTrainSetWehicleNumber]=3; //likwidacja tabliczki na końcu? - } - parser->getTokens(); - *parser >> int2; //ilość ładunku - if (int2>0) - {//jeżeli ładunku jest więcej niż 0, to rozpoznajemy jego typ - parser->getTokens(); - *parser >> token; - str2=AnsiString(token.c_str()); //LoadType - if (str2==AnsiString("enddynamic")) //idiotoodporność: ładunek bez podanego typu - { - str2=""; int2=0; //ilość bez typu się nie liczy jako ładunek - } - } - else - str2=""; //brak ladunku - - tmp1=FindGroundNode(str,TP_TRACK); //poszukiwanie toru - if (tmp1?tmp1->pTrack!=NULL:false) - {//jeśli tor znaleziony - Track=tmp1->pTrack; - if (!iTrainSetWehicleNumber) //jeśli pierwszy pojazd - if (Track->evEvent0) //jeśli tor ma Event0 - if (fabs(fTrainSetVel)<=1.0) //a skład stoi - if (fTrainSetDist>=0.0) //ale może nie sięgać na owy tor - if (fTrainSetDist<8.0) //i raczej nie sięga - fTrainSetDist=8.0; //przesuwamy około pół EU07 dla wstecznej zgodności - //WriteLog("Dynamic shift: "+AnsiString(fTrainSetDist)); -/* //Ra: to jednak robi duże problemy - przesunięcie w dynamic jest przesunięciem do tyłu, odwrotnie niż w trainset - if (!iTrainSetWehicleNumber) //dla pierwszego jest to przesunięcie (ujemne = do tyłu) - if (tf1!=-1.0) //-1 wyjątkowo oznacza odwrócenie - tf1=-tf1; //a dla kolejnych odległość między sprzęgami (ujemne = wbite) -*/ - tf3=tmp->DynamicObject->Init(asNodeName,str1,Skin,str3,Track,(tf1==-1.0?fTrainSetDist:fTrainSetDist-tf1),DriverType,tf3,asTrainName,int2,str2,(tf1==-1.0),str4); - if (tf3!=0.0) //zero oznacza błąd - {fTrainSetDist-=tf3; //przesunięcie dla kolejnego, minus bo idziemy w stronę punktu 1 - tmp->pCenter=tmp->DynamicObject->GetPosition(); - if (TempConnectionType[iTrainSetWehicleNumber]) //jeśli jest sprzęg - if (tmp->DynamicObject->MoverParameters->Couplers[tf1==-1.0?0:1].AllowedFlag&ctrain_depot) //jesli zablokowany - TempConnectionType[iTrainSetWehicleNumber]|=ctrain_depot; //będzie blokada - iTrainSetWehicleNumber++; - } - else - {//LastNode=NULL; - delete tmp; - tmp=NULL; //nie może być tu return, bo trzeba pominąć jeszcze enddynamic - } - } - else - {//gdy tor nie znaleziony - ErrorLog("Missed track: dynamic placed on \""+tmp->DynamicObject->asTrack+"\""); - delete tmp; - tmp=NULL; //nie może być tu return, bo trzeba pominąć jeszcze enddynamic - } - parser->getTokens(); - *parser >> token; - if (token.compare("destination")==0) - {//dokąd wagon ma jechać, uwzględniane przy manewrach - parser->getTokens(); - *parser >> token; - if (tmp) - tmp->DynamicObject->asDestination=AnsiString(token.c_str()); - *parser >> token; - } - if (token.compare("enddynamic")!=0) - Error("enddynamic statement missing"); - break; - case TP_MODEL: - 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->fAngle+=aRotate.y; // /180*M_PI -/* - if (tmp->iType==TP_MODEL) - {//jeśli standardowy model -*/ - 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? - } -/* - } - else if (tmp->iType==TP_TERRAIN) - {//nie potrzeba nakładki animującej submodele - *parser >> token; - tmp->pModel3D=TModelsManager::GetModel(token.c_str(),false); - do //Ra: z tym to trochę bez sensu jest - {parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - } while (str!="endterrains"); - } -*/ - 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->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 (i=1;iiCount;++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 - //tmp->nNode[i].asName= - } - } - else if (!tmp->asName.IsEmpty()) //jest pusta gdy "none" - {//dodanie do wyszukiwarki - if (sTracks->Update(TP_MODEL,tmp->asName.c_str(),tmp)) //najpierw sprawdzić, czy już jest - {//przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność wsteczna) - ErrorLog("Duplicated model: "+tmp->asName); //to zgłaszać duplikat - } - else - sTracks->Add(TP_MODEL,tmp->asName.c_str(),tmp); //nazwa jest unikalna - } - //str=Parser->GetNextSymbol().LowerCase(); - break; - //case TP_GEOMETRY : - case GL_TRIANGLES : - case GL_TRIANGLE_STRIP : - case GL_TRIANGLE_FAN : - parser->getTokens(); - *parser >> token; - //McZapkie-050702: opcjonalne wczytywanie parametrow materialu (ambient,diffuse,specular) - if (token.compare("material")==0) - { - parser->getTokens(); - *parser >> token; - while (token.compare("endmaterial")!=0) - { - if (token.compare("ambient:")==0) - { - parser->getTokens(); *parser >> tmp->Ambient[0]; - parser->getTokens(); *parser >> tmp->Ambient[1]; - parser->getTokens(); *parser >> tmp->Ambient[2]; - } - else if (token.compare("diffuse:")==0) - {//Ra: coś jest nie tak, bo w jednej linijce nie działa - parser->getTokens(); *parser >> tmp->Diffuse[0]; - parser->getTokens(); *parser >> tmp->Diffuse[1]; - parser->getTokens(); *parser >> tmp->Diffuse[2]; - } - else if (token.compare("specular:")==0) - { - parser->getTokens(); *parser >> tmp->Specular[0]; - parser->getTokens(); *parser >> tmp->Specular[1]; - parser->getTokens(); *parser >> tmp->Specular[2]; - } - else Error("Scene material failure!"); - parser->getTokens(); - *parser >> token; - } - } - if (token.compare("endmaterial")==0) - { - parser->getTokens(); - *parser >> token; - } - str=AnsiString(token.c_str()); -#ifdef _PROBLEND - // PROBLEND Q: 13122011 - Szociu: 27012012 - PROBLEND = true; // domyslnie uruchomione nowe wyświetlanie - tmp->PROBLEND = true; // odwolanie do tgroundnode, bo rendering jest w tej klasie - if (str.Pos("@") > 0) // sprawdza, czy w nazwie tekstury jest znak "@" - { - PROBLEND = false; // jeśli jest, wyswietla po staremu - tmp->PROBLEND = false; - } -#endif - tmp->TextureID=TTexturesManager::GetTextureID(szTexturePath,szSceneryPath,str.c_str()); - tmp->iFlags=TTexturesManager::GetAlpha(tmp->TextureID)?0x220:0x210; //z usuwaniem - if (((tmp->iType==GL_TRIANGLES)&&(tmp->iFlags&0x10))?Global::pTerrainCompact->TerrainLoaded():false) - {//jeśli jest tekstura nieprzezroczysta, a teren załadowany, to pomijamy trójkąty - do - {//pomijanie trójkątów - parser->getTokens(); - *parser >> token; - } while (token.compare("endtri")!=0); - //delete tmp; //nie ma co tego trzymać - //tmp=NULL; //to jest błąd - } - else - {i=0; - do - { - if (i<9999) //3333 trójkąty - {//liczba wierzchołków nie jest nieograniczona - parser->getTokens(3); - *parser >> TempVerts[i].Point.x >> TempVerts[i].Point.y >> TempVerts[i].Point.z; - parser->getTokens(3); - *parser >> TempVerts[i].Normal.x >> TempVerts[i].Normal.y >> TempVerts[i].Normal.z; -/* - str=Parser->GetNextSymbol().LowerCase(); - if (str==AnsiString("x")) - TempVerts[i].tu=(TempVerts[i].Point.x+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str==AnsiString("y")) - TempVerts[i].tu=(TempVerts[i].Point.y+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str==AnsiString("z")) - TempVerts[i].tu=(TempVerts[i].Point.z+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - TempVerts[i].tu=str.ToDouble();; - - str=Parser->GetNextSymbol().LowerCase(); - if (str==AnsiString("x")) - TempVerts[i].tv=(TempVerts[i].Point.x+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str==AnsiString("y")) - TempVerts[i].tv=(TempVerts[i].Point.y+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - if (str==AnsiString("z")) - TempVerts[i].tv=(TempVerts[i].Point.z+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); - else - TempVerts[i].tv=str.ToDouble();; -*/ - parser->getTokens(2); - *parser >> TempVerts[i].tu >> TempVerts[i].tv; - -// tf=Parser->GetNextSymbol().ToDouble(); - // TempVerts[i].tu=tf; - // tf=Parser->GetNextSymbol().ToDouble(); - // TempVerts[i].tv=tf; - - TempVerts[i].Point.RotateZ(aRotate.z/180*M_PI); - TempVerts[i].Point.RotateX(aRotate.x/180*M_PI); - TempVerts[i].Point.RotateY(aRotate.y/180*M_PI); - TempVerts[i].Normal.RotateZ(aRotate.z/180*M_PI); - TempVerts[i].Normal.RotateX(aRotate.x/180*M_PI); - TempVerts[i].Normal.RotateY(aRotate.y/180*M_PI); - TempVerts[i].Point+=pOrigin; - tmp->pCenter+=TempVerts[i].Point; - } - else if (i==9999) - ErrorLog("Bad triangles: too many verices"); - i++; - parser->getTokens(); - *parser >> token; - -// } - - } while (token.compare("endtri")!=0); - nv=i; - tmp->Init(nv); //utworzenie tablicy wierzchołków - tmp->pCenter/=(nv>0?nv:1); - -// memcpy(tmp->Vertices,TempVerts,nv*sizeof(TGroundVertex)); - - r=0; - for (int i=0;iVertices[i]=TempVerts[i]; - tf=SquareMagnitude(tmp->Vertices[i].Point-tmp->pCenter); - if (tf>r) r=tf; - } - -// tmp->fSquareRadius=2000*2000+r; - tmp->fSquareRadius+=r; - RaTriangleDivider(tmp); //Ra: dzielenie trójkątów jest teraz całkiem wydajne - } //koniec wczytywania trójkątów - break; - case GL_LINES : - case GL_LINE_STRIP : - case GL_LINE_LOOP : - parser->getTokens(3); - *parser >> tmp->Diffuse[0] >> tmp->Diffuse[1] >> tmp->Diffuse[2]; -// tmp->Diffuse[0]=Parser->GetNextSymbol().ToDouble()/255; -// tmp->Diffuse[1]=Parser->GetNextSymbol().ToDouble()/255; -// tmp->Diffuse[2]=Parser->GetNextSymbol().ToDouble()/255; - parser->getTokens(); - *parser >> tmp->fLineThickness; - i=0; - parser->getTokens(); - *parser >> token; - do - { - str=AnsiString(token.c_str()); - TempVerts[i].Point.x=str.ToDouble(); +TGroundNode *__fastcall TGround::AddGroundNode(cParser *parser) +{ // wczytanie wpisu typu "node" + // parser->LoadTraction=Global::bLoadTraction; //Ra: tu nie potrzeba powtarzać + AnsiString str, str1, str2, str3, str4, Skin, DriverType, asNodeName; + int nv, ti, i, n; + double tf, r, rmin, tf1, tf2, tf3, tf4, l, dist, mgn; + int int1, int2; + bool bError = false, curve; + vector3 pt, front, up, left, pos, tv; + matrix4x4 mat2, mat1, mat; + GLuint TexID; + TGroundNode *tmp1; + TTrack *Track; + TTextSound *tmpsound; + std::string token; parser->getTokens(2); - *parser >> TempVerts[i].Point.y >> TempVerts[i].Point.z; - TempVerts[i].Point.RotateZ(aRotate.z/180*M_PI); - TempVerts[i].Point.RotateX(aRotate.x/180*M_PI); - TempVerts[i].Point.RotateY(aRotate.y/180*M_PI); - TempVerts[i].Point+=pOrigin; - tmp->pCenter+=TempVerts[i].Point; - i++; + *parser >> r >> rmin; parser->getTokens(); *parser >> token; - } while (token.compare("endline")!=0); - nv=i; -// tmp->Init(nv); - tmp->Points=new vector3[nv]; - tmp->iNumPts=nv; - tmp->pCenter/=(nv>0?nv:1); - for (int i=0;iPoints[i]=TempVerts[i].Point; - break; - } - return tmp; + asNodeName = AnsiString(token.c_str()); + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + TGroundNode *tmp, *tmp2; + tmp = new TGroundNode(); + tmp->asName = (asNodeName == AnsiString("none") ? AnsiString("") : asNodeName); + if (r >= 0) + tmp->fSquareRadius = r * r; + tmp->fSquareMinRadius = rmin * rmin; + if (str == "triangles") + tmp->iType = GL_TRIANGLES; + else if (str == "triangle_strip") + tmp->iType = GL_TRIANGLE_STRIP; + else if (str == "triangle_fan") + tmp->iType = GL_TRIANGLE_FAN; + else if (str == "lines") + tmp->iType = GL_LINES; + else if (str == "line_strip") + tmp->iType = GL_LINE_STRIP; + else if (str == "line_loop") + tmp->iType = GL_LINE_LOOP; + else if (str == "model") + tmp->iType = TP_MODEL; + // else if (str=="terrain") tmp->iType=TP_TERRAIN; //tymczasowo do odwołania + else if (str == "dynamic") + tmp->iType = TP_DYNAMIC; + else if (str == "sound") + tmp->iType = TP_SOUND; + else if (str == "track") + tmp->iType = TP_TRACK; + else if (str == "memcell") + tmp->iType = TP_MEMCELL; + else if (str == "eventlauncher") + tmp->iType = TP_EVLAUNCH; + else if (str == "traction") + tmp->iType = TP_TRACTION; + else if (str == "tractionpowersource") + tmp->iType = TP_TRACTIONPOWERSOURCE; + // else if (str=="isolated") tmp->iType=TP_ISOLATED; + else + bError = true; + // WriteLog("-> node "+str+" "+tmp->asName); + if (bError) + { + Error(AnsiString("Scene parse error near " + str).c_str()); + for (int i = 0; i < 60; ++i) + { // Ra: skopiowanie dalszej części do logu - taka prowizorka, lepsza niż nic + parser->getTokens(); // pobranie linijki tekstu nie działa + *parser >> token; + WriteLog(token.c_str()); + } + // if (tmp==RootNode) RootNode=NULL; + delete tmp; + return NULL; + } + switch (tmp->iType) + { + case TP_TRACTION: + tmp->hvTraction = new TTraction(); + parser->getTokens(); + *parser >> token; + tmp->hvTraction->asPowerSupplyName = AnsiString(token.c_str()); // nazwa zasilacza + parser->getTokens(3); + *parser >> tmp->hvTraction->NominalVoltage >> tmp->hvTraction->MaxCurrent >> + tmp->hvTraction->fResistivity; + if (tmp->hvTraction->fResistivity == 0.01) // tyle jest w sceneriach [om/km] + tmp->hvTraction->fResistivity = + 0.075; // taka sensowniejsza wartość za + // http://www.ikolej.pl/fileadmin/user_upload/Seminaria_IK/13_05_07_Prezentacja_Kruczek.pdf + tmp->hvTraction->fResistivity *= 0.001; // teraz [om/m] + parser->getTokens(); + *parser >> token; + // Ra 2014-02: a tutaj damy symbol sieci i jej budowę, np.: + // SKB70-C, CuCd70-2C, KB95-2C, C95-C, C95-2C, YC95-2C, YpC95-2C, YC120-2C + // YpC120-2C, YzC120-2C, YwsC120-2C, YC150-C150, YC150-2C150, C150-C150 + // C120-2C, 2C120-2C, 2C120-2C-1, 2C120-2C-2, 2C120-2C-3, 2C120-2C-4 + if (token.compare("none") == 0) + tmp->hvTraction->Material = 0; + else if (token.compare("al") == 0) + tmp->hvTraction->Material = 2; // 1=aluminiowa, rysuje się na czarno + else + tmp->hvTraction->Material = 1; // 1=miedziana, rysuje się na zielono albo czerwono + parser->getTokens(); + *parser >> tmp->hvTraction->WireThickness; + parser->getTokens(); + *parser >> tmp->hvTraction->DamageFlag; + parser->getTokens(3); + *parser >> tmp->hvTraction->pPoint1.x >> tmp->hvTraction->pPoint1.y >> + tmp->hvTraction->pPoint1.z; + tmp->hvTraction->pPoint1 += pOrigin; + parser->getTokens(3); + *parser >> tmp->hvTraction->pPoint2.x >> tmp->hvTraction->pPoint2.y >> + tmp->hvTraction->pPoint2.z; + tmp->hvTraction->pPoint2 += pOrigin; + parser->getTokens(3); + *parser >> tmp->hvTraction->pPoint3.x >> tmp->hvTraction->pPoint3.y >> + tmp->hvTraction->pPoint3.z; + tmp->hvTraction->pPoint3 += pOrigin; + parser->getTokens(3); + *parser >> tmp->hvTraction->pPoint4.x >> tmp->hvTraction->pPoint4.y >> + tmp->hvTraction->pPoint4.z; + tmp->hvTraction->pPoint4 += pOrigin; + parser->getTokens(); + *parser >> tf1; + tmp->hvTraction->fHeightDifference = + (tmp->hvTraction->pPoint3.y - tmp->hvTraction->pPoint1.y + tmp->hvTraction->pPoint4.y - + tmp->hvTraction->pPoint2.y) * + 0.5f - + tf1; + parser->getTokens(); + *parser >> tf1; + if (tf1 > 0) + tmp->hvTraction->iNumSections = + (tmp->hvTraction->pPoint1 - tmp->hvTraction->pPoint2).Length() / tf1; + else + tmp->hvTraction->iNumSections = 0; + parser->getTokens(); + *parser >> tmp->hvTraction->Wires; + parser->getTokens(); + *parser >> tmp->hvTraction->WireOffset; + parser->getTokens(); + *parser >> token; + tmp->bVisible = (token.compare("vis") == 0); + parser->getTokens(); + *parser >> token; + if (token.compare("parallel") == 0) + { // jawne wskazanie innego przęsła, na które może przestawić się pantograf + parser->getTokens(); + *parser >> token; // wypadało by to zapamiętać... + tmp->hvTraction->asParallel = AnsiString(token.c_str()); + parser->getTokens(); + *parser >> token; // a tu już powinien być koniec + } + if (token.compare("endtraction") != 0) + Error("ENDTRACTION delimiter missing! " + str2 + " found instead."); + tmp->hvTraction->Init(); // przeliczenie parametrów + // if (Global::bLoadTraction) + // tmp->hvTraction->Optimize(); //generowanie DL dla wszystkiego przy wczytywaniu? + tmp->pCenter = (tmp->hvTraction->pPoint2 + tmp->hvTraction->pPoint1) * 0.5f; + // if (!Global::bLoadTraction) SafeDelete(tmp); //Ra: tak być nie może, bo NULL to błąd + break; + case TP_TRACTIONPOWERSOURCE: + parser->getTokens(3); + *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; + tmp->pCenter += pOrigin; + tmp->psTractionPowerSource = new TTractionPowerSource(); + tmp->psTractionPowerSource->gMyNode = + tmp; // Ra 2015-03: znowu prowizorka, aby mieć nazwę do logowania + tmp->psTractionPowerSource->Load(parser); + break; + case TP_MEMCELL: + parser->getTokens(3); + *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; + tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI); // Ra 2014-11: uwzględnienie rotacji + tmp->pCenter += pOrigin; + tmp->MemCell = new TMemCell(&tmp->pCenter); + tmp->MemCell->Load(parser); + if (!tmp->asName.IsEmpty()) // jest pusta gdy "none" + { // dodanie do wyszukiwarki + if (sTracks->Update(TP_MEMCELL, tmp->asName.c_str(), + tmp)) // najpierw sprawdzić, czy już jest + { // przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność + // wsteczna) + ErrorLog("Duplicated memcell: " + tmp->asName); // to zgłaszać duplikat + } + else + sTracks->Add(TP_MEMCELL, tmp->asName.c_str(), tmp); // nazwa jest unikalna + } + break; + case TP_EVLAUNCH: + parser->getTokens(3); + *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; + tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI); // Ra 2014-11: uwzględnienie rotacji + tmp->pCenter += pOrigin; + tmp->EvLaunch = new TEventLauncher(); + tmp->EvLaunch->Load(parser); + break; + case TP_TRACK: + tmp->pTrack = new TTrack(tmp); + if (Global::iWriteLogEnabled & 4) + if (!tmp->asName.IsEmpty()) + WriteLog(tmp->asName.c_str()); + tmp->pTrack->Load(parser, pOrigin, + tmp->asName); // w nazwie może być nazwa odcinka izolowanego + if (!tmp->asName.IsEmpty()) // jest pusta gdy "none" + { // dodanie do wyszukiwarki + if (sTracks->Update(TP_TRACK, tmp->asName.c_str(), + tmp)) // najpierw sprawdzić, czy już jest + { // przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność + // wsteczna) + if (tmp->pTrack->iCategoryFlag & 1) // jeśli jest zdublowany tor kolejowy + ErrorLog("Duplicated track: " + tmp->asName); // to zgłaszać duplikat + } + else + sTracks->Add(TP_TRACK, tmp->asName.c_str(), tmp); // nazwa jest unikalna + } + tmp->pCenter = (tmp->pTrack->CurrentSegment()->FastGetPoint_0() + + tmp->pTrack->CurrentSegment()->FastGetPoint(0.5) + + tmp->pTrack->CurrentSegment()->FastGetPoint_1()) / + 3.0; + break; + case TP_SOUND: + tmp->tsStaticSound = new TTextSound; + parser->getTokens(3); + *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; + tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI); // Ra 2014-11: uwzględnienie rotacji + tmp->pCenter += pOrigin; + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + tmp->tsStaticSound->Init(str.c_str(), sqrt(tmp->fSquareRadius), tmp->pCenter.x, + tmp->pCenter.y, tmp->pCenter.z, false, rmin); + if (rmin < 0.0) + rmin = + 0.0; // przywrócenie poprawnej wartości, jeśli służyła do wyłączenia efektu Dopplera + + // tmp->pDirectSoundBuffer=TSoundsManager::GetFromName(str.c_str()); + // tmp->iState=(Parser->GetNextSymbol().LowerCase()=="loop"?DSBPLAY_LOOPING:0); + parser->getTokens(); + *parser >> token; + break; + case TP_DYNAMIC: + tmp->DynamicObject = new TDynamicObject(); + // tmp->DynamicObject->Load(Parser); + parser->getTokens(); + *parser >> token; + str1 = AnsiString(token.c_str()); // katalog + // McZapkie: doszedl parametr ze zmienialna skora + parser->getTokens(); + *parser >> token; + Skin = AnsiString(token.c_str()); // tekstura wymienna + parser->getTokens(); + *parser >> token; + str3 = AnsiString(token.c_str()); // McZapkie-131102: model w MMD + if (bTrainSet) + { // jeśli pojazd jest umieszczony w składzie + str = asTrainSetTrack; + parser->getTokens(); + *parser >> tf1; // Ra: -1 oznacza odwrotne wstawienie, normalnie w składzie 0 + parser->getTokens(); + *parser >> token; + DriverType = AnsiString(token.c_str()); // McZapkie:010303 - w przyszlosci rozne + // konfiguracje mechanik/pomocnik itp + tf3 = fTrainSetVel; // prędkość + parser->getTokens(); + *parser >> token; + str4 = AnsiString(token.c_str()); + int2 = str4.Pos("."); // yB: wykorzystuje tutaj zmienna, ktora potem bedzie ladunkiem + if (int2 > 0) // yB: jesli znalazl kropke, to ja przetwarza jako parametry + { + int dlugosc = str4.Length(); + int1 = str4.SubString(1, int2 - 1).ToInt(); // niech sprzegiem bedzie do kropki cos + str4 = str4.SubString(int2 + 1, dlugosc - int2); + } + else + { + int1 = str4.ToInt(); + str4 = ""; + } + int2 = 0; // zeruje po wykorzystaniu + // *parser >> int1; //yB: nastawy i takie tam TUTAJ!!!!! + if (int1 < 0) + int1 = (-int1) | + ctrain_depot; // sprzęg zablokowany (pojazdy nierozłączalne przy manewrach) + if (tf1 != -1.0) + if (fabs(tf1) > 0.5) // maksymalna odległość między sprzęgami - do przemyślenia + int1 = 0; // likwidacja sprzęgu, jeśli odległość zbyt duża - to powinno być + // uwzględniane w fizyce sprzęgów... + TempConnectionType[iTrainSetWehicleNumber] = int1; // wartość dodatnia + } + else + { // pojazd wstawiony luzem + fTrainSetDist = 0; // zerowanie dodatkowego przesunięcia + asTrainName = ""; // puste oznacza jazdę pojedynczego bez rozkładu, "none" jest dla + // składu (trainset) + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); // track + parser->getTokens(); + *parser >> tf1; // Ra: -1 oznacza odwrotne wstawienie + parser->getTokens(); + *parser >> token; + DriverType = AnsiString(token.c_str()); // McZapkie:010303: obsada + parser->getTokens(); + *parser >> + tf3; // prędkość, niektórzy wpisują tu "3" jako sprzęg, żeby nie było tabliczki + iTrainSetWehicleNumber = 0; + TempConnectionType[iTrainSetWehicleNumber] = 3; // likwidacja tabliczki na końcu? + } + parser->getTokens(); + *parser >> int2; // ilość ładunku + if (int2 > 0) + { // jeżeli ładunku jest więcej niż 0, to rozpoznajemy jego typ + parser->getTokens(); + *parser >> token; + str2 = AnsiString(token.c_str()); // LoadType + if (str2 == AnsiString("enddynamic")) // idiotoodporność: ładunek bez podanego typu + { + str2 = ""; + int2 = 0; // ilość bez typu się nie liczy jako ładunek + } + } + else + str2 = ""; // brak ladunku + + tmp1 = FindGroundNode(str, TP_TRACK); // poszukiwanie toru + if (tmp1 ? tmp1->pTrack != NULL : false) + { // jeśli tor znaleziony + Track = tmp1->pTrack; + if (!iTrainSetWehicleNumber) // jeśli pierwszy pojazd + if (Track->evEvent0) // jeśli tor ma Event0 + if (fabs(fTrainSetVel) <= 1.0) // a skład stoi + if (fTrainSetDist >= 0.0) // ale może nie sięgać na owy tor + if (fTrainSetDist < 8.0) // i raczej nie sięga + fTrainSetDist = + 8.0; // przesuwamy około pół EU07 dla wstecznej zgodności + // WriteLog("Dynamic shift: "+AnsiString(fTrainSetDist)); + /* //Ra: to jednak robi duże problemy - przesunięcie w dynamic jest przesunięciem do + tyłu, odwrotnie niż w trainset + if (!iTrainSetWehicleNumber) //dla pierwszego jest to przesunięcie (ujemne = do + tyłu) + if (tf1!=-1.0) //-1 wyjątkowo oznacza odwrócenie + tf1=-tf1; //a dla kolejnych odległość między sprzęgami (ujemne = wbite) + */ + tf3 = tmp->DynamicObject->Init(asNodeName, str1, Skin, str3, Track, + (tf1 == -1.0 ? fTrainSetDist : fTrainSetDist - tf1), + DriverType, tf3, asTrainName, int2, str2, (tf1 == -1.0), + str4); + if (tf3 != 0.0) // zero oznacza błąd + { + fTrainSetDist -= + tf3; // przesunięcie dla kolejnego, minus bo idziemy w stronę punktu 1 + tmp->pCenter = tmp->DynamicObject->GetPosition(); + if (TempConnectionType[iTrainSetWehicleNumber]) // jeśli jest sprzęg + if (tmp->DynamicObject->MoverParameters->Couplers[tf1 == -1.0 ? 0 : 1] + .AllowedFlag & + ctrain_depot) // jesli zablokowany + TempConnectionType[iTrainSetWehicleNumber] |= ctrain_depot; // będzie + // blokada + iTrainSetWehicleNumber++; + } + else + { // LastNode=NULL; + delete tmp; + tmp = NULL; // nie może być tu return, bo trzeba pominąć jeszcze enddynamic + } + } + else + { // gdy tor nie znaleziony + ErrorLog("Missed track: dynamic placed on \"" + tmp->DynamicObject->asTrack + "\""); + delete tmp; + tmp = NULL; // nie może być tu return, bo trzeba pominąć jeszcze enddynamic + } + parser->getTokens(); + *parser >> token; + if (token.compare("destination") == 0) + { // dokąd wagon ma jechać, uwzględniane przy manewrach + parser->getTokens(); + *parser >> token; + if (tmp) + tmp->DynamicObject->asDestination = AnsiString(token.c_str()); + *parser >> token; + } + if (token.compare("enddynamic") != 0) + Error("enddynamic statement missing"); + break; + case TP_MODEL: + 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->fAngle+=aRotate.y; // /180*M_PI + /* + if (tmp->iType==TP_MODEL) + {//jeśli standardowy model + */ + 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? + } + /* + } + else if (tmp->iType==TP_TERRAIN) + {//nie potrzeba nakładki animującej submodele + *parser >> token; + tmp->pModel3D=TModelsManager::GetModel(token.c_str(),false); + do //Ra: z tym to trochę bez sensu jest + {parser->getTokens(); + *parser >> token; + str=AnsiString(token.c_str()); + } while (str!="endterrains"); + } + */ + 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->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 (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 + // tmp->nNode[i].asName= + } + } + else if (!tmp->asName.IsEmpty()) // jest pusta gdy "none" + { // dodanie do wyszukiwarki + if (sTracks->Update(TP_MODEL, tmp->asName.c_str(), + tmp)) // najpierw sprawdzić, czy już jest + { // przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność + // wsteczna) + ErrorLog("Duplicated model: " + tmp->asName); // to zgłaszać duplikat + } + else + sTracks->Add(TP_MODEL, tmp->asName.c_str(), tmp); // nazwa jest unikalna + } + // str=Parser->GetNextSymbol().LowerCase(); + break; + // case TP_GEOMETRY : + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + parser->getTokens(); + *parser >> token; + // McZapkie-050702: opcjonalne wczytywanie parametrow materialu (ambient,diffuse,specular) + if (token.compare("material") == 0) + { + parser->getTokens(); + *parser >> token; + while (token.compare("endmaterial") != 0) + { + if (token.compare("ambient:") == 0) + { + parser->getTokens(); + *parser >> tmp->Ambient[0]; + parser->getTokens(); + *parser >> tmp->Ambient[1]; + parser->getTokens(); + *parser >> tmp->Ambient[2]; + } + else if (token.compare("diffuse:") == 0) + { // Ra: coś jest nie tak, bo w jednej linijce nie działa + parser->getTokens(); + *parser >> tmp->Diffuse[0]; + parser->getTokens(); + *parser >> tmp->Diffuse[1]; + parser->getTokens(); + *parser >> tmp->Diffuse[2]; + } + else if (token.compare("specular:") == 0) + { + parser->getTokens(); + *parser >> tmp->Specular[0]; + parser->getTokens(); + *parser >> tmp->Specular[1]; + parser->getTokens(); + *parser >> tmp->Specular[2]; + } + else + Error("Scene material failure!"); + parser->getTokens(); + *parser >> token; + } + } + if (token.compare("endmaterial") == 0) + { + parser->getTokens(); + *parser >> token; + } + str = AnsiString(token.c_str()); +#ifdef _PROBLEND + // PROBLEND Q: 13122011 - Szociu: 27012012 + PROBLEND = true; // domyslnie uruchomione nowe wyświetlanie + tmp->PROBLEND = true; // odwolanie do tgroundnode, bo rendering jest w tej klasie + if (str.Pos("@") > 0) // sprawdza, czy w nazwie tekstury jest znak "@" + { + PROBLEND = false; // jeśli jest, wyswietla po staremu + tmp->PROBLEND = false; + } +#endif + tmp->TextureID = TTexturesManager::GetTextureID(szTexturePath, szSceneryPath, str.c_str()); + tmp->iFlags = TTexturesManager::GetAlpha(tmp->TextureID) ? 0x220 : 0x210; // z usuwaniem + if (((tmp->iType == GL_TRIANGLES) && (tmp->iFlags & 0x10)) ? + Global::pTerrainCompact->TerrainLoaded() : + false) + { // jeśli jest tekstura nieprzezroczysta, a teren załadowany, to pomijamy trójkąty + do + { // pomijanie trójkątów + parser->getTokens(); + *parser >> token; + } while (token.compare("endtri") != 0); + // delete tmp; //nie ma co tego trzymać + // tmp=NULL; //to jest błąd + } + else + { + i = 0; + do + { + if (i < 9999) // 3333 trójkąty + { // liczba wierzchołków nie jest nieograniczona + parser->getTokens(3); + *parser >> TempVerts[i].Point.x >> TempVerts[i].Point.y >> TempVerts[i].Point.z; + parser->getTokens(3); + *parser >> TempVerts[i].Normal.x >> TempVerts[i].Normal.y >> + TempVerts[i].Normal.z; + /* + str=Parser->GetNextSymbol().LowerCase(); + if (str==AnsiString("x")) + TempVerts[i].tu=(TempVerts[i].Point.x+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); + else + if (str==AnsiString("y")) + TempVerts[i].tu=(TempVerts[i].Point.y+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); + else + if (str==AnsiString("z")) + TempVerts[i].tu=(TempVerts[i].Point.z+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); + else + TempVerts[i].tu=str.ToDouble();; + + str=Parser->GetNextSymbol().LowerCase(); + if (str==AnsiString("x")) + TempVerts[i].tv=(TempVerts[i].Point.x+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); + else + if (str==AnsiString("y")) + TempVerts[i].tv=(TempVerts[i].Point.y+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); + else + if (str==AnsiString("z")) + TempVerts[i].tv=(TempVerts[i].Point.z+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble(); + else + TempVerts[i].tv=str.ToDouble();; + */ + parser->getTokens(2); + *parser >> TempVerts[i].tu >> TempVerts[i].tv; + + // tf=Parser->GetNextSymbol().ToDouble(); + // TempVerts[i].tu=tf; + // tf=Parser->GetNextSymbol().ToDouble(); + // TempVerts[i].tv=tf; + + TempVerts[i].Point.RotateZ(aRotate.z / 180 * M_PI); + TempVerts[i].Point.RotateX(aRotate.x / 180 * M_PI); + TempVerts[i].Point.RotateY(aRotate.y / 180 * M_PI); + TempVerts[i].Normal.RotateZ(aRotate.z / 180 * M_PI); + TempVerts[i].Normal.RotateX(aRotate.x / 180 * M_PI); + TempVerts[i].Normal.RotateY(aRotate.y / 180 * M_PI); + TempVerts[i].Point += pOrigin; + tmp->pCenter += TempVerts[i].Point; + } + else if (i == 9999) + ErrorLog("Bad triangles: too many verices"); + i++; + parser->getTokens(); + *parser >> token; + + // } + + } while (token.compare("endtri") != 0); + nv = i; + tmp->Init(nv); // utworzenie tablicy wierzchołków + tmp->pCenter /= (nv > 0 ? nv : 1); + + // memcpy(tmp->Vertices,TempVerts,nv*sizeof(TGroundVertex)); + + r = 0; + for (int i = 0; i < nv; i++) + { + tmp->Vertices[i] = TempVerts[i]; + tf = SquareMagnitude(tmp->Vertices[i].Point - tmp->pCenter); + if (tf > r) + r = tf; + } + + // tmp->fSquareRadius=2000*2000+r; + tmp->fSquareRadius += r; + RaTriangleDivider(tmp); // Ra: dzielenie trójkątów jest teraz całkiem wydajne + } // koniec wczytywania trójkątów + break; + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + parser->getTokens(3); + *parser >> tmp->Diffuse[0] >> tmp->Diffuse[1] >> tmp->Diffuse[2]; + // tmp->Diffuse[0]=Parser->GetNextSymbol().ToDouble()/255; + // tmp->Diffuse[1]=Parser->GetNextSymbol().ToDouble()/255; + // tmp->Diffuse[2]=Parser->GetNextSymbol().ToDouble()/255; + parser->getTokens(); + *parser >> tmp->fLineThickness; + i = 0; + parser->getTokens(); + *parser >> token; + do + { + str = AnsiString(token.c_str()); + TempVerts[i].Point.x = str.ToDouble(); + parser->getTokens(2); + *parser >> TempVerts[i].Point.y >> TempVerts[i].Point.z; + TempVerts[i].Point.RotateZ(aRotate.z / 180 * M_PI); + TempVerts[i].Point.RotateX(aRotate.x / 180 * M_PI); + TempVerts[i].Point.RotateY(aRotate.y / 180 * M_PI); + TempVerts[i].Point += pOrigin; + tmp->pCenter += TempVerts[i].Point; + i++; + parser->getTokens(); + *parser >> token; + } while (token.compare("endline") != 0); + nv = i; + // tmp->Init(nv); + tmp->Points = new vector3[nv]; + tmp->iNumPts = nv; + tmp->pCenter /= (nv > 0 ? nv : 1); + for (int i = 0; i < nv; i++) + tmp->Points[i] = TempVerts[i].Point; + break; + } + return tmp; } -TSubRect* __fastcall TGround::FastGetSubRect(int iCol, int iRow) +TSubRect *__fastcall TGround::FastGetSubRect(int iCol, int iRow) { - int br,bc,sr,sc; - br=iRow/iNumSubRects; - bc=iCol/iNumSubRects; - sr=iRow-br*iNumSubRects; - sc=iCol-bc*iNumSubRects; - if ( (br<0) || (bc<0) || (br>=iNumRects) || (bc>=iNumRects) ) return NULL; - return (Rects[br][bc].FastGetRect(sc,sr)); + int br, bc, sr, sc; + br = iRow / iNumSubRects; + bc = iCol / iNumSubRects; + sr = iRow - br * iNumSubRects; + sc = iCol - bc * iNumSubRects; + if ((br < 0) || (bc < 0) || (br >= iNumRects) || (bc >= iNumRects)) + return NULL; + return (Rects[br][bc].FastGetRect(sc, sr)); } -TSubRect* __fastcall TGround::GetSubRect(int iCol,int iRow) -{//znalezienie małego kwadratu mapy - int br,bc,sr,sc; - br=iRow/iNumSubRects; //współrzędne kwadratu kilometrowego - bc=iCol/iNumSubRects; - sr=iRow-br*iNumSubRects; //współrzędne wzglęne małego kwadratu - sc=iCol-bc*iNumSubRects; - if ( (br<0) || (bc<0) || (br>=iNumRects) || (bc>=iNumRects) ) - return NULL; //jeśli poza mapą - return (Rects[br][bc].SafeGetRect(sc,sr)); //pobranie małego kwadratu +TSubRect *__fastcall TGround::GetSubRect(int iCol, int iRow) +{ // znalezienie małego kwadratu mapy + int br, bc, sr, sc; + br = iRow / iNumSubRects; // współrzędne kwadratu kilometrowego + bc = iCol / iNumSubRects; + sr = iRow - br * iNumSubRects; // współrzędne wzglęne małego kwadratu + sc = iCol - bc * iNumSubRects; + if ((br < 0) || (bc < 0) || (br >= iNumRects) || (bc >= iNumRects)) + return NULL; // jeśli poza mapą + return (Rects[br][bc].SafeGetRect(sc, sr)); // pobranie małego kwadratu } -TEvent* __fastcall TGround::FindEvent(const AnsiString &asEventName) +TEvent *__fastcall TGround::FindEvent(const AnsiString &asEventName) { - return (TEvent*)sTracks->Find(0,asEventName.c_str()); //wyszukiwanie w drzewie -/* //powolna wyszukiwarka - for (TEvent *Current=RootEvent;Current;Current=Current->Next2) - { - if (Current->asName==asEventName) - return Current; - } - return NULL; -*/ + return (TEvent *)sTracks->Find(0, asEventName.c_str()); // wyszukiwanie w drzewie + /* //powolna wyszukiwarka + for (TEvent *Current=RootEvent;Current;Current=Current->Next2) + { + if (Current->asName==asEventName) + return Current; + } + return NULL; + */ } -TEvent* __fastcall TGround::FindEventScan(const AnsiString &asEventName) -{//wyszukanie eventu z opcją utworzenia niejawnego dla komórek skanowanych - TEvent *e=(TEvent*)sTracks->Find(0,asEventName.c_str()); //wyszukiwanie w drzewie eventów - if (e) return e; //jak istnieje, to w porządku - if (asEventName.SubString(asEventName.Length()-4,5)==":scan") //jeszcze może być event niejawny - {//no to szukamy komórki pamięci o nazwie zawartej w evencie - AnsiString n=asEventName.SubString(1,asEventName.Length()-5); //do dwukropka - if (sTracks->Find(TP_MEMCELL,n.c_str())) //jeśli jest takowa komórka pamięci - e=new TEvent(n); //utworzenie niejawnego eventu jej odczytu - } - return e; //utworzony albo się nie udało +TEvent *__fastcall TGround::FindEventScan(const AnsiString &asEventName) +{ // wyszukanie eventu z opcją utworzenia niejawnego dla komórek skanowanych + TEvent *e = (TEvent *)sTracks->Find(0, asEventName.c_str()); // wyszukiwanie w drzewie eventów + if (e) + return e; // jak istnieje, to w porządku + if (asEventName.SubString(asEventName.Length() - 4, 5) == + ":scan") // jeszcze może być event niejawny + { // no to szukamy komórki pamięci o nazwie zawartej w evencie + AnsiString n = asEventName.SubString(1, asEventName.Length() - 5); // do dwukropka + if (sTracks->Find(TP_MEMCELL, n.c_str())) // jeśli jest takowa komórka pamięci + e = new TEvent(n); // utworzenie niejawnego eventu jej odczytu + } + return e; // utworzony albo się nie udało } void __fastcall TGround::FirstInit() -{//ustalanie zależności na scenerii przed wczytaniem pojazdów - if (bInitDone) return; //Ra: żeby nie robiło się dwa razy - bInitDone=true; - WriteLog("InitNormals"); - int i,j; - for (i=0;inNext) - { - Current->InitNormals(); - if (Current->iType!=TP_DYNAMIC) - {//pojazdów w ogóle nie dotyczy dodawanie do mapy - if (i==TP_EVLAUNCH?Current->EvLaunch->IsGlobal():false) - srGlobal.NodeAdd(Current); //dodanie do globalnego obiektu - else if (i==TP_TERRAIN) - {//specjalne przetwarzanie terenu wczytanego z pliku E3D - AnsiString xxxzzz; //nazwa kwadratu - TGroundRect *gr; - for (j=1;jiCount;++j) - {//od 1 do końca są zestawy trójkątów - xxxzzz=AnsiString(Current->nNode[j].smTerrain->pName); //pobranie nazwy - gr=GetRect(1000*(xxxzzz.SubString(1,3).ToIntDef(0)-500),1000*(xxxzzz.SubString(4,3).ToIntDef(0)-500)); - if (Global::bUseVBO) - gr->nTerrain=Current->nNode+j; //zapamiętanie - else - gr->RaNodeAdd(&Current->nNode[j]); - } +{ // ustalanie zależności na scenerii przed wczytaniem pojazdów + if (bInitDone) + return; // Ra: żeby nie robiło się dwa razy + bInitDone = true; + WriteLog("InitNormals"); + int i, j; + for (i = 0; i < TP_LAST; ++i) + { + for (TGroundNode *Current = nRootOfType[i]; Current; Current = Current->nNext) + { + Current->InitNormals(); + if (Current->iType != TP_DYNAMIC) + { // pojazdów w ogóle nie dotyczy dodawanie do mapy + if (i == TP_EVLAUNCH ? Current->EvLaunch->IsGlobal() : false) + srGlobal.NodeAdd(Current); // dodanie do globalnego obiektu + else if (i == TP_TERRAIN) + { // specjalne przetwarzanie terenu wczytanego z pliku E3D + AnsiString xxxzzz; // nazwa kwadratu + TGroundRect *gr; + for (j = 1; j < Current->iCount; ++j) + { // od 1 do końca są zestawy trójkątów + xxxzzz = AnsiString(Current->nNode[j].smTerrain->pName); // pobranie nazwy + gr = GetRect(1000 * (xxxzzz.SubString(1, 3).ToIntDef(0) - 500), + 1000 * (xxxzzz.SubString(4, 3).ToIntDef(0) - 500)); + if (Global::bUseVBO) + gr->nTerrain = Current->nNode + j; // zapamiętanie + else + gr->RaNodeAdd(&Current->nNode[j]); + } + } + // else if + // ((Current->iType!=GL_TRIANGLES)&&(Current->iType!=GL_TRIANGLE_STRIP)?true + // //~czy trójkąt? + else if ((Current->iType != GL_TRIANGLES) ? + true //~czy trójkąt? + : + (Current->iFlags & 0x20) ? + true //~czy teksturę ma nieprzezroczystą? + : + (Current->fSquareMinRadius != 0.0) ? + true //~czy widoczny z bliska? + : + (Current->fSquareRadius <= 90000.0)) //~czy widoczny z daleka? + GetSubRect(Current->pCenter.x, Current->pCenter.z)->NodeAdd(Current); + else // dodajemy do kwadratu kilometrowego + GetRect(Current->pCenter.x, Current->pCenter.z)->NodeAdd(Current); + } + // if (Current->iType!=TP_DYNAMIC) + // GetSubRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current); + } } -// else if ((Current->iType!=GL_TRIANGLES)&&(Current->iType!=GL_TRIANGLE_STRIP)?true //~czy trójkąt? - else if ((Current->iType!=GL_TRIANGLES)?true //~czy trójkąt? - :(Current->iFlags&0x20)?true //~czy teksturę ma nieprzezroczystą? - :(Current->fSquareMinRadius!=0.0)?true //~czy widoczny z bliska? - :(Current->fSquareRadius<=90000.0)) //~czy widoczny z daleka? - GetSubRect(Current->pCenter.x,Current->pCenter.z)->NodeAdd(Current); - else //dodajemy do kwadratu kilometrowego - GetRect(Current->pCenter.x,Current->pCenter.z)->NodeAdd(Current); - } - //if (Current->iType!=TP_DYNAMIC) - // GetSubRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current); - } - } - for (i=0;i0) - { - glFogi(GL_FOG_MODE, GL_LINEAR); - glFogfv(GL_FOG_COLOR, Global::FogColor); // set fog color - glFogf(GL_FOG_START, Global::fFogStart); // fog start depth - glFogf(GL_FOG_END, Global::fFogEnd); // fog end depth - glEnable(GL_FOG); - } - else - glDisable(GL_FOG); - glDisable(GL_LIGHTING); - glLightfv(GL_LIGHT0,GL_POSITION,Global::lightPos); //daylight position - glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); //kolor wszechobceny - glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); //kolor padający - glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); //kolor odbity - //musi być tutaj, bo wcześniej nie mieliśmy wartości światła - if (Global::fMoveLight>=0.0) //albo tak, albo niech ustala minimum ciemności w nocy - { - Global::fLuminance= //obliczenie luminacji "światła w ciemności" - +0.150*Global::ambientDayLight[0] //R - +0.295*Global::ambientDayLight[1] //G - +0.055*Global::ambientDayLight[2]; //B - if (Global::fLuminance>0.1) //jeśli miało by być za jasno - for (int i=0;i<3;i++) - Global::ambientDayLight[i]*=0.1/Global::fLuminance; //ograniczenie jasności w nocy - glLightModelfv(GL_LIGHT_MODEL_AMBIENT,Global::ambientDayLight); - } - else if (Global::bDoubleAmbient) //Ra: wcześniej było ambient dawane na obydwa światła - glLightModelfv(GL_LIGHT_MODEL_AMBIENT,Global::ambientDayLight); - glEnable(GL_LIGHTING); - WriteLog("FirstInit is done"); + for (i = 0; i < iNumRects; ++i) + for (j = 0; j < iNumRects; ++j) + Rects[i][j].Optimize(); // optymalizacja obiektów w sektorach + WriteLog("InitNormals OK"); + WriteLog("InitTracks"); + InitTracks(); //łączenie odcinków ze sobą i przyklejanie eventów + WriteLog("InitTracks OK"); + WriteLog("InitTraction"); + InitTraction(); //łączenie drutów ze sobą + WriteLog("InitTraction OK"); + WriteLog("InitEvents"); + InitEvents(); + WriteLog("InitEvents OK"); + WriteLog("InitLaunchers"); + InitLaunchers(); + WriteLog("InitLaunchers OK"); + WriteLog("InitGlobalTime"); + // ABu 160205: juz nie TODO :) + GlobalTime = new TMTableTime( + hh, mm, srh, srm, ssh, + ssm); // McZapkie-300302: inicjacja czasu rozkladowego - TODO: czytac z trasy! + WriteLog("InitGlobalTime OK"); + // jeszcze ustawienie pogody, gdyby nie było w scenerii wpisów + glClearColor(Global::AtmoColor[0], Global::AtmoColor[1], Global::AtmoColor[2], + 0.0); // Background Color + if (Global::fFogEnd > 0) + { + glFogi(GL_FOG_MODE, GL_LINEAR); + glFogfv(GL_FOG_COLOR, Global::FogColor); // set fog color + glFogf(GL_FOG_START, Global::fFogStart); // fog start depth + glFogf(GL_FOG_END, Global::fFogEnd); // fog end depth + glEnable(GL_FOG); + } + else + glDisable(GL_FOG); + glDisable(GL_LIGHTING); + glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos); // daylight position + glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); // kolor wszechobceny + glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); // kolor padający + glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); // kolor odbity + // musi być tutaj, bo wcześniej nie mieliśmy wartości światła + if (Global::fMoveLight >= 0.0) // albo tak, albo niech ustala minimum ciemności w nocy + { + Global::fLuminance = // obliczenie luminacji "światła w ciemności" + +0.150 * Global::ambientDayLight[0] // R + + 0.295 * Global::ambientDayLight[1] // G + + 0.055 * Global::ambientDayLight[2]; // B + if (Global::fLuminance > 0.1) // jeśli miało by być za jasno + for (int i = 0; i < 3; i++) + Global::ambientDayLight[i] *= + 0.1 / Global::fLuminance; // ograniczenie jasności w nocy + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Global::ambientDayLight); + } + else if (Global::bDoubleAmbient) // Ra: wcześniej było ambient dawane na obydwa światła + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Global::ambientDayLight); + glEnable(GL_LIGHTING); + WriteLog("FirstInit is done"); }; -bool __fastcall TGround::Init(AnsiString asFile,HDC hDC) -{//główne wczytywanie scenerii - if (asFile.LowerCase().SubString(1,7)=="scenery") - asFile.Delete(1,8); //Ra: usunięcie niepotrzebnych znaków - zgodność wstecz z 2003 - WriteLog("Loading scenery from "+asFile); - Global::pGround=this; - //pTrain=NULL; - pOrigin=aRotate=vector3(0,0,0); //zerowanie przesunięcia i obrotu - AnsiString str=""; - //TFileStream *fs; - //int size; - std::string subpath=Global::asCurrentSceneryPath.c_str(); // "scenery/"; - cParser parser(asFile.c_str(),cParser::buffer_FILE,subpath,Global::bLoadTraction); - std::string token; +bool __fastcall TGround::Init(AnsiString asFile, HDC hDC) +{ // główne wczytywanie scenerii + if (asFile.LowerCase().SubString(1, 7) == "scenery") + asFile.Delete(1, 8); // Ra: usunięcie niepotrzebnych znaków - zgodność wstecz z 2003 + WriteLog("Loading scenery from " + asFile); + Global::pGround = this; + // pTrain=NULL; + pOrigin = aRotate = vector3(0, 0, 0); // zerowanie przesunięcia i obrotu + AnsiString str = ""; + // TFileStream *fs; + // int size; + std::string subpath = Global::asCurrentSceneryPath.c_str(); // "scenery/"; + cParser parser(asFile.c_str(), cParser::buffer_FILE, subpath, Global::bLoadTraction); + std::string token; -/* - TFileStream *fs; - fs=new TFileStream(asFile , fmOpenRead | fmShareCompat ); - AnsiString str=""; - int size=fs->Size; - str.SetLength(size); - fs->Read(str.c_str(),size); - str+=""; - delete fs; - TQueryParserComp *Parser; - Parser=new TQueryParserComp(NULL); - Parser->TextToParse=str; -// Parser->LoadStringToParse(asFile); - Parser->First(); - AnsiString Token,asFileName; -*/ - const int OriginStackMaxDepth=100; //rozmiar stosu dla zagnieżdżenia origin - int OriginStackTop=0; - vector3 OriginStack[OriginStackMaxDepth]; //stos zagnieżdżenia origin + /* + TFileStream *fs; + fs=new TFileStream(asFile , fmOpenRead | fmShareCompat ); + AnsiString str=""; + int size=fs->Size; + str.SetLength(size); + fs->Read(str.c_str(),size); + str+=""; + delete fs; + TQueryParserComp *Parser; + Parser=new TQueryParserComp(NULL); + Parser->TextToParse=str; + // Parser->LoadStringToParse(asFile); + Parser->First(); + AnsiString Token,asFileName; + */ + const int OriginStackMaxDepth = 100; // rozmiar stosu dla zagnieżdżenia origin + int OriginStackTop = 0; + vector3 OriginStack[OriginStackMaxDepth]; // stos zagnieżdżenia origin double tf; - int ParamCount,ParamPos; + int ParamCount, ParamPos; - //ABu: Jezeli nie ma definicji w scenerii to ustawiane ponizsze wartosci: - hh=10; //godzina startu - mm=30; //minuty startu - srh=6; //godzina wschodu slonca - srm=0; //minuty wschodu slonca - ssh=20; //godzina zachodu slonca - ssm=0; //minuty zachodu slonca - TGroundNode *LastNode=NULL; //do użycia w trainset - iNumNodes=0; - token=""; + // ABu: Jezeli nie ma definicji w scenerii to ustawiane ponizsze wartosci: + hh = 10; // godzina startu + mm = 30; // minuty startu + srh = 6; // godzina wschodu slonca + srm = 0; // minuty wschodu slonca + ssh = 20; // godzina zachodu slonca + ssm = 0; // minuty zachodu slonca + TGroundNode *LastNode = NULL; // do użycia w trainset + iNumNodes = 0; + token = ""; parser.getTokens(); parser >> token; - int refresh=0; + int refresh = 0; - while (token!="") //(!Parser->EndOfFile) + while (token != "") //(!Parser->EndOfFile) { - if (refresh==50) - {//SwapBuffers(hDC); //Ra: bez ogranicznika za bardzo spowalnia :( a u niektórych miga - refresh=0; - Global::DoEvents(); - } - else ++refresh; - str=AnsiString(token.c_str()); - if (str==AnsiString("node")) - { - LastNode=AddGroundNode(&parser); //rozpoznanie węzła - if (LastNode) - {//jeżeli przetworzony poprawnie - if (LastNode->iType==GL_TRIANGLES) - {if (!LastNode->Vertices) - SafeDelete(LastNode); //usuwamy nieprzezroczyste trójkąty terenu - } - else if (Global::bLoadTraction?false:LastNode->iType==TP_TRACTION) - SafeDelete(LastNode); //usuwamy druty, jeśli wyłączone - if (LastNode) //dopiero na koniec dopisujemy do tablic - if (LastNode->iType!=TP_DYNAMIC) - {//jeśli nie jest pojazdem - LastNode->nNext=nRootOfType[LastNode->iType]; //ostatni dodany dołączamy na końcu nowego - nRootOfType[LastNode->iType]=LastNode; //ustawienie nowego na początku listy - iNumNodes++; + if (refresh == 50) + { // SwapBuffers(hDC); //Ra: bez ogranicznika za bardzo spowalnia :( a u niektórych miga + refresh = 0; + Global::DoEvents(); } else - {//jeśli jest pojazdem - //if (!bInitDone) FirstInit(); //jeśli nie było w scenerii - if (LastNode->DynamicObject->Mechanik) //ale może być pasażer - if (LastNode->DynamicObject->Mechanik->Primary()) //jeśli jest głównym (pasażer nie jest) - nTrainSetDriver=LastNode; //pojazd, któremu zostanie wysłany rozkład - LastNode->nNext=nRootDynamic; - nRootDynamic=LastNode; //dopisanie z przodu do listy - //if (bTrainSet && (LastNode?(LastNode->iType==TP_DYNAMIC):false)) - if (nTrainSetNode) //jeżeli istnieje wcześniejszy TP_DYNAMIC - nTrainSetNode->DynamicObject->AttachPrev(LastNode->DynamicObject,TempConnectionType[iTrainSetWehicleNumber-2]); - nTrainSetNode=LastNode; //ostatnio wczytany - if (TempConnectionType[iTrainSetWehicleNumber-1]==0) //jeśli sprzęg jest zerowy, to wysłać rozkład do składu - {//powinien też tu wchodzić, gdy pojazd bez trainset - 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=NULL; //a przy "endtrainset" już wtedy nie potrzeba - } - } + ++refresh; + str = AnsiString(token.c_str()); + if (str == AnsiString("node")) + { + LastNode = AddGroundNode(&parser); // rozpoznanie węzła + if (LastNode) + { // jeżeli przetworzony poprawnie + if (LastNode->iType == GL_TRIANGLES) + { + if (!LastNode->Vertices) + SafeDelete(LastNode); // usuwamy nieprzezroczyste trójkąty terenu + } + else if (Global::bLoadTraction ? false : LastNode->iType == TP_TRACTION) + SafeDelete(LastNode); // usuwamy druty, jeśli wyłączone + if (LastNode) // dopiero na koniec dopisujemy do tablic + if (LastNode->iType != TP_DYNAMIC) + { // jeśli nie jest pojazdem + LastNode->nNext = nRootOfType[LastNode->iType]; // ostatni dodany dołączamy + // na końcu nowego + nRootOfType[LastNode->iType] = + LastNode; // ustawienie nowego na początku listy + iNumNodes++; + } + else + { // jeśli jest pojazdem + // if (!bInitDone) FirstInit(); //jeśli nie było w scenerii + if (LastNode->DynamicObject->Mechanik) // ale może być pasażer + if (LastNode->DynamicObject->Mechanik + ->Primary()) // jeśli jest głównym (pasażer nie jest) + nTrainSetDriver = + LastNode; // pojazd, któremu zostanie wysłany rozkład + LastNode->nNext = nRootDynamic; + nRootDynamic = LastNode; // dopisanie z przodu do listy + // if (bTrainSet && (LastNode?(LastNode->iType==TP_DYNAMIC):false)) + if (nTrainSetNode) // jeżeli istnieje wcześniejszy TP_DYNAMIC + nTrainSetNode->DynamicObject->AttachPrev( + LastNode->DynamicObject, + TempConnectionType[iTrainSetWehicleNumber - 2]); + nTrainSetNode = LastNode; // ostatnio wczytany + if (TempConnectionType[iTrainSetWehicleNumber - 1] == + 0) // jeśli sprzęg jest zerowy, to wysłać rozkład do składu + { // powinien też tu wchodzić, gdy pojazd bez trainset + 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 = + NULL; // a przy "endtrainset" już wtedy nie potrzeba + } + } + } + } + else + { + Error("Scene parse error near " + AnsiString(token.c_str())); + // break; + } } - } - else - { - Error("Scene parse error near "+AnsiString(token.c_str())); - //break; - } - } - else - if (str==AnsiString("trainset")) - { - iTrainSetWehicleNumber=0; - nTrainSetNode=NULL; - nTrainSetDriver=NULL; //pojazd, któremu zostanie wysłany rozkład - bTrainSet=true; - parser.getTokens(); - parser >> token; - asTrainName=AnsiString(token.c_str()); //McZapkie: rodzaj+nazwa pociagu w SRJP - parser.getTokens(); - parser >> token; - asTrainSetTrack=AnsiString(token.c_str()); //ścieżka startowa - parser.getTokens(2); - parser >> fTrainSetDist >> fTrainSetVel; //przesunięcie i prędkość - } - else - if (str==AnsiString("endtrainset")) - {//McZapkie-110103: sygnaly konca pociagu ale tylko dla pociagow rozkladowych - if (nTrainSetNode) //trainset bez dynamic się sypał - {//powinien też tu wchodzić, gdy pojazd bez trainset - 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); - } - } - if (LastNode) //ostatni wczytany obiekt - if (LastNode->iType==TP_DYNAMIC) //o ile jest pojazdem (na ogół jest, ale kto wie...) - if (iTrainSetWehicleNumber?!TempConnectionType[iTrainSetWehicleNumber-1]:false) //jeśli ostatni pojazd ma sprzęg 0 - LastNode->DynamicObject->RaLightsSet(-1,2+32+64); //to założymy mu końcówki blaszane (jak AI się odpali, to sobie poprawi) - bTrainSet=false; - fTrainSetVel=0; - //iTrainSetConnection=0; - nTrainSetNode=nTrainSetDriver=NULL; - iTrainSetWehicleNumber=0; - } - else if (str==AnsiString("event")) - { - TEvent *tmp=new TEvent(); - tmp->Load(&parser,&pOrigin); - if (tmp->Type==tp_Unknown) - delete tmp; - else - {//najpierw sprawdzamy, czy nie ma, a potem dopisujemy - TEvent *found=FindEvent(tmp->asName); - if (found) - {//jeśli znaleziony duplikat - int i=tmp->asName.Length(); - if (tmp->asName[1]=='#') //zawsze jeden znak co najmniej jest - {delete tmp; tmp=NULL;} //utylizacja duplikatu z krzyżykiem - else if (i>8?tmp->asName.SubString(1,9)=="lineinfo:":false) //tymczasowo wyjątki - {delete tmp; tmp=NULL;} //tymczasowa utylizacja duplikatów W5 - else if (i>8?tmp->asName.SubString(i-7,8)=="_warning":false) //tymczasowo wyjątki - {delete tmp; tmp=NULL;} //tymczasowa utylizacja duplikatu z trąbieniem - else if (i>4?tmp->asName.SubString(i-3,4)=="_shp":false) //nie podlegają logowaniu - {delete tmp; tmp=NULL;} //tymczasowa utylizacja duplikatu SHP - if (tmp) //jeśli nie został zutylizowany - if (Global::bJoinEvents) - found->Append(tmp); //doczepka (taki wirtualny multiple bez warunków) - else - {ErrorLog("Duplicated event: "+tmp->asName); - found->Append(tmp); //doczepka (taki wirtualny multiple bez warunków) - found->Type=tp_Ignored; //dezaktywacja pierwotnego - taka proteza na wsteczną zgodność - //SafeDelete(tmp); //bezlitośnie usuwamy wszelkie duplikaty, żeby nie zaśmiecać drzewka - } - } - if (tmp) - {//jeśli nie duplikat - tmp->evNext2=RootEvent; //lista wszystkich eventów (m.in. do InitEvents) - 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->asName.Pos("onstart")) //event uruchamiany automatycznie po starcie - AddToQuery(RootEvent,NULL); //dodanie do kolejki - sTracks->Add(0,tmp->asName.c_str(),tmp); //dodanie do wyszukiwarki + else if (str == AnsiString("trainset")) + { + iTrainSetWehicleNumber = 0; + nTrainSetNode = NULL; + nTrainSetDriver = NULL; // pojazd, któremu zostanie wysłany rozkład + bTrainSet = true; + parser.getTokens(); + parser >> token; + asTrainName = AnsiString(token.c_str()); // McZapkie: rodzaj+nazwa pociagu w SRJP + parser.getTokens(); + parser >> token; + asTrainSetTrack = AnsiString(token.c_str()); //ścieżka startowa + parser.getTokens(2); + parser >> fTrainSetDist >> fTrainSetVel; // przesunięcie i prędkość } - } - } - } -// else -// if (str==AnsiString("include")) //Tolaris to zrobil wewnatrz parsera -// { -// Include(Parser); -// } - else if (str==AnsiString("rotate")) - { - //parser.getTokens(3); - //parser >> aRotate.x >> aRotate.y >> aRotate.z; //Ra: to potrafi dawać błędne rezultaty - parser.getTokens(); parser >> aRotate.x; - parser.getTokens(); parser >> aRotate.y; - parser.getTokens(); parser >> aRotate.z; - //WriteLog("*** rotate "+AnsiString(aRotate.x)+" "+AnsiString(aRotate.y)+" "+AnsiString(aRotate.z)); - } - else if (str==AnsiString("origin")) - { -// str=Parser->GetNextSymbol().LowerCase(); -// if (str=="begin") - { - if (OriginStackTop>=OriginStackMaxDepth-1) - { - MessageBox(0,AnsiString("Origin stack overflow ").c_str(),"Error",MB_OK); - break; - } - parser.getTokens(3); - parser >> OriginStack[OriginStackTop].x >> OriginStack[OriginStackTop].y >> OriginStack[OriginStackTop].z; - pOrigin+=OriginStack[OriginStackTop]; //sumowanie całkowitego przesunięcia - OriginStackTop++; //zwiększenie wskaźnika stosu - } - } - else if (str==AnsiString("endorigin")) - { -// else - // if (str=="end") - { - if (OriginStackTop<=0) - { - MessageBox(0,AnsiString("Origin stack underflow ").c_str(),"Error",MB_OK); - break; - } + else if (str == AnsiString("endtrainset")) + { // McZapkie-110103: sygnaly konca pociagu ale tylko dla pociagow rozkladowych + if (nTrainSetNode) // trainset bez dynamic się sypał + { // powinien też tu wchodzić, gdy pojazd bez trainset + 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); + } + } + if (LastNode) // ostatni wczytany obiekt + if (LastNode->iType == + TP_DYNAMIC) // o ile jest pojazdem (na ogół jest, ale kto wie...) + if (iTrainSetWehicleNumber ? !TempConnectionType[iTrainSetWehicleNumber - 1] : + false) // jeśli ostatni pojazd ma sprzęg 0 + LastNode->DynamicObject->RaLightsSet(-1, 2 + 32 + 64); // to założymy mu + // końcówki blaszane + // (jak AI się + // odpali, to sobie + // poprawi) + bTrainSet = false; + fTrainSetVel = 0; + // iTrainSetConnection=0; + nTrainSetNode = nTrainSetDriver = NULL; + iTrainSetWehicleNumber = 0; + } + else if (str == AnsiString("event")) + { + TEvent *tmp = new TEvent(); + tmp->Load(&parser, &pOrigin); + if (tmp->Type == tp_Unknown) + delete tmp; + else + { // najpierw sprawdzamy, czy nie ma, a potem dopisujemy + TEvent *found = FindEvent(tmp->asName); + if (found) + { // jeśli znaleziony duplikat + int i = tmp->asName.Length(); + if (tmp->asName[1] == '#') // zawsze jeden znak co najmniej jest + { + delete tmp; + tmp = NULL; + } // utylizacja duplikatu z krzyżykiem + else if (i > 8 ? tmp->asName.SubString(1, 9) == "lineinfo:" : + false) // tymczasowo wyjątki + { + delete tmp; + tmp = NULL; + } // tymczasowa utylizacja duplikatów W5 + else if (i > 8 ? tmp->asName.SubString(i - 7, 8) == "_warning" : + false) // tymczasowo wyjątki + { + delete tmp; + tmp = NULL; + } // tymczasowa utylizacja duplikatu z trąbieniem + else if (i > 4 ? tmp->asName.SubString(i - 3, 4) == "_shp" : + false) // nie podlegają logowaniu + { + delete tmp; + tmp = NULL; + } // tymczasowa utylizacja duplikatu SHP + if (tmp) // jeśli nie został zutylizowany + if (Global::bJoinEvents) + found->Append(tmp); // doczepka (taki wirtualny multiple bez warunków) + else + { + ErrorLog("Duplicated event: " + tmp->asName); + found->Append(tmp); // doczepka (taki wirtualny multiple bez warunków) + found->Type = tp_Ignored; // dezaktywacja pierwotnego - taka proteza na + // wsteczną zgodność + // SafeDelete(tmp); //bezlitośnie usuwamy wszelkie duplikaty, żeby nie + // zaśmiecać drzewka + } + } + if (tmp) + { // jeśli nie duplikat + tmp->evNext2 = RootEvent; // lista wszystkich eventów (m.in. do InitEvents) + 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->asName.Pos( + "onstart")) // event uruchamiany automatycznie po starcie + AddToQuery(RootEvent, NULL); // dodanie do kolejki + sTracks->Add(0, tmp->asName.c_str(), tmp); // dodanie do wyszukiwarki + } + } + } + } + // else + // if (str==AnsiString("include")) //Tolaris to zrobil wewnatrz parsera + // { + // Include(Parser); + // } + else if (str == AnsiString("rotate")) + { + // parser.getTokens(3); + // parser >> aRotate.x >> aRotate.y >> aRotate.z; //Ra: to potrafi dawać błędne + // rezultaty + parser.getTokens(); + parser >> aRotate.x; + parser.getTokens(); + parser >> aRotate.y; + parser.getTokens(); + parser >> aRotate.z; + // WriteLog("*** rotate "+AnsiString(aRotate.x)+" "+AnsiString(aRotate.y)+" + // "+AnsiString(aRotate.z)); + } + else if (str == AnsiString("origin")) + { + // str=Parser->GetNextSymbol().LowerCase(); + // if (str=="begin") + { + if (OriginStackTop >= OriginStackMaxDepth - 1) + { + MessageBox(0, AnsiString("Origin stack overflow ").c_str(), "Error", MB_OK); + break; + } + parser.getTokens(3); + parser >> OriginStack[OriginStackTop].x >> OriginStack[OriginStackTop].y >> + OriginStack[OriginStackTop].z; + pOrigin += OriginStack[OriginStackTop]; // sumowanie całkowitego przesunięcia + OriginStackTop++; // zwiększenie wskaźnika stosu + } + } + else if (str == AnsiString("endorigin")) + { + // else + // if (str=="end") + { + if (OriginStackTop <= 0) + { + MessageBox(0, AnsiString("Origin stack underflow ").c_str(), "Error", MB_OK); + break; + } - OriginStackTop--; //zmniejszenie wskaźnika stosu - pOrigin-=OriginStack[OriginStackTop]; - } - } - else if (str==AnsiString("atmo")) //TODO: uporzadkowac gdzie maja byc parametry mgly! - {//Ra: ustawienie parametrów OpenGL przeniesione do FirstInit - WriteLog("Scenery atmo definition"); - parser.getTokens(3); - parser >> Global::AtmoColor[0] >> Global::AtmoColor[1] >> Global::AtmoColor[2]; - parser.getTokens(2); - parser >> Global::fFogStart >> Global::fFogEnd; - if (Global::fFogEnd>0.0) - {//ostatnie 3 parametry są opcjonalne - parser.getTokens(3); - parser >> Global::FogColor[0] >> Global::FogColor[1] >> Global::FogColor[2]; - } - parser.getTokens(); - parser >> token; - while (token.compare("endatmo")!=0) - {//a kolejne parametry są pomijane - parser.getTokens(); - parser >> token; - } - } - else if (str==AnsiString("time")) - { - WriteLog("Scenery time definition"); - char temp_in[9]; - char temp_out[9]; - int i, j; - parser.getTokens(); - parser >> temp_in; - for(j=0;j<=8;j++) temp_out[j]=' '; - for (i=0; temp_in[i]!=':'; i++) - temp_out[i]=temp_in[i]; - hh=atoi(temp_out); - for(j=0;j<=8;j++) temp_out[j]=' '; - for (j=i+1; j<=8; j++) - temp_out[j-(i+1)]=temp_in[j]; - mm=atoi(temp_out); + OriginStackTop--; // zmniejszenie wskaźnika stosu + pOrigin -= OriginStack[OriginStackTop]; + } + } + else if (str == AnsiString("atmo")) // TODO: uporzadkowac gdzie maja byc parametry mgly! + { // Ra: ustawienie parametrów OpenGL przeniesione do FirstInit + WriteLog("Scenery atmo definition"); + parser.getTokens(3); + parser >> Global::AtmoColor[0] >> Global::AtmoColor[1] >> Global::AtmoColor[2]; + parser.getTokens(2); + parser >> Global::fFogStart >> Global::fFogEnd; + if (Global::fFogEnd > 0.0) + { // ostatnie 3 parametry są opcjonalne + parser.getTokens(3); + parser >> Global::FogColor[0] >> Global::FogColor[1] >> Global::FogColor[2]; + } + parser.getTokens(); + parser >> token; + while (token.compare("endatmo") != 0) + { // a kolejne parametry są pomijane + parser.getTokens(); + parser >> token; + } + } + else if (str == AnsiString("time")) + { + WriteLog("Scenery time definition"); + char temp_in[9]; + char temp_out[9]; + int i, j; + parser.getTokens(); + parser >> temp_in; + for (j = 0; j <= 8; j++) + temp_out[j] = ' '; + for (i = 0; temp_in[i] != ':'; i++) + temp_out[i] = temp_in[i]; + hh = atoi(temp_out); + for (j = 0; j <= 8; j++) + temp_out[j] = ' '; + for (j = i + 1; j <= 8; j++) + temp_out[j - (i + 1)] = temp_in[j]; + mm = atoi(temp_out); + parser.getTokens(); + parser >> temp_in; + for (j = 0; j <= 8; j++) + temp_out[j] = ' '; + for (i = 0; temp_in[i] != ':'; i++) + temp_out[i] = temp_in[i]; + srh = atoi(temp_out); + for (j = 0; j <= 8; j++) + temp_out[j] = ' '; + for (j = i + 1; j <= 8; j++) + temp_out[j - (i + 1)] = temp_in[j]; + srm = atoi(temp_out); - parser.getTokens(); - parser >> temp_in; - for(j=0;j<=8;j++) temp_out[j]=' '; - for (i=0; temp_in[i]!=':'; i++) - temp_out[i]=temp_in[i]; - srh=atoi(temp_out); - for(j=0;j<=8;j++) temp_out[j]=' '; - for (j=i+1; j<=8; j++) - temp_out[j-(i+1)]=temp_in[j]; - srm=atoi(temp_out); + parser.getTokens(); + parser >> temp_in; + for (j = 0; j <= 8; j++) + temp_out[j] = ' '; + for (i = 0; temp_in[i] != ':'; i++) + temp_out[i] = temp_in[i]; + ssh = atoi(temp_out); + for (j = 0; j <= 8; j++) + temp_out[j] = ' '; + for (j = i + 1; j <= 8; j++) + temp_out[j - (i + 1)] = temp_in[j]; + ssm = atoi(temp_out); + while (token.compare("endtime") != 0) + { + parser.getTokens(); + parser >> token; + } + } + else if (str == AnsiString("light")) + { // Ra: ustawianie światła przeniesione do FirstInit + WriteLog("Scenery light definition"); + vector3 lp; + parser.getTokens(); + parser >> lp.x; + parser.getTokens(); + parser >> lp.y; + parser.getTokens(); + parser >> lp.z; + lp = Normalize(lp); // kierunek padania + Global::lightPos[0] = lp.x; // daylight position + Global::lightPos[1] = lp.y; + Global::lightPos[2] = lp.z; + parser.getTokens(); + parser >> Global::ambientDayLight[0]; // kolor wszechobceny + parser.getTokens(); + parser >> Global::ambientDayLight[1]; + parser.getTokens(); + parser >> Global::ambientDayLight[2]; - parser.getTokens(); - parser >> temp_in; - for(j=0;j<=8;j++) temp_out[j]=' '; - for (i=0; temp_in[i]!=':'; i++) - temp_out[i]=temp_in[i]; - ssh=atoi(temp_out); - for(j=0;j<=8;j++) temp_out[j]=' '; - for (j=i+1; j<=8; j++) - temp_out[j-(i+1)]=temp_in[j]; - ssm=atoi(temp_out); - while (token.compare("endtime")!=0) - { - parser.getTokens(); - parser >> token; - } - } - else if (str==AnsiString("light")) - {//Ra: ustawianie światła przeniesione do FirstInit - WriteLog("Scenery light definition"); - vector3 lp; - parser.getTokens(); parser >> lp.x; - parser.getTokens(); parser >> lp.y; - parser.getTokens(); parser >> lp.z; - lp=Normalize(lp); //kierunek padania - Global::lightPos[0]=lp.x; //daylight position - Global::lightPos[1]=lp.y; - Global::lightPos[2]=lp.z; - parser.getTokens(); parser >> Global::ambientDayLight[0]; //kolor wszechobceny - parser.getTokens(); parser >> Global::ambientDayLight[1]; - parser.getTokens(); parser >> Global::ambientDayLight[2]; + parser.getTokens(); + parser >> Global::diffuseDayLight[0]; // kolor padający + parser.getTokens(); + parser >> Global::diffuseDayLight[1]; + parser.getTokens(); + parser >> Global::diffuseDayLight[2]; - parser.getTokens(); parser >> Global::diffuseDayLight[0]; //kolor padający - parser.getTokens(); parser >> Global::diffuseDayLight[1]; - parser.getTokens(); parser >> Global::diffuseDayLight[2]; + parser.getTokens(); + parser >> Global::specularDayLight[0]; // kolor odbity + parser.getTokens(); + parser >> Global::specularDayLight[1]; + parser.getTokens(); + parser >> Global::specularDayLight[2]; - parser.getTokens(); parser >> Global::specularDayLight[0]; //kolor odbity - parser.getTokens(); parser >> Global::specularDayLight[1]; - parser.getTokens(); parser >> Global::specularDayLight[2]; + do + { + parser.getTokens(); + parser >> token; + } while (token.compare("endlight") != 0); + } + else if (str == AnsiString("camera")) + { + vector3 xyz, abc; + xyz = abc = vector3(0, 0, 0); // wartości domyślne, bo nie wszystie muszą być + int i = -1, into = -1; // do której definicji kamery wstawić + WriteLog("Scenery camera definition"); + do + { // opcjonalna siódma liczba określa numer kamery, a kiedyś były tylko 3 + parser.getTokens(); + parser >> token; + switch (++i) + { // kiedyś camera miało tylko 3 współrzędne + case 0: + xyz.x = atof(token.c_str()); + break; + case 1: + xyz.y = atof(token.c_str()); + break; + case 2: + xyz.z = atof(token.c_str()); + break; + case 3: + abc.x = atof(token.c_str()); + break; + case 4: + abc.y = atof(token.c_str()); + break; + case 5: + abc.z = atof(token.c_str()); + break; + case 6: + into = atoi(token.c_str()); // takie sobie, bo można wpisać -1 + } + } while (token.compare("endcamera") != 0); + if (into < 0) + into = ++Global::iCameraLast; + if ((into >= 0) && (into < 10)) + { // przepisanie do odpowiedniego miejsca w tabelce + Global::pFreeCameraInit[into] = xyz; + abc.x = DegToRad(abc.x); + abc.y = DegToRad(abc.y); + abc.z = DegToRad(abc.z); + Global::pFreeCameraInitAngle[into] = abc; + Global::iCameraLast = into; // numer ostatniej + } + } + else if (str == AnsiString("sky")) + { // youBy - niebo z pliku + WriteLog("Scenery sky definition"); + parser.getTokens(); + parser >> token; + AnsiString SkyTemp; + SkyTemp = AnsiString(token.c_str()); + if (Global::asSky == "1") + Global::asSky = SkyTemp; + do + { // pożarcie dodatkowych parametrów + parser.getTokens(); + parser >> token; + } while (token.compare("endsky") != 0); + WriteLog(Global::asSky.c_str()); + } + else if (str == AnsiString("firstinit")) + FirstInit(); + else if (str == AnsiString("description")) + { + do + { + parser.getTokens(); + parser >> token; + } while (token.compare("enddescription") != 0); + } + else if (str == AnsiString("test")) + { // wypisywanie treści po przetworzeniu + WriteLog("---> Parser test:"); + do + { + parser.getTokens(); + parser >> token; + WriteLog(token.c_str()); + } while (token.compare("endtest") != 0); + WriteLog("---> End of parser test."); + } + else if (str == AnsiString("config")) + { // możliwość przedefiniowania parametrów w scenerii + Global::ConfigParse(NULL, &parser); // parsowanie dodatkowych ustawień + } + else if (str != AnsiString("")) + { // pomijanie od nierozpoznanej komendy do jej zakończenia + if ((token.length() > 2) && (atof(token.c_str()) == 0.0)) + { // jeśli nie liczba, to spróbować pominąć komendę + WriteLog(AnsiString("Unrecognized command: " + str)); + str = "end" + str; + do + { + parser.getTokens(); + token = ""; + parser >> token; + } while ((token != "") && (token.compare(str.c_str()) != 0)); + } + else // jak liczba to na pewno błąd + Error(AnsiString("Unrecognized command: " + str)); + } + else if (str == AnsiString("")) + break; - do - { parser.getTokens(); parser >> token; - } while (token.compare("endlight")!=0); + // LastNode=NULL; - } - else if (str==AnsiString("camera")) - { - vector3 xyz,abc; - xyz=abc=vector3(0,0,0); //wartości domyślne, bo nie wszystie muszą być - int i=-1,into=-1; //do której definicji kamery wstawić - WriteLog("Scenery camera definition"); - do - {//opcjonalna siódma liczba określa numer kamery, a kiedyś były tylko 3 - parser.getTokens(); parser >> token; - switch (++i) - {//kiedyś camera miało tylko 3 współrzędne - case 0: xyz.x=atof(token.c_str()); break; - case 1: xyz.y=atof(token.c_str()); break; - case 2: xyz.z=atof(token.c_str()); break; - case 3: abc.x=atof(token.c_str()); break; - case 4: abc.y=atof(token.c_str()); break; - case 5: abc.z=atof(token.c_str()); break; - case 6: into=atoi(token.c_str()); //takie sobie, bo można wpisać -1 - } - } while (token.compare("endcamera")!=0); - if (into<0) into=++Global::iCameraLast; - if ((into>=0)&&(into<10)) - {//przepisanie do odpowiedniego miejsca w tabelce - Global::pFreeCameraInit[into]=xyz; - abc.x=DegToRad(abc.x); - abc.y=DegToRad(abc.y); - abc.z=DegToRad(abc.z); - Global::pFreeCameraInitAngle[into]=abc; - Global::iCameraLast=into; //numer ostatniej - } - } - else if (str==AnsiString("sky")) - {//youBy - niebo z pliku - WriteLog("Scenery sky definition"); - parser.getTokens(); - parser >> token; - AnsiString SkyTemp; - SkyTemp=AnsiString(token.c_str()); - if (Global::asSky=="1") Global::asSky=SkyTemp; - do - {//pożarcie dodatkowych parametrów - parser.getTokens(); parser >> token; - } while (token.compare("endsky")!=0); - WriteLog(Global::asSky.c_str()); - } - else if (str==AnsiString("firstinit")) - FirstInit(); - else if (str==AnsiString("description")) - { - do - { - parser.getTokens(); - parser >> token; - } while (token.compare("enddescription")!=0); - } - else if (str==AnsiString("test")) - {//wypisywanie treści po przetworzeniu - WriteLog("---> Parser test:"); - do - { - parser.getTokens(); - parser >> token; - WriteLog(token.c_str()); - } while (token.compare("endtest")!=0); - WriteLog("---> End of parser test."); - } - else if (str==AnsiString("config")) - {//możliwość przedefiniowania parametrów w scenerii - Global::ConfigParse(NULL,&parser); //parsowanie dodatkowych ustawień - } - else if (str!=AnsiString("")) - {//pomijanie od nierozpoznanej komendy do jej zakończenia - if ((token.length()>2)&&(atof(token.c_str())==0.0)) - {//jeśli nie liczba, to spróbować pominąć komendę - WriteLog(AnsiString("Unrecognized command: "+str)); - str="end"+str; - do - { + token = ""; parser.getTokens(); - token=""; parser >> token; - } while ((token!="")&&(token.compare(str.c_str())!=0)); - } - else //jak liczba to na pewno błąd - Error(AnsiString("Unrecognized command: "+str)); - } - else - if (str==AnsiString("")) - break; - - //LastNode=NULL; - - token=""; - parser.getTokens(); - parser >> token; } - delete parser; - sTracks->Sort(TP_TRACK); //finalne sortowanie drzewa torów - sTracks->Sort(TP_MEMCELL); //finalne sortowanie drzewa komórek pamięci - sTracks->Sort(TP_MODEL); //finalne sortowanie drzewa modeli - sTracks->Sort(0); //finalne sortowanie drzewa eventów - if (!bInitDone) FirstInit(); //jeśli nie było w scenerii - if (Global::pTerrainCompact) - TerrainWrite(); //Ra: teraz można zapisać teren w jednym pliku - Global::iPause&=~0x10; //koniec pauzy wczytywania - return true; + delete parser; + sTracks->Sort(TP_TRACK); // finalne sortowanie drzewa torów + sTracks->Sort(TP_MEMCELL); // finalne sortowanie drzewa komórek pamięci + sTracks->Sort(TP_MODEL); // finalne sortowanie drzewa modeli + sTracks->Sort(0); // finalne sortowanie drzewa eventów + if (!bInitDone) + FirstInit(); // jeśli nie było w scenerii + if (Global::pTerrainCompact) + TerrainWrite(); // Ra: teraz można zapisać teren w jednym pliku + Global::iPause &= ~0x10; // koniec pauzy wczytywania + return true; } bool __fastcall TGround::InitEvents() -{//łączenie eventów z pozostałymi obiektami - TGroundNode *tmp,*trk; - char buff[255]; - int i; - for (TEvent *Current=RootEvent;Current;Current=Current->evNext2) - { - switch (Current->Type) - { - case tp_AddValues: //sumowanie wartości - case tp_UpdateValues: //zmiana wartości - tmp=FindGroundNode(Current->asNodeName,TP_MEMCELL); //nazwa komórki powiązanej z eventem - if (tmp) - {//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) - trk=FindGroundNode(Current->asNodeName,TP_TRACK); //nazwa toru ta sama, co nazwa komórki - if (trk) Current->Params[9].asTrack=trk->pTrack; - if (!Current->Params[9].asTrack) - ErrorLog("Bad event: track \""+AnsiString(Current->asNodeName)+"\" does not exists in \""+Current->asName+"\""); - } - Current->Params[4].nGroundNode=tmp; - Current->Params[5].asMemCell=tmp->MemCell; //komórka do aktualizacji - if (Current->iFlags&(conditional_memcompare)) - Current->Params[9].asMemCell=tmp->MemCell; //komórka do badania warunku - if (!tmp->MemCell->asTrackName.IsEmpty()) //tor powiązany z komórką powiązaną z eventem - {//tu potrzebujemy wskaźnik do komórki w (tmp) - trk=FindGroundNode(tmp->MemCell->asTrackName,TP_TRACK); - if (trk) - Current->Params[6].asTrack=trk->pTrack; - else - ErrorLog("Bad memcell: track \""+tmp->MemCell->asTrackName+"\" not exists in memcell \""+tmp->asName+"\""); - } - else - Current->Params[6].asTrack=NULL; - } - else - {//nie ma komórki, to nie będzie działał poprawnie - Current->Type=tp_Ignored; //deaktywacja - ErrorLog("Bad event: \""+Current->asName+"\" cannot find memcell \""+Current->asNodeName+"\""); - } - break; - case tp_LogValues: //skojarzenie z memcell - if (Current->asNodeName.IsEmpty()) - {//brak skojarzenia daje logowanie wszystkich - Current->Params[9].asMemCell=NULL; - break; - } - case tp_GetValues: - case tp_WhoIs: - tmp=FindGroundNode(Current->asNodeName,TP_MEMCELL); - if (tmp) +{ //łączenie eventów z pozostałymi obiektami + TGroundNode *tmp, *trk; + char buff[255]; + int i; + for (TEvent *Current = RootEvent; Current; Current = Current->evNext2) { - Current->Params[8].nGroundNode=tmp; - Current->Params[9].asMemCell=tmp->MemCell; - if (Current->Type==tp_GetValues) //jeśli odczyt komórki - if (tmp->MemCell->IsVelocity()) //a komórka zawiera komendę SetVelocity albo ShuntVelocity - Current->bEnabled=false; //to event nie będzie dodawany do kolejki + switch (Current->Type) + { + case tp_AddValues: // sumowanie wartości + case tp_UpdateValues: // zmiana wartości + tmp = FindGroundNode(Current->asNodeName, + TP_MEMCELL); // nazwa komórki powiązanej z eventem + if (tmp) + { // 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) + trk = FindGroundNode(Current->asNodeName, + TP_TRACK); // nazwa toru ta sama, co nazwa komórki + if (trk) + Current->Params[9].asTrack = trk->pTrack; + if (!Current->Params[9].asTrack) + ErrorLog("Bad event: track \"" + AnsiString(Current->asNodeName) + + "\" does not exists in \"" + Current->asName + "\""); + } + Current->Params[4].nGroundNode = tmp; + Current->Params[5].asMemCell = tmp->MemCell; // komórka do aktualizacji + if (Current->iFlags & (conditional_memcompare)) + Current->Params[9].asMemCell = tmp->MemCell; // komórka do badania warunku + if (!tmp->MemCell->asTrackName + .IsEmpty()) // tor powiązany z komórką powiązaną z eventem + { // tu potrzebujemy wskaźnik do komórki w (tmp) + trk = FindGroundNode(tmp->MemCell->asTrackName, TP_TRACK); + if (trk) + Current->Params[6].asTrack = trk->pTrack; + else + ErrorLog("Bad memcell: track \"" + tmp->MemCell->asTrackName + + "\" not exists in memcell \"" + tmp->asName + "\""); + } + else + Current->Params[6].asTrack = NULL; + } + else + { // nie ma komórki, to nie będzie działał poprawnie + Current->Type = tp_Ignored; // deaktywacja + ErrorLog("Bad event: \"" + Current->asName + "\" cannot find memcell \"" + + Current->asNodeName + "\""); + } + break; + case tp_LogValues: // skojarzenie z memcell + if (Current->asNodeName.IsEmpty()) + { // brak skojarzenia daje logowanie wszystkich + Current->Params[9].asMemCell = NULL; + break; + } + case tp_GetValues: + case tp_WhoIs: + tmp = FindGroundNode(Current->asNodeName, TP_MEMCELL); + if (tmp) + { + Current->Params[8].nGroundNode = tmp; + Current->Params[9].asMemCell = tmp->MemCell; + if (Current->Type == tp_GetValues) // jeśli odczyt komórki + if (tmp->MemCell->IsVelocity()) // a komórka zawiera komendę SetVelocity albo + // ShuntVelocity + Current->bEnabled = false; // to event nie będzie dodawany do kolejki + } + else + { // nie ma komórki, to nie będzie działał poprawnie + Current->Type = tp_Ignored; // deaktywacja + ErrorLog("Bad event: \"" + Current->asName + "\" cannot find memcell \"" + + Current->asNodeName + "\""); + } + break; + case tp_CopyValues: // skopiowanie komórki do innej + tmp = FindGroundNode(Current->asNodeName, TP_MEMCELL); // komórka docelowa + if (tmp) + { + Current->Params[4].nGroundNode = tmp; + Current->Params[5].asMemCell = tmp->MemCell; // komórka docelowa + if (!tmp->MemCell->asTrackName + .IsEmpty()) // tor powiązany z komórką powiązaną z eventem + { // tu potrzebujemy wskaźnik do komórki w (tmp) + trk = FindGroundNode(tmp->MemCell->asTrackName, TP_TRACK); + if (trk) + Current->Params[6].asTrack = trk->pTrack; + else + ErrorLog("Bad memcell: track \"" + tmp->MemCell->asTrackName + + "\" not exists in memcell \"" + tmp->asName + "\""); + } + else + Current->Params[6].asTrack = NULL; + } + else + ErrorLog("Bad copyvalues: event \"" + Current->asName + + "\" cannot find memcell \"" + Current->asNodeName + "\""); + strcpy( + buff, + Current->Params[9].asText); // skopiowanie nazwy drugiej komórki do bufora roboczego + SafeDeleteArray(Current->Params[9].asText); // usunięcie nazwy komórki + tmp = FindGroundNode(buff, TP_MEMCELL); // komórka źódłowa + if (tmp) + { + Current->Params[8].nGroundNode = tmp; + Current->Params[9].asMemCell = tmp->MemCell; // komórka źródłowa + } + else + ErrorLog("Bad copyvalues: event \"" + Current->asName + + "\" cannot find memcell \"" + AnsiString(buff) + "\""); + break; + case tp_Animation: // animacja modelu + tmp = FindGroundNode(Current->asNodeName, TP_MODEL); // egzemplarza modelu do animowania + if (tmp) + { + strcpy( + buff, + Current->Params[9].asText); // skopiowanie nazwy submodelu do bufora roboczego + SafeDeleteArray(Current->Params[9].asText); // usunięcie nazwy submodelu + if (Current->Params[0].asInt == 4) + Current->Params[9].asModel = tmp->Model; // model dla całomodelowych animacji + else + { // standardowo przypisanie submodelu + Current->Params[9].asAnimContainer = tmp->Model->GetContainer(buff); // submodel + if (Current->Params[9].asAnimContainer) + { + Current->Params[9].asAnimContainer->WillBeAnimated(); // oflagowanie + // animacji + if (!Current->Params[9] + .asAnimContainer->Event()) // nie szukać, gdy znaleziony + Current->Params[9].asAnimContainer->EventAssign( + FindEvent(Current->asNodeName + "." + AnsiString(buff) + ":done")); + } + } + } + else + ErrorLog("Bad animation: event \"" + Current->asName + "\" cannot find model \"" + + Current->asNodeName + "\""); + Current->asNodeName = ""; + break; + case tp_Lights: // zmiana świeteł modelu + tmp = FindGroundNode(Current->asNodeName, TP_MODEL); + if (tmp) + Current->Params[9].asModel = tmp->Model; + else + ErrorLog("Bad lights: event \"" + Current->asName + "\" cannot find model \"" + + 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_TRACTION); // może druty? + if (!tmp) + tmp = FindGroundNode(Current->asNodeName, TP_TRACK); // albo tory? + if (tmp) + Current->Params[9].nGroundNode = tmp; + else + ErrorLog("Bad visibility: event \"" + Current->asName + "\" cannot find model \"" + + Current->asNodeName + "\""); + Current->asNodeName = ""; + break; + case tp_Switch: // przełożenie zwrotnicy albo zmiana stanu obrotnicy + tmp = FindGroundNode(Current->asNodeName, TP_TRACK); + if (tmp) + { // dowiązanie toru + if (!tmp->pTrack->iAction) // jeśli nie jest zwrotnicą ani obrotnicą + tmp->pTrack->iAction |= 0x100; // to będzie się zmieniał stan uszkodzenia + Current->Params[9].asTrack = tmp->pTrack; + if (!Current->Params[0].asInt) // jeśli przełącza do stanu 0 + if (Current->Params[2].asdouble >= + 0.0) // jeśli jest zdefiniowany dodatkowy ruch iglic + Current->Params[9].asTrack->Switch( + 0, Current->Params[1].asdouble, + Current->Params[2].asdouble); // przesłanie parametrów + } + else + ErrorLog("Bad switch: event \"" + Current->asName + "\" cannot find track \"" + + Current->asNodeName + "\""); + Current->asNodeName = ""; + break; + case tp_Sound: // odtworzenie dźwięku + tmp = FindGroundNode(Current->asNodeName, TP_SOUND); + if (tmp) + Current->Params[9].tsTextSound = tmp->tsStaticSound; + else + ErrorLog("Bad sound: event \"" + Current->asName + + "\" cannot find static sound \"" + Current->asNodeName + "\""); + Current->asNodeName = ""; + break; + case tp_TrackVel: // ustawienie prędkości na torze + if (!Current->asNodeName.IsEmpty()) + { + tmp = FindGroundNode(Current->asNodeName, TP_TRACK); + if (tmp) + { + tmp->pTrack->iAction |= + 0x200; // flaga zmiany prędkości toru jest istotna dla skanowania + Current->Params[9].asTrack = tmp->pTrack; + } + else + ErrorLog("Bad velocity: event \"" + Current->asName + + "\" cannot find track \"" + Current->asNodeName + "\""); + } + Current->asNodeName = ""; + break; + case tp_DynVel: // komunikacja z pojazdem o konkretnej nazwie + if (Current->asNodeName == "activator") + Current->Params[9].asDynamic = NULL; + else + { + tmp = FindGroundNode(Current->asNodeName, TP_DYNAMIC); + if (tmp) + Current->Params[9].asDynamic = tmp->DynamicObject; + else + Error("Event \"" + Current->asName + "\" cannot find dynamic \"" + + Current->asNodeName + "\""); + } + Current->asNodeName = ""; + break; + case tp_Multiple: + if (Current->Params[9].asText != NULL) + { // przepisanie nazwy do bufora + strcpy(buff, Current->Params[9].asText); + SafeDeleteArray(Current->Params[9].asText); + Current->Params[9].asPointer = NULL; // zerowanie wskaźnika, aby wykryć brak obeiktu + } + else + buff[0] = '\0'; + if (Current->iFlags & (conditional_trackoccupied | conditional_trackfree)) + { // jeśli chodzi o zajetosc toru + tmp = FindGroundNode(buff, TP_TRACK); + if (tmp) + Current->Params[9].asTrack = tmp->pTrack; + if (!Current->Params[9].asTrack) + { + ErrorLog(AnsiString("Bad event: Track \"") + AnsiString(buff) + + "\" does not exist in \"" + Current->asName + "\""); + Current->iFlags &= + ~(conditional_trackoccupied | conditional_trackfree); // zerowanie flag + } + } + else if (Current->iFlags & + (conditional_memstring | conditional_memval1 | conditional_memval2)) + { // jeśli chodzi o komorke pamieciową + tmp = FindGroundNode(buff, TP_MEMCELL); + if (tmp) + Current->Params[9].asMemCell = tmp->MemCell; + if (!Current->Params[9].asMemCell) + { + ErrorLog(AnsiString("Bad event: MemCell \"") + AnsiString(buff) + + AnsiString("\" does not exist in \"" + Current->asName + "\"")); + Current->iFlags &= + ~(conditional_memstring | conditional_memval1 | conditional_memval2); + } + } + for (i = 0; i < 8; i++) + { + if (Current->Params[i].asText != NULL) + { + strcpy(buff, Current->Params[i].asText); + SafeDeleteArray(Current->Params[i].asText); + Current->Params[i].asEvent = FindEvent(buff); + if (!Current->Params[i].asEvent) // Ra: tylko w logu informacja o braku + if (AnsiString(Current->Params[i].asText).SubString(1, 5) != "none_") + { + WriteLog(AnsiString("Event \"") + AnsiString(buff) + + AnsiString("\" does not exist")); + ErrorLog("Missed event: " + AnsiString(buff) + " in multiple " + + Current->asName); + } + } + } + break; + case tp_Voltage: // zmiana napięcia w zasilaczu (TractionPowerSource) + if (!Current->asNodeName.IsEmpty()) + { + tmp = FindGroundNode(Current->asNodeName, + TP_TRACTIONPOWERSOURCE); // podłączenie zasilacza + if (tmp) + Current->Params[9].psPower = tmp->psTractionPowerSource; + else + ErrorLog("Bad voltage: event \"" + Current->asName + + "\" cannot find power source \"" + Current->asNodeName + "\""); + } + Current->asNodeName = ""; + break; + case tp_Message: // wyświetlenie komunikatu + break; + } + if (Current->fDelay < 0) + AddToQuery(Current, NULL); } - else - {//nie ma komórki, to nie będzie działał poprawnie - Current->Type=tp_Ignored; //deaktywacja - ErrorLog("Bad event: \""+Current->asName+"\" cannot find memcell \""+Current->asNodeName+"\""); + 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")); } - break; - case tp_CopyValues: //skopiowanie komórki do innej - tmp=FindGroundNode(Current->asNodeName,TP_MEMCELL); //komórka docelowa - if (tmp) - { - Current->Params[4].nGroundNode=tmp; - Current->Params[5].asMemCell=tmp->MemCell; //komórka docelowa - if (!tmp->MemCell->asTrackName.IsEmpty()) //tor powiązany z komórką powiązaną z eventem - {//tu potrzebujemy wskaźnik do komórki w (tmp) - trk=FindGroundNode(tmp->MemCell->asTrackName,TP_TRACK); - if (trk) - Current->Params[6].asTrack=trk->pTrack; - else - ErrorLog("Bad memcell: track \""+tmp->MemCell->asTrackName+"\" not exists in memcell \""+tmp->asName+"\""); - } - else - Current->Params[6].asTrack=NULL; - } - else - ErrorLog("Bad copyvalues: event \""+Current->asName+"\" cannot find memcell \""+Current->asNodeName+"\""); - strcpy(buff,Current->Params[9].asText); //skopiowanie nazwy drugiej komórki do bufora roboczego - SafeDeleteArray(Current->Params[9].asText); //usunięcie nazwy komórki - tmp=FindGroundNode(buff,TP_MEMCELL); //komórka źódłowa - if (tmp) - { - Current->Params[8].nGroundNode=tmp; - Current->Params[9].asMemCell=tmp->MemCell; //komórka źródłowa - } - else - ErrorLog("Bad copyvalues: event \""+Current->asName+"\" cannot find memcell \""+AnsiString(buff)+"\""); - break; - case tp_Animation: //animacja modelu - tmp=FindGroundNode(Current->asNodeName,TP_MODEL); //egzemplarza modelu do animowania - if (tmp) - { - strcpy(buff,Current->Params[9].asText); //skopiowanie nazwy submodelu do bufora roboczego - SafeDeleteArray(Current->Params[9].asText); //usunięcie nazwy submodelu - if (Current->Params[0].asInt==4) - Current->Params[9].asModel=tmp->Model; //model dla całomodelowych animacji - else - {//standardowo przypisanie submodelu - Current->Params[9].asAnimContainer=tmp->Model->GetContainer(buff); //submodel - if (Current->Params[9].asAnimContainer) - {Current->Params[9].asAnimContainer->WillBeAnimated(); //oflagowanie animacji - if (!Current->Params[9].asAnimContainer->Event()) //nie szukać, gdy znaleziony - Current->Params[9].asAnimContainer->EventAssign(FindEvent(Current->asNodeName+"."+AnsiString(buff)+":done")); - } - } - } - else - ErrorLog("Bad animation: event \""+Current->asName+"\" cannot find model \""+Current->asNodeName+"\""); - Current->asNodeName=""; - break; - case tp_Lights: //zmiana świeteł modelu - tmp=FindGroundNode(Current->asNodeName,TP_MODEL); - if (tmp) - Current->Params[9].asModel=tmp->Model; - else - ErrorLog("Bad lights: event \""+Current->asName+"\" cannot find model \""+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_TRACTION); //może druty? - if (!tmp) tmp=FindGroundNode(Current->asNodeName,TP_TRACK); //albo tory? - if (tmp) - Current->Params[9].nGroundNode=tmp; - else - ErrorLog("Bad visibility: event \""+Current->asName+"\" cannot find model \""+Current->asNodeName+"\""); - Current->asNodeName=""; - break; - case tp_Switch: //przełożenie zwrotnicy albo zmiana stanu obrotnicy - tmp=FindGroundNode(Current->asNodeName,TP_TRACK); - if (tmp) - {//dowiązanie toru - if (!tmp->pTrack->iAction) //jeśli nie jest zwrotnicą ani obrotnicą - tmp->pTrack->iAction|=0x100; //to będzie się zmieniał stan uszkodzenia - Current->Params[9].asTrack=tmp->pTrack; - if (!Current->Params[0].asInt) //jeśli przełącza do stanu 0 - if (Current->Params[2].asdouble>=0.0) //jeśli jest zdefiniowany dodatkowy ruch iglic - Current->Params[9].asTrack->Switch(0,Current->Params[1].asdouble,Current->Params[2].asdouble); //przesłanie parametrów - } - else - ErrorLog("Bad switch: event \""+Current->asName+"\" cannot find track \""+Current->asNodeName+"\""); - Current->asNodeName=""; - break; - case tp_Sound: //odtworzenie dźwięku - tmp=FindGroundNode(Current->asNodeName,TP_SOUND); - if (tmp) - Current->Params[9].tsTextSound=tmp->tsStaticSound; - else - ErrorLog("Bad sound: event \""+Current->asName+"\" cannot find static sound \""+Current->asNodeName+"\""); - Current->asNodeName=""; - break; - case tp_TrackVel: //ustawienie prędkości na torze - if (!Current->asNodeName.IsEmpty()) - { - tmp=FindGroundNode(Current->asNodeName,TP_TRACK); - if (tmp) - {tmp->pTrack->iAction|=0x200; //flaga zmiany prędkości toru jest istotna dla skanowania - Current->Params[9].asTrack=tmp->pTrack; - } - else - ErrorLog("Bad velocity: event \""+Current->asName+"\" cannot find track \""+Current->asNodeName+"\""); - } - Current->asNodeName= ""; - break; - case tp_DynVel: //komunikacja z pojazdem o konkretnej nazwie - if (Current->asNodeName=="activator") - Current->Params[9].asDynamic=NULL; - else - { - tmp=FindGroundNode(Current->asNodeName,TP_DYNAMIC); - if (tmp) - Current->Params[9].asDynamic= tmp->DynamicObject; - else - Error("Event \""+Current->asName+"\" cannot find dynamic \""+Current->asNodeName+"\""); - } - Current->asNodeName= ""; - break; - case tp_Multiple: - if (Current->Params[9].asText!=NULL) - {//przepisanie nazwy do bufora - strcpy(buff,Current->Params[9].asText); - SafeDeleteArray(Current->Params[9].asText); - Current->Params[9].asPointer=NULL; //zerowanie wskaźnika, aby wykryć brak obeiktu - } - else buff[0]='\0'; - if (Current->iFlags&(conditional_trackoccupied|conditional_trackfree)) - {//jeśli chodzi o zajetosc toru - tmp=FindGroundNode(buff,TP_TRACK); - if (tmp) Current->Params[9].asTrack=tmp->pTrack; - if (!Current->Params[9].asTrack) - {ErrorLog(AnsiString("Bad event: Track \"")+AnsiString(buff)+"\" does not exist in \""+Current->asName+"\""); - Current->iFlags&=~(conditional_trackoccupied|conditional_trackfree); //zerowanie flag - } - } - else if (Current->iFlags&(conditional_memstring|conditional_memval1|conditional_memval2)) - {//jeśli chodzi o komorke pamieciową - tmp=FindGroundNode(buff,TP_MEMCELL); - if (tmp) Current->Params[9].asMemCell=tmp->MemCell; - if (!Current->Params[9].asMemCell) - {ErrorLog(AnsiString("Bad event: MemCell \"")+AnsiString(buff)+AnsiString("\" does not exist in \""+Current->asName+"\"")); - Current->iFlags&=~(conditional_memstring|conditional_memval1|conditional_memval2); - } - } - for (i=0;i<8;i++) - { - if (Current->Params[i].asText!=NULL) - { - strcpy(buff,Current->Params[i].asText); - SafeDeleteArray(Current->Params[i].asText); - Current->Params[i].asEvent=FindEvent(buff); - if (!Current->Params[i].asEvent) //Ra: tylko w logu informacja o braku - if (AnsiString(Current->Params[i].asText).SubString(1,5)!="none_") - {WriteLog(AnsiString("Event \"")+AnsiString(buff)+AnsiString("\" does not exist")); - ErrorLog("Missed event: "+AnsiString(buff)+" in multiple "+Current->asName); - } - } - } - break; - case tp_Voltage: //zmiana napięcia w zasilaczu (TractionPowerSource) - if (!Current->asNodeName.IsEmpty()) - { - tmp=FindGroundNode(Current->asNodeName,TP_TRACTIONPOWERSOURCE); //podłączenie zasilacza - if (tmp) - Current->Params[9].psPower=tmp->psTractionPowerSource; - else - ErrorLog("Bad voltage: event \""+Current->asName+"\" cannot find power source \""+Current->asNodeName+"\""); - } - Current->asNodeName= ""; - break; - case tp_Message: //wyświetlenie komunikatu - break; - } - if (Current->fDelay<0) - AddToQuery(Current,NULL); - } - 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")); - } - return true; + return true; } void __fastcall TGround::InitTracks() -{//łączenie torów ze sobą i z eventami - TGroundNode *Current,*Model; - TTrack *tmp; //znaleziony tor - TTrack *Track; - int iConnection,state; - AnsiString name; - //tracks=tracksfar=0; - for (Current=nRootOfType[TP_TRACK];Current;Current=Current->nNext) - { - Track=Current->pTrack; - if (Global::iHiddenEvents&1) - if (!Current->asName.IsEmpty()) - {//jeśli podana jest nazwa torów, można szukać eventów skojarzonych przez nazwę - if (Track->asEvent1Name.IsEmpty()) - if (FindEvent(Current->asName+":event1")) - Track->asEvent1Name=Current->asName+":event1"; - if (Track->asEvent2Name.IsEmpty()) - if (FindEvent(Current->asName+":event2")) - Track->asEvent2Name=Current->asName+":event2"; - } - Track->AssignEvents( - Track->asEvent0Name.IsEmpty()?NULL:FindEvent(Track->asEvent0Name), - Track->asEvent1Name.IsEmpty()?NULL:FindEventScan(Track->asEvent1Name), - Track->asEvent2Name.IsEmpty()?NULL:FindEventScan(Track->asEvent2Name)); - Track->AssignallEvents( - Track->asEventall0Name.IsEmpty()?NULL:FindEvent(Track->asEventall0Name), - Track->asEventall1Name.IsEmpty()?NULL:FindEvent(Track->asEventall1Name), - Track->asEventall2Name.IsEmpty()?NULL:FindEvent(Track->asEventall2Name)); //MC-280503 - switch (Track->eType) - { - case tt_Table: //obrotnicę też łączymy na starcie z innymi torami - Model=FindGroundNode(Current->asName,TP_MODEL); //szukamy modelu o tej samej nazwie - //if (tmp) //mamy model, trzeba zapamiętać wskaźnik do jego animacji - {//jak coś pójdzie źle, to robimy z tego normalny tor - //Track->ModelAssign(tmp->Model->GetContainer(NULL)); //wiązanie toru z modelem obrotnicy - Track->RaAssign(Current,Model?Model->Model:NULL,FindEvent(Current->asName+":done"),FindEvent(Current->asName+":joined")); //wiązanie toru z modelem obrotnicy - //break; //jednak połączę z sąsiednim, jak ma się wysypywać null track - } - if (!Model) //jak nie ma modelu - break; //to pewnie jest wykolejnica, a ta jest domyślnie zamknięta i wykoleja - case tt_Normal: //tylko proste są podłączane do rozjazdów, stąd dwa rozjazdy się nie połączą ze sobą - if (Track->CurrentPrev()==NULL) //tylko jeśli jeszcze nie podłączony +{ //łączenie torów ze sobą i z eventami + TGroundNode *Current, *Model; + TTrack *tmp; // znaleziony tor + TTrack *Track; + int iConnection, state; + AnsiString name; + // tracks=tracksfar=0; + for (Current = nRootOfType[TP_TRACK]; Current; Current = Current->nNext) { - tmp=FindTrack(Track->CurrentSegment()->FastGetPoint_0(),iConnection,Current); - switch (iConnection) - { - 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 - break; - case 0: - Track->ConnectPrevPrev(tmp,0); - break; - case 1: - Track->ConnectPrevNext(tmp,1); - break; - case 2: - Track->ConnectPrevPrev(tmp,0); //do Point1 pierwszego - tmp->SetConnections(0); //zapamiętanie ustawień w Segmencie - break; - case 3: - Track->ConnectPrevNext(tmp,1); //do Point2 pierwszego - tmp->SetConnections(0); //zapamiętanie ustawień w Segmencie - break; - case 4: - tmp->Switch(1); - Track->ConnectPrevPrev(tmp,2); //do Point1 drugiego - tmp->SetConnections(1); //robi też Switch(0) - tmp->Switch(0); - break; - case 5: - tmp->Switch(1); - Track->ConnectPrevNext(tmp,3); //do Point2 drugiego - tmp->SetConnections(1); //robi też Switch(0) - tmp->Switch(0); - break; - } + Track = Current->pTrack; + if (Global::iHiddenEvents & 1) + if (!Current->asName.IsEmpty()) + { // jeśli podana jest nazwa torów, można szukać eventów skojarzonych przez nazwę + if (Track->asEvent1Name.IsEmpty()) + if (FindEvent(Current->asName + ":event1")) + Track->asEvent1Name = Current->asName + ":event1"; + if (Track->asEvent2Name.IsEmpty()) + if (FindEvent(Current->asName + ":event2")) + Track->asEvent2Name = Current->asName + ":event2"; + } + Track->AssignEvents( + Track->asEvent0Name.IsEmpty() ? NULL : FindEvent(Track->asEvent0Name), + Track->asEvent1Name.IsEmpty() ? NULL : FindEventScan(Track->asEvent1Name), + Track->asEvent2Name.IsEmpty() ? NULL : FindEventScan(Track->asEvent2Name)); + Track->AssignallEvents( + Track->asEventall0Name.IsEmpty() ? NULL : FindEvent(Track->asEventall0Name), + Track->asEventall1Name.IsEmpty() ? NULL : FindEvent(Track->asEventall1Name), + Track->asEventall2Name.IsEmpty() ? NULL : + FindEvent(Track->asEventall2Name)); // MC-280503 + switch (Track->eType) + { + case tt_Table: // obrotnicę też łączymy na starcie z innymi torami + Model = FindGroundNode(Current->asName, TP_MODEL); // szukamy modelu o tej samej nazwie + // if (tmp) //mamy model, trzeba zapamiętać wskaźnik do jego animacji + { // jak coś pójdzie źle, to robimy z tego normalny tor + // Track->ModelAssign(tmp->Model->GetContainer(NULL)); //wiązanie toru z modelem + // obrotnicy + Track->RaAssign( + Current, Model ? Model->Model : NULL, FindEvent(Current->asName + ":done"), + FindEvent(Current->asName + ":joined")); // wiązanie toru z modelem obrotnicy + // break; //jednak połączę z sąsiednim, jak ma się wysypywać null track + } + if (!Model) // jak nie ma modelu + break; // to pewnie jest wykolejnica, a ta jest domyślnie zamknięta i wykoleja + case tt_Normal: // tylko proste są podłączane do rozjazdów, stąd dwa rozjazdy się nie + // połączą ze sobą + if (Track->CurrentPrev() == NULL) // tylko jeśli jeszcze nie podłączony + { + tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_0(), iConnection, Current); + switch (iConnection) + { + 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 + break; + case 0: + Track->ConnectPrevPrev(tmp, 0); + break; + case 1: + Track->ConnectPrevNext(tmp, 1); + break; + case 2: + Track->ConnectPrevPrev(tmp, 0); // do Point1 pierwszego + tmp->SetConnections(0); // zapamiętanie ustawień w Segmencie + break; + case 3: + Track->ConnectPrevNext(tmp, 1); // do Point2 pierwszego + tmp->SetConnections(0); // zapamiętanie ustawień w Segmencie + break; + case 4: + tmp->Switch(1); + Track->ConnectPrevPrev(tmp, 2); // do Point1 drugiego + tmp->SetConnections(1); // robi też Switch(0) + tmp->Switch(0); + break; + case 5: + tmp->Switch(1); + Track->ConnectPrevNext(tmp, 3); // do Point2 drugiego + tmp->SetConnections(1); // robi też Switch(0) + tmp->Switch(0); + break; + } + } + if (Track->CurrentNext() == NULL) // tylko jeśli jeszcze nie podłączony + { + tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_1(), iConnection, Current); + switch (iConnection) + { + 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 + break; + case 0: + Track->ConnectNextPrev(tmp, 0); + break; + case 1: + Track->ConnectNextNext(tmp, 1); + break; + case 2: + Track->ConnectNextPrev(tmp, 0); + tmp->SetConnections(0); // zapamiętanie ustawień w Segmencie + break; + case 3: + Track->ConnectNextNext(tmp, 1); + tmp->SetConnections(0); // zapamiętanie ustawień w Segmencie + break; + case 4: + tmp->Switch(1); + Track->ConnectNextPrev(tmp, 2); + tmp->SetConnections(1); // robi też Switch(0) + // tmp->Switch(0); + break; + case 5: + tmp->Switch(1); + Track->ConnectNextNext(tmp, 3); + tmp->SetConnections(1); // robi też Switch(0) + // tmp->Switch(0); + break; + } + } + break; + case tt_Switch: // dla rozjazdów szukamy eventów sygnalizacji rozprucia + Track->AssignForcedEvents(FindEvent(Current->asName + ":forced+"), + FindEvent(Current->asName + ":forced-")); + break; + } + name = Track->IsolatedName(); // pobranie nazwy odcinka izolowanego + if (!name.IsEmpty()) // jeśli została zwrócona nazwa + Track->IsolatedEventsAssign(FindEvent(name + ":busy"), FindEvent(name + ":free")); + if (Current->asName.SubString(1, 1) == + "*") // możliwy portal, jeśli nie podłączony od striny 1 + if (!Track->CurrentPrev() && Track->CurrentNext()) + Track->iCategoryFlag |= 0x100; // ustawienie flagi portalu } - if (Track->CurrentNext()==NULL) //tylko jeśli jeszcze nie podłączony - { - tmp=FindTrack(Track->CurrentSegment()->FastGetPoint_1(),iConnection,Current); - switch (iConnection) - { - 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 - break; - case 0: - Track->ConnectNextPrev(tmp,0); - break; - case 1: - Track->ConnectNextNext(tmp,1); - break; - case 2: - Track->ConnectNextPrev(tmp,0); - tmp->SetConnections(0); //zapamiętanie ustawień w Segmencie - break; - case 3: - Track->ConnectNextNext(tmp,1); - tmp->SetConnections(0); //zapamiętanie ustawień w Segmencie - break; - case 4: - tmp->Switch(1); - Track->ConnectNextPrev(tmp,2); - tmp->SetConnections(1); //robi też Switch(0) - //tmp->Switch(0); - break; - case 5: - tmp->Switch(1); - Track->ConnectNextNext(tmp,3); - tmp->SetConnections(1); //robi też Switch(0) - //tmp->Switch(0); - break; - } + // WriteLog("Total "+AnsiString(tracks)+", far "+AnsiString(tracksfar)); + TIsolated *p = TIsolated::Root(); + while (p) + { // jeśli się znajdzie, to podać wskaźnik + Current = FindGroundNode(p->asName, TP_MEMCELL); // czy jest komóka o odpowiedniej nazwie + if (Current) + p->pMemCell = Current->MemCell; // przypisanie powiązanej komórki + else + { // utworzenie automatycznej komórki + Current = new TGroundNode(); // to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy + // Current->asName=p->asName; //mazwa identyczna, jak nazwa odcinka izolowanego + Current->MemCell = new TMemCell(NULL); // nowa komórka + sTracks->Add(TP_MEMCELL, p->asName.c_str(), Current); // dodanie do wyszukiwarki + Current->nNext = + nRootOfType[TP_MEMCELL]; // to nie powinno tutaj być, bo robi się śmietnik + nRootOfType[TP_MEMCELL] = Current; + iNumNodes++; + p->pMemCell = Current->MemCell; // wskaźnik komóki przekazany do odcinka izolowanego + } + p = p->Next(); } - break; - case tt_Switch: //dla rozjazdów szukamy eventów sygnalizacji rozprucia - Track->AssignForcedEvents( - FindEvent(Current->asName+":forced+"), - FindEvent(Current->asName+":forced-")); - break; - } - name=Track->IsolatedName(); //pobranie nazwy odcinka izolowanego - if (!name.IsEmpty()) //jeśli została zwrócona nazwa - Track->IsolatedEventsAssign(FindEvent(name+":busy"),FindEvent(name+":free")); - if (Current->asName.SubString(1,1)=="*") //możliwy portal, jeśli nie podłączony od striny 1 - if (!Track->CurrentPrev()&&Track->CurrentNext()) - Track->iCategoryFlag|=0x100; //ustawienie flagi portalu - } - //WriteLog("Total "+AnsiString(tracks)+", far "+AnsiString(tracksfar)); - TIsolated *p=TIsolated::Root(); - while (p) - {//jeśli się znajdzie, to podać wskaźnik - Current=FindGroundNode(p->asName,TP_MEMCELL); //czy jest komóka o odpowiedniej nazwie - if (Current) - p->pMemCell=Current->MemCell; //przypisanie powiązanej komórki - else - {//utworzenie automatycznej komórki - Current=new TGroundNode(); //to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy - //Current->asName=p->asName; //mazwa identyczna, jak nazwa odcinka izolowanego - Current->MemCell=new TMemCell(NULL); //nowa komórka - sTracks->Add(TP_MEMCELL,p->asName.c_str(),Current); //dodanie do wyszukiwarki - Current->nNext=nRootOfType[TP_MEMCELL]; //to nie powinno tutaj być, bo robi się śmietnik - nRootOfType[TP_MEMCELL]=Current; - iNumNodes++; - p->pMemCell=Current->MemCell; //wskaźnik komóki przekazany do odcinka izolowanego - } - p=p->Next(); - } - //for (Current=nRootOfType[TP_TRACK];Current;Current=Current->nNext) - // if (Current->pTrack->eType==tt_Cross) - // Current->pTrack->ConnectionsLog(); //zalogowanie informacji o połączeniach + // for (Current=nRootOfType[TP_TRACK];Current;Current=Current->nNext) + // if (Current->pTrack->eType==tt_Cross) + // Current->pTrack->ConnectionsLog(); //zalogowanie informacji o połączeniach } void __fastcall TGround::InitTraction() -{//łączenie drutów ze sobą oraz z torami i eventami - TGroundNode *nCurrent,*nTemp; - TTraction *tmp; //znalezione przęsło - TTraction *Traction; - int iConnection; - AnsiString name; - for (nCurrent=nRootOfType[TP_TRACTION];nCurrent;nCurrent=nCurrent->nNext) - {//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 - Traction=nCurrent->hvTraction; - 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->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 - iNumNodes++; +{ //łączenie drutów ze sobą oraz z torami i eventami + TGroundNode *nCurrent, *nTemp; + TTraction *tmp; // znalezione przęsło + TTraction *Traction; + int iConnection; + AnsiString name; + for (nCurrent = nRootOfType[TP_TRACTION]; nCurrent; nCurrent = nCurrent->nNext) + { // 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 + Traction = nCurrent->hvTraction; + 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->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 + iNumNodes++; + } } - } - for (nCurrent=nRootOfType[TP_TRACTION];nCurrent;nCurrent=nCurrent->nNext) - { - Traction=nCurrent->hvTraction; - 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); - 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 "+FloatToStrF(Traction->pPoint1.x,ffFixed,6,2)+" "+FloatToStrF(Traction->pPoint1.y,ffFixed,6,2)+" "+FloatToStrF(Traction->pPoint1.z,ffFixed,6,2)); - } - } - 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); - 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 - } - 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 "+FloatToStrF(Traction->pPoint2.x,ffFixed,6,2)+" "+FloatToStrF(Traction->pPoint2.y,ffFixed,6,2)+" "+FloatToStrF(Traction->pPoint2.z,ffFixed,6,2)); - } - } - } - iConnection=0; //teraz będzie licznikiem końców - for (nCurrent=nRootOfType[TP_TRACTION];nCurrent;nCurrent=nCurrent->nNext) - {//operacje mające na celu wykrywanie bieżni wspólnych i łączenie przęseł naprążania - if (nCurrent->hvTraction->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 - nCurrent->hvTraction->iTries=5; //oznaczanie końcowych - ++iConnection; - } - if (nCurrent->hvTraction->fResistance[0]==0.0) - {nCurrent->hvTraction->ResistanceCalc(); //obliczanie przęseł w segmencie z bezpośrednim zasilaniem - //ErrorLog("Section "+nCurrent->hvTraction->asPowerSupplyName+" connected"); //jako niby błąd będzie bardziej widoczne - nCurrent->hvTraction->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 - TGroundNode **nEnds=new TGroundNode*[iConnection]; //końców jest ok. 10 razy mniej niż wszystkich przęseł (Quark: 216) - for (nCurrent=nRootOfType[TP_TRACTION];nCurrent;nCurrent=nCurrent->nNext) - {//łączenie bieżni wspólnych, w tym oznaczanie niepodanych jawnie - Traction=nCurrent->hvTraction; - if (!Traction->asParallel.IsEmpty()) //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 - {nTemp=FindGroundNode(Traction->asParallel,TP_TRACTION); - if (nTemp) - {//o ile zostanie znalezione przęsło o takiej nazwie - if (!nTemp->hvTraction->hvParallel) //jeśli tamten jeszcze nie ma wskaźnika bieżni wspólnej - Traction->hvParallel=nTemp->hvTraction; //wpisać siebie i dalej dać mu wskaźnik zwrotny - else //a jak ma, to albo dołączyć się do kółeczka - Traction->hvParallel=nTemp->hvTraction->hvParallel; //przjąć dotychczasowy wskaźnik od niego - nTemp->hvTraction->hvParallel=Traction; //i na koniec ustawienie wskaźnika zwrotnego + for (nCurrent = nRootOfType[TP_TRACTION]; nCurrent; nCurrent = nCurrent->nNext) + { + Traction = nCurrent->hvTraction; + 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); + 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 " + + FloatToStrF(Traction->pPoint1.x, ffFixed, 6, 2) + " " + + FloatToStrF(Traction->pPoint1.y, ffFixed, 6, 2) + " " + + FloatToStrF(Traction->pPoint1.z, ffFixed, 6, 2)); + } + } + 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); + 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 + } + 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 " + + FloatToStrF(Traction->pPoint2.x, ffFixed, 6, 2) + " " + + FloatToStrF(Traction->pPoint2.y, ffFixed, 6, 2) + " " + + FloatToStrF(Traction->pPoint2.z, ffFixed, 6, 2)); + } + } } - 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 (zghvTraction->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 - } + iConnection = 0; // teraz będzie licznikiem końców + for (nCurrent = nRootOfType[TP_TRACTION]; nCurrent; nCurrent = nCurrent->nNext) + { // operacje mające na celu wykrywanie bieżni wspólnych i łączenie przęseł naprążania + if (nCurrent->hvTraction->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 + nCurrent->hvTraction->iTries = 5; // oznaczanie końcowych + ++iConnection; + } + if (nCurrent->hvTraction->fResistance[0] == 0.0) + { + nCurrent->hvTraction + ->ResistanceCalc(); // obliczanie przęseł w segmencie z bezpośrednim zasilaniem + // ErrorLog("Section "+nCurrent->hvTraction->asPowerSupplyName+" connected"); //jako + // niby błąd będzie bardziej widoczne + nCurrent->hvTraction->iTries = 0; // nie potrzeba mu szukać zasilania + } + // if (!Traction->hvParallel) //jeszcze utworzyć pętle z bieżni wspólnych } - 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 - } + int zg = 0; // zgodność kierunku przęseł, tymczasowo iterator do tabeli końców + TGroundNode **nEnds = new TGroundNode *[iConnection]; // końców jest ok. 10 razy mniej niż + // wszystkich przęseł (Quark: 216) + for (nCurrent = nRootOfType[TP_TRACTION]; nCurrent; nCurrent = nCurrent->nNext) + { //łączenie bieżni wspólnych, w tym oznaczanie niepodanych jawnie + Traction = nCurrent->hvTraction; + if (!Traction->asParallel.IsEmpty()) // 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 + { + nTemp = FindGroundNode(Traction->asParallel, TP_TRACTION); + if (nTemp) + { // o ile zostanie znalezione przęsło o takiej nazwie + if (!nTemp->hvTraction + ->hvParallel) // jeśli tamten jeszcze nie ma wskaźnika bieżni wspólnej + Traction->hvParallel = + nTemp->hvTraction; // wpisać siebie i dalej dać mu wskaźnik zwrotny + else // a jak ma, to albo dołączyć się do kółeczka + Traction->hvParallel = + nTemp->hvTraction->hvParallel; // przjąć dotychczasowy wskaźnik od niego + nTemp->hvTraction->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ń } - else - {//gdy koniec jest samotny, to na razie nie zostanie podłączony (nie powinno takich być) - nEnds[i]=NULL; + while (zg < iConnection) + nEnds[zg++] = NULL; // zapełnienie do końca tablicy, jeśli by jakieś końce wypadły + 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; + } + } } - } - } - delete[] nEnds; //nie potrzebne już + delete[] nEnds; // nie potrzebne już }; void __fastcall TGround::TrackJoin(TGroundNode *Current) -{//wyszukiwanie sąsiednich torów do podłączenia (wydzielone na użytek obrotnicy) - TTrack *Track=Current->pTrack; - TTrack *tmp; - int iConnection; - if (!Track->CurrentPrev()) - {tmp=FindTrack(Track->CurrentSegment()->FastGetPoint_0(),iConnection,Current); //Current do pominięcia - switch (iConnection) - { - case 0: Track->ConnectPrevPrev(tmp,0); break; - case 1: Track->ConnectPrevNext(tmp,1); break; - } - } - if (!Track->CurrentNext()) - { - tmp=FindTrack(Track->CurrentSegment()->FastGetPoint_1(),iConnection,Current); - switch (iConnection) - { - case 0: Track->ConnectNextPrev(tmp,0); break; - case 1: Track->ConnectNextNext(tmp,1); break; - } - } +{ // wyszukiwanie sąsiednich torów do podłączenia (wydzielone na użytek obrotnicy) + TTrack *Track = Current->pTrack; + TTrack *tmp; + int iConnection; + if (!Track->CurrentPrev()) + { + tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_0(), iConnection, + Current); // Current do pominięcia + switch (iConnection) + { + case 0: + Track->ConnectPrevPrev(tmp, 0); + break; + case 1: + Track->ConnectPrevNext(tmp, 1); + break; + } + } + if (!Track->CurrentNext()) + { + tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_1(), iConnection, Current); + switch (iConnection) + { + case 0: + Track->ConnectNextPrev(tmp, 0); + break; + case 1: + Track->ConnectNextNext(tmp, 1); + break; + } + } } -//McZapkie-070602: wyzwalacze zdarzen +// McZapkie-070602: wyzwalacze zdarzen bool __fastcall TGround::InitLaunchers() { - TGroundNode *Current,*tmp; - TEventLauncher *EventLauncher; - int i; - for (Current=nRootOfType[TP_EVLAUNCH];Current;Current=Current->nNext) - { - EventLauncher=Current->EvLaunch; - if (EventLauncher->iCheckMask!=0) - if (EventLauncher->asMemCellName!=AnsiString("none")) - {//jeśli jest powiązana komórka pamięci - tmp=FindGroundNode(EventLauncher->asMemCellName,TP_MEMCELL); - if (tmp) - EventLauncher->MemCell=tmp->MemCell; //jeśli znaleziona, dopisać - else - MessageBox(0,"Cannot find Memory Cell for Event Launcher","Error",MB_OK); - } - else - EventLauncher->MemCell=NULL; - EventLauncher->Event1=(EventLauncher->asEvent1Name!=AnsiString("none"))?FindEvent(EventLauncher->asEvent1Name):NULL; - EventLauncher->Event2=(EventLauncher->asEvent2Name!=AnsiString("none"))?FindEvent(EventLauncher->asEvent2Name):NULL; - } - return true; + TGroundNode *Current, *tmp; + TEventLauncher *EventLauncher; + int i; + for (Current = nRootOfType[TP_EVLAUNCH]; Current; Current = Current->nNext) + { + EventLauncher = Current->EvLaunch; + if (EventLauncher->iCheckMask != 0) + if (EventLauncher->asMemCellName != AnsiString("none")) + { // jeśli jest powiązana komórka pamięci + tmp = FindGroundNode(EventLauncher->asMemCellName, TP_MEMCELL); + if (tmp) + EventLauncher->MemCell = tmp->MemCell; // jeśli znaleziona, dopisać + else + MessageBox(0, "Cannot find Memory Cell for Event Launcher", "Error", MB_OK); + } + else + EventLauncher->MemCell = NULL; + EventLauncher->Event1 = (EventLauncher->asEvent1Name != AnsiString("none")) ? + FindEvent(EventLauncher->asEvent1Name) : + NULL; + EventLauncher->Event2 = (EventLauncher->asEvent2Name != AnsiString("none")) ? + FindEvent(EventLauncher->asEvent2Name) : + NULL; + } + return true; } -TTrack* __fastcall TGround::FindTrack(vector3 Point,int &iConnection,TGroundNode *Exclude) -{//wyszukiwanie innego toru kończącego się w (Point) - TTrack *Track; - TGroundNode *Current; - TTrack *tmp; - iConnection=-1; - TSubRect *sr; - //najpierw szukamy w okolicznych segmentach - int c=GetColFromX(Point.x); - int r=GetRowFromZ(Point.z); - if ((sr=FastGetSubRect(c,r))!=NULL) //75% torów jest w tym samym sektorze - if ((tmp=sr->FindTrack(&Point,iConnection,Exclude->pTrack))!=NULL) - return tmp; - int i,x,y; - for (i=1;i<9;++i) //sektory w kolejności odległości, 4 jest tu wystarczające, 9 na wszelki wypadek - {//niemal wszystkie podłączone tory znajdują się w sąsiednich 8 sektorach - x=SectorOrder[i].x; - y=SectorOrder[i].y; - if ((sr=FastGetSubRect(c+y,r+x))!=NULL) - if ((tmp=sr->FindTrack(&Point,iConnection,Exclude->pTrack))!=NULL) - return tmp; - if (x) - if ((sr=FastGetSubRect(c+y,r-x))!=NULL) - if ((tmp=sr->FindTrack(&Point,iConnection,Exclude->pTrack))!=NULL) - return tmp; - if (y) - if ((sr=FastGetSubRect(c-y,r+x))!=NULL) - if ((tmp=sr->FindTrack(&Point,iConnection,Exclude->pTrack))!=NULL) - return tmp; - if ((sr=FastGetSubRect(c-y,r-x))!=NULL) - if ((tmp=sr->FindTrack(&Point,iConnection,Exclude->pTrack))!=NULL) - return tmp; - } +TTrack *__fastcall TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude) +{ // wyszukiwanie innego toru kończącego się w (Point) + TTrack *Track; + TGroundNode *Current; + TTrack *tmp; + iConnection = -1; + TSubRect *sr; + // najpierw szukamy w okolicznych segmentach + int c = GetColFromX(Point.x); + int r = GetRowFromZ(Point.z); + if ((sr = FastGetSubRect(c, r)) != NULL) // 75% torów jest w tym samym sektorze + if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL) + return tmp; + int i, x, y; + for (i = 1; i < 9; + ++i) // sektory w kolejności odległości, 4 jest tu wystarczające, 9 na wszelki wypadek + { // niemal wszystkie podłączone tory znajdują się w sąsiednich 8 sektorach + x = SectorOrder[i].x; + y = SectorOrder[i].y; + if ((sr = FastGetSubRect(c + y, r + x)) != NULL) + if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL) + return tmp; + if (x) + if ((sr = FastGetSubRect(c + y, r - x)) != NULL) + if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL) + return tmp; + if (y) + if ((sr = FastGetSubRect(c - y, r + x)) != NULL) + if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL) + return tmp; + if ((sr = FastGetSubRect(c - y, r - x)) != NULL) + if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL) + return tmp; + } #if 0 //wyszukiwanie czołgowe (po wszystkich jak leci) - nie ma chyba sensu for (Current=nRootOfType[TP_TRACK];Current;Current=Current->Next) @@ -3236,1276 +3641,1497 @@ TTrack* __fastcall TGround::FindTrack(vector3 Point,int &iConnection,TGroundNode } } #endif - return NULL; + return NULL; } -TTraction* __fastcall TGround::FindTraction(vector3 *Point,int &iConnection,TGroundNode *Exclude) -{//wyszukiwanie innego przęsła kończącego się w (Point) - TTraction *Traction; - TGroundNode *Current; - TTraction *tmp; - iConnection=-1; - TSubRect *sr; - //najpierw szukamy w okolicznych segmentach - int c=GetColFromX(Point->x); - int r=GetRowFromZ(Point->z); - if ((sr=FastGetSubRect(c,r))!=NULL) //większość będzie w tym samym sektorze - if ((tmp=sr->FindTraction(Point,iConnection,Exclude->hvTraction))!=NULL) - return tmp; - int i,x,y; - for (i=1;i<9;++i) //sektory w kolejności odległości, 4 jest tu wystarczające, 9 na wszelki wypadek - {//wszystkie przęsła powinny zostać znajdować się w sąsiednich 8 sektorach - x=SectorOrder[i].x; - y=SectorOrder[i].y; - if ((sr=FastGetSubRect(c+y,r+x))!=NULL) - if ((tmp=sr->FindTraction(Point,iConnection,Exclude->hvTraction))!=NULL) - return tmp; - if (x&y) - {if ((sr=FastGetSubRect(c+y,r-x))!=NULL) - if ((tmp=sr->FindTraction(Point,iConnection,Exclude->hvTraction))!=NULL) - return tmp; - if ((sr=FastGetSubRect(c-y,r+x))!=NULL) - if ((tmp=sr->FindTraction(Point,iConnection,Exclude->hvTraction))!=NULL) - return tmp; - } - if ((sr=FastGetSubRect(c-y,r-x))!=NULL) - if ((tmp=sr->FindTraction(Point,iConnection,Exclude->hvTraction))!=NULL) - return tmp; - } - return NULL; +TTraction *__fastcall TGround::FindTraction(vector3 *Point, int &iConnection, TGroundNode *Exclude) +{ // wyszukiwanie innego przęsła kończącego się w (Point) + TTraction *Traction; + TGroundNode *Current; + TTraction *tmp; + iConnection = -1; + TSubRect *sr; + // najpierw szukamy w okolicznych segmentach + int c = GetColFromX(Point->x); + int r = GetRowFromZ(Point->z); + if ((sr = FastGetSubRect(c, r)) != NULL) // większość będzie w tym samym sektorze + if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL) + return tmp; + int i, x, y; + for (i = 1; i < 9; + ++i) // sektory w kolejności odległości, 4 jest tu wystarczające, 9 na wszelki wypadek + { // wszystkie przęsła powinny zostać znajdować się w sąsiednich 8 sektorach + x = SectorOrder[i].x; + y = SectorOrder[i].y; + if ((sr = FastGetSubRect(c + y, r + x)) != NULL) + if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL) + return tmp; + if (x & y) + { + if ((sr = FastGetSubRect(c + y, r - x)) != NULL) + if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL) + return tmp; + if ((sr = FastGetSubRect(c - y, r + x)) != NULL) + if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL) + return tmp; + } + if ((sr = FastGetSubRect(c - y, r - x)) != NULL) + if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL) + return tmp; + } + return NULL; }; -TTraction* __fastcall TGround::TractionNearestFind(vector3 &p,int dir,TGroundNode *n) -{//wyszukanie najbliższego do (p) przęsła o tej samej nazwie sekcji (ale innego niż podłączone) oraz zasilanego z kierunku (dir) - TGroundNode *nCurrent,*nBest=NULL; - int i,j,k,zg; - double d,dist=200.0*200.0; //[m] odległość graniczna - //najpierw szukamy w okolicznych segmentach - int c=GetColFromX(n->pCenter.x); - int r=GetRowFromZ(n->pCenter.z); - TSubRect *sr; - for (i=-1;i<=1;++i) //przeglądamy 9 najbliższych sektorów - for (j=-1;j<=1;++j) // - 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!=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[1]) - if (nCurrent->hvTraction->psPower[k=(DotProduct(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 - d=SquareMagnitude(p-nCurrent->pCenter); //kwadrat odległości środków - 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 - } - } - 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)); - } - return (nBest?nBest->hvTraction:NULL); +TTraction *__fastcall TGround::TractionNearestFind(vector3 &p, int dir, TGroundNode *n) +{ // wyszukanie najbliższego do (p) przęsła o tej samej nazwie sekcji (ale innego niż podłączone) + // oraz zasilanego z kierunku (dir) + TGroundNode *nCurrent, *nBest = NULL; + int i, j, k, zg; + double d, dist = 200.0 * 200.0; //[m] odległość graniczna + // najpierw szukamy w okolicznych segmentach + int c = GetColFromX(n->pCenter.x); + int r = GetRowFromZ(n->pCenter.z); + TSubRect *sr; + for (i = -1; i <= 1; ++i) // przeglądamy 9 najbliższych sektorów + for (j = -1; j <= 1; ++j) // + 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 != 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[1]) + if (nCurrent->hvTraction->psPower + [k = (DotProduct( + 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 + d = SquareMagnitude( + p - + nCurrent + ->pCenter); // kwadrat odległości środków + 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 + } + } + 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)); + } + return (nBest ? nBest->hvTraction : NULL); }; bool __fastcall TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) { - if (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) - Event->Activator=Node; - if (Event->Type==tp_AddValues?(Event->fDelay==0.0):false) - {//eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieś dodawanie - //Ra: kopiowanie wykonania tu jest bez sensu, lepiej by było wydzielić funkcję wykonującą eventy i ją wywołać - if (EventConditon(Event)) - {//teraz mogą być warunki do tych eventów - Event->Params[5].asMemCell->UpdateValues(Event->Params[0].asText,Event->Params[1].asdouble,Event->Params[2].asdouble,Event->iFlags); - if (Event->Params[6].asTrack) - {//McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla wszystkich 'dynamic' na danym torze - for (int i=0;iParams[6].asTrack->iNumDynamics;++i) - Event->Params[5].asMemCell->PutCommand(Event->Params[6].asTrack->Dynamics[i]->Mechanik,&Event->Params[4].nGroundNode->pCenter); - if (DebugModeFlag) - WriteLog("EVENT EXECUTED: AddValues & Track command - "+AnsiString(Event->Params[0].asText)+" "+AnsiString(Event->Params[1].asdouble)+" "+AnsiString(Event->Params[2].asdouble)); - } - else - if (DebugModeFlag) - WriteLog("EVENT EXECUTED: AddValues - "+AnsiString(Event->Params[0].asText)+" "+AnsiString(Event->Params[1].asdouble)+" "+AnsiString(Event->Params[2].asdouble)); - } - Event=Event->evJoined; //jeśli jest kolejny o takiej samej nazwie, to idzie do kolejki - } - if (Event) - {//standardowe dodanie do kolejki - WriteLog("EVENT ADDED TO QUEUE: "+Event->asName+(Node?AnsiString(" by "+Node->asName):AnsiString(""))); - Event->fStartTime=fabs(Event->fDelay)+Timer::GetTime(); //czas od uruchomienia scenerii - if (Event->fRandomDelay>0.0) - Event->fStartTime+=Event->fRandomDelay*random(10000)*0.0001; //doliczenie losowego czasu opóźnienia - ++Event->iQueued; //zabezpieczenie przed podwójnym dodaniem do kolejki - if (QueryRootEvent?Event->fStartTime>=QueryRootEvent->fStartTime:false) - QueryRootEvent->AddToQuery(Event); //dodanie gdzieś w środku - else - {//dodanie z przodu: albo nic nie ma, albo ma być wykonany szybciej niż pierwszy - Event->evNext=QueryRootEvent; - QueryRootEvent=Event; - } - } - } - return true; + if (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) + Event->Activator = Node; + if (Event->Type == tp_AddValues ? (Event->fDelay == 0.0) : false) + { // eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić + // jakieś dodawanie + // Ra: kopiowanie wykonania tu jest bez sensu, lepiej by było wydzielić funkcję + // wykonującą eventy i ją wywołać + if (EventConditon(Event)) + { // teraz mogą być warunki do tych eventów + Event->Params[5].asMemCell->UpdateValues( + Event->Params[0].asText, Event->Params[1].asdouble, + Event->Params[2].asdouble, Event->iFlags); + if (Event->Params[6].asTrack) + { // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla + // wszystkich 'dynamic' na danym torze + for (int i = 0; i < Event->Params[6].asTrack->iNumDynamics; ++i) + Event->Params[5].asMemCell->PutCommand( + Event->Params[6].asTrack->Dynamics[i]->Mechanik, + &Event->Params[4].nGroundNode->pCenter); + if (DebugModeFlag) + WriteLog("EVENT EXECUTED: AddValues & Track command - " + + AnsiString(Event->Params[0].asText) + " " + + AnsiString(Event->Params[1].asdouble) + " " + + AnsiString(Event->Params[2].asdouble)); + } + else if (DebugModeFlag) + WriteLog("EVENT EXECUTED: AddValues - " + + AnsiString(Event->Params[0].asText) + " " + + AnsiString(Event->Params[1].asdouble) + " " + + AnsiString(Event->Params[2].asdouble)); + } + Event = + Event + ->evJoined; // jeśli jest kolejny o takiej samej nazwie, to idzie do kolejki + } + if (Event) + { // standardowe dodanie do kolejki + WriteLog("EVENT ADDED TO QUEUE: " + Event->asName + + (Node ? AnsiString(" by " + Node->asName) : AnsiString(""))); + Event->fStartTime = + fabs(Event->fDelay) + Timer::GetTime(); // czas od uruchomienia scenerii + if (Event->fRandomDelay > 0.0) + Event->fStartTime += Event->fRandomDelay * random(10000) * + 0.0001; // doliczenie losowego czasu opóźnienia + ++Event->iQueued; // zabezpieczenie przed podwójnym dodaniem do kolejki + if (QueryRootEvent ? Event->fStartTime >= QueryRootEvent->fStartTime : false) + QueryRootEvent->AddToQuery(Event); // dodanie gdzieś w środku + else + { // dodanie z przodu: albo nic nie ma, albo ma być wykonany szybciej niż pierwszy + Event->evNext = QueryRootEvent; + QueryRootEvent = Event; + } + } + } + return true; } bool __fastcall TGround::EventConditon(TEvent *e) -{//sprawdzenie spelnienia warunków dla eventu - if (e->iFlags<=update_only) return true; //bezwarunkowo - if (e->iFlags&conditional_trackoccupied) - return (!e->Params[9].asTrack->IsEmpty()); - else if (e->iFlags&conditional_trackfree) - return (e->Params[9].asTrack->IsEmpty()); - else if (e->iFlags&conditional_propability) - { - double rprobability=1.0*rand()/RAND_MAX; - WriteLog("Random integer: "+CurrToStr(rprobability)+"/"+CurrToStr(e->Params[10].asdouble)); - return (e->Params[10].asdouble>rprobability); - } - else if (e->iFlags&conditional_memcompare) - {//porównanie wartości - if (tmpEvent->Params[9].asMemCell->Compare(e->Params[10].asText,e->Params[11].asdouble,e->Params[12].asdouble,e->iFlags)) - return true; - else if (Global::iWriteLogEnabled && DebugModeFlag) - {//nie zgadza się, więc sprawdzmy, co - LogComment=e->Params[9].asMemCell->Text()+AnsiString(" ")+FloatToStrF(e->Params[9].asMemCell->Value1(),ffFixed,8,2)+" "+FloatToStrF(tmpEvent->Params[9].asMemCell->Value2(),ffFixed,8,2)+" != "; - if (TestFlag(e->iFlags,conditional_memstring)) - LogComment+=AnsiString(tmpEvent->Params[10].asText); - else - LogComment+="*"; - if (TestFlag(tmpEvent->iFlags,conditional_memval1)) - LogComment+=" "+FloatToStrF(tmpEvent->Params[11].asdouble,ffFixed,8,2); - else - LogComment+=" *"; - if (TestFlag(tmpEvent->iFlags,conditional_memval2)) - LogComment+=" "+FloatToStrF(tmpEvent->Params[12].asdouble,ffFixed,8,2); - else - LogComment+=" *"; - WriteLog(LogComment.c_str()); - } - } - return false; +{ // sprawdzenie spelnienia warunków dla eventu + if (e->iFlags <= update_only) + return true; // bezwarunkowo + if (e->iFlags & conditional_trackoccupied) + return (!e->Params[9].asTrack->IsEmpty()); + else if (e->iFlags & conditional_trackfree) + return (e->Params[9].asTrack->IsEmpty()); + else if (e->iFlags & conditional_propability) + { + double rprobability = 1.0 * rand() / RAND_MAX; + WriteLog("Random integer: " + CurrToStr(rprobability) + "/" + + CurrToStr(e->Params[10].asdouble)); + return (e->Params[10].asdouble > rprobability); + } + else if (e->iFlags & conditional_memcompare) + { // porównanie wartości + if (tmpEvent->Params[9].asMemCell->Compare(e->Params[10].asText, e->Params[11].asdouble, + e->Params[12].asdouble, e->iFlags)) + return true; + else if (Global::iWriteLogEnabled && DebugModeFlag) + { // nie zgadza się, więc sprawdzmy, co + LogComment = e->Params[9].asMemCell->Text() + AnsiString(" ") + + FloatToStrF(e->Params[9].asMemCell->Value1(), ffFixed, 8, 2) + " " + + FloatToStrF(tmpEvent->Params[9].asMemCell->Value2(), ffFixed, 8, 2) + + " != "; + if (TestFlag(e->iFlags, conditional_memstring)) + LogComment += AnsiString(tmpEvent->Params[10].asText); + else + LogComment += "*"; + if (TestFlag(tmpEvent->iFlags, conditional_memval1)) + LogComment += " " + FloatToStrF(tmpEvent->Params[11].asdouble, ffFixed, 8, 2); + else + LogComment += " *"; + if (TestFlag(tmpEvent->iFlags, conditional_memval2)) + LogComment += " " + FloatToStrF(tmpEvent->Params[12].asdouble, ffFixed, 8, 2); + else + LogComment += " *"; + WriteLog(LogComment.c_str()); + } + } + return false; }; bool __fastcall TGround::CheckQuery() -{//sprawdzenie kolejki eventów oraz wykonanie tych, którym czas minął - TLocation loc; - int i; -/* //Ra: to w ogóle jakiś chory kod jest; wygląda jak wyszukanie eventu z najlepszym czasem - Double evtime,evlowesttime; //Ra: co to za typ? - //evlowesttime=1000000; - if (QueryRootEvent) - { - OldQRE=QueryRootEvent; - tmpEvent=QueryRootEvent; - } - if (QueryRootEvent) - { - for (i=0;i<90;++i) - { - evtime=((tmpEvent->fStartTime)-(Timer::GetTime())); //pobranie wartości zmiennej - if (evtimeNext) - tmpEvent=tmpEvent->Next; - else - i=100; - } - if (OldQRE!=tmp2Event) - { - QueryRootEvent->AddToQuery(QueryRootEvent); - QueryRootEvent=tmp2Event; - } - } -*/ -/* - if (QueryRootEvent) - {//wypisanie kolejki - tmpEvent=QueryRootEvent; - WriteLog("--> Event queue:"); - while (tmpEvent) - { - WriteLog(tmpEvent->asName+" "+AnsiString(tmpEvent->fStartTime)); - tmpEvent=tmpEvent->Next; - } - } -*/ - while (QueryRootEvent?QueryRootEvent->fStartTimeevJoined) //jeśli jest kolejny o takiej samej nazwie - {//to teraz on będzie następny do wykonania - QueryRootEvent=QueryRootEvent->evJoined; //następny będzie ten doczepiony - QueryRootEvent->evNext=tmpEvent->evNext; //pamiętając o następnym z kolejki - QueryRootEvent->fStartTime=tmpEvent->fStartTime; //czas musi być ten sam, bo nie jest aktualizowany - QueryRootEvent->Activator=tmpEvent->Activator; //pojazd aktywujący - //w sumie można by go dodać normalnie do kolejki, ale trzeba te połączone posortować wg czasu wykonania - } - 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źć - WriteLog("EVENT LAUNCHED: "+tmpEvent->asName+(tmpEvent->Activator?AnsiString(" by "+tmpEvent->Activator->asName):AnsiString(""))); - switch (tmpEvent->Type) - { - case tp_CopyValues: //skopiowanie wartości z innej komórki - tmpEvent->Params[5].asMemCell->UpdateValues - (tmpEvent->Params[9].asMemCell->Text(), - tmpEvent->Params[9].asMemCell->Value1(), - tmpEvent->Params[9].asMemCell->Value2(), - tmpEvent->iFlags //flagi określają, co ma być skopiowane - ); - //break; //żeby się wysłało do torów i nie było potrzeby na AddValues * 0 0 - case tp_AddValues: //różni się jedną flagą od UpdateValues - case tp_UpdateValues: - if (EventConditon(tmpEvent)) - {//teraz mogą być warunki do tych eventów - if (tmpEvent->Type!=tp_CopyValues) //dla CopyValues zrobiło się wcześniej - tmpEvent->Params[5].asMemCell->UpdateValues(tmpEvent->Params[0].asText,tmpEvent->Params[1].asdouble,tmpEvent->Params[2].asdouble,tmpEvent->iFlags); - if (tmpEvent->Params[6].asTrack) - {//McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla wszystkich 'dynamic' na danym torze - for (int i=0;iParams[6].asTrack->iNumDynamics;++i) - tmpEvent->Params[5].asMemCell->PutCommand(tmpEvent->Params[6].asTrack->Dynamics[i]->Mechanik,&tmpEvent->Params[4].nGroundNode->pCenter); - if (DebugModeFlag) - WriteLog("Type: UpdateValues & Track command - "+AnsiString(tmpEvent->Params[0].asText)+" "+AnsiString(tmpEvent->Params[1].asdouble)+" "+AnsiString(tmpEvent->Params[2].asdouble)); - } - else - if (DebugModeFlag) - WriteLog("Type: UpdateValues - "+AnsiString(tmpEvent->Params[0].asText)+" "+AnsiString(tmpEvent->Params[1].asdouble)+" "+AnsiString(tmpEvent->Params[2].asdouble)); - } - break; - case tp_GetValues: - if (tmpEvent->Activator) +{ // sprawdzenie kolejki eventów oraz wykonanie tych, którym czas minął + TLocation loc; + int i; + /* //Ra: to w ogóle jakiś chory kod jest; wygląda jak wyszukanie eventu z najlepszym czasem + Double evtime,evlowesttime; //Ra: co to za typ? + //evlowesttime=1000000; + if (QueryRootEvent) { - //loc.X= -tmpEvent->Params[8].nGroundNode->pCenter.x; - //loc.Y= tmpEvent->Params[8].nGroundNode->pCenter.z; - //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()); - //tmpEvent->Params[9].asMemCell->PutCommand(tmpEvent->Activator->Mechanik,loc); - tmpEvent->Params[9].asMemCell->PutCommand(tmpEvent->Activator->Mechanik,&tmpEvent->Params[8].nGroundNode->pCenter); + OldQRE=QueryRootEvent; + tmpEvent=QueryRootEvent; } - WriteLog("Type: GetValues"); - break; - case tp_PutValues: - if (tmpEvent->Activator) + if (QueryRootEvent) { - loc.X=-tmpEvent->Params[3].asdouble; //zamiana, bo fizyka ma inaczej niż sceneria - loc.Y= tmpEvent->Params[5].asdouble; - loc.Z= tmpEvent->Params[4].asdouble; - if (tmpEvent->Activator->Mechanik) //przekazanie rozkazu do AI - tmpEvent->Activator->Mechanik->PutCommand(tmpEvent->Params[0].asText,tmpEvent->Params[1].asdouble,tmpEvent->Params[2].asdouble,loc); - else - {//przekazanie do pojazdu - tmpEvent->Activator->MoverParameters->PutCommand(tmpEvent->Params[0].asText,tmpEvent->Params[1].asdouble,tmpEvent->Params[2].asdouble,loc); - } - } - WriteLog("Type: PutValues"); - break; - case tp_Lights: - if (tmpEvent->Params[9].asModel) - for (i=0;iParams[i].asdouble>=0) //-1 zostawia bez zmiany - tmpEvent->Params[9].asModel->LightSet(i,tmpEvent->Params[i].asdouble); //teraz też ułamek - break; - case tp_Visible: - if (tmpEvent->Params[9].nGroundNode) - tmpEvent->Params[9].nGroundNode->bVisible=(tmpEvent->Params[i].asInt>0); - break; - case tp_Velocity : - Error("Not implemented yet :("); - break; - case tp_Exit : - MessageBox(0,tmpEvent->asNodeName.c_str()," THE END ",MB_OK); - Global::iTextMode=-1; //wyłączenie takie samo jak sekwencja F10 -> Y - return false; - case tp_Sound : - switch (tmpEvent->Params[0].asInt) - {//trzy możliwe przypadki: - case 0: tmpEvent->Params[9].tsTextSound->Stop(); break; - case 1: tmpEvent->Params[9].tsTextSound->Play(1,0,true,tmpEvent->Params[9].tsTextSound->vSoundPosition); break; - case -1: tmpEvent->Params[9].tsTextSound->Play(1,DSBPLAY_LOOPING,true,tmpEvent->Params[9].tsTextSound->vSoundPosition); break; - } - break; - case tp_Disable : - Error("Not implemented yet :("); - break; - case tp_Animation : //Marcin: dorobic translacje - Ra: dorobiłem ;-) - if (tmpEvent->Params[0].asInt==1) - tmpEvent->Params[9].asAnimContainer->SetRotateAnim( - vector3(tmpEvent->Params[1].asdouble, - tmpEvent->Params[2].asdouble, - tmpEvent->Params[3].asdouble), - tmpEvent->Params[4].asdouble); - else if (tmpEvent->Params[0].asInt==2) - tmpEvent->Params[9].asAnimContainer->SetTranslateAnim( - vector3(tmpEvent->Params[1].asdouble, - tmpEvent->Params[2].asdouble, - tmpEvent->Params[3].asdouble), - tmpEvent->Params[4].asdouble); - else if (tmpEvent->Params[0].asInt==4) - tmpEvent->Params[9].asModel->AnimationVND( - tmpEvent->Params[8].asPointer, - tmpEvent->Params[1].asdouble, //tu mogą być dodatkowe parametry, np. od-do - tmpEvent->Params[2].asdouble, - tmpEvent->Params[3].asdouble, - tmpEvent->Params[4].asdouble); - break; - case tp_Switch: - if (tmpEvent->Params[9].asTrack) - tmpEvent->Params[9].asTrack->Switch(tmpEvent->Params[0].asInt,tmpEvent->Params[1].asdouble,tmpEvent->Params[2].asdouble); - if (Global::iMultiplayer) //dajemy znać do serwera o przełożeniu - WyslijEvent(tmpEvent->asName,""); //wysłanie nazwy eventu przełączajacego - //Ra: bardziej by się przydała nazwa toru, ale nie ma do niej stąd dostępu - break; - case tp_TrackVel: - if (tmpEvent->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"); - //WriteLog("Vel: ",tmpEvent->Params[0].asdouble); - tmpEvent->Params[9].asTrack->VelocitySet(tmpEvent->Params[0].asdouble); - if (DebugModeFlag) //wyświetlana jest ta faktycznie ustawiona - WriteLog("vel: ",tmpEvent->Params[9].asTrack->VelocityGet()); - } - break; - case tp_DynVel: - Error("Event \"DynVel\" is obsolete"); - break; - case tp_Multiple: - { - bCondition=EventConditon(tmpEvent); - if (bCondition||(tmpEvent->iFlags&conditional_anyelse)) //warunek spelniony albo było użyte else - { - WriteLog("Multiple passed"); - for (i=0;i<8;++i) - {//dodawane do kolejki w kolejności zapisania - if (tmpEvent->Params[i].asEvent) - if (bCondition!=bool(tmpEvent->iFlags&(conditional_else<Params[i].asEvent!=tmpEvent) - AddToQuery(tmpEvent->Params[i].asEvent,tmpEvent->Activator); //normalnie dodać - else //jeśli ma być rekurencja - if (tmpEvent->fDelay>=5.0) //to musi mieć sensowny okres powtarzania - if (tmpEvent->iQueued<2) - {//trzeba zrobić wyjątek, aby event mógł się sam dodać do kolejki, raz już jest, ale będzie usunięty - //pętla eventowa może być uruchomiona wiele razy, ale tylko pierwsze uruchomienie zadziała - tmpEvent->iQueued=0; //tymczasowo, aby był ponownie dodany do kolejki - AddToQuery(tmpEvent,tmpEvent->Activator); - tmpEvent->iQueued=2; //kolejny raz już absolutnie nie dodawać - } - } - } - if (Global::iMultiplayer) //dajemy znać do serwera o wykonaniu - if ((tmpEvent->iFlags&conditional_anyelse)==0) //jednoznaczne tylko, gdy nie było else + for (i=0;i<90;++i) + { + evtime=((tmpEvent->fStartTime)-(Timer::GetTime())); //pobranie wartości zmiennej + if (evtimeActivator) - WyslijEvent(tmpEvent->asName,tmpEvent->Activator->GetName()); - else - WyslijEvent(tmpEvent->asName,""); + evlowesttime=evtime; + tmp2Event=tmpEvent; } - } - } - break; - case tp_WhoIs: //pobranie nazwy pociągu do komórki pamięci - if (tmpEvent->iFlags&update_load) - {//jeśli pytanie o ładunek - if (tmpEvent->iFlags&update_memadd) //jeśli typ pojazdu - tmpEvent->Params[9].asMemCell->UpdateValues( - tmpEvent->Activator->MoverParameters->TypeName.c_str(), //typ pojazdu - 0, //na razie nic - 0, //na razie nic - tmpEvent->iFlags&(update_memstring|update_memval1|update_memval2)); - else //jeśli parametry ładunku - tmpEvent->Params[9].asMemCell->UpdateValues( - tmpEvent->Activator->MoverParameters->LoadType!=""?tmpEvent->Activator->MoverParameters->LoadType.c_str():"none", //nazwa ładunku - tmpEvent->Activator->MoverParameters->Load, //aktualna ilość - tmpEvent->Activator->MoverParameters->MaxLoad, //maksymalna ilość - tmpEvent->iFlags&(update_memstring|update_memval1|update_memval2)); - } - else if (tmpEvent->iFlags&update_memadd) - {//jeśli miejsce docelowe pojazdu - tmpEvent->Params[9].asMemCell->UpdateValues( - tmpEvent->Activator->asDestination.c_str(), //adres docelowy - tmpEvent->Activator->DirectionGet(), //kierunek pojazdu względem czoła składu (1=zgodny,-1=przeciwny) - tmpEvent->Activator->MoverParameters->Power, //moc pojazdu silnikowego: 0 dla wagonu - tmpEvent->iFlags&(update_memstring|update_memval1|update_memval2)); - } - else if (tmpEvent->Activator->Mechanik) - if (tmpEvent->Activator->Mechanik->Primary()) - {//tylko jeśli ktoś tam siedzi - nie powinno dotyczyć pasażera! - tmpEvent->Params[9].asMemCell->UpdateValues( - tmpEvent->Activator->Mechanik->TrainName().c_str(), - tmpEvent->Activator->Mechanik->StationCount()-tmpEvent->Activator->Mechanik->StationIndex(), //ile przystanków do końca - tmpEvent->Activator->Mechanik->IsStop()?1:0, //1, gdy ma tu zatrzymanie - tmpEvent->iFlags); - WriteLog("Train detected: "+tmpEvent->Activator->Mechanik->TrainName()); + if (tmpEvent->Next) + tmpEvent=tmpEvent->Next; + else + i=100; + } + if (OldQRE!=tmp2Event) + { + QueryRootEvent->AddToQuery(QueryRootEvent); + QueryRootEvent=tmp2Event; } - break; - case tp_LogValues: //zapisanie zawartości komórki pamięci do logu - if (tmpEvent->Params[9].asMemCell) //jeśli była podana nazwa komórki - WriteLog("Memcell \""+tmpEvent->asNodeName+"\": "+ - tmpEvent->Params[9].asMemCell->Text()+" "+ - tmpEvent->Params[9].asMemCell->Value1()+" "+ - tmpEvent->Params[9].asMemCell->Value2()); - else //lista wszystkich - for (TGroundNode *Current=nRootOfType[TP_MEMCELL];Current;Current=Current->nNext) - WriteLog("Memcell \""+Current->asName+"\": "+ - Current->MemCell->Text()+" "+ - Current->MemCell->Value1()+" "+ - Current->MemCell->Value2()); - break; - case tp_Voltage: //zmiana napięcia w zasilaczu (TractionPowerSource) - if (tmpEvent->Params[9].psPower) - {//na razie takie chamskie ustawienie napięcia zasilania - WriteLog("type: Voltage"); - tmpEvent->Params[9].psPower->VoltageSet(tmpEvent->Params[0].asdouble); } - case tp_Friction: //zmiana tarcia na scenerii - {//na razie takie chamskie ustawienie napięcia zasilania - WriteLog("type: Friction"); - Global::fFriction=(tmpEvent->Params[0].asdouble); + */ + /* + if (QueryRootEvent) + {//wypisanie kolejki + tmpEvent=QueryRootEvent; + WriteLog("--> Event queue:"); + while (tmpEvent) + { + WriteLog(tmpEvent->asName+" "+AnsiString(tmpEvent->fStartTime)); + tmpEvent=tmpEvent->Next; + } } - break; - case tp_Message: //wyświetlenie komunikatu - break; - } //switch (tmpEvent->Type) - } //if (tmpEvent->bEnabled) - --tmpEvent->iQueued; //teraz moze być ponownie dodany do kolejki -/* - if (QueryRootEvent->eJoined) //jeśli jest kolejny o takiej samej nazwie - {//to teraz jego dajemy do wykonania - QueryRootEvent->eJoined->Next=QueryRootEvent->Next; //pamiętając o następnym z kolejki - QueryRootEvent->eJoined->fStartTime=QueryRootEvent->fStartTime; //czas musi być ten sam, bo nie jest aktualizowany - //QueryRootEvent->fStartTime=0; - QueryRootEvent=QueryRootEvent->eJoined; //a wykonać ten doczepiony - } - else - {//a jak nazwa jest unikalna, to kolejka idzie dalej - //QueryRootEvent->fStartTime=0; - QueryRootEvent=QueryRootEvent->Next; //NULL w skrajnym przypadku - } -*/ - } //while - return true; + */ + while (QueryRootEvent ? QueryRootEvent->fStartTime < Timer::GetTime() : false) + { // eventy są posortowana wg czasu wykonania + tmpEvent = QueryRootEvent; // wyjęcie eventu z kolejki + if (QueryRootEvent->evJoined) // jeśli jest kolejny o takiej samej nazwie + { // to teraz on będzie następny do wykonania + QueryRootEvent = QueryRootEvent->evJoined; // następny będzie ten doczepiony + QueryRootEvent->evNext = tmpEvent->evNext; // pamiętając o następnym z kolejki + QueryRootEvent->fStartTime = + tmpEvent->fStartTime; // czas musi być ten sam, bo nie jest aktualizowany + QueryRootEvent->Activator = tmpEvent->Activator; // pojazd aktywujący + // w sumie można by go dodać normalnie do kolejki, ale trzeba te połączone posortować wg + // czasu wykonania + } + 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źć + WriteLog("EVENT LAUNCHED: " + tmpEvent->asName + + (tmpEvent->Activator ? AnsiString(" by " + tmpEvent->Activator->asName) : + AnsiString(""))); + switch (tmpEvent->Type) + { + case tp_CopyValues: // skopiowanie wartości z innej komórki + tmpEvent->Params[5].asMemCell->UpdateValues( + tmpEvent->Params[9].asMemCell->Text(), tmpEvent->Params[9].asMemCell->Value1(), + tmpEvent->Params[9].asMemCell->Value2(), + tmpEvent->iFlags // flagi określają, co ma być skopiowane + ); + // break; //żeby się wysłało do torów i nie było potrzeby na AddValues * 0 0 + case tp_AddValues: // różni się jedną flagą od UpdateValues + case tp_UpdateValues: + if (EventConditon(tmpEvent)) + { // teraz mogą być warunki do tych eventów + if (tmpEvent->Type != tp_CopyValues) // dla CopyValues zrobiło się wcześniej + tmpEvent->Params[5].asMemCell->UpdateValues( + tmpEvent->Params[0].asText, tmpEvent->Params[1].asdouble, + tmpEvent->Params[2].asdouble, tmpEvent->iFlags); + if (tmpEvent->Params[6].asTrack) + { // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla + // wszystkich 'dynamic' na danym torze + for (int i = 0; i < tmpEvent->Params[6].asTrack->iNumDynamics; ++i) + tmpEvent->Params[5].asMemCell->PutCommand( + tmpEvent->Params[6].asTrack->Dynamics[i]->Mechanik, + &tmpEvent->Params[4].nGroundNode->pCenter); + if (DebugModeFlag) + WriteLog("Type: UpdateValues & Track command - " + + AnsiString(tmpEvent->Params[0].asText) + " " + + AnsiString(tmpEvent->Params[1].asdouble) + " " + + AnsiString(tmpEvent->Params[2].asdouble)); + } + else if (DebugModeFlag) + WriteLog("Type: UpdateValues - " + AnsiString(tmpEvent->Params[0].asText) + + " " + AnsiString(tmpEvent->Params[1].asdouble) + " " + + AnsiString(tmpEvent->Params[2].asdouble)); + } + break; + case tp_GetValues: + if (tmpEvent->Activator) + { + // loc.X= -tmpEvent->Params[8].nGroundNode->pCenter.x; + // loc.Y= tmpEvent->Params[8].nGroundNode->pCenter.z; + // 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()); + // tmpEvent->Params[9].asMemCell->PutCommand(tmpEvent->Activator->Mechanik,loc); + tmpEvent->Params[9].asMemCell->PutCommand( + tmpEvent->Activator->Mechanik, &tmpEvent->Params[8].nGroundNode->pCenter); + } + WriteLog("Type: GetValues"); + break; + case tp_PutValues: + if (tmpEvent->Activator) + { + loc.X = + -tmpEvent->Params[3].asdouble; // zamiana, bo fizyka ma inaczej niż sceneria + loc.Y = tmpEvent->Params[5].asdouble; + loc.Z = tmpEvent->Params[4].asdouble; + if (tmpEvent->Activator->Mechanik) // przekazanie rozkazu do AI + tmpEvent->Activator->Mechanik->PutCommand( + tmpEvent->Params[0].asText, tmpEvent->Params[1].asdouble, + tmpEvent->Params[2].asdouble, loc); + else + { // przekazanie do pojazdu + tmpEvent->Activator->MoverParameters->PutCommand( + tmpEvent->Params[0].asText, tmpEvent->Params[1].asdouble, + tmpEvent->Params[2].asdouble, loc); + } + } + WriteLog("Type: PutValues"); + break; + case tp_Lights: + if (tmpEvent->Params[9].asModel) + for (i = 0; i < iMaxNumLights; i++) + if (tmpEvent->Params[i].asdouble >= 0) //-1 zostawia bez zmiany + tmpEvent->Params[9].asModel->LightSet( + i, tmpEvent->Params[i].asdouble); // teraz też ułamek + break; + case tp_Visible: + if (tmpEvent->Params[9].nGroundNode) + tmpEvent->Params[9].nGroundNode->bVisible = (tmpEvent->Params[i].asInt > 0); + break; + case tp_Velocity: + Error("Not implemented yet :("); + break; + case tp_Exit: + MessageBox(0, tmpEvent->asNodeName.c_str(), " THE END ", MB_OK); + Global::iTextMode = -1; // wyłączenie takie samo jak sekwencja F10 -> Y + return false; + case tp_Sound: + switch (tmpEvent->Params[0].asInt) + { // trzy możliwe przypadki: + case 0: + tmpEvent->Params[9].tsTextSound->Stop(); + break; + case 1: + tmpEvent->Params[9].tsTextSound->Play( + 1, 0, true, tmpEvent->Params[9].tsTextSound->vSoundPosition); + break; + case -1: + tmpEvent->Params[9].tsTextSound->Play( + 1, DSBPLAY_LOOPING, true, tmpEvent->Params[9].tsTextSound->vSoundPosition); + break; + } + break; + case tp_Disable: + Error("Not implemented yet :("); + break; + case tp_Animation: // Marcin: dorobic translacje - Ra: dorobiłem ;-) + if (tmpEvent->Params[0].asInt == 1) + tmpEvent->Params[9].asAnimContainer->SetRotateAnim( + vector3(tmpEvent->Params[1].asdouble, tmpEvent->Params[2].asdouble, + tmpEvent->Params[3].asdouble), + tmpEvent->Params[4].asdouble); + else if (tmpEvent->Params[0].asInt == 2) + tmpEvent->Params[9].asAnimContainer->SetTranslateAnim( + vector3(tmpEvent->Params[1].asdouble, tmpEvent->Params[2].asdouble, + tmpEvent->Params[3].asdouble), + tmpEvent->Params[4].asdouble); + else if (tmpEvent->Params[0].asInt == 4) + tmpEvent->Params[9].asModel->AnimationVND( + tmpEvent->Params[8].asPointer, + tmpEvent->Params[1].asdouble, // tu mogą być dodatkowe parametry, np. od-do + tmpEvent->Params[2].asdouble, tmpEvent->Params[3].asdouble, + tmpEvent->Params[4].asdouble); + break; + case tp_Switch: + if (tmpEvent->Params[9].asTrack) + tmpEvent->Params[9].asTrack->Switch(tmpEvent->Params[0].asInt, + tmpEvent->Params[1].asdouble, + tmpEvent->Params[2].asdouble); + if (Global::iMultiplayer) // dajemy znać do serwera o przełożeniu + WyslijEvent(tmpEvent->asName, ""); // wysłanie nazwy eventu przełączajacego + // Ra: bardziej by się przydała nazwa toru, ale nie ma do niej stąd dostępu + break; + case tp_TrackVel: + if (tmpEvent->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"); + // WriteLog("Vel: ",tmpEvent->Params[0].asdouble); + tmpEvent->Params[9].asTrack->VelocitySet(tmpEvent->Params[0].asdouble); + if (DebugModeFlag) // wyświetlana jest ta faktycznie ustawiona + WriteLog("vel: ", tmpEvent->Params[9].asTrack->VelocityGet()); + } + break; + case tp_DynVel: + Error("Event \"DynVel\" is obsolete"); + break; + case tp_Multiple: + { + bCondition = EventConditon(tmpEvent); + if (bCondition || (tmpEvent->iFlags & + conditional_anyelse)) // warunek spelniony albo było użyte else + { + WriteLog("Multiple passed"); + for (i = 0; i < 8; ++i) + { // dodawane do kolejki w kolejności zapisania + if (tmpEvent->Params[i].asEvent) + if (bCondition != bool(tmpEvent->iFlags & (conditional_else << i))) + { + if (tmpEvent->Params[i].asEvent != tmpEvent) + AddToQuery(tmpEvent->Params[i].asEvent, + tmpEvent->Activator); // normalnie dodać + else // jeśli ma być rekurencja + if (tmpEvent->fDelay >= + 5.0) // to musi mieć sensowny okres powtarzania + if (tmpEvent->iQueued < 2) + { // trzeba zrobić wyjątek, aby event mógł się sam dodać do + // kolejki, raz już jest, ale będzie usunięty + // pętla eventowa może być uruchomiona wiele razy, ale tylko + // pierwsze uruchomienie zadziała + tmpEvent->iQueued = + 0; // tymczasowo, aby był ponownie dodany do kolejki + AddToQuery(tmpEvent, tmpEvent->Activator); + tmpEvent->iQueued = + 2; // kolejny raz już absolutnie nie dodawać + } + } + } + if (Global::iMultiplayer) // dajemy znać do serwera o wykonaniu + if ((tmpEvent->iFlags & conditional_anyelse) == + 0) // jednoznaczne tylko, gdy nie było else + { + if (tmpEvent->Activator) + WyslijEvent(tmpEvent->asName, tmpEvent->Activator->GetName()); + else + WyslijEvent(tmpEvent->asName, ""); + } + } + } + break; + case tp_WhoIs: // pobranie nazwy pociągu do komórki pamięci + if (tmpEvent->iFlags & update_load) + { // jeśli pytanie o ładunek + if (tmpEvent->iFlags & update_memadd) // jeśli typ pojazdu + tmpEvent->Params[9].asMemCell->UpdateValues( + tmpEvent->Activator->MoverParameters->TypeName.c_str(), // typ pojazdu + 0, // na razie nic + 0, // na razie nic + tmpEvent->iFlags & + (update_memstring | update_memval1 | update_memval2)); + else // jeśli parametry ładunku + tmpEvent->Params[9].asMemCell->UpdateValues( + tmpEvent->Activator->MoverParameters->LoadType != "" ? + tmpEvent->Activator->MoverParameters->LoadType.c_str() : + "none", // nazwa ładunku + tmpEvent->Activator->MoverParameters->Load, // aktualna ilość + tmpEvent->Activator->MoverParameters->MaxLoad, // maksymalna ilość + tmpEvent->iFlags & + (update_memstring | update_memval1 | update_memval2)); + } + else if (tmpEvent->iFlags & update_memadd) + { // jeśli miejsce docelowe pojazdu + tmpEvent->Params[9].asMemCell->UpdateValues( + tmpEvent->Activator->asDestination.c_str(), // adres docelowy + tmpEvent->Activator->DirectionGet(), // kierunek pojazdu względem czoła + // składu (1=zgodny,-1=przeciwny) + tmpEvent->Activator->MoverParameters + ->Power, // moc pojazdu silnikowego: 0 dla wagonu + tmpEvent->iFlags & (update_memstring | update_memval1 | update_memval2)); + } + else if (tmpEvent->Activator->Mechanik) + if (tmpEvent->Activator->Mechanik->Primary()) + { // tylko jeśli ktoś tam siedzi - nie powinno dotyczyć pasażera! + tmpEvent->Params[9].asMemCell->UpdateValues( + tmpEvent->Activator->Mechanik->TrainName().c_str(), + tmpEvent->Activator->Mechanik->StationCount() - + tmpEvent->Activator->Mechanik + ->StationIndex(), // ile przystanków do końca + tmpEvent->Activator->Mechanik->IsStop() ? 1 : + 0, // 1, gdy ma tu zatrzymanie + tmpEvent->iFlags); + WriteLog("Train detected: " + tmpEvent->Activator->Mechanik->TrainName()); + } + break; + case tp_LogValues: // zapisanie zawartości komórki pamięci do logu + if (tmpEvent->Params[9].asMemCell) // jeśli była podana nazwa komórki + WriteLog("Memcell \"" + tmpEvent->asNodeName + "\": " + + tmpEvent->Params[9].asMemCell->Text() + " " + + tmpEvent->Params[9].asMemCell->Value1() + " " + + tmpEvent->Params[9].asMemCell->Value2()); + else // lista wszystkich + for (TGroundNode *Current = nRootOfType[TP_MEMCELL]; Current; + Current = Current->nNext) + WriteLog("Memcell \"" + Current->asName + "\": " + + Current->MemCell->Text() + " " + Current->MemCell->Value1() + " " + + Current->MemCell->Value2()); + break; + case tp_Voltage: // zmiana napięcia w zasilaczu (TractionPowerSource) + if (tmpEvent->Params[9].psPower) + { // na razie takie chamskie ustawienie napięcia zasilania + WriteLog("type: Voltage"); + tmpEvent->Params[9].psPower->VoltageSet(tmpEvent->Params[0].asdouble); + } + case tp_Friction: // zmiana tarcia na scenerii + { // na razie takie chamskie ustawienie napięcia zasilania + WriteLog("type: Friction"); + Global::fFriction = (tmpEvent->Params[0].asdouble); + } + break; + case tp_Message: // wyświetlenie komunikatu + break; + } // switch (tmpEvent->Type) + } // if (tmpEvent->bEnabled) + --tmpEvent->iQueued; // teraz moze być ponownie dodany do kolejki + /* + if (QueryRootEvent->eJoined) //jeśli jest kolejny o takiej samej nazwie + {//to teraz jego dajemy do wykonania + QueryRootEvent->eJoined->Next=QueryRootEvent->Next; //pamiętając o następnym z kolejki + QueryRootEvent->eJoined->fStartTime=QueryRootEvent->fStartTime; //czas musi być ten sam, + bo nie jest aktualizowany + //QueryRootEvent->fStartTime=0; + QueryRootEvent=QueryRootEvent->eJoined; //a wykonać ten doczepiony + } + else + {//a jak nazwa jest unikalna, to kolejka idzie dalej + //QueryRootEvent->fStartTime=0; + QueryRootEvent=QueryRootEvent->Next; //NULL w skrajnym przypadku + } + */ + } // while + return true; } void __fastcall TGround::OpenGLUpdate(HDC hDC) { - SwapBuffers(hDC); //swap buffers (double buffering) + SwapBuffers(hDC); // swap buffers (double buffering) }; -void __fastcall TGround::UpdatePhys(double dt,int iter) -{//aktualizacja fizyki stałym krokiem: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń - for (TGroundNode *Current=nRootOfType[TP_TRACTIONPOWERSOURCE];Current;Current=Current->nNext) - Current->psTractionPowerSource->Update(dt*iter); //zerowanie sumy prądów +void __fastcall TGround::UpdatePhys(double dt, int iter) +{ // aktualizacja fizyki stałym krokiem: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń + for (TGroundNode *Current = nRootOfType[TP_TRACTIONPOWERSOURCE]; Current; + Current = Current->nNext) + Current->psTractionPowerSource->Update(dt * iter); // zerowanie sumy prądów }; -bool __fastcall TGround::Update(double dt,int iter) -{//aktualizacja animacji krokiem FPS: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń - if (dt==0.0) - {//jeśli załączona jest pauza, to tylko obsłużyć ruch w kabinie trzeba - return true; - } - //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 - if (iter>1) //ABu: ponizsze wykonujemy tylko jesli wiecej niz jedna iteracja - {//pierwsza iteracja i wyznaczenie stalych: - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - {// - Current->DynamicObject->MoverParameters->ComputeConstans(); - Current->DynamicObject->CoupleDist(); - Current->DynamicObject->UpdateForce(dt,dt,false); - } - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - Current->DynamicObject->FastUpdate(dt); - //pozostale iteracje - for (int i=1;i<(iter-1);++i) //jeśli iter==5, to wykona się 3 razy - { - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - Current->DynamicObject->UpdateForce(dt,dt,false); - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - Current->DynamicObject->FastUpdate(dt); - } - //ABu 200205: a to robimy tylko raz, bo nie potrzeba więcej - //Winger 180204 - pantografy - double dt1=dt*iter; //całkowity czas - UpdatePhys(dt1,1); - TAnimModel::AnimUpdate(dt1); //wykonanie zakolejkowanych animacji - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - {//Ra: zmienić warunek na sprawdzanie pantografów w jednej zmiennej: czy pantografy i czy podniesione - if (Current->DynamicObject->MoverParameters->EnginePowerSource.SourceType==CurrentCollector) - GetTraction(Current->DynamicObject); //poszukiwanie drutu dla pantografów - Current->DynamicObject->UpdateForce(dt,dt1,true);//,true); - } - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - Current->DynamicObject->Update(dt,dt1); //Ra 2015-01: tylko tu przelicza sieć trakcyjną - } - else - {//jezeli jest tylko jedna iteracja - UpdatePhys(dt,1); - TAnimModel::AnimUpdate(dt); //wykonanie zakolejkowanych animacji - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - { - if (Current->DynamicObject->MoverParameters->EnginePowerSource.SourceType==CurrentCollector) - GetTraction(Current->DynamicObject); - Current->DynamicObject->MoverParameters->ComputeConstans(); - Current->DynamicObject->CoupleDist(); - Current->DynamicObject->UpdateForce(dt,dt,true);//,true); - } - for (TGroundNode *Current=nRootDynamic;Current;Current=Current->nNext) - Current->DynamicObject->Update(dt,dt);//Ra 2015-01: tylko tu przelicza sieć trakcyjną - } - 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 (!Current->DynamicObject->bEnabled) - { - DynamicRemove(Current->DynamicObject); //usunięcie tego i podłączonych - Current=nRootDynamic; //sprawdzanie listy od początku - } - bDynamicRemove=false; //na razie koniec - } - return true; -}; - -//Winger 170204 - szukanie trakcji nad pantografami -bool __fastcall TGround::GetTraction(TDynamicObject *model) -{//aktualizacja drutu zasilającego dla każdego pantografu, żeby odczytać napięcie - //jeśli pojazd się nie porusza, to nie ma sensu przeliczać tego więcej niż raz - double fRaParam; //parametr równania parametrycznego odcinka drutu - double fVertical; //odległość w pionie; musi być w zasięgu ruchu "pionowego" pantografu - double fHorizontal; //odległość w bok; powinna być mniejsza niż pół szerokości pantografu - vector3 vLeft,vUp,vFront,dwys; - vector3 pant0; - vector3 vParam; //współczynniki równania parametrycznego drutu - vector3 vStyk; //punkt przebicia drutu przez płaszczyznę ruchu pantografu - vector3 vGdzie; //wektor położenia drutu względem pojazdu - vFront=model->VectorFront(); //wektor normalny dla płaszczyzny ruchu pantografu - vUp=model->VectorUp(); //wektor pionu pudła (pochylony od pionu na przechyłce) - vLeft=model->VectorLeft(); //wektor odległości w bok (odchylony od poziomu na przechyłce) - dwys=model->GetPosition(); //współrzędne środka pojazdu - TAnimPant *p; //wskaźnik do obiektu danych pantografu - for (int k=0;kiAnimType[ANIM_PANTS];++k) - {//pętla po pantografach - p=model->pants[k].fParamPants; - if (k?model->MoverParameters->PantRearUp:model->MoverParameters->PantFrontUp) - {//jeśli pantograf podniesiony - pant0=dwys+(vLeft*p->vPos.z)+(vUp*p->vPos.y)+(vFront*p->vPos.x); - if (p->hvPowerWire) - {//jeżeli znamy drut z poprzedniego przebiegu - int n=30; //żeby się nie zapętlił - while (p->hvPowerWire) - {//powtarzane aż do znalezienia odpowiedniego odcinka na liście dwukierunkowej - //obliczamy wyraz wolny równania płaszczyzny (to miejsce nie jest odpowienie) - vParam=p->hvPowerWire->vParametric; //współczynniki równania parametrycznego - fRaParam=-DotProduct(pant0,vFront); - //podstawiamy równanie parametryczne drutu do równania płaszczyzny pantografu - //vFront.x*(t1x+t*vParam.x)+vFront.y*(t1y+t*vParam.y)+vFront.z*(t1z+t*vParam.z)+fRaDist=0; - fRaParam=-(DotProduct(p->hvPowerWire->pPoint1,vFront)+fRaParam)/DotProduct(vParam,vFront); - if (fRaParam<-0.001) //histereza rzędu 7cm na 70m typowego przęsła daje 1 promil - p->hvPowerWire=p->hvPowerWire->hvNext[0]; - else if (fRaParam>1.001) - p->hvPowerWire=p->hvPowerWire->hvNext[1]; - else if (p->hvPowerWire->iLast&3) - {//dla ostatniego i przedostatniego przęsła wymuszamy szukanie innego - p->hvPowerWire=NULL; //nie to, że nie ma, ale trzeba sprawdzić inne - //p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu - break; - } - else if (p->hvPowerWire->hvParallel) - {//jeśli przęsło tworzy bieżnię wspólną, to trzeba sprawdzić pozostałe - p->hvPowerWire=NULL; //nie to, że nie ma, ale trzeba sprawdzić inne - //p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu - break; //tymczasowo dla bieżni wspólnych poszukiwanie po całości - } - else - {//jeśli t jest w przedziale, wyznaczyć odległość wzdłuż wektorów vUp i vLeft - vStyk=p->hvPowerWire->pPoint1+fRaParam*vParam; //punkt styku płaszczyzny z drutem (dla generatora łuku el.) - vGdzie=vStyk-pant0; //wektor - //odległość w pionie musi być w zasięgu ruchu "pionowego" pantografu - fVertical=DotProduct(vGdzie,vUp); //musi się mieścić w przedziale ruchu pantografu - //odległość w bok powinna być mniejsza niż pół szerokości pantografu - fHorizontal=fabs(DotProduct(vGdzie,vLeft))-p->fWidth; //to się musi mieścić w przedziale zależnym od szerokości pantografu - //jeśli w pionie albo w bok jest za daleko, to dany drut jest nieużyteczny - if (fHorizontal>0) //0.635 dla AKP-1 AKP-4E - {//drut wyszedł poza zakres roboczy, ale jeszcze jest nabieżnik - pantograf się unosi bez utraty prądu - if (fHorizontal>p->fWidthExtra) //czy wyszedł za nabieżnik - {p->hvPowerWire=NULL; //dotychczasowy drut nie liczy się - //p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu - } - else - {//problem jest, gdy nowy drut jest wyżej, wtedy pantograf odłącza się od starego, a na podniesienie do nowego potrzebuje czasu - p->PantTraction=fVertical+0.15*fHorizontal/p->fWidthExtra; //na razie liniowo na nabieżniku, dokładność poprawi się później - //p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu - } - } - else - {//po wyselekcjonowaniu drutu, przypisać go do toru, żeby nie trzeba było szukać - //dla 3 końcowych przęseł sprawdzić wszystkie dostępne przęsła - //bo mogą być umieszczone równolegle nad torem - połączyć w pierścień - //najlepiej, jakby odcinki równoległe były oznaczone we wpisach - //WriteLog("Drut: "+AnsiString(fHorizontal)+" "+AnsiString(fVertical)); - p->PantTraction=fVertical; - //p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu - break; //koniec pętli, aktualny drut pasuje - } - } - if (--n<=0) //coś za długo to szukanie trwa - p->hvPowerWire=NULL; +bool __fastcall TGround::Update(double dt, int iter) +{ // aktualizacja animacji krokiem FPS: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń + if (dt == 0.0) + { // jeśli załączona jest pauza, to tylko obsłużyć ruch w kabinie trzeba + return true; } - } - if (!p->hvPowerWire) //else nie, bo mógł zostać wyrzucony - {//poszukiwanie po okolicznych sektorach - int c=GetColFromX(dwys.x)+1; - int r=GetRowFromZ(dwys.z)+1; - TSubRect *tmp; - TGroundNode *node; - p->PantTraction=5.0; //taka za duża wartość - for (int j=r-2;j<=r;j++) - for (int i=c-2;i<=c;i++) - {//poszukiwanie po najbliższych sektorach niewiele da przy większym zagęszczeniu - tmp=FastGetSubRect(i,j); - if (tmp) - {//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 + // 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 + if (iter > 1) // ABu: ponizsze wykonujemy tylko jesli wiecej niz jedna iteracja + { // pierwsza iteracja i wyznaczenie stalych: + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + { // + Current->DynamicObject->MoverParameters->ComputeConstans(); + Current->DynamicObject->CoupleDist(); + Current->DynamicObject->UpdateForce(dt, dt, false); + } + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + Current->DynamicObject->FastUpdate(dt); + // pozostale iteracje + for (int i = 1; i < (iter - 1); ++i) // jeśli iter==5, to wykona się 3 razy { - vParam=node->hvTraction->vParametric; //współczynniki równania parametrycznego - fRaParam=-DotProduct(pant0,vFront); - fRaParam=-(DotProduct(node->hvTraction->pPoint1,vFront)+fRaParam)/DotProduct(vParam,vFront); - 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=DotProduct(vGdzie,vUp); //musi się mieścić w przedziale ruchu pantografu - if (fVertical>=0.0) //jeśli ponad pantografem (bo może łapać druty spod wiaduktu) - if (Global::bEnableTraction?fVerticalPantWys-0.15: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 - fHorizontal=fabs(DotProduct(vGdzie,vLeft))-p->fWidth; //i do tego jeszcze wejdzie pod ślizg - if (fHorizontal<=0.0) //0.635 dla AKP-1 AKP-4E - {p->PantWys=-1.0; //ujemna liczba oznacza połamanie - p->hvPowerWire=NULL; //bo inaczej się zasila w nieskończoność z połamanego - //p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu - if (model->MoverParameters->EnginePowerSource.CollectorParameters.CollectorsNo>0) //liczba pantografów - --model->MoverParameters->EnginePowerSource.CollectorParameters.CollectorsNo; //teraz będzie mniejsza - if (DebugModeFlag) - ErrorLog("Pant. break: at "+FloatToStrF(pant0.x,ffFixed,7,2)+" "+FloatToStrF(pant0.y,ffFixed,7,2)+" "+FloatToStrF(pant0.z,ffFixed,7,2)); + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + Current->DynamicObject->UpdateForce(dt, dt, false); + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + Current->DynamicObject->FastUpdate(dt); + } + // ABu 200205: a to robimy tylko raz, bo nie potrzeba więcej + // Winger 180204 - pantografy + double dt1 = dt * iter; // całkowity czas + UpdatePhys(dt1, 1); + TAnimModel::AnimUpdate(dt1); // wykonanie zakolejkowanych animacji + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + { // Ra: zmienić warunek na sprawdzanie pantografów w jednej zmiennej: czy pantografy i czy + // podniesione + if (Current->DynamicObject->MoverParameters->EnginePowerSource.SourceType == + CurrentCollector) + GetTraction(Current->DynamicObject); // poszukiwanie drutu dla pantografów + Current->DynamicObject->UpdateForce(dt, dt1, true); //,true); + } + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + Current->DynamicObject->Update(dt, dt1); // Ra 2015-01: tylko tu przelicza sieć + // trakcyjną + } + else + { // jezeli jest tylko jedna iteracja + UpdatePhys(dt, 1); + TAnimModel::AnimUpdate(dt); // wykonanie zakolejkowanych animacji + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + { + if (Current->DynamicObject->MoverParameters->EnginePowerSource.SourceType == + CurrentCollector) + GetTraction(Current->DynamicObject); + Current->DynamicObject->MoverParameters->ComputeConstans(); + Current->DynamicObject->CoupleDist(); + Current->DynamicObject->UpdateForce(dt, dt, true); //,true); + } + for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) + Current->DynamicObject->Update(dt, dt); // Ra 2015-01: tylko tu przelicza sieć trakcyjną + } + 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 (!Current->DynamicObject->bEnabled) + { + DynamicRemove(Current->DynamicObject); // usunięcie tego i podłączonych + Current = nRootDynamic; // sprawdzanie listy od początku } - } - else if (fVerticalPantTraction) //ale niżej, niż poprzednio znaleziony - { - fHorizontal=fabs(DotProduct(vGdzie,vLeft))-p->fWidth; - if (fHorizontal<=0.0) //0.635 dla AKP-1 AKP-4E - {//to się musi mieścić w przedziale zaleznym od szerokości pantografu - p->hvPowerWire=node->hvTraction; //jakiś znaleziony - p->PantTraction=fVertical; //zapamiętanie nowej wysokości - //p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu + bDynamicRemove = false; // na razie koniec + } + return true; +}; + +// Winger 170204 - szukanie trakcji nad pantografami +bool __fastcall TGround::GetTraction(TDynamicObject *model) +{ // aktualizacja drutu zasilającego dla każdego pantografu, żeby odczytać napięcie + // jeśli pojazd się nie porusza, to nie ma sensu przeliczać tego więcej niż raz + double fRaParam; // parametr równania parametrycznego odcinka drutu + double fVertical; // odległość w pionie; musi być w zasięgu ruchu "pionowego" pantografu + double fHorizontal; // odległość w bok; powinna być mniejsza niż pół szerokości pantografu + vector3 vLeft, vUp, vFront, dwys; + vector3 pant0; + vector3 vParam; // współczynniki równania parametrycznego drutu + vector3 vStyk; // punkt przebicia drutu przez płaszczyznę ruchu pantografu + vector3 vGdzie; // wektor położenia drutu względem pojazdu + vFront = model->VectorFront(); // wektor normalny dla płaszczyzny ruchu pantografu + vUp = model->VectorUp(); // wektor pionu pudła (pochylony od pionu na przechyłce) + vLeft = model->VectorLeft(); // wektor odległości w bok (odchylony od poziomu na przechyłce) + dwys = model->GetPosition(); // współrzędne środka pojazdu + TAnimPant *p; // wskaźnik do obiektu danych pantografu + for (int k = 0; k < model->iAnimType[ANIM_PANTS]; ++k) + { // pętla po pantografach + p = model->pants[k].fParamPants; + if (k ? model->MoverParameters->PantRearUp : model->MoverParameters->PantFrontUp) + { // jeśli pantograf podniesiony + pant0 = dwys + (vLeft * p->vPos.z) + (vUp * p->vPos.y) + (vFront * p->vPos.x); + if (p->hvPowerWire) + { // jeżeli znamy drut z poprzedniego przebiegu + int n = 30; //żeby się nie zapętlił + while (p->hvPowerWire) + { // powtarzane aż do znalezienia odpowiedniego odcinka na liście dwukierunkowej + // obliczamy wyraz wolny równania płaszczyzny (to miejsce nie jest odpowienie) + vParam = p->hvPowerWire->vParametric; // współczynniki równania parametrycznego + fRaParam = -DotProduct(pant0, vFront); + // podstawiamy równanie parametryczne drutu do równania płaszczyzny pantografu + // vFront.x*(t1x+t*vParam.x)+vFront.y*(t1y+t*vParam.y)+vFront.z*(t1z+t*vParam.z)+fRaDist=0; + fRaParam = -(DotProduct(p->hvPowerWire->pPoint1, vFront) + fRaParam) / + DotProduct(vParam, vFront); + if (fRaParam < + -0.001) // histereza rzędu 7cm na 70m typowego przęsła daje 1 promil + p->hvPowerWire = p->hvPowerWire->hvNext[0]; + else if (fRaParam > 1.001) + p->hvPowerWire = p->hvPowerWire->hvNext[1]; + else if (p->hvPowerWire->iLast & 3) + { // dla ostatniego i przedostatniego przęsła wymuszamy szukanie innego + p->hvPowerWire = NULL; // nie to, że nie ma, ale trzeba sprawdzić inne + // p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu + break; + } + else if (p->hvPowerWire->hvParallel) + { // jeśli przęsło tworzy bieżnię wspólną, to trzeba sprawdzić pozostałe + p->hvPowerWire = NULL; // nie to, że nie ma, ale trzeba sprawdzić inne + // p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu + break; // tymczasowo dla bieżni wspólnych poszukiwanie po całości + } + else + { // jeśli t jest w przedziale, wyznaczyć odległość wzdłuż wektorów vUp i vLeft + vStyk = p->hvPowerWire->pPoint1 + fRaParam * vParam; // punkt styku + // płaszczyzny z drutem + // (dla generatora łuku + // el.) + vGdzie = vStyk - pant0; // wektor + // odległość w pionie musi być w zasięgu ruchu "pionowego" pantografu + fVertical = DotProduct( + vGdzie, vUp); // musi się mieścić w przedziale ruchu pantografu + // odległość w bok powinna być mniejsza niż pół szerokości pantografu + fHorizontal = fabs(DotProduct(vGdzie, vLeft)) - + p->fWidth; // to się musi mieścić w przedziale zależnym od + // szerokości pantografu + // jeśli w pionie albo w bok jest za daleko, to dany drut jest nieużyteczny + if (fHorizontal > 0) // 0.635 dla AKP-1 AKP-4E + { // drut wyszedł poza zakres roboczy, ale jeszcze jest nabieżnik - + // pantograf się unosi bez utraty prądu + if (fHorizontal > p->fWidthExtra) // czy wyszedł za nabieżnik + { + p->hvPowerWire = NULL; // dotychczasowy drut nie liczy się + // p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu + } + else + { // problem jest, gdy nowy drut jest wyżej, wtedy pantograf odłącza się + // od starego, a na podniesienie do nowego potrzebuje czasu + p->PantTraction = + fVertical + + 0.15 * fHorizontal / p->fWidthExtra; // na razie liniowo na + // nabieżniku, dokładność + // poprawi się później + // p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu + } + } + else + { // po wyselekcjonowaniu drutu, przypisać go do toru, żeby nie trzeba było + // szukać + // dla 3 końcowych przęseł sprawdzić wszystkie dostępne przęsła + // bo mogą być umieszczone równolegle nad torem - połączyć w pierścień + // najlepiej, jakby odcinki równoległe były oznaczone we wpisach + // WriteLog("Drut: "+AnsiString(fHorizontal)+" "+AnsiString(fVertical)); + p->PantTraction = fVertical; + // p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu + break; // koniec pętli, aktualny drut pasuje + } + } + if (--n <= 0) // coś za długo to szukanie trwa + p->hvPowerWire = NULL; + } } - else if (fHorizontalfWidthExtra) //czy zmieścił się w zakresie nabieżnika? - {//problem jest, gdy nowy drut jest wyżej, wtedy pantograf odłącza się od starego, a na podniesienie do nowego potrzebuje czasu - fVertical+=0.15*fHorizontal/p->fWidthExtra; //korekta wysokości o nabieżnik - drut nad nabieżnikiem jest geometrycznie jakby nieco wyżej - if (fVerticalPantTraction) //gdy po korekcie jest niżej, niż poprzednio znaleziony - {//gdyby to wystarczyło, to możemy go uznać - p->hvPowerWire=node->hvTraction; //może być - p->PantTraction=fVertical; //na razie liniowo na nabieżniku, dokładność poprawi się później - //p->fHorizontal=fHorizontal; //zapamiętanie położenia drutu - } - } - } - } //warunek na parametr drutu <0;1> - } //pętla po drutach - } //sektor istnieje - } //pętla po sektorach - } //koniec poszukiwania w sektorach - if (!p->hvPowerWire) //jeśli drut nie znaleziony - if (!Global::bLiveTraction) //ale można oszukiwać - model->pants[k].fParamPants->PantTraction=1.4; //to dajemy coś tam dla picu - } //koniec obsługi podniesionego - else - p->hvPowerWire=NULL; //pantograf opuszczony - } - //if (model->fWahaczeAmpMoverParameters->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; + if (!p->hvPowerWire) // else nie, bo mógł zostać wyrzucony + { // poszukiwanie po okolicznych sektorach + int c = GetColFromX(dwys.x) + 1; + int r = GetRowFromZ(dwys.z) + 1; + TSubRect *tmp; + TGroundNode *node; + p->PantTraction = 5.0; // taka za duża wartość + for (int j = r - 2; j <= r; j++) + for (int i = c - 2; i <= c; i++) + { // poszukiwanie po najbliższych sektorach niewiele da przy większym + // zagęszczeniu + tmp = FastGetSubRect(i, j); + if (tmp) + { // 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 + { + vParam = + node->hvTraction + ->vParametric; // współczynniki równania parametrycznego + fRaParam = -DotProduct(pant0, vFront); + fRaParam = -(DotProduct(node->hvTraction->pPoint1, vFront) + + fRaParam) / + DotProduct(vParam, vFront); + 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 = DotProduct( + vGdzie, + vUp); // musi się mieścić w przedziale ruchu pantografu + 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; + // (bEnableTraction) aby dało się jeździć na koślawych + // sceneriach + fHorizontal = fabs(DotProduct(vGdzie, vLeft)) - + p->fWidth; // i do tego jeszcze + // wejdzie pod ślizg + if (fHorizontal <= 0.0) // 0.635 dla AKP-1 AKP-4E + { + p->PantWys = + -1.0; // ujemna liczba oznacza połamanie + p->hvPowerWire = NULL; // bo inaczej się zasila + // w nieskończoność z + // połamanego + // p->fHorizontal=fHorizontal; //zapamiętanie + // położenia drutu + if (model->MoverParameters->EnginePowerSource + .CollectorParameters.CollectorsNo > + 0) // liczba pantografów + --model->MoverParameters->EnginePowerSource + .CollectorParameters + .CollectorsNo; // teraz będzie + // mniejsza + if (DebugModeFlag) + ErrorLog( + "Pant. break: at " + + FloatToStrF(pant0.x, ffFixed, 7, 2) + + " " + + FloatToStrF(pant0.y, ffFixed, 7, 2) + + " " + + FloatToStrF(pant0.z, ffFixed, 7, 2)); + } + } + else if (fVertical < p->PantTraction) // ale niżej, niż + // poprzednio + // znaleziony + { + fHorizontal = + fabs(DotProduct(vGdzie, vLeft)) - p->fWidth; + if (fHorizontal <= 0.0) // 0.635 dla AKP-1 AKP-4E + { // to się musi mieścić w przedziale zaleznym od + // szerokości pantografu + p->hvPowerWire = + node->hvTraction; // jakiś znaleziony + p->PantTraction = + fVertical; // zapamiętanie nowej wysokości + // p->fHorizontal=fHorizontal; //zapamiętanie + // położenia drutu + } + else if (fHorizontal < + p->fWidthExtra) // czy zmieścił się w + // zakresie nabieżnika? + { // problem jest, gdy nowy drut jest wyżej, wtedy + // pantograf odłącza się od starego, a na + // podniesienie do nowego potrzebuje czasu + fVertical += + 0.15 * fHorizontal / + p->fWidthExtra; // korekta wysokości o + // nabieżnik - drut nad + // nabieżnikiem jest + // geometrycznie jakby nieco + // wyżej + if (fVertical < + p->PantTraction) // gdy po korekcie jest + // niżej, niż poprzednio + // znaleziony + { // gdyby to wystarczyło, to możemy go uznać + p->hvPowerWire = + node->hvTraction; // może być + p->PantTraction = + fVertical; // na razie liniowo na + // nabieżniku, dokładność + // poprawi się później + // p->fHorizontal=fHorizontal; + // //zapamiętanie położenia drutu + } + } + } + } // warunek na parametr drutu <0;1> + } // pętla po drutach + } // sektor istnieje + } // pętla po sektorach + } // koniec poszukiwania w sektorach + if (!p->hvPowerWire) // jeśli drut nie znaleziony + if (!Global::bLiveTraction) // ale można oszukiwać + model->pants[k].fParamPants->PantTraction = 1.4; // to dajemy coś tam dla picu + } // koniec obsługi podniesionego + else + p->hvPowerWire = NULL; // pantograf opuszczony + } + // if (model->fWahaczeAmpMoverParameters->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; }; bool __fastcall TGround::RenderDL(vector3 pPosition) -{//renderowanie scenerii z Display List - faza nieprzezroczystych - glDisable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.45); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - ++TGroundRect::iFrameNumber; //zwięszenie licznika ramek (do usuwniania nadanimacji) - CameraDirection.x=sin(Global::pCameraRotation); //wektor kierunkowy - CameraDirection.z=cos(Global::pCameraRotation); - int tr,tc; - TGroundNode *node; - glColor3f(1.0f,1.0f,1.0f); - glEnable(GL_LIGHTING); - int n=2*iNumSubRects; //(2*==2km) promień wyświetlanej mapy w sektorach - int c=GetColFromX(pPosition.x); - int r=GetRowFromZ(pPosition.z); - TSubRect *tmp; - for (node=srGlobal.nRenderHidden;node;node=node->nNext3) - node->RenderHidden(); //rednerowanie globalnych (nie za często?) - int i,j,k; - //renderowanie czołgowe dla obiektów aktywnych a niewidocznych - for (j=r-n;j<=r+n;j++) - for (i=c-n;i<=c+n;i++) - if ((tmp=FastGetSubRect(i,j))!=NULL) - {tmp->LoadNodes(); //oznaczanie aktywnych sektorów - for (node=tmp->nRenderHidden;node;node=node->nNext3) - node->RenderHidden(); - tmp->RenderSounds(); //jeszcze dźwięki pojazdów by się przydały, również niewidocznych - } - //renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - iRendered=0; //ilość renderowanych sektorów - vector3 direction; - for (k=0;k=0 - j=SectorOrder[k].y; - do - { - if (j<=0) i=-i; //pierwszy przebieg: j<=0, i>=0; drugi: j>=0, i<=0; trzeci: j<=0, i<=0 czwarty: j>=0, i>=0; - j=-j; //i oraz j musi być zmienione wcześniej, żeby continue działało - direction=vector3(i,0,j); //wektor od kamery do danego sektora - if (LengthSquared3(direction)>5) //te blisko są zawsze wyświetlane - {direction=SafeNormalize(direction); //normalizacja - if (CameraDirection.x*direction.x+CameraDirection.z*direction.z<0.55) - continue; //pomijanie sektorów poza kątem patrzenia - } - Rects[(i+c)/iNumSubRects][(j+r)/iNumSubRects].RenderDL(); //kwadrat kilometrowy nie zawsze, bo szkoda FPS - if ((tmp=FastGetSubRect(i+c,j+r))!=NULL) - if (tmp->iNodeCount) //o ile są jakieś obiekty, bo po co puste sektory przelatywać - pRendered[iRendered++]=tmp; //tworzenie listy sektorów do renderowania - } - while ((i<0)||(j<0)); //są 4 przypadki, oprócz i=j=0 - } - for (i=0;iRenderDL(); //renderowanie nieprzezroczystych - return true; +{ // renderowanie scenerii z Display List - faza nieprzezroczystych + glDisable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.45); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji) + CameraDirection.x = sin(Global::pCameraRotation); // wektor kierunkowy + CameraDirection.z = cos(Global::pCameraRotation); + int tr, tc; + TGroundNode *node; + glColor3f(1.0f, 1.0f, 1.0f); + glEnable(GL_LIGHTING); + int n = 2 * iNumSubRects; //(2*==2km) promień wyświetlanej mapy w sektorach + int c = GetColFromX(pPosition.x); + int r = GetRowFromZ(pPosition.z); + TSubRect *tmp; + for (node = srGlobal.nRenderHidden; node; node = node->nNext3) + node->RenderHidden(); // rednerowanie globalnych (nie za często?) + int i, j, k; + // renderowanie czołgowe dla obiektów aktywnych a niewidocznych + for (j = r - n; j <= r + n; j++) + for (i = c - n; i <= c + n; i++) + if ((tmp = FastGetSubRect(i, j)) != NULL) + { + tmp->LoadNodes(); // oznaczanie aktywnych sektorów + for (node = tmp->nRenderHidden; node; node = node->nNext3) + node->RenderHidden(); + tmp->RenderSounds(); // jeszcze dźwięki pojazdów by się przydały, również + // niewidocznych + } + // renderowanie progresywne - zależne od FPS oraz kierunku patrzenia + iRendered = 0; // ilość renderowanych sektorów + vector3 direction; + for (k = 0; k < Global::iSegmentsRendered; ++k) // sektory w kolejności odległości + { // przerobione na użycie SectorOrder + i = SectorOrder[k].x; // na starcie oba >=0 + j = SectorOrder[k].y; + do + { + if (j <= 0) + i = -i; // pierwszy przebieg: j<=0, i>=0; drugi: j>=0, i<=0; trzeci: j<=0, i<=0 + // czwarty: j>=0, i>=0; + j = -j; // i oraz j musi być zmienione wcześniej, żeby continue działało + direction = vector3(i, 0, j); // wektor od kamery do danego sektora + if (LengthSquared3(direction) > 5) // te blisko są zawsze wyświetlane + { + direction = SafeNormalize(direction); // normalizacja + if (CameraDirection.x * direction.x + CameraDirection.z * direction.z < 0.55) + continue; // pomijanie sektorów poza kątem patrzenia + } + Rects[(i + c) / iNumSubRects][(j + r) / iNumSubRects] + .RenderDL(); // kwadrat kilometrowy nie zawsze, bo szkoda FPS + if ((tmp = FastGetSubRect(i + c, j + r)) != NULL) + if (tmp->iNodeCount) // o ile są jakieś obiekty, bo po co puste sektory przelatywać + pRendered[iRendered++] = tmp; // tworzenie listy sektorów do renderowania + } while ((i < 0) || (j < 0)); // są 4 przypadki, oprócz i=j=0 + } + for (i = 0; i < iRendered; i++) + pRendered[i]->RenderDL(); // renderowanie nieprzezroczystych + return true; } bool __fastcall TGround::RenderAlphaDL(vector3 pPosition) -{//renderowanie scenerii z Display List - faza przezroczystych - glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.04); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - TGroundNode *node; - glColor4f(1.0f,1.0f,1.0f,1.0f); - TSubRect *tmp; - //Ra: renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - int i; - for (i=iRendered-1;i>=0;--i) //od najdalszych - {//przezroczyste trójkąty w oddzielnym cyklu przed modelami - tmp=pRendered[i]; - for (node=tmp->nRenderRectAlpha;node;node=node->nNext3) - node->RenderAlphaDL(); //przezroczyste modele - } - for (i=iRendered-1;i>=0;--i) //od najdalszych - {//renderowanie przezroczystych modeli oraz pojazdów - pRendered[i]->RenderAlphaDL(); - } - glDisable(GL_LIGHTING); //linie nie powinny świecić - for (i=iRendered-1;i>=0;--i) //od najdalszych - {//druty na końcu, żeby się nie robiły białe plamy na tle lasu - tmp=pRendered[i]; - for (node=tmp->nRenderWires;node;node=node->nNext3) - node->RenderAlphaDL(); //druty - } - return true; +{ // renderowanie scenerii z Display List - faza przezroczystych + glEnable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.04); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + TGroundNode *node; + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + TSubRect *tmp; + // Ra: renderowanie progresywne - zależne od FPS oraz kierunku patrzenia + int i; + for (i = iRendered - 1; i >= 0; --i) // od najdalszych + { // przezroczyste trójkąty w oddzielnym cyklu przed modelami + tmp = pRendered[i]; + for (node = tmp->nRenderRectAlpha; node; node = node->nNext3) + node->RenderAlphaDL(); // przezroczyste modele + } + for (i = iRendered - 1; i >= 0; --i) // od najdalszych + { // renderowanie przezroczystych modeli oraz pojazdów + pRendered[i]->RenderAlphaDL(); + } + glDisable(GL_LIGHTING); // linie nie powinny świecić + for (i = iRendered - 1; i >= 0; --i) // od najdalszych + { // druty na końcu, żeby się nie robiły białe plamy na tle lasu + tmp = pRendered[i]; + for (node = tmp->nRenderWires; node; node = node->nNext3) + node->RenderAlphaDL(); // druty + } + return true; } bool __fastcall TGround::RenderVBO(vector3 pPosition) -{//renderowanie scenerii z VBO - faza nieprzezroczystych - glDisable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.45); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - ++TGroundRect::iFrameNumber; //zwięszenie licznika ramek - CameraDirection.x=sin(Global::pCameraRotation); //wektor kierunkowy - CameraDirection.z=cos(Global::pCameraRotation); - int tr,tc; - TGroundNode *node; - glColor3f(1.0f,1.0f,1.0f); - glEnable(GL_LIGHTING); - int n=2*iNumSubRects; //(2*==2km) promień wyświetlanej mapy w sektorach - int c=GetColFromX(pPosition.x); - int r=GetRowFromZ(pPosition.z); - TSubRect *tmp; - for (node=srGlobal.nRenderHidden;node;node=node->nNext3) - node->RenderHidden(); //rednerowanie globalnych (nie za często?) - int i,j,k; - //renderowanie czołgowe dla obiektów aktywnych a niewidocznych - for (j=r-n;j<=r+n;j++) - for (i=c-n;i<=c+n;i++) - { - if ((tmp=FastGetSubRect(i,j))!=NULL) - {for (node=tmp->nRenderHidden;node;node=node->nNext3) - node->RenderHidden(); - tmp->RenderSounds(); //jeszcze dźwięki pojazdów by się przydały, również niewidocznych - } - } - //renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - iRendered=0; //ilość renderowanych sektorów - vector3 direction; - for (k=0;k=0 - j=SectorOrder[k].y; - do - { - if (j<=0) i=-i; //pierwszy przebieg: j<=0, i>=0; drugi: j>=0, i<=0; trzeci: j<=0, i<=0 czwarty: j>=0, i>=0; - j=-j; //i oraz j musi być zmienione wcześniej, żeby continue działało - direction=vector3(i,0,j); //wektor od kamery do danego sektora - if (LengthSquared3(direction)>5) //te blisko są zawsze wyświetlane - {direction=SafeNormalize(direction); //normalizacja - if (CameraDirection.x*direction.x+CameraDirection.z*direction.z<0.55) - continue; //pomijanie sektorów poza kątem patrzenia - } - Rects[(i+c)/iNumSubRects][(j+r)/iNumSubRects].RenderVBO(); //kwadrat kilometrowy nie zawsze, bo szkoda FPS - if ((tmp=FastGetSubRect(i+c,j+r))!=NULL) - if (tmp->iNodeCount) //jeżeli są jakieś obiekty, bo po co puste sektory przelatywać - pRendered[iRendered++]=tmp; //tworzenie listy sektorów do renderowania - } - while ((i<0)||(j<0)); //są 4 przypadki, oprócz i=j=0 - } - //dodać rednerowanie terenu z E3D - jedno VBO jest używane dla całego modelu, chyba że jest ich więcej - if (Global::pTerrainCompact) - Global::pTerrainCompact->TerrainRenderVBO(TGroundRect::iFrameNumber); - for (i=0;iRenderVBO(); - } - return true; +{ // renderowanie scenerii z VBO - faza nieprzezroczystych + glDisable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.45); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek + CameraDirection.x = sin(Global::pCameraRotation); // wektor kierunkowy + CameraDirection.z = cos(Global::pCameraRotation); + int tr, tc; + TGroundNode *node; + glColor3f(1.0f, 1.0f, 1.0f); + glEnable(GL_LIGHTING); + int n = 2 * iNumSubRects; //(2*==2km) promień wyświetlanej mapy w sektorach + int c = GetColFromX(pPosition.x); + int r = GetRowFromZ(pPosition.z); + TSubRect *tmp; + for (node = srGlobal.nRenderHidden; node; node = node->nNext3) + node->RenderHidden(); // rednerowanie globalnych (nie za często?) + int i, j, k; + // renderowanie czołgowe dla obiektów aktywnych a niewidocznych + for (j = r - n; j <= r + n; j++) + for (i = c - n; i <= c + n; i++) + { + if ((tmp = FastGetSubRect(i, j)) != NULL) + { + for (node = tmp->nRenderHidden; node; node = node->nNext3) + node->RenderHidden(); + tmp->RenderSounds(); // jeszcze dźwięki pojazdów by się przydały, również + // niewidocznych + } + } + // renderowanie progresywne - zależne od FPS oraz kierunku patrzenia + iRendered = 0; // ilość renderowanych sektorów + vector3 direction; + for (k = 0; k < Global::iSegmentsRendered; ++k) // sektory w kolejności odległości + { // przerobione na użycie SectorOrder + i = SectorOrder[k].x; // na starcie oba >=0 + j = SectorOrder[k].y; + do + { + if (j <= 0) + i = -i; // pierwszy przebieg: j<=0, i>=0; drugi: j>=0, i<=0; trzeci: j<=0, i<=0 + // czwarty: j>=0, i>=0; + j = -j; // i oraz j musi być zmienione wcześniej, żeby continue działało + direction = vector3(i, 0, j); // wektor od kamery do danego sektora + if (LengthSquared3(direction) > 5) // te blisko są zawsze wyświetlane + { + direction = SafeNormalize(direction); // normalizacja + if (CameraDirection.x * direction.x + CameraDirection.z * direction.z < 0.55) + continue; // pomijanie sektorów poza kątem patrzenia + } + Rects[(i + c) / iNumSubRects][(j + r) / iNumSubRects] + .RenderVBO(); // kwadrat kilometrowy nie zawsze, bo szkoda FPS + if ((tmp = FastGetSubRect(i + c, j + r)) != NULL) + if (tmp->iNodeCount) // jeżeli są jakieś obiekty, bo po co puste sektory przelatywać + pRendered[iRendered++] = tmp; // tworzenie listy sektorów do renderowania + } while ((i < 0) || (j < 0)); // są 4 przypadki, oprócz i=j=0 + } + // dodać rednerowanie terenu z E3D - jedno VBO jest używane dla całego modelu, chyba że jest ich + // więcej + if (Global::pTerrainCompact) + Global::pTerrainCompact->TerrainRenderVBO(TGroundRect::iFrameNumber); + for (i = 0; i < iRendered; i++) + { // renderowanie nieprzezroczystych + pRendered[i]->RenderVBO(); + } + return true; } bool __fastcall TGround::RenderAlphaVBO(vector3 pPosition) -{//renderowanie scenerii z VBO - faza przezroczystych - glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER,0.04); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - TGroundNode *node; - glColor4f(1.0f,1.0f,1.0f,1.0f); - TSubRect *tmp; - int i; - for (i=iRendered-1;i>=0;--i) //od najdalszych - {//renderowanie przezroczystych trójkątów sektora - tmp=pRendered[i]; - tmp->LoadNodes(); //ewentualne tworzenie siatek - if (tmp->StartVBO()) - {for (node=tmp->nRenderRectAlpha;node;node=node->nNext3) - if (node->iVboPtr>=0) - node->RenderAlphaVBO(); //nieprzezroczyste obiekty terenu - tmp->EndVBO(); - } - } - for (i=iRendered-1;i>=0;--i) //od najdalszych - pRendered[i]->RenderAlphaVBO(); //przezroczyste modeli oraz pojazdy - glDisable(GL_LIGHTING); //linie nie powinny świecić - for (i=iRendered-1;i>=0;--i) //od najdalszych - {//druty na końcu, żeby się nie robiły białe plamy na tle lasu - tmp=pRendered[i]; - if (tmp->StartVBO()) - {for (node=tmp->nRenderWires;node;node=node->nNext3) - node->RenderAlphaVBO(); //przezroczyste modele - tmp->EndVBO(); - } - } - return true; +{ // renderowanie scenerii z VBO - faza przezroczystych + glEnable(GL_BLEND); + glAlphaFunc(GL_GREATER, 0.04); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + TGroundNode *node; + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + TSubRect *tmp; + int i; + for (i = iRendered - 1; i >= 0; --i) // od najdalszych + { // renderowanie przezroczystych trójkątów sektora + tmp = pRendered[i]; + tmp->LoadNodes(); // ewentualne tworzenie siatek + if (tmp->StartVBO()) + { + for (node = tmp->nRenderRectAlpha; node; node = node->nNext3) + if (node->iVboPtr >= 0) + node->RenderAlphaVBO(); // nieprzezroczyste obiekty terenu + tmp->EndVBO(); + } + } + for (i = iRendered - 1; i >= 0; --i) // od najdalszych + pRendered[i]->RenderAlphaVBO(); // przezroczyste modeli oraz pojazdy + glDisable(GL_LIGHTING); // linie nie powinny świecić + for (i = iRendered - 1; i >= 0; --i) // od najdalszych + { // druty na końcu, żeby się nie robiły białe plamy na tle lasu + tmp = pRendered[i]; + if (tmp->StartVBO()) + { + for (node = tmp->nRenderWires; node; node = node->nNext3) + node->RenderAlphaVBO(); // przezroczyste modele + tmp->EndVBO(); + } + } + return true; }; //--------------------------------------------------------------------------- -void __fastcall TGround::Navigate(String ClassName,UINT Msg,WPARAM wParam,LPARAM lParam) -{//wysłanie komunikatu do sterującego - HWND h=FindWindow(ClassName.c_str(),0); //można by to zapamiętać - if (h==0) h=FindWindow(0,ClassName.c_str()); //można by to zapamiętać - SendMessage(h,Msg,wParam,lParam); +void __fastcall TGround::Navigate(String ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) +{ // wysłanie komunikatu do sterującego + HWND h = FindWindow(ClassName.c_str(), 0); // można by to zapamiętać + if (h == 0) + h = FindWindow(0, ClassName.c_str()); // można by to zapamiętać + SendMessage(h, Msg, wParam, lParam); }; //-------------------------------- -void __fastcall TGround::WyslijEvent(const AnsiString &e,const AnsiString &d) -{//Ra: jeszcze do wyczyszczenia - DaneRozkaz r; - r.iSygn='EU07'; - r.iComm=2; //2 - event - int i=e.Length(),j=d.Length(); - r.cString[0]=char(i); - strcpy(r.cString+1,e.c_str()); //zakończony zerem - r.cString[i+2]=char(j); //licznik po zerze kończącym - strcpy(r.cString+3+i,d.c_str()); //zakończony zerem - COPYDATASTRUCT cData; - cData.dwData='EU07'; //sygnatura - cData.cbData=12+i+j; //8+dwa liczniki i dwa zera kończące - cData.lpData=&r; - Navigate("TEU07SRK",WM_COPYDATA,(WPARAM)Global::hWnd,(LPARAM)&cData); +void __fastcall TGround::WyslijEvent(const AnsiString &e, const AnsiString &d) +{ // Ra: jeszcze do wyczyszczenia + DaneRozkaz r; + r.iSygn = 'EU07'; + r.iComm = 2; // 2 - event + int i = e.Length(), j = d.Length(); + r.cString[0] = char(i); + strcpy(r.cString + 1, e.c_str()); // zakończony zerem + r.cString[i + 2] = char(j); // licznik po zerze kończącym + strcpy(r.cString + 3 + i, d.c_str()); // zakończony zerem + COPYDATASTRUCT cData; + cData.dwData = 'EU07'; // sygnatura + cData.cbData = 12 + i + j; // 8+dwa liczniki i dwa zera kończące + cData.lpData = &r; + Navigate("TEU07SRK", WM_COPYDATA, (WPARAM)Global::hWnd, (LPARAM)&cData); }; //--------------------------------------------------------------------------- -void __fastcall TGround::WyslijString(const AnsiString &t,int n) -{//wysłanie informacji w postaci pojedynczego tekstu - DaneRozkaz r; - r.iSygn='EU07'; - r.iComm=n; //numer komunikatu - int i=t.Length(); - r.cString[0]=char(i); - strcpy(r.cString+1,t.c_str()); //z zerem kończącym - COPYDATASTRUCT cData; - cData.dwData='EU07'; //sygnatura - cData.cbData=10+i; //8+licznik i zero kończące - cData.lpData=&r; - Navigate("TEU07SRK",WM_COPYDATA,(WPARAM)Global::hWnd,(LPARAM)&cData); +void __fastcall TGround::WyslijString(const AnsiString &t, int n) +{ // wysłanie informacji w postaci pojedynczego tekstu + DaneRozkaz r; + r.iSygn = 'EU07'; + r.iComm = n; // numer komunikatu + int i = t.Length(); + r.cString[0] = char(i); + strcpy(r.cString + 1, t.c_str()); // z zerem kończącym + COPYDATASTRUCT cData; + cData.dwData = 'EU07'; // sygnatura + cData.cbData = 10 + i; // 8+licznik i zero kończące + cData.lpData = &r; + Navigate("TEU07SRK", WM_COPYDATA, (WPARAM)Global::hWnd, (LPARAM)&cData); }; //--------------------------------------------------------------------------- void __fastcall TGround::WyslijWolny(const AnsiString &t) -{//Ra: jeszcze do wyczyszczenia - WyslijString(t,4); //tor wolny +{ // Ra: jeszcze do wyczyszczenia + WyslijString(t, 4); // tor wolny }; //-------------------------------- -void __fastcall TGround::WyslijNamiary(TGroundNode* t) -{//wysłanie informacji o pojeździe - (float), długość ramki będzie zwiększana w miarę potrzeby -// WriteLog("Wysylam pojazd"); - DaneRozkaz r; - r.iSygn='EU07'; - r.iComm=7; //7 - dane pojazdu - int i=32,j=t->asName.Length(); - r.iPar[ 0]=i; //ilość danych liczbowych - r.fPar[ 1]=Global::fTimeAngleDeg/360.0; //aktualny czas (1.0=doba) - r.fPar[ 2]=t->DynamicObject->MoverParameters->Loc.X; //pozycja X - r.fPar[ 3]=t->DynamicObject->MoverParameters->Loc.Y; //pozycja Y - r.fPar[ 4]=t->DynamicObject->MoverParameters->Loc.Z; //pozycja Z - r.fPar[ 5]=t->DynamicObject->MoverParameters->V; //prędkość ruchu X - r.fPar[ 6]=t->DynamicObject->MoverParameters->nrot*M_PI*t->DynamicObject->MoverParameters->WheelDiameter; //prędkość obrotowa kóŁ - r.fPar[ 7]=0; //prędkość ruchu Z - r.fPar[ 8]=t->DynamicObject->MoverParameters->AccS; //przyspieszenie X - r.fPar[ 9]=t->DynamicObject->MoverParameters->AccN; //przyspieszenie Y //na razie nie - r.fPar[10]=t->DynamicObject->MoverParameters->AccV; //przyspieszenie Z - r.fPar[11]=t->DynamicObject->MoverParameters->DistCounter; //przejechana odległość w km - r.fPar[12]=t->DynamicObject->MoverParameters->PipePress; //ciśnienie w PG - r.fPar[13]=t->DynamicObject->MoverParameters->ScndPipePress; //ciśnienie w PZ - r.fPar[14]=t->DynamicObject->MoverParameters->BrakePress; //ciśnienie w CH - r.fPar[15]=t->DynamicObject->MoverParameters->Compressor; //ciśnienie w ZG - r.fPar[16]=t->DynamicObject->MoverParameters->Itot; //Prąd całkowity - r.iPar[17]=t->DynamicObject->MoverParameters->MainCtrlPos; //Pozycja NJ - r.iPar[18]=t->DynamicObject->MoverParameters->ScndCtrlPos; //Pozycja NB - r.iPar[19]=t->DynamicObject->MoverParameters->MainCtrlActualPos; //Pozycja jezdna - r.iPar[20]=t->DynamicObject->MoverParameters->ScndCtrlActualPos; //Pozycja bocznikowania - r.iPar[21]=t->DynamicObject->MoverParameters->ScndCtrlActualPos; //Pozycja bocznikowania - r.iPar[22]=t->DynamicObject->MoverParameters->ResistorsFlag*1+t->DynamicObject->MoverParameters->ConverterFlag*2+ - +t->DynamicObject->MoverParameters->CompressorFlag*4+t->DynamicObject->MoverParameters->Mains*8+ - +t->DynamicObject->MoverParameters->DoorLeftOpened*16+t->DynamicObject->MoverParameters->DoorRightOpened*32+ - +t->DynamicObject->MoverParameters->FuseFlag*64+t->DynamicObject->MoverParameters->DepartureSignal*128; -// WriteLog("Zapisalem stare"); -// WriteLog("Mam patykow "+IntToStr(t->DynamicObject->iAnimType[ANIM_PANTS])); - for(int p=0;p<4;p++) - { -// WriteLog("Probuje pant "+IntToStr(p)); - if(pDynamicObject->iAnimType[ANIM_PANTS]) +void __fastcall TGround::WyslijNamiary(TGroundNode *t) +{ // wysłanie informacji o pojeździe - (float), długość ramki będzie zwiększana w miarę potrzeby + // WriteLog("Wysylam pojazd"); + DaneRozkaz r; + r.iSygn = 'EU07'; + r.iComm = 7; // 7 - dane pojazdu + int i = 32, j = t->asName.Length(); + r.iPar[0] = i; // ilość danych liczbowych + r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba) + r.fPar[2] = t->DynamicObject->MoverParameters->Loc.X; // pozycja X + r.fPar[3] = t->DynamicObject->MoverParameters->Loc.Y; // pozycja Y + r.fPar[4] = t->DynamicObject->MoverParameters->Loc.Z; // pozycja Z + r.fPar[5] = t->DynamicObject->MoverParameters->V; // prędkość ruchu X + r.fPar[6] = t->DynamicObject->MoverParameters->nrot * M_PI * + t->DynamicObject->MoverParameters->WheelDiameter; // prędkość obrotowa kóŁ + r.fPar[7] = 0; // prędkość ruchu Z + r.fPar[8] = t->DynamicObject->MoverParameters->AccS; // przyspieszenie X + r.fPar[9] = t->DynamicObject->MoverParameters->AccN; // przyspieszenie Y //na razie nie + r.fPar[10] = t->DynamicObject->MoverParameters->AccV; // przyspieszenie Z + r.fPar[11] = t->DynamicObject->MoverParameters->DistCounter; // przejechana odległość w km + r.fPar[12] = t->DynamicObject->MoverParameters->PipePress; // ciśnienie w PG + r.fPar[13] = t->DynamicObject->MoverParameters->ScndPipePress; // ciśnienie w PZ + r.fPar[14] = t->DynamicObject->MoverParameters->BrakePress; // ciśnienie w CH + r.fPar[15] = t->DynamicObject->MoverParameters->Compressor; // ciśnienie w ZG + r.fPar[16] = t->DynamicObject->MoverParameters->Itot; // Prąd całkowity + r.iPar[17] = t->DynamicObject->MoverParameters->MainCtrlPos; // Pozycja NJ + r.iPar[18] = t->DynamicObject->MoverParameters->ScndCtrlPos; // Pozycja NB + r.iPar[19] = t->DynamicObject->MoverParameters->MainCtrlActualPos; // Pozycja jezdna + r.iPar[20] = t->DynamicObject->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania + r.iPar[21] = t->DynamicObject->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania + r.iPar[22] = t->DynamicObject->MoverParameters->ResistorsFlag * 1 + + t->DynamicObject->MoverParameters->ConverterFlag * 2 + + +t->DynamicObject->MoverParameters->CompressorFlag * 4 + + t->DynamicObject->MoverParameters->Mains * 8 + + +t->DynamicObject->MoverParameters->DoorLeftOpened * 16 + + t->DynamicObject->MoverParameters->DoorRightOpened * 32 + + +t->DynamicObject->MoverParameters->FuseFlag * 64 + + t->DynamicObject->MoverParameters->DepartureSignal * 128; + // WriteLog("Zapisalem stare"); + // WriteLog("Mam patykow "+IntToStr(t->DynamicObject->iAnimType[ANIM_PANTS])); + for (int p = 0; p < 4; p++) { - r.fPar[23+p]=t->DynamicObject->pants[p].fParamPants->PantWys; //stan pantografów 4 -// WriteLog("Zapisalem pant "+IntToStr(p)); + // WriteLog("Probuje pant "+IntToStr(p)); + if (p < t->DynamicObject->iAnimType[ANIM_PANTS]) + { + r.fPar[23 + p] = t->DynamicObject->pants[p].fParamPants->PantWys; // stan pantografów 4 + // WriteLog("Zapisalem pant "+IntToStr(p)); + } + else + { + r.fPar[23 + p] = -2; + // WriteLog("Nie mam pant "+IntToStr(p)); + } } - else - { - r.fPar[23+p]=-2; -// WriteLog("Nie mam pant "+IntToStr(p)); - } - } -// WriteLog("Zapisalem pantografy"); - for(int p=0;p<3;p++) - r.fPar[27+p]=t->DynamicObject->MoverParameters->ShowCurrent(p+1); //amperomierze kolejnych grup -// WriteLog("zapisalem prady"); - r.iPar[30]=t->DynamicObject->MoverParameters->WarningSignal; //trabienie - r.fPar[31]=t->DynamicObject->MoverParameters->RunningTraction.TractionVoltage; //napiecie WN -// WriteLog("Parametry gotowe"); - i<<=2; //ilość bajtów - r.cString[i]=char(j); //na końcu nazwa, żeby jakoś zidentyfikować - strcpy(r.cString+i+1,t->asName.c_str()); //zakończony zerem - COPYDATASTRUCT cData; - cData.dwData='EU07'; //sygnatura - cData.cbData=10+i+j; //8+licznik i zero kończące - cData.lpData=&r; -// WriteLog("Ramka gotowa"); - Navigate("TEU07SRK",WM_COPYDATA,(WPARAM)Global::hWnd,(LPARAM)&cData); -// WriteLog("Ramka poszla!"); + // WriteLog("Zapisalem pantografy"); + for (int p = 0; p < 3; p++) + r.fPar[27 + p] = + t->DynamicObject->MoverParameters->ShowCurrent(p + 1); // amperomierze kolejnych grup + // WriteLog("zapisalem prady"); + r.iPar[30] = t->DynamicObject->MoverParameters->WarningSignal; // trabienie + r.fPar[31] = t->DynamicObject->MoverParameters->RunningTraction.TractionVoltage; // napiecie WN + // WriteLog("Parametry gotowe"); + i <<= 2; // ilość bajtów + r.cString[i] = char(j); // na końcu nazwa, żeby jakoś zidentyfikować + strcpy(r.cString + i + 1, t->asName.c_str()); // zakończony zerem + COPYDATASTRUCT cData; + cData.dwData = 'EU07'; // sygnatura + cData.cbData = 10 + i + j; // 8+licznik i zero kończące + cData.lpData = &r; + // WriteLog("Ramka gotowa"); + Navigate("TEU07SRK", WM_COPYDATA, (WPARAM)Global::hWnd, (LPARAM)&cData); + // WriteLog("Ramka poszla!"); }; //-------------------------------- -void __fastcall TGround::WyslijParam(int nr,int fl) -{//wysłanie parametrów symulacji w ramce (nr) z flagami (fl) - DaneRozkaz r; - r.iSygn='EU07'; - r.iComm=nr; //zwykle 5 - r.iPar[0]=fl; //flagi istotności kolejnych parametrów - int i=0; //domyślnie brak danych - switch (nr) - {//można tym przesyłać różne zestawy parametrów - case 5: //czas i pauza - r.fPar[1]=Global::fTimeAngleDeg/360.0; //aktualny czas (1.0=doba) - r.iPar[2]=Global::iPause; //stan zapauzowania - i=8; //dwa parametry po 4 bajty każdy - break; - } - COPYDATASTRUCT cData; - cData.dwData='EU07'; //sygnatura - cData.cbData=12+i; //12+rozmiar danych - cData.lpData=&r; - Navigate("TEU07SRK",WM_COPYDATA,(WPARAM)Global::hWnd,(LPARAM)&cData); +void __fastcall TGround::WyslijParam(int nr, int fl) +{ // wysłanie parametrów symulacji w ramce (nr) z flagami (fl) + DaneRozkaz r; + r.iSygn = 'EU07'; + r.iComm = nr; // zwykle 5 + r.iPar[0] = fl; // flagi istotności kolejnych parametrów + int i = 0; // domyślnie brak danych + switch (nr) + { // można tym przesyłać różne zestawy parametrów + case 5: // czas i pauza + r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba) + r.iPar[2] = Global::iPause; // stan zapauzowania + i = 8; // dwa parametry po 4 bajty każdy + break; + } + COPYDATASTRUCT cData; + cData.dwData = 'EU07'; // sygnatura + cData.cbData = 12 + i; // 12+rozmiar danych + cData.lpData = &r; + Navigate("TEU07SRK", WM_COPYDATA, (WPARAM)Global::hWnd, (LPARAM)&cData); }; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void __fastcall TGround::RadioStop(vector3 pPosition) -{//zatrzymanie pociągów w okolicy - TGroundNode *node; - TSubRect *tmp; - int c=GetColFromX(pPosition.x); - int r=GetRowFromZ(pPosition.z); - int i,j; - int n=2*iNumSubRects; //przeglądanie czołgowe okolicznych torów w kwadracie 4km×4km - for (j=r-n;j<=r+n;j++) - for (i=c-n;i<=c+n;i++) - if ((tmp=FastGetSubRect(i,j))!=NULL) - for (node=tmp->nRootNode;node!=NULL;node=node->nNext2) - if (node->iType==TP_TRACK) - node->pTrack->RadioStop(); //przekazanie do każdego toru w każdym segmencie +{ // zatrzymanie pociągów w okolicy + TGroundNode *node; + TSubRect *tmp; + int c = GetColFromX(pPosition.x); + int r = GetRowFromZ(pPosition.z); + int i, j; + int n = 2 * iNumSubRects; // przeglądanie czołgowe okolicznych torów w kwadracie 4km×4km + for (j = r - n; j <= r + n; j++) + for (i = c - n; i <= c + n; i++) + if ((tmp = FastGetSubRect(i, j)) != NULL) + for (node = tmp->nRootNode; node != NULL; node = node->nNext2) + if (node->iType == TP_TRACK) + node->pTrack->RadioStop(); // przekazanie do każdego toru w każdym segmencie }; -TDynamicObject* __fastcall TGround::DynamicNearest(vector3 pPosition,double distance,bool mech) -{//wyszukanie pojazdu najbliższego względem (pPosition) - TGroundNode *node; - TSubRect *tmp; - TDynamicObject *dyn=NULL; - int c=GetColFromX(pPosition.x); - int r=GetRowFromZ(pPosition.z); - int i,j,k; - double sqm=distance*distance,sqd; //maksymalny promien poszukiwań do kwadratu - for (j=r-1;j<=r+1;j++) //plus dwa zewnętrzne sektory, łącznie 9 - for (i=c-1;i<=c+1;i++) - if ((tmp=FastGetSubRect(i,j))!=NULL) - for (node=tmp->nRootNode;node;node=node->nNext2) //następny z sektora - if (node->iType==TP_TRACK) //Ra: przebudować na użycie tabeli torów? - for (k=0;kpTrack->iNumDynamics;k++) - if (mech?(node->pTrack->Dynamics[k]->Mechanik!=NULL):true) //czy ma mieć obsadę - if ((sqd=SquareMagnitude(node->pTrack->Dynamics[k]->GetPosition()-pPosition))pTrack->Dynamics[k]; //nowy lider - } - return dyn; +TDynamicObject *__fastcall TGround::DynamicNearest(vector3 pPosition, double distance, bool mech) +{ // wyszukanie pojazdu najbliższego względem (pPosition) + TGroundNode *node; + TSubRect *tmp; + TDynamicObject *dyn = NULL; + int c = GetColFromX(pPosition.x); + int r = GetRowFromZ(pPosition.z); + int i, j, k; + double sqm = distance * distance, sqd; // maksymalny promien poszukiwań do kwadratu + for (j = r - 1; j <= r + 1; j++) // plus dwa zewnętrzne sektory, łącznie 9 + for (i = c - 1; i <= c + 1; i++) + if ((tmp = FastGetSubRect(i, j)) != NULL) + for (node = tmp->nRootNode; node; node = node->nNext2) // następny z sektora + if (node->iType == TP_TRACK) // Ra: przebudować na użycie tabeli torów? + for (k = 0; k < node->pTrack->iNumDynamics; k++) + if (mech ? (node->pTrack->Dynamics[k]->Mechanik != NULL) : + true) // czy ma mieć obsadę + if ((sqd = SquareMagnitude( + node->pTrack->Dynamics[k]->GetPosition() - pPosition)) < + sqm) + { + sqm = sqd; // nowa odległość + dyn = node->pTrack->Dynamics[k]; // nowy lider + } + return dyn; }; -TDynamicObject* __fastcall TGround::CouplerNearest(vector3 pPosition,double distance,bool mech) -{//wyszukanie pojazdu, którego sprzęg jest najbliżej względem (pPosition) - TGroundNode *node; - TSubRect *tmp; - TDynamicObject *dyn=NULL; - int c=GetColFromX(pPosition.x); - int r=GetRowFromZ(pPosition.z); - int i,j,k; - double sqm=distance*distance,sqd; //maksymalny promien poszukiwań do kwadratu - for (j=r-1;j<=r+1;j++) //plus dwa zewnętrzne sektory, łącznie 9 - for (i=c-1;i<=c+1;i++) - if ((tmp=FastGetSubRect(i,j))!=NULL) - for (node=tmp->nRootNode;node;node=node->nNext2) //następny z sektora - if (node->iType==TP_TRACK) //Ra: przebudować na użycie tabeli torów? - for (k=0;kpTrack->iNumDynamics;k++) - if (mech?(node->pTrack->Dynamics[k]->Mechanik!=NULL):true) //czy ma mieć obsadę - {if ((sqd=SquareMagnitude(node->pTrack->Dynamics[k]->HeadPosition()-pPosition))pTrack->Dynamics[k]; //nowy lider - } - if ((sqd=SquareMagnitude(node->pTrack->Dynamics[k]->RearPosition()-pPosition))pTrack->Dynamics[k]; //nowy lider - } - } - return dyn; +TDynamicObject *__fastcall TGround::CouplerNearest(vector3 pPosition, double distance, bool mech) +{ // wyszukanie pojazdu, którego sprzęg jest najbliżej względem (pPosition) + TGroundNode *node; + TSubRect *tmp; + TDynamicObject *dyn = NULL; + int c = GetColFromX(pPosition.x); + int r = GetRowFromZ(pPosition.z); + int i, j, k; + double sqm = distance * distance, sqd; // maksymalny promien poszukiwań do kwadratu + for (j = r - 1; j <= r + 1; j++) // plus dwa zewnętrzne sektory, łącznie 9 + for (i = c - 1; i <= c + 1; i++) + if ((tmp = FastGetSubRect(i, j)) != NULL) + for (node = tmp->nRootNode; node; node = node->nNext2) // następny z sektora + if (node->iType == TP_TRACK) // Ra: przebudować na użycie tabeli torów? + for (k = 0; k < node->pTrack->iNumDynamics; k++) + if (mech ? (node->pTrack->Dynamics[k]->Mechanik != NULL) : + true) // czy ma mieć obsadę + { + if ((sqd = SquareMagnitude( + node->pTrack->Dynamics[k]->HeadPosition() - pPosition)) < + sqm) + { + sqm = sqd; // nowa odległość + dyn = node->pTrack->Dynamics[k]; // nowy lider + } + if ((sqd = SquareMagnitude( + node->pTrack->Dynamics[k]->RearPosition() - pPosition)) < + sqm) + { + sqm = sqd; // nowa odległość + dyn = node->pTrack->Dynamics[k]; // nowy lider + } + } + return dyn; }; //--------------------------------------------------------------------------- -void __fastcall TGround::DynamicRemove(TDynamicObject* dyn) -{//Ra: usunięcie pojazdów ze scenerii (gdy dojadą na koniec i nie sa potrzebne) - TDynamicObject* d=dyn->Prev(); - if (d) //jeśli coś jest z przodu - DynamicRemove(d); //zaczynamy od tego z przodu - else - {//jeśli mamy już tego na początku - TGroundNode **n,*node; - d=dyn; //od pierwszego - while (d) - {if (d->MyTrack) d->MyTrack->RemoveDynamicObject(d); //usunięcie z toru o ile nie usunięty - n=&nRootDynamic; //lista pojazdów od początku - //node=NULL; //nie znalezione - while (*n?(*n)->DynamicObject!=d:false) - {//usuwanie z listy pojazdów - n=&((*n)->nNext); //sprawdzenie kolejnego pojazdu na liście - } - if ((*n)->DynamicObject==d) - {//jeśli znaleziony - node=(*n); //zapamiętanie węzła, aby go usunąć - (*n)=node->nNext; //pominięcie na liście - Global::TrainDelete(d); - d=d->Next(); //przejście do kolejnego pojazdu, póki jeszcze jest - delete node; //usuwanie fizyczne z pamięci - } - else - d=NULL; //coś nie tak! - } - } +void __fastcall TGround::DynamicRemove(TDynamicObject *dyn) +{ // Ra: usunięcie pojazdów ze scenerii (gdy dojadą na koniec i nie sa potrzebne) + TDynamicObject *d = dyn->Prev(); + if (d) // jeśli coś jest z przodu + DynamicRemove(d); // zaczynamy od tego z przodu + else + { // jeśli mamy już tego na początku + TGroundNode **n, *node; + d = dyn; // od pierwszego + while (d) + { + if (d->MyTrack) + d->MyTrack->RemoveDynamicObject(d); // usunięcie z toru o ile nie usunięty + n = &nRootDynamic; // lista pojazdów od początku + // node=NULL; //nie znalezione + while (*n ? (*n)->DynamicObject != d : false) + { // usuwanie z listy pojazdów + n = &((*n)->nNext); // sprawdzenie kolejnego pojazdu na liście + } + if ((*n)->DynamicObject == d) + { // jeśli znaleziony + node = (*n); // zapamiętanie węzła, aby go usunąć + (*n) = node->nNext; // pominięcie na liście + Global::TrainDelete(d); + d = d->Next(); // przejście do kolejnego pojazdu, póki jeszcze jest + delete node; // usuwanie fizyczne z pamięci + } + else + d = NULL; // coś nie tak! + } + } }; //--------------------------------------------------------------------------- -void __fastcall TGround::TerrainRead(const AnsiString &f) -{//Ra: wczytanie trójkątów terenu z pliku E3D +void __fastcall TGround::TerrainRead(const AnsiString &f){ + // Ra: wczytanie trójkątów terenu z pliku E3D }; //--------------------------------------------------------------------------- void __fastcall TGround::TerrainWrite() -{//Ra: zapisywanie trójkątów terenu do pliku E3D - if (Global::pTerrainCompact->TerrainLoaded()) - return; //jeśli zostało wczytane, to nie ma co dalej robić - if (Global::asTerrainModel.IsEmpty()) return; - //Trójkąty są zapisywane kwadratami kilometrowymi. - //Kwadrat 500500 jest na środku (od 0.0 do 1000.0 na OX oraz OZ). - //Ewentualnie w numerowaniu kwadratów uwzględnic wpis //$g. - //Trójkąty są grupowane w submodele wg tekstury. - //Triangle_strip oraz triangle_fan są rozpisywane na pojedyncze trójkąty, - // chyba że dla danej tekstury wychodzi tylko jeden submodel. - TModel3d *m=new TModel3d(); //wirtualny model roboczy z oddzielnymi submodelami - TSubModel *sk; //wskaźnik roboczy na submodel kwadratu - TSubModel *st; //wskaźnik roboczy na submodel tekstury - //Zliczamy kwadraty z trójkątami, ilość tekstur oraz wierzchołków. - //Ilość kwadratów i ilość tekstur określi ilość submodeli. - //int sub=0; //całkowita ilość submodeli - //int ver=0; //całkowita ilość wierzchołków - int i,j,k; //indeksy w pętli - TGroundNode *Current; - float8 *ver; //trójkąty - TSubModel::iInstance=0; //pozycja w tabeli wierzchołków liczona narastająco - for (i=0;iNameSet(AnsiString(1000*(500+i-iNumRects/2)+(500+j-iNumRects/2)).c_str()); //nazwa=numer kwadratu - m->AddTo(NULL,sk); //dodanie submodelu dla kwadratu - for (Current=Rects[i][j].nRootNode;Current;Current=Current->nNext2) - if (Current->TextureID) - switch (Current->iType) - {//pętla po trójkątach - zliczanie wierzchołków, dodaje submodel dla każdej tekstury - case GL_TRIANGLES: - Current->iVboPtr=sk->TriangleAdd(m,Current->TextureID,Current->iNumVerts); //zwiększenie ilości trójkątów w submodelu - m->iNumVerts+=Current->iNumVerts; //zwiększenie całkowitej ilości wierzchołków - break; - case GL_TRIANGLE_STRIP: //na razie nie, bo trzeba przerabiać na pojedyncze trójkąty - break; - case GL_TRIANGLE_FAN: //na razie nie, bo trzeba przerabiać na pojedyncze trójkąty - break; - } - for (Current=Rects[i][j].nRootNode;Current;Current=Current->nNext2) - if (Current->TextureID) - switch (Current->iType) - {//pętla po trójkątach - dopisywanie wierzchołków - case GL_TRIANGLES: - //ver=sk->TrianglePtr(TTexturesManager::GetName(Current->TextureID).c_str(),Current->iNumVerts); //wskaźnik na początek - ver=sk->TrianglePtr(Current->TextureID,Current->iVboPtr,Current->Ambient,Current->Diffuse,Current->Specular); //wskaźnik na początek - //WriteLog("Zapis "+AnsiString(Current->iNumVerts)+" trójkątów w ("+AnsiString(i)+","+AnsiString(j)+") od "+AnsiString(Current->iVboPtr)+" dla "+AnsiString(Current->TextureID)); - Current->iVboPtr=-1; //bo to było tymczasowo używane - for (k=0;kiNumVerts;++k) - {//przepisanie współrzędnych - ver[k].Point.x=Current->Vertices[k].Point.x; - ver[k].Point.y=Current->Vertices[k].Point.y; - ver[k].Point.z=Current->Vertices[k].Point.z; - ver[k].Normal.x=Current->Vertices[k].Normal.x; - ver[k].Normal.y=Current->Vertices[k].Normal.y; - ver[k].Normal.z=Current->Vertices[k].Normal.z; - ver[k].tu=Current->Vertices[k].tu; - ver[k].tv=Current->Vertices[k].tv; - } - break; - case GL_TRIANGLE_STRIP: //na razie nie, bo trzeba przerabiać na pojedyncze trójkąty - break; - case GL_TRIANGLE_FAN: //na razie nie, bo trzeba przerabiać na pojedyncze trójkąty - break; - } - } - m->SaveToBinFile(AnsiString("models\\"+Global::asTerrainModel).c_str()); +{ // Ra: zapisywanie trójkątów terenu do pliku E3D + if (Global::pTerrainCompact->TerrainLoaded()) + return; // jeśli zostało wczytane, to nie ma co dalej robić + if (Global::asTerrainModel.IsEmpty()) + return; + // Trójkąty są zapisywane kwadratami kilometrowymi. + // Kwadrat 500500 jest na środku (od 0.0 do 1000.0 na OX oraz OZ). + // Ewentualnie w numerowaniu kwadratów uwzględnic wpis //$g. + // Trójkąty są grupowane w submodele wg tekstury. + // Triangle_strip oraz triangle_fan są rozpisywane na pojedyncze trójkąty, + // chyba że dla danej tekstury wychodzi tylko jeden submodel. + TModel3d *m = new TModel3d(); // wirtualny model roboczy z oddzielnymi submodelami + TSubModel *sk; // wskaźnik roboczy na submodel kwadratu + TSubModel *st; // wskaźnik roboczy na submodel tekstury + // Zliczamy kwadraty z trójkątami, ilość tekstur oraz wierzchołków. + // Ilość kwadratów i ilość tekstur określi ilość submodeli. + // int sub=0; //całkowita ilość submodeli + // int ver=0; //całkowita ilość wierzchołków + int i, j, k; // indeksy w pętli + TGroundNode *Current; + float8 *ver; // trójkąty + TSubModel::iInstance = 0; // pozycja w tabeli wierzchołków liczona narastająco + for (i = 0; i < iNumRects; ++i) // pętla po wszystkich kwadratach kilometrowych + for (j = 0; j < iNumRects; ++j) + if (Rects[i][j].iNodeCount) + { // o ile są jakieś trójkąty w środku + sk = new TSubModel(); // nowy submodel dla kawadratu + // numer kwadratu XXXZZZ, przy czym X jest ujemne - XXX rośnie na wschód, ZZZ rośnie + // na północ + sk->NameSet(AnsiString(1000 * (500 + i - iNumRects / 2) + (500 + j - iNumRects / 2)) + .c_str()); // nazwa=numer kwadratu + m->AddTo(NULL, sk); // dodanie submodelu dla kwadratu + for (Current = Rects[i][j].nRootNode; Current; Current = Current->nNext2) + if (Current->TextureID) + switch (Current->iType) + { // pętla po trójkątach - zliczanie wierzchołków, dodaje submodel dla + // każdej tekstury + case GL_TRIANGLES: + Current->iVboPtr = sk->TriangleAdd( + m, Current->TextureID, + Current->iNumVerts); // zwiększenie ilości trójkątów w submodelu + m->iNumVerts += + Current->iNumVerts; // zwiększenie całkowitej ilości wierzchołków + break; + case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze + // trójkąty + break; + case GL_TRIANGLE_FAN: // na razie nie, bo trzeba przerabiać na pojedyncze + // trójkąty + break; + } + for (Current = Rects[i][j].nRootNode; Current; Current = Current->nNext2) + if (Current->TextureID) + switch (Current->iType) + { // pętla po trójkątach - dopisywanie wierzchołków + case GL_TRIANGLES: + // ver=sk->TrianglePtr(TTexturesManager::GetName(Current->TextureID).c_str(),Current->iNumVerts); + // //wskaźnik na początek + ver = sk->TrianglePtr(Current->TextureID, Current->iVboPtr, + Current->Ambient, Current->Diffuse, + Current->Specular); // wskaźnik na początek + // WriteLog("Zapis "+AnsiString(Current->iNumVerts)+" trójkątów w + // ("+AnsiString(i)+","+AnsiString(j)+") od + // "+AnsiString(Current->iVboPtr)+" dla + // "+AnsiString(Current->TextureID)); + Current->iVboPtr = -1; // bo to było tymczasowo używane + for (k = 0; k < Current->iNumVerts; ++k) + { // przepisanie współrzędnych + ver[k].Point.x = Current->Vertices[k].Point.x; + ver[k].Point.y = Current->Vertices[k].Point.y; + ver[k].Point.z = Current->Vertices[k].Point.z; + ver[k].Normal.x = Current->Vertices[k].Normal.x; + ver[k].Normal.y = Current->Vertices[k].Normal.y; + ver[k].Normal.z = Current->Vertices[k].Normal.z; + ver[k].tu = Current->Vertices[k].tu; + ver[k].tv = Current->Vertices[k].tv; + } + break; + case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze + // trójkąty + break; + case GL_TRIANGLE_FAN: // na razie nie, bo trzeba przerabiać na pojedyncze + // trójkąty + break; + } + } + m->SaveToBinFile(AnsiString("models\\" + Global::asTerrainModel).c_str()); }; //--------------------------------------------------------------------------- void __fastcall TGround::TrackBusyList() -{//wysłanie informacji o wszystkich zajętych odcinkach - TGroundNode *Current; - TTrack *Track; - AnsiString name; - for (Current=nRootOfType[TP_TRACK];Current;Current=Current->nNext) - if (!Current->asName.IsEmpty()) //musi być nazwa - if (Current->pTrack->iNumDynamics) //osi to chyba nie ma jak policzyć - WyslijString(Current->asName,8); //zajęty +{ // wysłanie informacji o wszystkich zajętych odcinkach + TGroundNode *Current; + TTrack *Track; + AnsiString name; + for (Current = nRootOfType[TP_TRACK]; Current; Current = Current->nNext) + if (!Current->asName.IsEmpty()) // musi być nazwa + if (Current->pTrack->iNumDynamics) // osi to chyba nie ma jak policzyć + WyslijString(Current->asName, 8); // zajęty }; //--------------------------------------------------------------------------- void __fastcall TGround::IsolatedBusyList() -{//wysłanie informacji o wszystkich odcinkach izolowanych - TIsolated *Current; - for (Current=TIsolated::Root();Current;Current=Current->Next()) - if (Current->Busy()) //sprawdź zajętość - WyslijString(Current->asName,11); //zajęty - else - WyslijString(Current->asName,10); //wolny - WyslijString("none",10); //informacja o końcu listy +{ // wysłanie informacji o wszystkich odcinkach izolowanych + TIsolated *Current; + for (Current = TIsolated::Root(); Current; Current = Current->Next()) + if (Current->Busy()) // sprawdź zajętość + WyslijString(Current->asName, 11); // zajęty + else + WyslijString(Current->asName, 10); // wolny + WyslijString("none", 10); // informacja o końcu listy }; //--------------------------------------------------------------------------- void __fastcall TGround::IsolatedBusy(const AnsiString t) -{//wysłanie informacji o odcinku izolowanym (t) - //Ra 2014-06: do wyszukania użyć drzewka nazw - TIsolated *Current; - for (Current=TIsolated::Root();Current;Current=Current->Next()) - if (Current->asName==t) //wyszukiwanie odcinka o nazwie (t) - if (Current->Busy()) //sprawdź zajetość - {WyslijString(Current->asName,11); //zajęty - return; //nie sprawdzaj dalszych - } - WyslijString(t,10); //wolny +{ // wysłanie informacji o odcinku izolowanym (t) + // Ra 2014-06: do wyszukania użyć drzewka nazw + TIsolated *Current; + for (Current = TIsolated::Root(); Current; Current = Current->Next()) + if (Current->asName == t) // wyszukiwanie odcinka o nazwie (t) + if (Current->Busy()) // sprawdź zajetość + { + WyslijString(Current->asName, 11); // zajęty + return; // nie sprawdzaj dalszych + } + WyslijString(t, 10); // wolny }; //--------------------------------------------------------------------------- void __fastcall TGround::Silence(vector3 gdzie) -{//wyciszenie wszystkiego w sektorach przed przeniesieniem kamery z (gdzie) - int tr,tc; - TGroundNode *node; - int n=2*iNumSubRects; //(2*==2km) promień wyświetlanej mapy w sektorach - int c=GetColFromX(gdzie.x); //sektory wg dotychczasowej pozycji kamery - int r=GetRowFromZ(gdzie.z); - TSubRect *tmp; - int i,j,k; - //renderowanie czołgowe dla obiektów aktywnych a niewidocznych - for (j=r-n;j<=r+n;j++) - for (i=c-n;i<=c+n;i++) - if ((tmp=FastGetSubRect(i,j))!=NULL) - {//tylko dźwięki interesują - for (node=tmp->nRenderHidden;node;node=node->nNext3) - node->RenderHidden(); - tmp->RenderSounds(); //dźwięki pojazdów by się przydało wyłączyć - } +{ // wyciszenie wszystkiego w sektorach przed przeniesieniem kamery z (gdzie) + int tr, tc; + TGroundNode *node; + int n = 2 * iNumSubRects; //(2*==2km) promień wyświetlanej mapy w sektorach + int c = GetColFromX(gdzie.x); // sektory wg dotychczasowej pozycji kamery + int r = GetRowFromZ(gdzie.z); + TSubRect *tmp; + int i, j, k; + // renderowanie czołgowe dla obiektów aktywnych a niewidocznych + for (j = r - n; j <= r + n; j++) + for (i = c - n; i <= c + n; i++) + if ((tmp = FastGetSubRect(i, j)) != NULL) + { // tylko dźwięki interesują + for (node = tmp->nRenderHidden; node; node = node->nNext3) + node->RenderHidden(); + tmp->RenderSounds(); // dźwięki pojazdów by się przydało wyłączyć + } }; //--------------------------------------------------------------------------- diff --git a/Ground.h b/Ground.h index e69309f2..5997f1eb 100644 --- a/Ground.h +++ b/Ground.h @@ -10,358 +10,379 @@ using namespace Math3D; -//Ra: zmniejszone liczby, aby zrobić tabelkę i zoptymalizować wyszukiwanie -const int TP_MODEL=10; -const int TP_MESH=11; //Ra: specjalny obiekt grupojący siatki dla tekstury -const int TP_DUMMYTRACK=12; //Ra: zdublowanie obiektu toru dla rozdzielenia tekstur -const int TP_TERRAIN=13; //Ra: specjalny model dla terenu -const int TP_DYNAMIC=14; -const int TP_SOUND=15; -const int TP_TRACK=16; -//const int TP_GEOMETRY=17; -const int TP_MEMCELL=18; -const int TP_EVLAUNCH=19; //MC -const int TP_TRACTION=20; -const int TP_TRACTIONPOWERSOURCE=21; //MC -//const int TP_ISOLATED=22; //Ra -const int TP_SUBMODEL=22; //Ra: submodele terenu -const int TP_LAST=25; //rozmiar tablicy +// Ra: zmniejszone liczby, aby zrobić tabelkę i zoptymalizować wyszukiwanie +const int TP_MODEL = 10; +const int TP_MESH = 11; // Ra: specjalny obiekt grupojący siatki dla tekstury +const int TP_DUMMYTRACK = 12; // Ra: zdublowanie obiektu toru dla rozdzielenia tekstur +const int TP_TERRAIN = 13; // Ra: specjalny model dla terenu +const int TP_DYNAMIC = 14; +const int TP_SOUND = 15; +const int TP_TRACK = 16; +// const int TP_GEOMETRY=17; +const int TP_MEMCELL = 18; +const int TP_EVLAUNCH = 19; // MC +const int TP_TRACTION = 20; +const int TP_TRACTIONPOWERSOURCE = 21; // MC +// const int TP_ISOLATED=22; //Ra +const int TP_SUBMODEL = 22; // Ra: submodele terenu +const int TP_LAST = 25; // rozmiar tablicy struct DaneRozkaz -{//struktura komunikacji z EU07.EXE - int iSygn; //sygnatura 'EU07' - int iComm; //rozkaz/status (kod ramki) - union - {float fPar[62]; - int iPar[62]; - char cString[248]; //upakowane stringi - }; +{ // struktura komunikacji z EU07.EXE + int iSygn; // sygnatura 'EU07' + int iComm; // rozkaz/status (kod ramki) + union + { + float fPar[62]; + int iPar[62]; + char cString[248]; // upakowane stringi + }; }; - - typedef int TGroundNodeType; struct TGroundVertex { - vector3 Point; - vector3 Normal; - float tu,tv; - void HalfSet(const TGroundVertex &v1,const TGroundVertex &v2) - {//wyliczenie współrzędnych i mapowania punktu na środku odcinka v1<->v2 - Point=0.5*(v1.Point+v2.Point); - Normal=0.5*(v1.Normal+v2.Normal); - tu=0.5*(v1.tu+v2.tu); - tv=0.5*(v1.tv+v2.tv); - } - void SetByX(const TGroundVertex &v1,const TGroundVertex &v2,double x) - {//wyliczenie współrzędnych i mapowania punktu na odcinku v1<->v2 - double i=(x-v1.Point.x)/(v2.Point.x-v1.Point.x); //parametr równania - double j=1.0-i; - Point=j*v1.Point+i*v2.Point; - Normal=j*v1.Normal+i*v2.Normal; - tu=j*v1.tu+i*v2.tu; - tv=j*v1.tv+i*v2.tv; - } - void SetByZ(const TGroundVertex &v1,const TGroundVertex &v2,double z) - {//wyliczenie współrzędnych i mapowania punktu na odcinku v1<->v2 - double i=(z-v1.Point.z)/(v2.Point.z-v1.Point.z); //parametr równania - double j=1.0-i; - Point=j*v1.Point+i*v2.Point; - Normal=j*v1.Normal+i*v2.Normal; - tu=j*v1.tu+i*v2.tu; - tv=j*v1.tv+i*v2.tv; - } + vector3 Point; + vector3 Normal; + float tu, tv; + void HalfSet(const TGroundVertex &v1, const TGroundVertex &v2) + { // wyliczenie współrzędnych i mapowania punktu na środku odcinka v1<->v2 + Point = 0.5 * (v1.Point + v2.Point); + Normal = 0.5 * (v1.Normal + v2.Normal); + tu = 0.5 * (v1.tu + v2.tu); + tv = 0.5 * (v1.tv + v2.tv); + } + void SetByX(const TGroundVertex &v1, const TGroundVertex &v2, double x) + { // wyliczenie współrzędnych i mapowania punktu na odcinku v1<->v2 + double i = (x - v1.Point.x) / (v2.Point.x - v1.Point.x); // parametr równania + double j = 1.0 - i; + Point = j * v1.Point + i * v2.Point; + Normal = j * v1.Normal + i * v2.Normal; + tu = j * v1.tu + i * v2.tu; + tv = j * v1.tv + i * v2.tv; + } + void SetByZ(const TGroundVertex &v1, const TGroundVertex &v2, double z) + { // wyliczenie współrzędnych i mapowania punktu na odcinku v1<->v2 + double i = (z - v1.Point.z) / (v2.Point.z - v1.Point.z); // parametr równania + double j = 1.0 - i; + Point = j * v1.Point + i * v2.Point; + Normal = j * v1.Normal + i * v2.Normal; + tu = j * v1.tu + i * v2.tu; + tv = j * v1.tv + i * v2.tv; + } }; -class TSubRect; //sektor (aktualnie 200m×200m, ale może być zmieniony) +class TSubRect; // sektor (aktualnie 200m×200m, ale może być zmieniony) class TGroundNode : public Resource -{//obiekt scenerii -private: -public: - TGroundNodeType iType; //typ obiektu - union - {//Ra: wskażniki zależne od typu - zrobić klasy dziedziczone zamiast - void *Pointer; //do przypisywania NULL - TSubModel *smTerrain; //modele terenu (kwadratow kilometrowych) - TAnimModel *Model; //model z animacjami - TDynamicObject *DynamicObject; //pojazd - vector3 *Points; //punkty dla linii - TTrack *pTrack; //trajektoria ruchu - TGroundVertex *Vertices; //wierzchołki dla trójkątów - TMemCell *MemCell; //komórka pamięci - TEventLauncher *EvLaunch; //wyzwalacz zdarzeń - TTraction *hvTraction; //drut zasilający - TTractionPowerSource *psTractionPowerSource; //zasilanie drutu (zaniedbane w sceneriach) - TTextSound *tsStaticSound; //dźwięk przestrzenny - TGroundNode *nNode; //obiekt renderujący grupowo ma tu wskaźnik na listę obiektów - }; - AnsiString asName; //nazwa (nie zawsze ma znaczenie) - union - { - int iNumVerts; //dla trójkątów - int iNumPts; //dla linii - int iCount; //dla terenu - //int iState; //Ra: nie używane - dźwięki zapętlone - }; - vector3 pCenter; //współrzędne środka do przydzielenia sektora +{ // obiekt scenerii + private: + public: + TGroundNodeType iType; // typ obiektu + union + { // Ra: wskażniki zależne od typu - zrobić klasy dziedziczone zamiast + void *Pointer; // do przypisywania NULL + TSubModel *smTerrain; // modele terenu (kwadratow kilometrowych) + TAnimModel *Model; // model z animacjami + TDynamicObject *DynamicObject; // pojazd + vector3 *Points; // punkty dla linii + TTrack *pTrack; // trajektoria ruchu + TGroundVertex *Vertices; // wierzchołki dla trójkątów + TMemCell *MemCell; // komórka pamięci + TEventLauncher *EvLaunch; // wyzwalacz zdarzeń + TTraction *hvTraction; // drut zasilający + TTractionPowerSource *psTractionPowerSource; // zasilanie drutu (zaniedbane w sceneriach) + TTextSound *tsStaticSound; // dźwięk przestrzenny + TGroundNode *nNode; // obiekt renderujący grupowo ma tu wskaźnik na listę obiektów + }; + AnsiString asName; // nazwa (nie zawsze ma znaczenie) + union + { + int iNumVerts; // dla trójkątów + int iNumPts; // dla linii + int iCount; // dla terenu + // int iState; //Ra: nie używane - dźwięki zapętlone + }; + vector3 pCenter; // współrzędne środka do przydzielenia sektora - union - { - //double fAngle; //kąt obrotu dla modelu - double fLineThickness; //McZapkie-120702: grubosc linii - //int Status; //McZapkie-170303: status dzwieku - }; - double fSquareRadius; //kwadrat widoczności do - double fSquareMinRadius; //kwadrat widoczności od - //TGroundNode *nMeshGroup; //Ra: obiekt grupujący trójkąty w TSubRect dla tekstury - int iVersion; //wersja siatki (do wykonania rekompilacji) - //union ? - GLuint DisplayListID; //numer siatki DisplayLists - bool PROBLEND; - int iVboPtr; //indeks w buforze VBO - GLuint TextureID; //główna (jedna) tekstura obiektu - int iFlags; //tryb przezroczystości: 0x10-nieprz.,0x20-przezroczysty,0x30-mieszany - int Ambient[4],Diffuse[4],Specular[4]; //oświetlenie - bool bVisible; - TGroundNode *nNext; //lista wszystkich w scenerii, ostatni na początku - TGroundNode *nNext2; //lista obiektów w sektorze - TGroundNode *nNext3; //lista obiektów renderowanych we wspólnym cyklu - __fastcall TGroundNode(); - __fastcall TGroundNode(TGroundNodeType t,int n=0); - __fastcall ~TGroundNode(); - void __fastcall Init(int n); - void __fastcall InitCenter(); //obliczenie współrzędnych środka - void __fastcall InitNormals(); + union + { + // double fAngle; //kąt obrotu dla modelu + double fLineThickness; // McZapkie-120702: grubosc linii + // int Status; //McZapkie-170303: status dzwieku + }; + double fSquareRadius; // kwadrat widoczności do + double fSquareMinRadius; // kwadrat widoczności od + // TGroundNode *nMeshGroup; //Ra: obiekt grupujący trójkąty w TSubRect dla tekstury + int iVersion; // wersja siatki (do wykonania rekompilacji) + // union ? + GLuint DisplayListID; // numer siatki DisplayLists + bool PROBLEND; + int iVboPtr; // indeks w buforze VBO + GLuint TextureID; // główna (jedna) tekstura obiektu + int iFlags; // tryb przezroczystości: 0x10-nieprz.,0x20-przezroczysty,0x30-mieszany + int Ambient[4], Diffuse[4], Specular[4]; // oświetlenie + bool bVisible; + TGroundNode *nNext; // lista wszystkich w scenerii, ostatni na początku + TGroundNode *nNext2; // lista obiektów w sektorze + TGroundNode *nNext3; // lista obiektów renderowanych we wspólnym cyklu + __fastcall TGroundNode(); + __fastcall TGroundNode(TGroundNodeType t, int n = 0); + __fastcall ~TGroundNode(); + void __fastcall Init(int n); + void __fastcall InitCenter(); // obliczenie współrzędnych środka + void __fastcall InitNormals(); - void __fastcall MoveMe(vector3 pPosition); //przesuwanie (nie działa) + void __fastcall MoveMe(vector3 pPosition); // przesuwanie (nie działa) - //bool __fastcall Disable(); - inline TGroundNode* __fastcall Find(const AnsiString &asNameToFind,TGroundNodeType iNodeType) - {//wyszukiwanie czołgowe z typem - if ((iNodeType==iType)&&(asNameToFind==asName)) - return this; - else - if (nNext) return nNext->Find(asNameToFind,iNodeType); - return NULL; - }; + // bool __fastcall Disable(); + inline TGroundNode *__fastcall Find(const AnsiString &asNameToFind, TGroundNodeType iNodeType) + { // wyszukiwanie czołgowe z typem + if ((iNodeType == iType) && (asNameToFind == asName)) + return this; + else if (nNext) + return nNext->Find(asNameToFind, iNodeType); + return NULL; + }; - void __fastcall Compile(bool many=false); - void Release(); - bool __fastcall GetTraction(); + void __fastcall Compile(bool many = false); + void Release(); + bool __fastcall GetTraction(); - void __fastcall RenderHidden(); //obsługa dźwięków i wyzwalaczy zdarzeń - void __fastcall RenderDL(); //renderowanie nieprzezroczystych w Display Lists - void __fastcall RenderAlphaDL(); //renderowanie przezroczystych w Display Lists (McZapkie-131202) - void __fastcall RaRenderVBO(); //renderowanie (nieprzezroczystych) ze wspólnego VBO - void __fastcall RenderVBO(); //renderowanie nieprzezroczystych z własnego VBO - void __fastcall RenderAlphaVBO(); //renderowanie przezroczystych z (własnego) VBO + void __fastcall RenderHidden(); // obsługa dźwięków i wyzwalaczy zdarzeń + void __fastcall RenderDL(); // renderowanie nieprzezroczystych w Display Lists + void __fastcall RenderAlphaDL(); // renderowanie przezroczystych w Display Lists + // (McZapkie-131202) + void __fastcall RaRenderVBO(); // renderowanie (nieprzezroczystych) ze wspólnego VBO + void __fastcall RenderVBO(); // renderowanie nieprzezroczystych z własnego VBO + void __fastcall RenderAlphaVBO(); // renderowanie przezroczystych z (własnego) VBO }; class TSubRect : public Resource, public CMesh -{//sektor składowy kwadratu kilometrowego -public: - int iTracks; //ilość torów w (tTracks) - TTrack **tTracks; //tory do renderowania pojazdów -protected: - TTrack *tTrackAnim; //obiekty do przeliczenia animacji - TGroundNode *nRootMesh; //obiekty renderujące wg tekstury (wtórne, lista po nNext2) - TGroundNode *nMeshed; //lista obiektów dla których istnieją obiekty renderujące grupowo -public: - TGroundNode *nRootNode; //wszystkie obiekty w sektorze, z wyjątkiem renderujących i pojazdów (nNext2) - TGroundNode *nRenderHidden; //lista obiektów niewidocznych, "renderowanych" również z tyłu (nNext3) - TGroundNode *nRenderRect; //z poziomu sektora - nieprzezroczyste (nNext3) - TGroundNode *nRenderRectAlpha; //z poziomu sektora - przezroczyste (nNext3) - TGroundNode *nRenderWires; //z poziomu sektora - druty i inne linie (nNext3) - TGroundNode *nRender; //indywidualnie - nieprzezroczyste (nNext3) - TGroundNode *nRenderMixed; //indywidualnie - nieprzezroczyste i przezroczyste (nNext3) - TGroundNode *nRenderAlpha; //indywidualnie - przezroczyste (nNext3) - int iNodeCount; //licznik obiektów, do pomijania pustych sektorów -public: - void __fastcall LoadNodes(); //utworzenie VBO sektora -public: - __fastcall TSubRect(); - virtual __fastcall ~TSubRect(); - virtual void Release(); //zwalnianie VBO sektora - void __fastcall NodeAdd(TGroundNode *Node); //dodanie obiektu do sektora na etapie rozdzielania na sektory - void __fastcall RaNodeAdd(TGroundNode *Node); //dodanie obiektu do listy renderowania - void __fastcall Sort(); //optymalizacja obiektów w sektorze (sortowanie wg tekstur) - TTrack* __fastcall FindTrack(vector3 *Point,int &iConnection,TTrack *Exclude); - TTraction* __fastcall FindTraction(vector3 *Point,int &iConnection,TTraction *Exclude); - bool __fastcall StartVBO(); //ustwienie VBO sektora dla (nRenderRect), (nRenderRectAlpha) i (nRenderWires) - bool __fastcall RaTrackAnimAdd(TTrack *t); //zgłoszenie toru do animacji - void __fastcall RaAnimate(); //przeliczenie animacji torów - void __fastcall RenderDL(); //renderowanie nieprzezroczystych w Display Lists - void __fastcall RenderAlphaDL(); //renderowanie przezroczystych w Display Lists (McZapkie-131202) - void __fastcall RenderVBO(); //renderowanie nieprzezroczystych z własnego VBO - void __fastcall RenderAlphaVBO(); //renderowanie przezroczystych z (własnego) VBO - void __fastcall RenderSounds(); //dźwięki pojazdów z niewidocznych sektorów +{ // sektor składowy kwadratu kilometrowego + public: + int iTracks; // ilość torów w (tTracks) + TTrack **tTracks; // tory do renderowania pojazdów + protected: + TTrack *tTrackAnim; // obiekty do przeliczenia animacji + TGroundNode *nRootMesh; // obiekty renderujące wg tekstury (wtórne, lista po nNext2) + TGroundNode *nMeshed; // lista obiektów dla których istnieją obiekty renderujące grupowo + public: + TGroundNode * + nRootNode; // wszystkie obiekty w sektorze, z wyjątkiem renderujących i pojazdów (nNext2) + TGroundNode * + nRenderHidden; // lista obiektów niewidocznych, "renderowanych" również z tyłu (nNext3) + TGroundNode *nRenderRect; // z poziomu sektora - nieprzezroczyste (nNext3) + TGroundNode *nRenderRectAlpha; // z poziomu sektora - przezroczyste (nNext3) + TGroundNode *nRenderWires; // z poziomu sektora - druty i inne linie (nNext3) + TGroundNode *nRender; // indywidualnie - nieprzezroczyste (nNext3) + TGroundNode *nRenderMixed; // indywidualnie - nieprzezroczyste i przezroczyste (nNext3) + TGroundNode *nRenderAlpha; // indywidualnie - przezroczyste (nNext3) + int iNodeCount; // licznik obiektów, do pomijania pustych sektorów + public: + void __fastcall LoadNodes(); // utworzenie VBO sektora + public: + __fastcall TSubRect(); + virtual __fastcall ~TSubRect(); + virtual void Release(); // zwalnianie VBO sektora + void __fastcall NodeAdd( + TGroundNode *Node); // dodanie obiektu do sektora na etapie rozdzielania na sektory + void __fastcall RaNodeAdd(TGroundNode *Node); // dodanie obiektu do listy renderowania + void __fastcall Sort(); // optymalizacja obiektów w sektorze (sortowanie wg tekstur) + TTrack *__fastcall FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude); + TTraction *__fastcall FindTraction(vector3 *Point, int &iConnection, TTraction *Exclude); + bool __fastcall StartVBO(); // ustwienie VBO sektora dla (nRenderRect), (nRenderRectAlpha) i + // (nRenderWires) + bool __fastcall RaTrackAnimAdd(TTrack *t); // zgłoszenie toru do animacji + void __fastcall RaAnimate(); // przeliczenie animacji torów + void __fastcall RenderDL(); // renderowanie nieprzezroczystych w Display Lists + void __fastcall RenderAlphaDL(); // renderowanie przezroczystych w Display Lists + // (McZapkie-131202) + void __fastcall RenderVBO(); // renderowanie nieprzezroczystych z własnego VBO + void __fastcall RenderAlphaVBO(); // renderowanie przezroczystych z (własnego) VBO + void __fastcall RenderSounds(); // dźwięki pojazdów z niewidocznych sektorów }; -//Ra: trzeba sprawdzić wydajność siatki -const int iNumSubRects=5; //na ile dzielimy kilometr -const int iNumRects=500; -//const double fHalfNumRects=iNumRects/2.0; //połowa do wyznaczenia środka -const int iTotalNumSubRects=iNumRects*iNumSubRects; -const double fHalfTotalNumSubRects=iTotalNumSubRects/2.0; -const double fSubRectSize=1000.0/iNumSubRects; -const double fRectSize=fSubRectSize*iNumSubRects; +// Ra: trzeba sprawdzić wydajność siatki +const int iNumSubRects = 5; // na ile dzielimy kilometr +const int iNumRects = 500; +// const double fHalfNumRects=iNumRects/2.0; //połowa do wyznaczenia środka +const int iTotalNumSubRects = iNumRects * iNumSubRects; +const double fHalfTotalNumSubRects = iTotalNumSubRects / 2.0; +const double fSubRectSize = 1000.0 / iNumSubRects; +const double fRectSize = fSubRectSize * iNumSubRects; class TGroundRect : public TSubRect -{//kwadrat kilometrowy - //obiekty o niewielkiej ilości wierzchołków będą renderowane stąd - //Ra: 2012-02 doszły submodele terenu -private: - int iLastDisplay; //numer klatki w której był ostatnio wyświetlany - TSubRect *pSubRects; - void __fastcall Init() { pSubRects=new TSubRect[iNumSubRects*iNumSubRects]; }; -public: - static int iFrameNumber; //numer kolejny wyświetlanej klatki - TGroundNode *nTerrain; //model terenu z E3D - użyć nRootMesh? - __fastcall TGroundRect(); - virtual __fastcall ~TGroundRect(); +{ // kwadrat kilometrowy + // obiekty o niewielkiej ilości wierzchołków będą renderowane stąd + // Ra: 2012-02 doszły submodele terenu + private: + int iLastDisplay; // numer klatki w której był ostatnio wyświetlany + TSubRect *pSubRects; + void __fastcall Init() { pSubRects = new TSubRect[iNumSubRects * iNumSubRects]; }; - TSubRect* __fastcall SafeGetRect(int iCol,int iRow) - {//pobranie wskaźnika do małego kwadratu, utworzenie jeśli trzeba - if (!pSubRects) Init(); //utworzenie małych kwadratów - return pSubRects+iRow*iNumSubRects+iCol; //zwrócenie właściwego - }; - TSubRect* __fastcall FastGetRect(int iCol,int iRow) - {//pobranie wskaźnika do małego kwadratu, bez tworzenia jeśli nie ma - return (pSubRects?pSubRects+iRow*iNumSubRects+iCol:NULL); - }; - void __fastcall Optimize() - {//optymalizacja obiektów w sektorach - if (pSubRects) - for (int i=iNumSubRects*iNumSubRects-1;i>=0;--i) - pSubRects[i].Sort(); //optymalizacja obiektów w sektorach - }; - void __fastcall RenderDL(); - void __fastcall RenderVBO(); + public: + static int iFrameNumber; // numer kolejny wyświetlanej klatki + TGroundNode *nTerrain; // model terenu z E3D - użyć nRootMesh? + __fastcall TGroundRect(); + virtual __fastcall ~TGroundRect(); + + TSubRect *__fastcall SafeGetRect(int iCol, int iRow) + { // pobranie wskaźnika do małego kwadratu, utworzenie jeśli trzeba + if (!pSubRects) + Init(); // utworzenie małych kwadratów + return pSubRects + iRow * iNumSubRects + iCol; // zwrócenie właściwego + }; + TSubRect *__fastcall FastGetRect(int iCol, int iRow) + { // pobranie wskaźnika do małego kwadratu, bez tworzenia jeśli nie ma + return (pSubRects ? pSubRects + iRow * iNumSubRects + iCol : NULL); + }; + void __fastcall Optimize() + { // optymalizacja obiektów w sektorach + if (pSubRects) + for (int i = iNumSubRects * iNumSubRects - 1; i >= 0; --i) + pSubRects[i].Sort(); // optymalizacja obiektów w sektorach + }; + void __fastcall RenderDL(); + void __fastcall RenderVBO(); }; - class TGround { - vector3 CameraDirection; //zmienna robocza przy renderowaniu - int const *iRange; //tabela widoczności - //TGroundNode *nRootNode; //lista wszystkich węzłów - TGroundNode *nRootDynamic; //lista pojazdów - TGroundRect Rects[iNumRects][iNumRects]; //mapa kwadratów kilometrowych - TEvent *RootEvent; //lista zdarzeń - TEvent *QueryRootEvent,*tmpEvent,*tmp2Event,*OldQRE; - TSubRect *pRendered[1500]; //lista renderowanych sektorów - int iNumNodes; - vector3 pOrigin; - vector3 aRotate; - bool bInitDone; - TGroundNode *nRootOfType[TP_LAST]; //tablica grupująca obiekty, przyspiesza szukanie - //TGroundNode *nLastOfType[TP_LAST]; //ostatnia - TSubRect srGlobal; //zawiera obiekty globalne (na razie wyzwalacze czasowe) - int hh,mm,srh,srm,ssh,ssm; //ustawienia czasu - //int tracks,tracksfar; //liczniki torów - TNames *sTracks; //posortowane nazwy torów i eventów -private: //metody prywatne - bool __fastcall EventConditon(TEvent *e); -public: - bool bDynamicRemove; //czy uruchomić procedurę usuwania pojazdów - TDynamicObject *LastDyn; //ABu: paskudnie, ale na bardzo szybko moze jakos przejdzie... - //TTrain *pTrain; - //double fVDozwolona; - //bool bTrabil; + vector3 CameraDirection; // zmienna robocza przy renderowaniu + int const *iRange; // tabela widoczności + // TGroundNode *nRootNode; //lista wszystkich węzłów + TGroundNode *nRootDynamic; // lista pojazdów + TGroundRect Rects[iNumRects][iNumRects]; // mapa kwadratów kilometrowych + TEvent *RootEvent; // lista zdarzeń + TEvent *QueryRootEvent, *tmpEvent, *tmp2Event, *OldQRE; + TSubRect *pRendered[1500]; // lista renderowanych sektorów + int iNumNodes; + vector3 pOrigin; + vector3 aRotate; + bool bInitDone; + TGroundNode *nRootOfType[TP_LAST]; // tablica grupująca obiekty, przyspiesza szukanie + // TGroundNode *nLastOfType[TP_LAST]; //ostatnia + TSubRect srGlobal; // zawiera obiekty globalne (na razie wyzwalacze czasowe) + int hh, mm, srh, srm, ssh, ssm; // ustawienia czasu + // int tracks,tracksfar; //liczniki torów + TNames *sTracks; // posortowane nazwy torów i eventów + private: // metody prywatne + bool __fastcall EventConditon(TEvent *e); - __fastcall TGround(); - __fastcall ~TGround(); - void __fastcall Free(); - bool __fastcall Init(AnsiString asFile,HDC hDC); - void __fastcall FirstInit(); - void __fastcall InitTracks(); - void __fastcall InitTraction(); - bool __fastcall InitEvents(); - bool __fastcall InitLaunchers(); - TTrack* __fastcall FindTrack(vector3 Point,int &iConnection,TGroundNode *Exclude); - TTraction* __fastcall FindTraction(vector3 *Point,int &iConnection,TGroundNode *Exclude); - TTraction* __fastcall TractionNearestFind(vector3 &p,int dir,TGroundNode *n); - //TGroundNode* __fastcall CreateGroundNode(); - TGroundNode* __fastcall AddGroundNode(cParser* parser); - bool __fastcall AddGroundNode(double x,double z,TGroundNode *Node) - { - TSubRect *tmp=GetSubRect(x,z); - if (tmp) - { - tmp->NodeAdd(Node); - return true; - } - else - return false; - }; -// bool __fastcall Include(TQueryParserComp *Parser); - //TGroundNode* __fastcall GetVisible(AnsiString asName); - TGroundNode* __fastcall GetNode(AnsiString asName); - bool __fastcall AddDynamic(TGroundNode *Node); - void __fastcall MoveGroundNode(vector3 pPosition); - void __fastcall UpdatePhys(double dt,int iter); //aktualizacja fizyki stałym krokiem - bool __fastcall Update(double dt,int iter); //aktualizacja przesunięć zgodna z FPS - bool __fastcall AddToQuery(TEvent *Event, TDynamicObject *Node); - bool __fastcall GetTraction(TDynamicObject *model); - bool __fastcall RenderDL(vector3 pPosition); - bool __fastcall RenderAlphaDL(vector3 pPosition); - bool __fastcall RenderVBO(vector3 pPosition); - bool __fastcall RenderAlphaVBO(vector3 pPosition); - bool __fastcall CheckQuery(); -// __fastcall GetRect(double x, double z) { return &(Rects[int(x/fSubRectSize+fHalfNumRects)][int(z/fSubRectSize+fHalfNumRects)]); }; -/* - int __fastcall GetRowFromZ(double z) { return (z/fRectSize+fHalfNumRects); }; - int __fastcall GetColFromX(double x) { return (x/fRectSize+fHalfNumRects); }; - int __fastcall GetSubRowFromZ(double z) { return (z/fSubRectSize+fHalfNumSubRects); }; - int __fastcall GetSubColFromX(double x) { return (x/fSubRectSize+fHalfNumSubRects); }; - */ -/* - inline TGroundNode* __fastcall FindGroundNode(const AnsiString &asNameToFind ) - { - if (RootNode) - return (RootNode->Find( asNameToFind )); - else - return NULL; - } -*/ - TGroundNode* __fastcall DynamicFindAny(AnsiString asNameToFind); - TGroundNode* __fastcall DynamicFind(AnsiString asNameToFind); - void __fastcall DynamicList(bool all=false); - TGroundNode* __fastcall FindGroundNode(AnsiString asNameToFind,TGroundNodeType iNodeType); - TGroundRect* __fastcall GetRect(double x, double z) { return &Rects[GetColFromX(x)/iNumSubRects][GetRowFromZ(z)/iNumSubRects]; }; - TSubRect* __fastcall GetSubRect(double x, double z) { return GetSubRect(GetColFromX(x),GetRowFromZ(z)); }; - TSubRect* __fastcall FastGetSubRect(double x, double z) { return FastGetSubRect(GetColFromX(x),GetRowFromZ(z)); }; - TSubRect* __fastcall GetSubRect(int iCol, int iRow); - TSubRect* __fastcall FastGetSubRect(int iCol, int iRow); - int __fastcall GetRowFromZ(double z) { return (z/fSubRectSize+fHalfTotalNumSubRects); }; - int __fastcall GetColFromX(double x) { return (x/fSubRectSize+fHalfTotalNumSubRects); }; - TEvent* __fastcall FindEvent(const AnsiString &asEventName); - TEvent* __fastcall FindEventScan(const AnsiString &asEventName); - void __fastcall TrackJoin(TGroundNode *Current); -private: - void __fastcall OpenGLUpdate(HDC hDC); - void __fastcall RaTriangleDivider(TGroundNode* node); - void __fastcall Navigate(String ClassName,UINT Msg,WPARAM wParam,LPARAM lParam); - bool PROBLEND; -public: - void __fastcall WyslijEvent(const AnsiString &e,const AnsiString &d); - int iRendered; //ilość renderowanych sektorów, pobierana przy pokazywniu FPS - void __fastcall WyslijString(const AnsiString &t,int n); - void __fastcall WyslijWolny(const AnsiString &t); - void __fastcall WyslijNamiary(TGroundNode* t); - void __fastcall WyslijParam(int nr,int fl); - void __fastcall RadioStop(vector3 pPosition); - TDynamicObject* __fastcall DynamicNearest(vector3 pPosition,double distance=20.0,bool mech=false); - TDynamicObject* __fastcall CouplerNearest(vector3 pPosition,double distance=20.0,bool mech=false); - void __fastcall DynamicRemove(TDynamicObject* dyn); - void __fastcall TerrainRead(const AnsiString &f); - void __fastcall TerrainWrite(); - void __fastcall TrackBusyList(); - void __fastcall IsolatedBusyList(); - void __fastcall IsolatedBusy(const AnsiString t); - void __fastcall Silence(vector3 gdzie); + public: + bool bDynamicRemove; // czy uruchomić procedurę usuwania pojazdów + TDynamicObject *LastDyn; // ABu: paskudnie, ale na bardzo szybko moze jakos przejdzie... + // TTrain *pTrain; + // double fVDozwolona; + // bool bTrabil; + + __fastcall TGround(); + __fastcall ~TGround(); + void __fastcall Free(); + bool __fastcall Init(AnsiString asFile, HDC hDC); + void __fastcall FirstInit(); + void __fastcall InitTracks(); + void __fastcall InitTraction(); + bool __fastcall InitEvents(); + bool __fastcall InitLaunchers(); + TTrack *__fastcall FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude); + TTraction *__fastcall FindTraction(vector3 *Point, int &iConnection, TGroundNode *Exclude); + TTraction *__fastcall TractionNearestFind(vector3 &p, int dir, TGroundNode *n); + // TGroundNode* __fastcall CreateGroundNode(); + TGroundNode *__fastcall AddGroundNode(cParser *parser); + bool __fastcall AddGroundNode(double x, double z, TGroundNode *Node) + { + TSubRect *tmp = GetSubRect(x, z); + if (tmp) + { + tmp->NodeAdd(Node); + return true; + } + else + return false; + }; + // bool __fastcall Include(TQueryParserComp *Parser); + // TGroundNode* __fastcall GetVisible(AnsiString asName); + TGroundNode *__fastcall GetNode(AnsiString asName); + bool __fastcall AddDynamic(TGroundNode *Node); + void __fastcall MoveGroundNode(vector3 pPosition); + void __fastcall UpdatePhys(double dt, int iter); // aktualizacja fizyki stałym krokiem + bool __fastcall Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS + bool __fastcall AddToQuery(TEvent *Event, TDynamicObject *Node); + bool __fastcall GetTraction(TDynamicObject *model); + bool __fastcall RenderDL(vector3 pPosition); + bool __fastcall RenderAlphaDL(vector3 pPosition); + bool __fastcall RenderVBO(vector3 pPosition); + bool __fastcall RenderAlphaVBO(vector3 pPosition); + bool __fastcall CheckQuery(); + // __fastcall GetRect(double x, double z) { return + // &(Rects[int(x/fSubRectSize+fHalfNumRects)][int(z/fSubRectSize+fHalfNumRects)]); }; + /* + int __fastcall GetRowFromZ(double z) { return (z/fRectSize+fHalfNumRects); }; + int __fastcall GetColFromX(double x) { return (x/fRectSize+fHalfNumRects); }; + int __fastcall GetSubRowFromZ(double z) { return (z/fSubRectSize+fHalfNumSubRects); }; + int __fastcall GetSubColFromX(double x) { return (x/fSubRectSize+fHalfNumSubRects); }; + */ + /* + inline TGroundNode* __fastcall FindGroundNode(const AnsiString &asNameToFind ) + { + if (RootNode) + return (RootNode->Find( asNameToFind )); + else + return NULL; + } + */ + TGroundNode *__fastcall DynamicFindAny(AnsiString asNameToFind); + TGroundNode *__fastcall DynamicFind(AnsiString asNameToFind); + void __fastcall DynamicList(bool all = false); + TGroundNode *__fastcall FindGroundNode(AnsiString asNameToFind, TGroundNodeType iNodeType); + TGroundRect *__fastcall GetRect(double x, double z) + { + return &Rects[GetColFromX(x) / iNumSubRects][GetRowFromZ(z) / iNumSubRects]; + }; + TSubRect *__fastcall GetSubRect(double x, double z) + { + return GetSubRect(GetColFromX(x), GetRowFromZ(z)); + }; + TSubRect *__fastcall FastGetSubRect(double x, double z) + { + return FastGetSubRect(GetColFromX(x), GetRowFromZ(z)); + }; + TSubRect *__fastcall GetSubRect(int iCol, int iRow); + TSubRect *__fastcall FastGetSubRect(int iCol, int iRow); + int __fastcall GetRowFromZ(double z) { return (z / fSubRectSize + fHalfTotalNumSubRects); }; + int __fastcall GetColFromX(double x) { return (x / fSubRectSize + fHalfTotalNumSubRects); }; + TEvent *__fastcall FindEvent(const AnsiString &asEventName); + TEvent *__fastcall FindEventScan(const AnsiString &asEventName); + void __fastcall TrackJoin(TGroundNode *Current); + + private: + void __fastcall OpenGLUpdate(HDC hDC); + void __fastcall RaTriangleDivider(TGroundNode *node); + void __fastcall Navigate(String ClassName, UINT Msg, WPARAM wParam, LPARAM lParam); + bool PROBLEND; + + public: + void __fastcall WyslijEvent(const AnsiString &e, const AnsiString &d); + int iRendered; // ilość renderowanych sektorów, pobierana przy pokazywniu FPS + void __fastcall WyslijString(const AnsiString &t, int n); + void __fastcall WyslijWolny(const AnsiString &t); + void __fastcall WyslijNamiary(TGroundNode *t); + void __fastcall WyslijParam(int nr, int fl); + void __fastcall RadioStop(vector3 pPosition); + TDynamicObject *__fastcall DynamicNearest(vector3 pPosition, double distance = 20.0, + bool mech = false); + TDynamicObject *__fastcall CouplerNearest(vector3 pPosition, double distance = 20.0, + bool mech = false); + void __fastcall DynamicRemove(TDynamicObject *dyn); + void __fastcall TerrainRead(const AnsiString &f); + void __fastcall TerrainWrite(); + void __fastcall TrackBusyList(); + void __fastcall IsolatedBusyList(); + void __fastcall IsolatedBusy(const AnsiString t); + void __fastcall Silence(vector3 gdzie); }; //--------------------------------------------------------------------------- #endif diff --git a/Logs.cpp b/Logs.cpp index b2ec162a..4fad3fc8 100644 --- a/Logs.cpp +++ b/Logs.cpp @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------- -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Logs.h" @@ -11,84 +11,85 @@ #include #include -std::ofstream output; //standardowy "log.txt", można go wyłączyć -std::ofstream errors; //lista błędów "errors.txt", zawsze działa +std::ofstream output; // standardowy "log.txt", można go wyłączyć +std::ofstream errors; // lista błędów "errors.txt", zawsze działa -char endstring[10]="\n"; +char endstring[10] = "\n"; -void __fastcall WriteConsoleOnly(const char* str, double value) +void __fastcall WriteConsoleOnly(const char *str, double value) { - char buf[255]; - sprintf(buf,"%s %f \n",str,value); - //stdout= GetStdHandle(STD_OUTPUT_HANDLE); - DWORD wr= 0; - WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),buf,strlen(buf),&wr,NULL); - //WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),endstring,strlen(endstring),&wr,NULL); + char buf[255]; + sprintf(buf, "%s %f \n", str, value); + // stdout= GetStdHandle(STD_OUTPUT_HANDLE); + DWORD wr = 0; + WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), buf, strlen(buf), &wr, NULL); + // WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),endstring,strlen(endstring),&wr,NULL); } -void __fastcall WriteConsoleOnly(const char* str) +void __fastcall WriteConsoleOnly(const char *str) { - //printf("%n ffafaf /n",str); - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN|FOREGROUND_INTENSITY); - DWORD wr= 0; - WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),str,strlen(str),&wr,NULL); - WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),endstring,strlen(endstring),&wr,NULL); + // printf("%n ffafaf /n",str); + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), + FOREGROUND_GREEN | FOREGROUND_INTENSITY); + DWORD wr = 0; + WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), str, strlen(str), &wr, NULL); + WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), endstring, strlen(endstring), &wr, NULL); } -void __fastcall WriteLog(const char* str, double value) +void __fastcall WriteLog(const char *str, double value) { - if (Global::iWriteLogEnabled) - { - if (str) - { - char buf[255]; - sprintf(buf,"%s %f",str,value); - WriteLog(buf); - } - } + if (Global::iWriteLogEnabled) + { + if (str) + { + char buf[255]; + sprintf(buf, "%s %f", str, value); + WriteLog(buf); + } + } }; -void __fastcall WriteLog(const char* str) +void __fastcall WriteLog(const char *str) { - if (str) - { - if (Global::iWriteLogEnabled&1) - {if (!output.is_open()) - output.open("log.txt",std::ios::trunc); - output << str << "\n"; - output.flush(); - } - //hunter-271211: pisanie do konsoli tylko, gdy nie jest ukrywana - if (Global::iWriteLogEnabled&2) - WriteConsoleOnly(str); - } + if (str) + { + if (Global::iWriteLogEnabled & 1) + { + if (!output.is_open()) + output.open("log.txt", std::ios::trunc); + output << str << "\n"; + output.flush(); + } + // hunter-271211: pisanie do konsoli tylko, gdy nie jest ukrywana + if (Global::iWriteLogEnabled & 2) + WriteConsoleOnly(str); + } }; -void __fastcall ErrorLog(const char* str) -{//Ra: bezwarunkowa rejestracja poważnych błędów - if (!errors.is_open()) - {errors.open("errors.txt",std::ios::trunc); - errors << AnsiString("EU07.EXE "+Global::asRelease).c_str() << "\n"; - } - if (str) errors << str; - errors << "\n"; - errors.flush(); +void __fastcall ErrorLog(const char *str) +{ // Ra: bezwarunkowa rejestracja poważnych błędów + if (!errors.is_open()) + { + errors.open("errors.txt", std::ios::trunc); + errors << AnsiString("EU07.EXE " + Global::asRelease).c_str() << "\n"; + } + if (str) + errors << str; + errors << "\n"; + errors.flush(); }; -void __fastcall Error(const AnsiString &asMessage,bool box) +void __fastcall Error(const AnsiString &asMessage, bool box) { - if (box) - MessageBox(NULL,asMessage.c_str(),AnsiString("EU07 "+Global::asRelease).c_str(),MB_OK); - WriteLog(asMessage.c_str()); + if (box) + MessageBox(NULL, asMessage.c_str(), AnsiString("EU07 " + Global::asRelease).c_str(), MB_OK); + WriteLog(asMessage.c_str()); } void __fastcall ErrorLog(const AnsiString &asMessage) -{//zapisywanie błędów "errors.txt" - ErrorLog(asMessage.c_str()); - WriteLog(asMessage.c_str()); //do "log.txt" ewentualnie też +{ // zapisywanie błędów "errors.txt" + ErrorLog(asMessage.c_str()); + WriteLog(asMessage.c_str()); // do "log.txt" ewentualnie też } -void __fastcall WriteLog(const AnsiString &str) -{//Ra: wersja z AnsiString jest zamienna z Error() - WriteLog(str.c_str()); -}; +void __fastcall WriteLog(const AnsiString &str) { // Ra: wersja z AnsiString jest zamienna z Error() WriteLog(str.c_str()); }; //--------------------------------------------------------------------------- #pragma package(smart_init) diff --git a/Logs.h b/Logs.h index 81c32a45..7ee59a7a 100644 --- a/Logs.h +++ b/Logs.h @@ -2,13 +2,13 @@ #ifndef LogsH #define LogsH -#include +#include void __fastcall WriteConsoleOnly(const char *str, double value); void __fastcall WriteConsoleOnly(const char *str); void __fastcall WriteLog(const char *str, double value); void __fastcall WriteLog(const char *str); -void __fastcall Error(const AnsiString &asMessage,bool box=true); +void __fastcall Error(const AnsiString &asMessage, bool box = true); void __fastcall ErrorLog(const AnsiString &asMessage); void __fastcall WriteLog(const AnsiString &str); //--------------------------------------------------------------------------- diff --git a/Machajka.cpp b/Machajka.cpp index 62d418bc..e59c459b 100644 --- a/Machajka.cpp +++ b/Machajka.cpp @@ -1,23 +1,16 @@ //--------------------------------------------------------------------------- -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop - #include "Machajka.h" #include "Timer.h" #include "Globals.h" -__fastcall TMachajka::TMachajka():TTrain() -{ - TTrain::TTrain(); -} +__fastcall TMachajka::TMachajka() : TTrain() { TTrain::TTrain(); } -__fastcall TMachajka::~TMachajka() -{ - -} +__fastcall TMachajka::~TMachajka() {} bool __fastcall TMachajka::Init(TDynamicObject *NewDynamicObject) { @@ -27,68 +20,47 @@ bool __fastcall TMachajka::Init(TDynamicObject *NewDynamicObject) void __fastcall TMachajka::OnKeyPress(int cKey) { - if (!GetAsyncKeyState(VK_SHIFT)<0) //bez shifta - { - if (cKey==Global::Keys[k_IncMainCtrl]) - (DynamicObject->MoverParameters->AddPulseForce(1)); - else - if (cKey==Global::Keys[k_DecMainCtrl]) - (DynamicObject->MoverParameters->AddPulseForce(-1)); - else - if (cKey==Global::Keys[k_IncLocalBrakeLevel]) - (DynamicObject->MoverParameters->IncLocalBrakeLevel(1)); - else - if (cKey==Global::Keys[k_DecLocalBrakeLevel]) - (DynamicObject->MoverParameters->DecLocalBrakeLevel(1)); - else - if (cKey==Global::Keys[k_MechLeft]) - vMechMovement.x+=fMechCroach; - else - if (cKey==Global::Keys[k_MechRight]) - vMechMovement.x-=fMechCroach; - else - if (cKey==Global::Keys[k_MechBackward]) - vMechMovement.z-=fMechCroach; - else - if (cKey==Global::Keys[k_MechForward]) - vMechMovement.z+=fMechCroach; - else - if (cKey==Global::Keys[k_MechUp]) - pMechOffset.y+=0.3; //McZapkie-120302 - wstawanie - else - if (cKey==Global::Keys[k_MechDown]) - pMechOffset.y-=0.3; //McZapkie-120302 - siadanie, kucanie itp - } - else //z shiftem - { - if (cKey==Global::Keys[k_IncMainCtrlFAST]) - (DynamicObject->MoverParameters->AddPulseForce(2)); - else - if (cKey==Global::Keys[k_DecMainCtrlFAST]) - (DynamicObject->MoverParameters->AddPulseForce(-2)); - else - if (cKey==Global::Keys[k_IncLocalBrakeLevelFAST]) - (DynamicObject->MoverParameters->IncLocalBrakeLevel(2)); - else - if (cKey==Global::Keys[k_DecLocalBrakeLevelFAST]) - (DynamicObject->MoverParameters->DecLocalBrakeLevel(2)); - } + if (!GetAsyncKeyState(VK_SHIFT) < 0) // bez shifta + { + if (cKey == Global::Keys[k_IncMainCtrl]) + (DynamicObject->MoverParameters->AddPulseForce(1)); + else if (cKey == Global::Keys[k_DecMainCtrl]) + (DynamicObject->MoverParameters->AddPulseForce(-1)); + else if (cKey == Global::Keys[k_IncLocalBrakeLevel]) + (DynamicObject->MoverParameters->IncLocalBrakeLevel(1)); + else if (cKey == Global::Keys[k_DecLocalBrakeLevel]) + (DynamicObject->MoverParameters->DecLocalBrakeLevel(1)); + else if (cKey == Global::Keys[k_MechLeft]) + vMechMovement.x += fMechCroach; + else if (cKey == Global::Keys[k_MechRight]) + vMechMovement.x -= fMechCroach; + else if (cKey == Global::Keys[k_MechBackward]) + vMechMovement.z -= fMechCroach; + else if (cKey == Global::Keys[k_MechForward]) + vMechMovement.z += fMechCroach; + else if (cKey == Global::Keys[k_MechUp]) + pMechOffset.y += 0.3; // McZapkie-120302 - wstawanie + else if (cKey == Global::Keys[k_MechDown]) + pMechOffset.y -= 0.3; // McZapkie-120302 - siadanie, kucanie itp + } + else // z shiftem + { + if (cKey == Global::Keys[k_IncMainCtrlFAST]) + (DynamicObject->MoverParameters->AddPulseForce(2)); + else if (cKey == Global::Keys[k_DecMainCtrlFAST]) + (DynamicObject->MoverParameters->AddPulseForce(-2)); + else if (cKey == Global::Keys[k_IncLocalBrakeLevelFAST]) + (DynamicObject->MoverParameters->IncLocalBrakeLevel(2)); + else if (cKey == Global::Keys[k_DecLocalBrakeLevelFAST]) + (DynamicObject->MoverParameters->DecLocalBrakeLevel(2)); + } } -bool __fastcall TMachajka::Update(double dt) -{ - TTrain::Update(dt); -} +bool __fastcall TMachajka::Update(double dt) { TTrain::Update(dt); } -bool __fastcall TMachajka::UpdateMechPosition() -{ - TTrain::UpdateMechPosition(); -} +bool __fastcall TMachajka::UpdateMechPosition() { TTrain::UpdateMechPosition(); } -bool __fastcall TMachajka::Render() -{ - TTrain::Render(); -} +bool __fastcall TMachajka::Render() { TTrain::Render(); } //--------------------------------------------------------------------------- #pragma package(smart_init) diff --git a/Machajka.h b/Machajka.h index 81649103..58d8d6c3 100644 --- a/Machajka.h +++ b/Machajka.h @@ -5,17 +5,17 @@ #include "Train.h" -class TMachajka:public TTrain +class TMachajka : public TTrain { -public: + public: TSubModel *wajcha; -// double v; -// double m; -// double a; -// double f; -// bool enter; -// bool space; -// double wa,wv; + // double v; + // double m; + // double a; + // double f; + // bool enter; + // bool space; + // double wa,wv; __fastcall TMachajka(); virtual __fastcall ~TMachajka(); virtual bool __fastcall Init(TDynamicObject *NewDynamicObject); @@ -25,6 +25,5 @@ public: virtual bool __fastcall Render(); }; - //--------------------------------------------------------------------------- #endif diff --git a/MdlMngr.cpp b/MdlMngr.cpp index e7ab9024..18365e88 100644 --- a/MdlMngr.cpp +++ b/MdlMngr.cpp @@ -6,8 +6,8 @@ */ -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #include "Texture.h" #pragma hdrstop @@ -16,26 +16,26 @@ #define SeekFiles AnsiString("*.t3d") -TModel3d* __fastcall TMdlContainer::LoadModel(char *newName,bool dynamic) -{//wczytanie modelu do kontenerka - SafeDeleteArray(Name); - SafeDelete(Model); - Name=new char[strlen(newName)+1]; - strcpy(Name,newName); - Model=new TModel3d(); - if (!Model->LoadFromFile(Name,dynamic)) //np. "models\\pkp/head1-y.t3d" - SafeDelete(Model); - return Model; +TModel3d *__fastcall TMdlContainer::LoadModel(char *newName, bool dynamic) +{ // wczytanie modelu do kontenerka + SafeDeleteArray(Name); + SafeDelete(Model); + Name = new char[strlen(newName) + 1]; + strcpy(Name, newName); + Model = new TModel3d(); + if (!Model->LoadFromFile(Name, dynamic)) // np. "models\\pkp/head1-y.t3d" + SafeDelete(Model); + return Model; }; TMdlContainer *TModelsManager::Models; int TModelsManager::Count; -const MAX_MODELS=1000; +const MAX_MODELS = 1000; void __fastcall TModelsManager::Init() { - Models=new TMdlContainer[MAX_MODELS]; - Count=0; + Models = new TMdlContainer[MAX_MODELS]; + Count = 0; } /* __fastcall TModelsManager::TModelsManager() @@ -50,115 +50,122 @@ __fastcall TModelsManager::~TModelsManager() Free(); }; */ -void __fastcall TModelsManager::Free() -{ - SafeDeleteArray(Models); +void __fastcall TModelsManager::Free() { SafeDeleteArray(Models); } + +TModel3d *__fastcall TModelsManager::LoadModel(char *Name, bool dynamic) +{ // wczytanie modelu do tablicy + TModel3d *mdl = NULL; + if (Count >= MAX_MODELS) + Error("FIXME: Too many models, program will now crash :)"); + else + { + mdl = Models[Count].LoadModel(Name, dynamic); + if (mdl) + Count++; // jeśli błąd wczytania modelu, to go nie wliczamy + } + return mdl; } - -TModel3d* __fastcall TModelsManager::LoadModel(char *Name,bool dynamic) -{//wczytanie modelu do tablicy - TModel3d *mdl=NULL; - if (Count>=MAX_MODELS) - Error("FIXME: Too many models, program will now crash :)"); - else - { - mdl=Models[Count].LoadModel(Name,dynamic); - if (mdl) Count++; //jeśli błąd wczytania modelu, to go nie wliczamy - } - return mdl; -} - -TModel3d* __fastcall TModelsManager::GetModel(const char *Name,bool dynamic) -{//model może być we wpisie "node...model" albo "node...dynamic", a także być dodatkowym w dynamic (kabina, wnętrze, ładunek) - //dla "node...dynamic" mamy podaną ścieżkę w "\dynamic\" i musi być co najmniej 1 poziom, zwkle są 2 - //dla "node...model" może być typowy model statyczny ze ścieżką, domyślnie w "\scenery\" albo "\models" - //albo może być model z "\dynamic\", jeśli potrzebujemy wstawić auto czy wagon nieruchomo - // - ze ścieżki z której jest wywołany, np. dir="scenery\bud\" albo dir="dynamic\pkp\st44_v1\" plus name="model.t3d" - // - z domyślnej ścieżki dla modeli, np. "scenery\" albo "models\" plus name="bud\dombale.t3d" (dir="") - // - konkretnie podanej ścieżki np. name="\scenery\bud\dombale.t3d" (dir="") - //wywołania: - // - konwersja wszystkiego do E3D, podawana dokładna ścieżka, tekstury tam, gdzie plik - // - wczytanie kabiny, dokładna ścieżka, tekstury z katalogu modelu - // - wczytanie ładunku, ścieżka dokładna, tekstury z katalogu modelu - // - wczytanie modelu, ścieżka dokładna, tekstury z katalogu modelu - // - wczytanie przedsionków, ścieżka dokładna, tekstury z katalogu modelu - // - wczytanie uproszczonego wnętrza, ścieżka dokładna, tekstury z katalogu modelu - // - niebo animowane, ścieżka brana ze wpisu, tekstury nieokreślone - // - wczytanie modelu animowanego - Init() - sprawdzić - char buf[255]; - AnsiString buftp=Global::asCurrentTexturePath; //zapamiętanie aktualnej ścieżki do tekstur, bo będzie tyczmasowo zmieniana -/* -// Ra: niby tak jest lepiej, ale działa gorzej, więc przywrócone jest oryginalne - //nawet jeśli model będzie pobrany z tablicy, to trzeba ustalić ścieżkę dla tekstur - if (dynamic) //na razie tak, bo nie wiadomo, jaki może mieć wpływ na pozostałe modele - {//dla pojazdów podana jest zawsze pełna ścieżka do modelu - strcpy(buf,Name); - if (strchr(Name,'/')!=NULL) - {//pobieranie tekstur z katalogu, w którym jest model - Global::asCurrentTexturePath=Global::asCurrentTexturePath+AnsiString(Name); - Global::asCurrentTexturePath.Delete(Global::asCurrentTexturePath.Pos("/")+1,Global::asCurrentTexturePath.Length()); - } - } - else - {//dla modeli scenerii trzeba ustalić ścieżkę - if (strchr(Name,'\\')==NULL) - {//jeśli nie ma lewego ukośnika w ścieżce, a jest prawy, to zmienić ścieżkę dla tekstur na tę z modelem - strcpy(buf,"models\\"); //Ra: było by lepiej katalog dodać w parserze - //strcpy(buf,"scenery\\"); //Ra: było by lepiej katalog dodać w parserze - strcat(buf,Name); - if (strchr(Name,'/')!=NULL) - {//jeszcze musi być prawy ukośnik - Global::asCurrentTexturePath=Global::asCurrentTexturePath+AnsiString(Name); - Global::asCurrentTexturePath.Delete(Global::asCurrentTexturePath.Pos("/")+1,Global::asCurrentTexturePath.Length()); - } - } - else - {//jeśli jest lewy ukośnik, to ścieżkę do tekstur zmienić tylko dla pojazdów - strcpy(buf,Name); - } - } - StrLower(buf); - for (int i=0;igetTokens(1,false); //case sensitive - *parser >> token; - SafeDeleteArray(szText); - szText=new char[256]; //musi być bufor do łączenia tekstów - strcpy(szText,token.c_str()); - parser->getTokens(); - *parser >> fValue1; - parser->getTokens(); - *parser >> fValue2; - parser->getTokens(); - *parser >> token; - if (token.compare("none")!=0) //gdy różne od "none" - asTrackName=AnsiString(token.c_str()); //sprawdzane przez IsEmpty() - parser->getTokens(); - *parser >> token; - if (token.compare("endmemcell")!=0) - Error("endmemcell statement missing"); - CommandCheck(); - return true; + std::string token; + parser->getTokens(1, false); // case sensitive + *parser >> token; + SafeDeleteArray(szText); + szText = new char[256]; // musi być bufor do łączenia tekstów + strcpy(szText, token.c_str()); + parser->getTokens(); + *parser >> fValue1; + parser->getTokens(); + *parser >> fValue2; + parser->getTokens(); + *parser >> token; + if (token.compare("none") != 0) // gdy różne od "none" + asTrackName = AnsiString(token.c_str()); // sprawdzane przez IsEmpty() + parser->getTokens(); + *parser >> token; + if (token.compare("endmemcell") != 0) + Error("endmemcell statement missing"); + CommandCheck(); + return true; } void __fastcall TMemCell::PutCommand(TController *Mech, vector3 *Loc) -{//wysłanie zawartości komórki do AI - if (Mech) - Mech->PutCommand(szText,fValue1,fValue2,Loc); +{ // wysłanie zawartości komórki do AI + if (Mech) + Mech->PutCommand(szText, fValue1, fValue2, Loc); } -bool __fastcall TMemCell::Compare(char *szTestText,double fTestValue1,double fTestValue2,int CheckMask) -{//porównanie zawartości komórki pamięci z podanymi wartościami - if (TestFlag(CheckMask,conditional_memstring)) - {//porównać teksty - char *pos=StrPos(szTestText,"*"); //zwraca wskaźnik na pozycję albo NULL - if (pos) - {//porównanie fragmentu łańcucha - int i=pos-szTestText; //ilość porównywanych znaków - if (i) //jeśli nie jest pierwszym znakiem - if (AnsiString(szTestText,i)!=AnsiString(szText,i)) - return false; //początki o długości (i) są różne - } - else - if (AnsiString(szTestText)!=AnsiString(szText)) - return false; //łąńcuchy są różne - } - //tekst zgodny, porównać resztę - return ((!TestFlag(CheckMask,conditional_memval1) || (fValue1==fTestValue1)) && - (!TestFlag(CheckMask,conditional_memval2) || (fValue2==fTestValue2))); +bool __fastcall TMemCell::Compare(char *szTestText, double fTestValue1, double fTestValue2, + int CheckMask) +{ // porównanie zawartości komórki pamięci z podanymi wartościami + if (TestFlag(CheckMask, conditional_memstring)) + { // porównać teksty + char *pos = StrPos(szTestText, "*"); // zwraca wskaźnik na pozycję albo NULL + if (pos) + { // porównanie fragmentu łańcucha + int i = pos - szTestText; // ilość porównywanych znaków + if (i) // jeśli nie jest pierwszym znakiem + if (AnsiString(szTestText, i) != AnsiString(szText, i)) + return false; // początki o długości (i) są różne + } + else if (AnsiString(szTestText) != AnsiString(szText)) + return false; //łąńcuchy są różne + } + // tekst zgodny, porównać resztę + return ((!TestFlag(CheckMask, conditional_memval1) || (fValue1 == fTestValue1)) && + (!TestFlag(CheckMask, conditional_memval2) || (fValue2 == fTestValue2))); }; -bool __fastcall TMemCell::Render() -{ - return true; -} +bool __fastcall TMemCell::Render() { return true; } bool __fastcall TMemCell::IsVelocity() -{//sprawdzenie, czy event odczytu tej komórki ma być do skanowania, czy do kolejkowania - if (eCommand==cm_SetVelocity) return true; - if (eCommand==cm_ShuntVelocity) return true; - return (eCommand==cm_SetProximityVelocity); +{ // sprawdzenie, czy event odczytu tej komórki ma być do skanowania, czy do kolejkowania + if (eCommand == cm_SetVelocity) + return true; + if (eCommand == cm_ShuntVelocity) + return true; + return (eCommand == cm_SetProximityVelocity); }; void __fastcall TMemCell::StopCommandSent() -{// - if (!bCommand) return; - bCommand=false; - if (OnSent) //jeśli jest event - Global::AddToQuery(OnSent,NULL); +{ // + if (!bCommand) + return; + bCommand = false; + if (OnSent) // jeśli jest event + Global::AddToQuery(OnSent, NULL); }; -void __fastcall TMemCell::AssignEvents(TEvent *e) -{//powiązanie eventu - OnSent=e; -}; +void __fastcall TMemCell::AssignEvents(TEvent *e) { // powiązanie eventu OnSent = e; }; diff --git a/MemCell.h b/MemCell.h index 5b637bf9..adff9d52 100644 --- a/MemCell.h +++ b/MemCell.h @@ -9,34 +9,37 @@ using namespace Math3D; class TMemCell { -private: - vector3 vPosition; - char *szText; - double fValue1; - double fValue2; - TCommandType eCommand; - bool bCommand; //czy zawiera komendę dla zatrzymanego AI - TEvent *OnSent; //event dodawany do kolejki po wysłaniu komendy zatrzymującej skład -public: - AnsiString asTrackName; //McZapkie-100302 - zeby nazwe toru na ktory jest Putcommand wysylane pamietac - __fastcall TMemCell(vector3 *p); - __fastcall ~TMemCell(); - void __fastcall Init(); - void __fastcall UpdateValues(char *szNewText, double fNewValue1, double fNewValue2, int CheckMask); - bool __fastcall Load(cParser *parser); - void __fastcall PutCommand(TController *Mech, vector3 *Loc); - bool __fastcall Compare(char *szTestText, double fTestValue1, double fTestValue2, int CheckMask); - bool __fastcall Render(); - inline char* __fastcall Text() {return szText;}; - inline double __fastcall Value1() {return fValue1;}; - inline double __fastcall Value2() {return fValue2;}; - inline vector3 __fastcall Position() {return vPosition;}; - inline TCommandType __fastcall Command() {return eCommand;}; - inline bool __fastcall StopCommand() {return bCommand;}; - void __fastcall StopCommandSent(); - TCommandType __fastcall CommandCheck(); - bool __fastcall IsVelocity(); - void __fastcall AssignEvents(TEvent *e); + private: + vector3 vPosition; + char *szText; + double fValue1; + double fValue2; + TCommandType eCommand; + bool bCommand; // czy zawiera komendę dla zatrzymanego AI + TEvent *OnSent; // event dodawany do kolejki po wysłaniu komendy zatrzymującej skład + public: + AnsiString + asTrackName; // McZapkie-100302 - zeby nazwe toru na ktory jest Putcommand wysylane pamietac + __fastcall TMemCell(vector3 *p); + __fastcall ~TMemCell(); + void __fastcall Init(); + void __fastcall UpdateValues(char *szNewText, double fNewValue1, double fNewValue2, + int CheckMask); + bool __fastcall Load(cParser *parser); + void __fastcall PutCommand(TController *Mech, vector3 *Loc); + bool __fastcall Compare(char *szTestText, double fTestValue1, double fTestValue2, + int CheckMask); + bool __fastcall Render(); + inline char *__fastcall Text() { return szText; }; + inline double __fastcall Value1() { return fValue1; }; + inline double __fastcall Value2() { return fValue2; }; + inline vector3 __fastcall Position() { return vPosition; }; + inline TCommandType __fastcall Command() { return eCommand; }; + inline bool __fastcall StopCommand() { return bCommand; }; + void __fastcall StopCommandSent(); + TCommandType __fastcall CommandCheck(); + bool __fastcall IsVelocity(); + void __fastcall AssignEvents(TEvent *e); }; //--------------------------------------------------------------------------- diff --git a/Model3d.cpp b/Model3d.cpp index b29087c5..bfede0db 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -5,8 +5,8 @@ */ -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Model3d.h" @@ -19,196 +19,204 @@ //--------------------------------------------------------------------------- #pragma package(smart_init) -double TSubModel::fSquareDist=0; -int TSubModel::iInstance; //numer renderowanego egzemplarza obiektu -GLuint *TSubModel::ReplacableSkinId=NULL; -int TSubModel::iAlpha=0x30300030; //maska do testowania flag tekstur wymiennych -TModel3d* TSubModel::pRoot; //Ra: tymczasowo wskaźnik na model widoczny z submodelu -AnsiString* TSubModel::pasText; -//przykłady dla TSubModel::iAlpha: +double TSubModel::fSquareDist = 0; +int TSubModel::iInstance; // numer renderowanego egzemplarza obiektu +GLuint *TSubModel::ReplacableSkinId = NULL; +int TSubModel::iAlpha = 0x30300030; // maska do testowania flag tekstur wymiennych +TModel3d *TSubModel::pRoot; // Ra: tymczasowo wskaźnik na model widoczny z submodelu +AnsiString *TSubModel::pasText; +// przykłady dla TSubModel::iAlpha: // 0x30300030 - wszystkie bez kanału alfa // 0x31310031 - tekstura -1 używana w danym cyklu, pozostałe nie // 0x32320032 - tekstura -2 używana w danym cyklu, pozostałe nie // 0x34340034 - tekstura -3 używana w danym cyklu, pozostałe nie // 0x38380038 - tekstura -4 używana w danym cyklu, pozostałe nie // 0x3F3F003F - wszystkie wymienne tekstury używane w danym cyklu -//Ale w TModel3d okerśla przezroczystość tekstur wymiennych! +// Ale w TModel3d okerśla przezroczystość tekstur wymiennych! -int TSubModelInfo::iTotalTransforms=0; //ilość transformów -int TSubModelInfo::iTotalNames=0; //długość obszaru nazw -int TSubModelInfo::iTotalTextures=0; //długość obszaru tekstur -int TSubModelInfo::iCurrent=0; //aktualny obiekt -TSubModelInfo* TSubModelInfo::pTable=NULL; //tabele obiektów pomocniczych +int TSubModelInfo::iTotalTransforms = 0; // ilość transformów +int TSubModelInfo::iTotalNames = 0; // długość obszaru nazw +int TSubModelInfo::iTotalTextures = 0; // długość obszaru tekstur +int TSubModelInfo::iCurrent = 0; // aktualny obiekt +TSubModelInfo *TSubModelInfo::pTable = NULL; // tabele obiektów pomocniczych - -char* TStringPack::String(int n) -{//zwraca wskaźnik do łańcucha o podanym numerze - if (index?n<(index[1]>>2)-2:false) - return data+8+index[n+2]; //indeks upraszcza kwestię wyszukiwania - //jak nie ma indeksu, to trzeba szukać - int max=*((int*)(data+4)); //długość obszaru łańcuchów - char* ptr=data+8; //począek obszaru łańcuchów - for (int i=0;idata+max) return NULL; //zbyt wysoki numer - } - return ptr; +char *TStringPack::String(int n) +{ // zwraca wskaźnik do łańcucha o podanym numerze + if (index ? n < (index[1] >> 2) - 2 : false) + return data + 8 + index[n + 2]; // indeks upraszcza kwestię wyszukiwania + // jak nie ma indeksu, to trzeba szukać + int max = *((int *)(data + 4)); // długość obszaru łańcuchów + char *ptr = data + 8; // począek obszaru łańcuchów + for (int i = 0; i < n; ++i) + { // wyszukiwanie łańcuchów nie jest zbyt optymalne, ale nie musi być + while (*ptr) + ++ptr; // wyszukiwanie zera + ++ptr; // pominięcie zera + if (ptr > data + max) + return NULL; // zbyt wysoki numer + } + return ptr; }; __fastcall TSubModel::TSubModel() { - ZeroMemory(this,sizeof(TSubModel)); //istotne przy zapisywaniu wersji binarnej - FirstInit(); + ZeroMemory(this, sizeof(TSubModel)); // istotne przy zapisywaniu wersji binarnej + FirstInit(); }; void __fastcall TSubModel::FirstInit() { - eType=TP_ROTATOR; - Vertices=NULL; - uiDisplayList=0; - iNumVerts=-1; //do sprawdzenia - iVboPtr=-1; - fLight=-1.0; //świetcenie wyłączone - v_RotateAxis=float3(0,0,0); - v_TransVector=float3(0,0,0); - f_Angle=0; - b_Anim=at_None; - b_aAnim=at_None; - fVisible=0.0; //zawsze widoczne - iVisible=1; - fMatrix=NULL; //to samo co iMatrix=0; - Next=NULL; - Child=NULL; - TextureID=0; - //TexAlpha=false; - iFlags=0x0200; //bit 9=1: submodel został utworzony a nie ustawiony na wczytany plik - //TexHash=false; - //Hits=NULL; - //CollisionPts=NULL; - //CollisionPtsCount=0; - Opacity=1.0; //przy wczytywaniu modeli było dzielone przez 100... - bWire=false; - fWireSize=0; - fNearAttenStart=40; - fNearAttenEnd=80; - bUseNearAtten=false; - iFarAttenDecay=0; - fFarDecayRadius=100; - fCosFalloffAngle=0.5; //120°? - fCosHotspotAngle=0.3; //145°? - fCosViewAngle=0; - fSquareMaxDist=10000*10000; //10km - fSquareMinDist=0; - iName=-1; //brak nazwy - iTexture=0; //brak tekstury - //asName=""; - //asTexture=""; - pName=pTexture=NULL; - f4Ambient[0]=f4Ambient[1]=f4Ambient[2]=f4Ambient[3]=1.0; //{1,1,1,1}; - f4Diffuse[0]=f4Diffuse[1]=f4Diffuse[2]=f4Diffuse[3]=1.0; //{1,1,1,1}; - f4Specular[0]=f4Specular[1]=f4Specular[2]=0.0; f4Specular[3]=1.0; //{0,0,0,1}; - f4Emision[0]=f4Emision[1]=f4Emision[2]=f4Emision[3]=1.0; - smLetter=NULL; //używany tylko roboczo dla TP_TEXT, do przyspieszenia wyświetlania + eType = TP_ROTATOR; + Vertices = NULL; + uiDisplayList = 0; + iNumVerts = -1; // do sprawdzenia + iVboPtr = -1; + fLight = -1.0; //świetcenie wyłączone + v_RotateAxis = float3(0, 0, 0); + v_TransVector = float3(0, 0, 0); + f_Angle = 0; + b_Anim = at_None; + b_aAnim = at_None; + fVisible = 0.0; // zawsze widoczne + iVisible = 1; + fMatrix = NULL; // to samo co iMatrix=0; + Next = NULL; + Child = NULL; + TextureID = 0; + // TexAlpha=false; + iFlags = 0x0200; // bit 9=1: submodel został utworzony a nie ustawiony na wczytany plik + // TexHash=false; + // Hits=NULL; + // CollisionPts=NULL; + // CollisionPtsCount=0; + Opacity = 1.0; // przy wczytywaniu modeli było dzielone przez 100... + bWire = false; + fWireSize = 0; + fNearAttenStart = 40; + fNearAttenEnd = 80; + bUseNearAtten = false; + iFarAttenDecay = 0; + fFarDecayRadius = 100; + fCosFalloffAngle = 0.5; // 120°? + fCosHotspotAngle = 0.3; // 145°? + fCosViewAngle = 0; + fSquareMaxDist = 10000 * 10000; // 10km + fSquareMinDist = 0; + iName = -1; // brak nazwy + iTexture = 0; // brak tekstury + // asName=""; + // asTexture=""; + pName = pTexture = NULL; + f4Ambient[0] = f4Ambient[1] = f4Ambient[2] = f4Ambient[3] = 1.0; //{1,1,1,1}; + f4Diffuse[0] = f4Diffuse[1] = f4Diffuse[2] = f4Diffuse[3] = 1.0; //{1,1,1,1}; + f4Specular[0] = f4Specular[1] = f4Specular[2] = 0.0; + f4Specular[3] = 1.0; //{0,0,0,1}; + f4Emision[0] = f4Emision[1] = f4Emision[2] = f4Emision[3] = 1.0; + smLetter = NULL; // używany tylko roboczo dla TP_TEXT, do przyspieszenia wyświetlania }; __fastcall TSubModel::~TSubModel() { - if (uiDisplayList) glDeleteLists(uiDisplayList,1); - if (iFlags&0x0200) - {//wczytany z pliku tekstowego musi sam posprzątać - //SafeDeleteArray(Indices); - SafeDelete(Next); - SafeDelete(Child); - delete fMatrix; //własny transform trzeba usunąć (zawsze jeden) - delete[] Vertices; - delete[] pTexture; - delete[] pName; - } -/* - else - {//wczytano z pliku binarnego (nie jest właścicielem tablic) - } -*/ - delete[] smLetter; //używany tylko roboczo dla TP_TEXT, do przyspieszenia wyświetlania + if (uiDisplayList) + glDeleteLists(uiDisplayList, 1); + if (iFlags & 0x0200) + { // wczytany z pliku tekstowego musi sam posprzątać + // SafeDeleteArray(Indices); + SafeDelete(Next); + SafeDelete(Child); + delete fMatrix; // własny transform trzeba usunąć (zawsze jeden) + delete[] Vertices; + delete[] pTexture; + delete[] pName; + } + /* + else + {//wczytano z pliku binarnego (nie jest właścicielem tablic) + } + */ + delete[] smLetter; // używany tylko roboczo dla TP_TEXT, do przyspieszenia wyświetlania }; void __fastcall TSubModel::TextureNameSet(const char *n) -{//ustawienie nazwy submodelu, o ile nie jest wczytany z E3D - if (iFlags&0x0200) - {//tylko jeżeli submodel zosta utworzony przez new - delete[] pTexture; //usunięcie poprzedniej - int i=strlen(n); - if (i) - {//utworzenie nowej - pTexture=new char[i+1]; - strcpy(pTexture,n); - } - else - pTexture=NULL; - } +{ // ustawienie nazwy submodelu, o ile nie jest wczytany z E3D + if (iFlags & 0x0200) + { // tylko jeżeli submodel zosta utworzony przez new + delete[] pTexture; // usunięcie poprzedniej + int i = strlen(n); + if (i) + { // utworzenie nowej + pTexture = new char[i + 1]; + strcpy(pTexture, n); + } + else + pTexture = NULL; + } }; void __fastcall TSubModel::NameSet(const char *n) -{//ustawienie nazwy submodelu, o ile nie jest wczytany z E3D - if (iFlags&0x0200) - {//tylko jeżeli submodel zosta utworzony przez new - delete[] pName; //usunięcie poprzedniej - int i=strlen(n); - if (i) - {//utworzenie nowej - pName=new char[i+1]; - strcpy(pName,n); - } - else - pName=NULL; - } +{ // ustawienie nazwy submodelu, o ile nie jest wczytany z E3D + if (iFlags & 0x0200) + { // tylko jeżeli submodel zosta utworzony przez new + delete[] pName; // usunięcie poprzedniej + int i = strlen(n); + if (i) + { // utworzenie nowej + pName = new char[i + 1]; + strcpy(pName, n); + } + else + pName = NULL; + } }; -//int __fastcall TSubModel::SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 *pt,GLVERTEX *Vertices) -int __fastcall TSubModel::SeekFaceNormal(DWORD *Masks,int f,DWORD dwMask,float3 *pt,float8 *Vertices) -{//szukanie punktu stycznego do (pt), zwraca numer wierzchołka, a nie trójkąta - int iNumFaces=iNumVerts/3; //bo maska powierzchni jest jedna na trójkąt - //GLVERTEX *p; //roboczy wskaźnik - float8 *p; //roboczy wskaźnik - for (int i=f;iPoint==*pt) return 3*i; - if ((++p)->Point==*pt) return 3*i+1; - if ((++p)->Point==*pt) return 3*i+2; - } - return -1; //nie znaleziono stycznego wierzchołka +// int __fastcall TSubModel::SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 *pt,GLVERTEX +// *Vertices) +int __fastcall TSubModel::SeekFaceNormal(DWORD *Masks, int f, DWORD dwMask, float3 *pt, + float8 *Vertices) +{ // szukanie punktu stycznego do (pt), zwraca numer wierzchołka, a nie trójkąta + int iNumFaces = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkąt + // GLVERTEX *p; //roboczy wskaźnik + float8 *p; // roboczy wskaźnik + for (int i = f; i < iNumFaces; ++i) // pętla po trójkątach, od trójkąta (f) + if (Masks[i] & dwMask) // jeśli wspólna maska powierzchni + { + p = Vertices + 3 * i; + if (p->Point == *pt) + return 3 * i; + if ((++p)->Point == *pt) + return 3 * i + 1; + if ((++p)->Point == *pt) + return 3 * i + 2; + } + return -1; // nie znaleziono stycznego wierzchołka } -float emm1[]={1,1,1,0}; -float emm2[]={0,0,0,1}; +float emm1[] = {1, 1, 1, 0}; +float emm2[] = {0, 0, 0, 1}; -inline double readIntAsDouble(cParser& parser,int base=255) +inline double readIntAsDouble(cParser &parser, int base = 255) { - int value; - parser.getToken(value); - return double(value)/base; + int value; + parser.getToken(value); + return double(value) / base; }; -template -inline void readColor(cParser& parser,ColorT* color) +template inline void readColor(cParser &parser, ColorT *color) { - parser.ignoreToken(); - color[0]=readIntAsDouble(parser); - color[1]=readIntAsDouble(parser); - color[2]=readIntAsDouble(parser); + parser.ignoreToken(); + color[0] = readIntAsDouble(parser); + color[1] = readIntAsDouble(parser); + color[2] = readIntAsDouble(parser); }; -inline void readColor(cParser& parser,int &color) +inline void readColor(cParser &parser, int &color) { - int r,g,b; - parser.ignoreToken(); - parser.getToken(r); - parser.getToken(g); - parser.getToken(b); - color=r+(g<<8)+(b<<16); + int r, g, b; + parser.ignoreToken(); + parser.getToken(r); + parser.getToken(g); + parser.getToken(b); + color = r + (g << 8) + (b << 16); }; /* inline void readMatrix(cParser& parser,matrix4x4& matrix) @@ -218,1276 +226,1420 @@ inline void readMatrix(cParser& parser,matrix4x4& matrix) parser.getToken(matrix(x)[y]); }; */ -inline void readMatrix(cParser& parser,float4x4& matrix) -{//Ra: wczytanie transforma - for (int x=0;x<=3;x++) //wiersze - for (int y=0;y<=3;y++) //kolumny - parser.getToken(matrix(x)[y]); +inline void readMatrix(cParser &parser, float4x4 &matrix) +{ // Ra: wczytanie transforma + for (int x = 0; x <= 3; x++) // wiersze + for (int y = 0; y <= 3; y++) // kolumny + parser.getToken(matrix(x)[y]); }; -int __fastcall TSubModel::Load(cParser& parser,TModel3d *Model,int Pos,bool dynamic) -{//Ra: VBO tworzone na poziomie modelu, a nie submodeli - iNumVerts=0; - iVboPtr=Pos; //pozycja w VBO - //TMaterialColorf Ambient,Diffuse,Specular; - //GLuint TextureID; - //char *extName; - if (!parser.expectToken("type:")) - Error("Model type parse failure!"); - { - std::string type; - parser.getToken(type); - if (type=="mesh") - eType=GL_TRIANGLES; //submodel - trójkaty - else if (type=="point") - eType=GL_POINTS; //co to niby jest? - else if (type=="freespotlight") - eType=TP_FREESPOTLIGHT; //światełko - else if (type=="text") - eType=TP_TEXT; //wyświetlacz tekstowy (generator napisów) - else if (type=="stars") - eType=TP_STARS; //wiele punktów świetlnych - }; - parser.ignoreToken(); - std::string token; - //parser.getToken(token1); //ze zmianą na małe! - parser.getTokens(1,false); //nazwa submodelu bez zmieny na małe - parser >> token; - NameSet(token.c_str()); - if (dynamic) - {//dla pojazdu, blokujemy załączone submodele, które mogą być nieobsługiwane - if (token.find("_on")+3==token.length()) //jeśli nazwa kończy się na "_on" - iVisible=0; //to domyślnie wyłączyć, żeby się nie nakładało z obiektem "_off" - } - else //dla pozostałych modeli blokujemy zapalone światła, które mogą być nieobsługiwane - if (token.find("Light_On")==0) //jeśli nazwa zaczyna się od "Light_On" - iVisible=0; //to domyślnie wyłączyć, żeby się nie nakładało z obiektem "Light_Off" - - if (parser.expectToken("anim:")) //Ra: ta informacja by się przydała! - {//rodzaj animacji - std::string type; - parser.getToken(type); - if (type!="false") - {iFlags|=0x4000; //jak animacja, to trzeba przechowywać macierz zawsze - if (type=="seconds_jump") b_Anim=b_aAnim=at_SecondsJump; //sekundy z przeskokiem - else if (type=="minutes_jump") b_Anim=b_aAnim=at_MinutesJump; //minuty z przeskokiem - else if (type=="hours_jump") b_Anim=b_aAnim=at_HoursJump; //godziny z przeskokiem - else if (type=="hours24_jump") b_Anim=b_aAnim=at_Hours24Jump; //godziny z przeskokiem - else if (type=="seconds") b_Anim=b_aAnim=at_Seconds; //minuty płynnie - else if (type=="minutes") b_Anim=b_aAnim=at_Minutes; //minuty płynnie - else if (type=="hours") b_Anim=b_aAnim=at_Hours; //godziny płynnie - else if (type=="hours24") b_Anim=b_aAnim=at_Hours24; //godziny płynnie - else if (type=="billboard") b_Anim=b_aAnim=at_Billboard; //obrót w pionie do kamery - else if (type=="wind") b_Anim=b_aAnim=at_Wind; //ruch pod wpływem wiatru - else if (type=="sky") b_Anim=b_aAnim=at_Sky; //aniamacja nieba - else if (type=="ik") b_Anim=b_aAnim=at_IK; //IK: zadający - else if (type=="ik11") b_Anim=b_aAnim=at_IK11; //IK: kierunkowany - else if (type=="ik21") b_Anim=b_aAnim=at_IK21; //IK: kierunkowany - else if (type=="ik22") b_Anim=b_aAnim=at_IK22; //IK: kierunkowany - else if (type=="digital") b_Anim=b_aAnim=at_Digital; //licznik mechaniczny - else if (type=="digiclk") b_Anim=b_aAnim=at_DigiClk; //zegar cyfrowy - else b_Anim=b_aAnim=at_Undefined; //nieznana forma animacji - } - } - if (eType1.0) Opacity*=0.01; //w 2013 był błąd i aby go obejść, trzeba było wpisać 10000.0 - if ((Global::iConvertModels&1)==0) //dla zgodności wstecz - Opacity=0.0; //wszystko idzie w przezroczyste albo zależnie od tekstury - if (!parser.expectToken("map:")) - Error("Model map parse failure!"); - std::string texture; - parser.getToken(texture); - if (texture=="none") - {//rysowanie podanym kolorem - TextureID=0; - iFlags|=0x10; //rysowane w cyklu nieprzezroczystych - } - else if (texture.find("replacableskin")!=texture.npos) - {// McZapkie-060702: zmienialne skory modelu - TextureID=-1; - iFlags|=(Opacity<1.0)?1:0x10; //zmienna tekstura 1 - } - else if (texture=="-1") - { - TextureID=-1; - iFlags|=(Opacity<1.0)?1:0x10; //zmienna tekstura 1 - } - else if (texture=="-2") - { - TextureID=-2; - iFlags|=(Opacity<1.0)?2:0x10; //zmienna tekstura 2 - } - else if (texture=="-3") - { - TextureID=-3; - iFlags|=(Opacity<1.0)?4:0x10; //zmienna tekstura 3 - } - else if (texture=="-4") - { - TextureID=-4; - iFlags|=(Opacity<1.0)?8:0x10; //zmienna tekstura 4 - } - else - {//jeśli tylko nazwa pliku, to dawać bieżącą ścieżkę do tekstur - //asTexture=AnsiString(texture.c_str()); //zapamiętanie nazwy tekstury - TextureNameSet(texture.c_str()); - if (texture.find_first_of("/\\")==texture.npos) - texture.insert(0,Global::asCurrentTexturePath.c_str()); - TextureID=TTexturesManager::GetTextureID(szTexturePath,Global::asCurrentTexturePath.c_str(),texture); - //TexAlpha=TTexturesManager::GetAlpha(TextureID); - //iFlags|=TexAlpha?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta - if (Opacity<1.0) //przezroczystość z tekstury brana tylko dla Opacity 0! - iFlags|=TTexturesManager::GetAlpha(TextureID)?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta - else - iFlags|=0x10; //normalnie nieprzezroczyste - //renderowanie w cyklu przezroczystych tylko jeśli: - //1. Opacity=0 (przejściowo <1, czy tam <100) oraz - //2. tekstura ma przezroczystość - }; - } - else iFlags|=0x10; - parser.ignoreToken(); - parser.getToken(fSquareMaxDist); - if (fSquareMaxDist>=0.0) - fSquareMaxDist*=fSquareMaxDist; - else - fSquareMaxDist=15000*15000; //15km to więcej, niż się obecnie wyświetla - parser.ignoreToken(); - parser.getToken(fSquareMinDist); - fSquareMinDist*=fSquareMinDist; - parser.ignoreToken(); - fMatrix=new float4x4(); - readMatrix(parser,*fMatrix); //wczytanie transform - if (!fMatrix->IdentityIs()) - iFlags|=0x8000; //transform niejedynkowy - trzeba go przechować - int iNumFaces; //ilość trójkątów - DWORD *sg; //maski przynależności trójkątów do powierzchni - if (eType0"); - return 0; - } - //Vertices=new GLVERTEX[iNumVerts]; - if (iNumVerts) - {Vertices=new float8[iNumVerts]; - iNumFaces=iNumVerts/3; - sg=new DWORD[iNumFaces]; //maski powierzchni: 0 oznacza brak użredniania wektorów normalnych - int *wsp=new int[iNumVerts]; //z którego wierzchołka kopiować wektor normalny - int maska=0; - for (int i=0;i0) //jeśli pierwszy trójkąt będzie zdegenerowany, to zostanie usunięty i nie ma co sprawdzać - if (((Vertices[i ].Point-Vertices[i-1].Point).Length()>1000.0) || - ((Vertices[i-1].Point-Vertices[i-2].Point).Length()>1000.0) || - ((Vertices[i-2].Point-Vertices[i ].Point).Length()>1000.0)) - {//jeżeli są dalej niż 2km od siebie //Ra 15-01: obiekt wstawiany nie powinien być większy niż 300m (trójkąty terenu w E3D mogą mieć 1.5km) - --iNumFaces; //o jeden trójkąt mniej - iNumVerts-=3; //czyli o 3 wierzchołki - i-=3; //wczytanie kolejnego w to miejsce - WriteLog(AnsiString("Too large triangle ignored in: \"")+AnsiString(pName)+"\""); - } - } +int __fastcall TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) +{ // Ra: VBO tworzone na poziomie modelu, a nie submodeli + iNumVerts = 0; + iVboPtr = Pos; // pozycja w VBO + // TMaterialColorf Ambient,Diffuse,Specular; + // GLuint TextureID; + // char *extName; + if (!parser.expectToken("type:")) + Error("Model type parse failure!"); + { + std::string type; + parser.getToken(type); + if (type == "mesh") + eType = GL_TRIANGLES; // submodel - trójkaty + else if (type == "point") + eType = GL_POINTS; // co to niby jest? + else if (type == "freespotlight") + eType = TP_FREESPOTLIGHT; //światełko + else if (type == "text") + eType = TP_TEXT; // wyświetlacz tekstowy (generator napisów) + else if (type == "stars") + eType = TP_STARS; // wiele punktów świetlnych + }; + parser.ignoreToken(); + std::string token; + // parser.getToken(token1); //ze zmianą na małe! + parser.getTokens(1, false); // nazwa submodelu bez zmieny na małe + parser >> token; + NameSet(token.c_str()); + if (dynamic) + { // dla pojazdu, blokujemy załączone submodele, które mogą być nieobsługiwane + if (token.find("_on") + 3 == token.length()) // jeśli nazwa kończy się na "_on" + iVisible = 0; // to domyślnie wyłączyć, żeby się nie nakładało z obiektem "_off" } - int i; //indeks dla trójkątów - float3 *n=new float3[iNumFaces]; //tablica wektorów normalnych dla trójkątów - for (i=0;i=0) //jeśli już był liczony wektor normalny z użyciem tego wierzchołka - Vertices[v].Normal=Vertices[wsp[v]].Normal; //to wystarczy skopiować policzony wcześniej - else - {//inaczej musimy dopiero policzyć - i=v/3; //numer trójkąta - norm=float3(0,0,0); //liczenie zaczynamy od zera - f=v; //zaczynamy dodawanie wektorów normalnych od własnego - while (f>=0) - {//sumowanie z wektorem normalnym sąsiada (włącznie ze sobą) - wsp[f]=v; //informacja, że w tym wierzchołku jest już policzony wektor normalny - norm+=n[f/3]; - f=SeekFaceNormal(sg,f/3+1,sg[i],&Vertices[v].Point,Vertices); //i szukanie od kolejnego trójkąta - } - //Ra 15-01: należało by jeszcze uwzględnić skalowanie wprowadzane przez transformy, aby normalne po przeskalowaniu były jednostkowe - Vertices[v].Normal=SafeNormalize(norm); //przepisanie do wierzchołka trójkąta - } + else // dla pozostałych modeli blokujemy zapalone światła, które mogą być nieobsługiwane + if (token.find("Light_On") == 0) // jeśli nazwa zaczyna się od "Light_On" + iVisible = 0; // to domyślnie wyłączyć, żeby się nie nakładało z obiektem "Light_Off" + + if (parser.expectToken("anim:")) // Ra: ta informacja by się przydała! + { // rodzaj animacji + std::string type; + parser.getToken(type); + if (type != "false") + { + iFlags |= 0x4000; // jak animacja, to trzeba przechowywać macierz zawsze + if (type == "seconds_jump") + b_Anim = b_aAnim = at_SecondsJump; // sekundy z przeskokiem + else if (type == "minutes_jump") + b_Anim = b_aAnim = at_MinutesJump; // minuty z przeskokiem + else if (type == "hours_jump") + b_Anim = b_aAnim = at_HoursJump; // godziny z przeskokiem + else if (type == "hours24_jump") + b_Anim = b_aAnim = at_Hours24Jump; // godziny z przeskokiem + else if (type == "seconds") + b_Anim = b_aAnim = at_Seconds; // minuty płynnie + else if (type == "minutes") + b_Anim = b_aAnim = at_Minutes; // minuty płynnie + else if (type == "hours") + b_Anim = b_aAnim = at_Hours; // godziny płynnie + else if (type == "hours24") + b_Anim = b_aAnim = at_Hours24; // godziny płynnie + else if (type == "billboard") + b_Anim = b_aAnim = at_Billboard; // obrót w pionie do kamery + else if (type == "wind") + b_Anim = b_aAnim = at_Wind; // ruch pod wpływem wiatru + else if (type == "sky") + b_Anim = b_aAnim = at_Sky; // aniamacja nieba + else if (type == "ik") + b_Anim = b_aAnim = at_IK; // IK: zadający + else if (type == "ik11") + b_Anim = b_aAnim = at_IK11; // IK: kierunkowany + else if (type == "ik21") + b_Anim = b_aAnim = at_IK21; // IK: kierunkowany + else if (type == "ik22") + b_Anim = b_aAnim = at_IK22; // IK: kierunkowany + else if (type == "digital") + b_Anim = b_aAnim = at_Digital; // licznik mechaniczny + else if (type == "digiclk") + b_Anim = b_aAnim = at_DigiClk; // zegar cyfrowy + else + b_Anim = b_aAnim = at_Undefined; // nieznana forma animacji + } } - delete[] wsp; - delete[] n; - delete[] sg; - } - else //gdy brak wierzchołków - {eType=TP_ROTATOR; //submodel pomocniczy, ma tylko macierz przekształcenia - iVboPtr=iNumVerts=0; //dla formalności - } - } //obsługa submodelu z własną listą wierzchołków - } - else if (eType==TP_STARS) - {//punkty świecące dookólnie - składnia jak dla smt_Mesh - parser.ignoreToken(); - parser.getToken(iNumVerts); - //Vertices=new GLVERTEX[iNumVerts]; - Vertices=new float8[iNumVerts]; - int i,j; - for (i=0;i> 8)&0xFF)/255.0; //G - Vertices[i].Normal.z=((j>>16)&0xFF)/255.0; //B - } - } - //Visible=true; //się potem wyłączy w razie potrzeby - //iFlags|=0x0200; //wczytano z pliku tekstowego (jest właścicielem tablic) - if (iNumVerts<1) iFlags&=~0x3F; //cykl renderowania uzależniony od potomnych - return iNumVerts; //do określenia wielkości VBO + if (eType < TP_ROTATOR) + readColor(parser, f4Ambient); // ignoruje token przed + readColor(parser, f4Diffuse); + if (eType < TP_ROTATOR) + readColor(parser, f4Specular); + parser.ignoreTokens(1); // zignorowanie nazwy "SelfIllum:" + { + std::string light; + parser.getToken(light); + if (light == "true") + fLight = 2.0; // zawsze świeci + else if (light == "false") + fLight = -1.0; // zawsze ciemy + else + fLight = atof(light.c_str()); + }; + if (eType == TP_FREESPOTLIGHT) + { + if (!parser.expectToken("nearattenstart:")) + Error("Model light parse failure!"); + parser.getToken(fNearAttenStart); + parser.ignoreToken(); + parser.getToken(fNearAttenEnd); + parser.ignoreToken(); + bUseNearAtten = parser.expectToken("true"); + parser.ignoreToken(); + parser.getToken(iFarAttenDecay); + parser.ignoreToken(); + parser.getToken(fFarDecayRadius); + parser.ignoreToken(); + parser.getToken(fCosFalloffAngle); // kąt liczony dla średnicy, a nie promienia + fCosFalloffAngle = cos(DegToRad(0.5 * fCosFalloffAngle)); + parser.ignoreToken(); + parser.getToken(fCosHotspotAngle); // kąt liczony dla średnicy, a nie promienia + fCosHotspotAngle = cos(DegToRad(0.5 * fCosHotspotAngle)); + iNumVerts = 1; + iFlags |= 0x4010; // rysowane w cyklu nieprzezroczystych, macierz musi zostać bez zmiany + } + else if (eType < TP_ROTATOR) + { + parser.ignoreToken(); + bWire = parser.expectToken("true"); + parser.ignoreToken(); + parser.getToken(fWireSize); + parser.ignoreToken(); + Opacity = readIntAsDouble(parser, + 100.0f); // wymagane jest 0 dla szyb, 100 idzie w nieprzezroczyste + if (Opacity > 1.0) + Opacity *= 0.01; // w 2013 był błąd i aby go obejść, trzeba było wpisać 10000.0 + if ((Global::iConvertModels & 1) == 0) // dla zgodności wstecz + Opacity = 0.0; // wszystko idzie w przezroczyste albo zależnie od tekstury + if (!parser.expectToken("map:")) + Error("Model map parse failure!"); + std::string texture; + parser.getToken(texture); + if (texture == "none") + { // rysowanie podanym kolorem + TextureID = 0; + iFlags |= 0x10; // rysowane w cyklu nieprzezroczystych + } + else if (texture.find("replacableskin") != texture.npos) + { // McZapkie-060702: zmienialne skory modelu + TextureID = -1; + iFlags |= (Opacity < 1.0) ? 1 : 0x10; // zmienna tekstura 1 + } + else if (texture == "-1") + { + TextureID = -1; + iFlags |= (Opacity < 1.0) ? 1 : 0x10; // zmienna tekstura 1 + } + else if (texture == "-2") + { + TextureID = -2; + iFlags |= (Opacity < 1.0) ? 2 : 0x10; // zmienna tekstura 2 + } + else if (texture == "-3") + { + TextureID = -3; + iFlags |= (Opacity < 1.0) ? 4 : 0x10; // zmienna tekstura 3 + } + else if (texture == "-4") + { + TextureID = -4; + iFlags |= (Opacity < 1.0) ? 8 : 0x10; // zmienna tekstura 4 + } + else + { // jeśli tylko nazwa pliku, to dawać bieżącą ścieżkę do tekstur + // asTexture=AnsiString(texture.c_str()); //zapamiętanie nazwy tekstury + TextureNameSet(texture.c_str()); + if (texture.find_first_of("/\\") == texture.npos) + texture.insert(0, Global::asCurrentTexturePath.c_str()); + TextureID = TTexturesManager::GetTextureID( + szTexturePath, Global::asCurrentTexturePath.c_str(), texture); + // TexAlpha=TTexturesManager::GetAlpha(TextureID); + // iFlags|=TexAlpha?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta + if (Opacity < 1.0) // przezroczystość z tekstury brana tylko dla Opacity 0! + iFlags |= TTexturesManager::GetAlpha(TextureID) ? + 0x20 : + 0x10; // 0x10-nieprzezroczysta, 0x20-przezroczysta + else + iFlags |= 0x10; // normalnie nieprzezroczyste + // renderowanie w cyklu przezroczystych tylko jeśli: + // 1. Opacity=0 (przejściowo <1, czy tam <100) oraz + // 2. tekstura ma przezroczystość + }; + } + else + iFlags |= 0x10; + parser.ignoreToken(); + parser.getToken(fSquareMaxDist); + if (fSquareMaxDist >= 0.0) + fSquareMaxDist *= fSquareMaxDist; + else + fSquareMaxDist = 15000 * 15000; // 15km to więcej, niż się obecnie wyświetla + parser.ignoreToken(); + parser.getToken(fSquareMinDist); + fSquareMinDist *= fSquareMinDist; + parser.ignoreToken(); + fMatrix = new float4x4(); + readMatrix(parser, *fMatrix); // wczytanie transform + if (!fMatrix->IdentityIs()) + iFlags |= 0x8000; // transform niejedynkowy - trzeba go przechować + int iNumFaces; // ilość trójkątów + DWORD *sg; // maski przynależności trójkątów do powierzchni + if (eType < TP_ROTATOR) + { // wczytywanie wierzchołków + parser.ignoreToken(); + // Ra 15-01: to wczytać jako tekst - jeśli pierwszy znak zawiera "*", to dalej będzie nazwa + // wcześniejszego submodelu, z którego należy wziąć wierzchołki + // zapewni to jakąś zgodność wstecz, bo zamiast liczby będzie ciąg, którego wartość powinna + // być uznana jako zerowa + // parser.getToken(iNumVerts); + parser.getToken(token); + if (token[0] == '*') + { // jeśli pierwszy znak jest gwiazdką, poszukać submodelu o nazwie bez tej gwiazdki i wziąć + // z niego wierzchołki + Error("Verticles reference not yet supported!"); + } + else + { // normalna lista wierzchołków + iNumVerts = atoi(token.c_str()); + if (iNumVerts % 3) + { + iNumVerts = 0; + Error("Mesh error, (iNumVertices=" + AnsiString(iNumVerts) + ")%3<>0"); + return 0; + } + // Vertices=new GLVERTEX[iNumVerts]; + if (iNumVerts) + { + Vertices = new float8[iNumVerts]; + iNumFaces = iNumVerts / 3; + sg = new DWORD[iNumFaces]; // maski powierzchni: 0 oznacza brak użredniania wektorów + // normalnych + int *wsp = new int[iNumVerts]; // z którego wierzchołka kopiować wektor normalny + int maska = 0; + for (int i = 0; i < iNumVerts; i++) + { // Ra: z konwersją na układ scenerii - będzie wydajniejsze wyświetlanie + wsp[i] = -1; // wektory normalne nie są policzone dla tego wierzchołka + if ((i % 3) == 0) + { // jeśli będzie maska -1, to dalej będą wierzchołki z wektorami normalnymi, + // podanymi jawnie + parser.getToken(maska); // maska powierzchni trójkąta + sg[i / 3] = (maska == -1) ? 0 : maska; // dla maski -1 będzie 0, czyli nie + // ma wspólnych wektorów normalnych + } + parser.getToken(Vertices[i].Point.x); + parser.getToken(Vertices[i].Point.y); + parser.getToken(Vertices[i].Point.z); + if (maska == -1) + { // jeśli wektory normalne podane jawnie + parser.getToken(Vertices[i].Normal.x); + parser.getToken(Vertices[i].Normal.y); + parser.getToken(Vertices[i].Normal.z); + wsp[i] = i; // wektory normalne "są już policzone" + } + parser.getToken(Vertices[i].tu); + parser.getToken(Vertices[i].tv); + if (i % 3 == 2) // jeżeli wczytano 3 punkty + { + if (Vertices[i].Point == Vertices[i - 1].Point || + Vertices[i - 1].Point == Vertices[i - 2].Point || + Vertices[i - 2].Point == Vertices[i].Point) + { // jeżeli punkty się nakładają na siebie + --iNumFaces; // o jeden trójkąt mniej + iNumVerts -= 3; // czyli o 3 wierzchołki + i -= 3; // wczytanie kolejnego w to miejsce + WriteLog(AnsiString("Degenerated triangle ignored in: \"") + + AnsiString(pName) + "\", verticle " + AnsiString(i)); + } + if (i > 0) // jeśli pierwszy trójkąt będzie zdegenerowany, to zostanie + // usunięty i nie ma co sprawdzać + if (((Vertices[i].Point - Vertices[i - 1].Point).Length() > 1000.0) || + ((Vertices[i - 1].Point - Vertices[i - 2].Point).Length() > + 1000.0) || + ((Vertices[i - 2].Point - Vertices[i].Point).Length() > 1000.0)) + { // jeżeli są dalej niż 2km od siebie //Ra 15-01: obiekt wstawiany nie + // powinien być większy niż 300m (trójkąty terenu w E3D mogą mieć + // 1.5km) + --iNumFaces; // o jeden trójkąt mniej + iNumVerts -= 3; // czyli o 3 wierzchołki + i -= 3; // wczytanie kolejnego w to miejsce + WriteLog(AnsiString("Too large triangle ignored in: \"") + + AnsiString(pName) + "\""); + } + } + } + int i; // indeks dla trójkątów + float3 *n = new float3[iNumFaces]; // tablica wektorów normalnych dla trójkątów + for (i = 0; i < iNumFaces; i++) // pętla po trójkątach - będzie szybciej, jak + // wstępnie przeliczymy normalne trójkątów + n[i] = SafeNormalize( + CrossProduct(Vertices[i * 3].Point - Vertices[i * 3 + 1].Point, + Vertices[i * 3].Point - Vertices[i * 3 + 2].Point)); + int v; // indeks dla wierzchołków + int f; // numer trójkąta stycznego + float3 norm; // roboczy wektor normalny + for (v = 0; v < iNumVerts; v++) + { // pętla po wierzchołkach trójkątów + if (wsp[v] >= + 0) // jeśli już był liczony wektor normalny z użyciem tego wierzchołka + Vertices[v].Normal = + Vertices[wsp[v]].Normal; // to wystarczy skopiować policzony wcześniej + else + { // inaczej musimy dopiero policzyć + i = v / 3; // numer trójkąta + norm = float3(0, 0, 0); // liczenie zaczynamy od zera + f = v; // zaczynamy dodawanie wektorów normalnych od własnego + while (f >= 0) + { // sumowanie z wektorem normalnym sąsiada (włącznie ze sobą) + wsp[f] = v; // informacja, że w tym wierzchołku jest już policzony + // wektor normalny + norm += n[f / 3]; + f = SeekFaceNormal(sg, f / 3 + 1, sg[i], &Vertices[v].Point, + Vertices); // i szukanie od kolejnego trójkąta + } + // Ra 15-01: należało by jeszcze uwzględnić skalowanie wprowadzane przez + // transformy, aby normalne po przeskalowaniu były jednostkowe + Vertices[v].Normal = + SafeNormalize(norm); // przepisanie do wierzchołka trójkąta + } + } + delete[] wsp; + delete[] n; + delete[] sg; + } + else // gdy brak wierzchołków + { + eType = TP_ROTATOR; // submodel pomocniczy, ma tylko macierz przekształcenia + iVboPtr = iNumVerts = 0; // dla formalności + } + } // obsługa submodelu z własną listą wierzchołków + } + else if (eType == TP_STARS) + { // punkty świecące dookólnie - składnia jak dla smt_Mesh + parser.ignoreToken(); + parser.getToken(iNumVerts); + // Vertices=new GLVERTEX[iNumVerts]; + Vertices = new float8[iNumVerts]; + int i, j; + for (i = 0; i < iNumVerts; i++) + { + if (i % 3 == 0) + parser.ignoreToken(); // maska powierzchni trójkąta + parser.getToken(Vertices[i].Point.x); + parser.getToken(Vertices[i].Point.y); + parser.getToken(Vertices[i].Point.z); + parser.getToken(j); // zakodowany kolor + parser.ignoreToken(); + Vertices[i].Normal.x = ((j)&0xFF) / 255.0; // R + Vertices[i].Normal.y = ((j >> 8) & 0xFF) / 255.0; // G + Vertices[i].Normal.z = ((j >> 16) & 0xFF) / 255.0; // B + } + } + // Visible=true; //się potem wyłączy w razie potrzeby + // iFlags|=0x0200; //wczytano z pliku tekstowego (jest właścicielem tablic) + if (iNumVerts < 1) + iFlags &= ~0x3F; // cykl renderowania uzależniony od potomnych + return iNumVerts; // do określenia wielkości VBO }; -int __fastcall TSubModel::TriangleAdd(TModel3d *m,int tex,int tri) -{//dodanie trójkątów do submodelu, używane przy tworzeniu E3D terenu - TSubModel *s=this; - while (s?(s->TextureID!=tex):false) - {//szukanie submodelu o danej teksturze - if (s==this) - s=Child; - else - s=s->Next; - } - if (!s) - {if (TextureID<=0) - s=this; //użycie głównego - else - {//dodanie nowego submodelu do listy potomnych - s=new TSubModel(); - m->AddTo(this,s); - } - //s->asTexture=AnsiString(TTexturesManager::GetName(tex).c_str()); - s->TextureNameSet(TTexturesManager::GetName(tex).c_str()); - s->TextureID=tex; - s->eType=GL_TRIANGLES; - //iAnimOwner=0; //roboczy wskaźnik na wierzchołek - } - if (s->iNumVerts<0) - s->iNumVerts=tri; //bo na początku jest -1, czyli że nie wiadomo - else - s->iNumVerts+=tri; //aktualizacja ilości wierzchołków - return s->iNumVerts-tri; //zwraca pozycję tych trójkątów w submodelu +int __fastcall TSubModel::TriangleAdd(TModel3d *m, int tex, int tri) +{ // dodanie trójkątów do submodelu, używane przy tworzeniu E3D terenu + TSubModel *s = this; + while (s ? (s->TextureID != tex) : false) + { // szukanie submodelu o danej teksturze + if (s == this) + s = Child; + else + s = s->Next; + } + if (!s) + { + if (TextureID <= 0) + s = this; // użycie głównego + else + { // dodanie nowego submodelu do listy potomnych + s = new TSubModel(); + m->AddTo(this, s); + } + // s->asTexture=AnsiString(TTexturesManager::GetName(tex).c_str()); + s->TextureNameSet(TTexturesManager::GetName(tex).c_str()); + s->TextureID = tex; + s->eType = GL_TRIANGLES; + // iAnimOwner=0; //roboczy wskaźnik na wierzchołek + } + if (s->iNumVerts < 0) + s->iNumVerts = tri; // bo na początku jest -1, czyli że nie wiadomo + else + s->iNumVerts += tri; // aktualizacja ilości wierzchołków + return s->iNumVerts - tri; // zwraca pozycję tych trójkątów w submodelu }; -float8* __fastcall TSubModel::TrianglePtr(int tex,int pos,int *la,int *ld,int*ls) -{//zwraca wskaźnik do wypełnienia tabeli wierzchołków, używane przy tworzeniu E3D terenu - TSubModel *s=this; - while (s?s->TextureID!=tex:false) - {//szukanie submodelu o danej teksturze - if (s==this) - s=Child; - else - s=s->Next; - } - if (!s) - return NULL; //coś nie tak poszło - if (!s->Vertices) - {//utworznie tabeli trójkątów - s->Vertices=new float8[s->iNumVerts]; - //iVboPtr=pos; //pozycja submodelu w tabeli wierzchołków - //pos+=iNumVerts; //rezerwacja miejsca w tabeli - s->iVboPtr=iInstance; //pozycja submodelu w tabeli wierzchołków - iInstance+=s->iNumVerts; //pozycja dla następnego - } - s->ColorsSet(la,ld,ls); //ustawienie kolorów świateł - return s->Vertices+pos; //wskaźnik na wolne miejsce w tabeli wierzchołków +float8 *__fastcall TSubModel::TrianglePtr(int tex, int pos, int *la, int *ld, int *ls) +{ // zwraca wskaźnik do wypełnienia tabeli wierzchołków, używane przy tworzeniu E3D terenu + TSubModel *s = this; + while (s ? s->TextureID != tex : false) + { // szukanie submodelu o danej teksturze + if (s == this) + s = Child; + else + s = s->Next; + } + if (!s) + return NULL; // coś nie tak poszło + if (!s->Vertices) + { // utworznie tabeli trójkątów + s->Vertices = new float8[s->iNumVerts]; + // iVboPtr=pos; //pozycja submodelu w tabeli wierzchołków + // pos+=iNumVerts; //rezerwacja miejsca w tabeli + s->iVboPtr = iInstance; // pozycja submodelu w tabeli wierzchołków + iInstance += s->iNumVerts; // pozycja dla następnego + } + s->ColorsSet(la, ld, ls); // ustawienie kolorów świateł + return s->Vertices + pos; // wskaźnik na wolne miejsce w tabeli wierzchołków }; void __fastcall TSubModel::DisplayLists() -{//utworznie po jednej skompilowanej liście dla każdego submodelu - if (Global::bUseVBO) return; //Ra: przy VBO to się nie przyda - //iFlags|=0x4000; //wyłączenie przeliczania wierzchołków, bo nie są zachowane - if (eType0) - { - uiDisplayList=glGenLists(1); - glNewList(uiDisplayList,GL_COMPILE); - glColor3fv(f4Diffuse); //McZapkie-240702: zamiast ub +{ // utworznie po jednej skompilowanej liście dla każdego submodelu + if (Global::bUseVBO) + return; // Ra: przy VBO to się nie przyda + // iFlags|=0x4000; //wyłączenie przeliczania wierzchołków, bo nie są zachowane + if (eType < TP_ROTATOR) + { + if (iNumVerts > 0) + { + uiDisplayList = glGenLists(1); + glNewList(uiDisplayList, GL_COMPILE); + glColor3fv(f4Diffuse); // McZapkie-240702: zamiast ub #ifdef USE_VERTEX_ARRAYS - // ShaXbee-121209: przekazywanie wierzcholkow hurtem - glVertexPointer(3,GL_DOUBLE,sizeof(GLVERTEX),&Vertices[0].Point.x); - glNormalPointer(GL_DOUBLE,sizeof(GLVERTEX),&Vertices[0].Normal.x); - glTexCoordPointer(2,GL_FLOAT,sizeof(GLVERTEX),&Vertices[0].tu); - glDrawArrays(eType,0,iNumVerts); + // ShaXbee-121209: przekazywanie wierzcholkow hurtem + glVertexPointer(3, GL_DOUBLE, sizeof(GLVERTEX), &Vertices[0].Point.x); + glNormalPointer(GL_DOUBLE, sizeof(GLVERTEX), &Vertices[0].Normal.x); + glTexCoordPointer(2, GL_FLOAT, sizeof(GLVERTEX), &Vertices[0].tu); + glDrawArrays(eType, 0, iNumVerts); #else - glBegin(eType); - for (int i=0;iDisplayLists(); - if (Next) Next->DisplayLists(); + glEndList(); + } + } + else if (eType == TP_FREESPOTLIGHT) + { + uiDisplayList = glGenLists(1); + glNewList(uiDisplayList, GL_COMPILE); + glBindTexture(GL_TEXTURE_2D, 0); + // if (eType==smt_FreeSpotLight) + // { + // if (iFarAttenDecay==0) + // glColor3f(Diffuse[0],Diffuse[1],Diffuse[2]); + // } + // else + // TODO: poprawic zeby dzialalo + // glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]); + glColorMaterial(GL_FRONT, GL_EMISSION); + glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie blendowaly + glBegin(GL_POINTS); + glVertex3f(0, 0, 0); + glEnd(); + glEnable(GL_LIGHTING); + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + glMaterialfv(GL_FRONT, GL_EMISSION, emm2); + glEndList(); + } + else if (eType == TP_STARS) + { // punkty świecące dookólnie + uiDisplayList = glGenLists(1); + glNewList(uiDisplayList, GL_COMPILE); + glBindTexture(GL_TEXTURE_2D, 0); // tekstury nie ma + glColorMaterial(GL_FRONT, GL_EMISSION); + glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie blendowaly + glBegin(GL_POINTS); + for (int i = 0; i < iNumVerts; i++) + { + glColor3f(Vertices[i].Normal.x, Vertices[i].Normal.y, Vertices[i].Normal.z); + // glVertex3dv(&Vertices[i].Point.x); + glVertex3fv(&Vertices[i].Point.x); + }; + glEnd(); + glEnable(GL_LIGHTING); + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + glMaterialfv(GL_FRONT, GL_EMISSION, emm2); + glEndList(); + } + // SafeDeleteArray(Vertices); //przy VBO muszą zostać do załadowania całego modelu + if (Child) + Child->DisplayLists(); + if (Next) + Next->DisplayLists(); }; void __fastcall TSubModel::InitialRotate(bool doit) -{//konwersja układu współrzędnych na zgodny ze scenerią - if (iFlags&0xC000) //jeśli jest animacja albo niejednostkowy transform - {//niejednostkowy transform jest mnożony i wystarczy zabawy - if (doit) - {//obrót lewostronny - if (!fMatrix) //macierzy może nie być w dodanym "bananie" - {fMatrix=new float4x4(); //tworzy macierz o przypadkowej zawartości - fMatrix->Identity(); //a zaczynamy obracanie od jednostkowej - } - iFlags|=0x8000; //po obróceniu będzie raczej niejedynkowy matrix - fMatrix->InitialRotate(); //zmiana znaku X oraz zamiana Y i Z - if (fMatrix->IdentityIs()) iFlags&=~0x8000; //jednak jednostkowa po obróceniu - } - if (Child) - Child->InitialRotate(false); //potomnych nie obracamy już, tylko ewentualnie optymalizujemy - else - if (Global::iConvertModels&2) //optymalizacja jest opcjonalna - if ((iFlags&0xC000)==0x8000) //o ile nie ma animacji - {//jak nie ma potomnych, można wymnożyć przez transform i wyjedynkować go - float4x4 *mat=GetMatrix(); //transform submodelu - if (Vertices) - {for (int i=0;iIdentity(); //jedynkowanie transformu po przeliczeniu wierzchołków - iFlags&=~0x8000; //transform jedynkowy +{ // konwersja układu współrzędnych na zgodny ze scenerią + if (iFlags & 0xC000) // jeśli jest animacja albo niejednostkowy transform + { // niejednostkowy transform jest mnożony i wystarczy zabawy + if (doit) + { // obrót lewostronny + if (!fMatrix) // macierzy może nie być w dodanym "bananie" + { + fMatrix = new float4x4(); // tworzy macierz o przypadkowej zawartości + fMatrix->Identity(); // a zaczynamy obracanie od jednostkowej + } + iFlags |= 0x8000; // po obróceniu będzie raczej niejedynkowy matrix + fMatrix->InitialRotate(); // zmiana znaku X oraz zamiana Y i Z + if (fMatrix->IdentityIs()) + iFlags &= ~0x8000; // jednak jednostkowa po obróceniu + } + if (Child) + Child->InitialRotate( + false); // potomnych nie obracamy już, tylko ewentualnie optymalizujemy + else if (Global::iConvertModels & 2) // optymalizacja jest opcjonalna + if ((iFlags & 0xC000) == 0x8000) // o ile nie ma animacji + { // jak nie ma potomnych, można wymnożyć przez transform i wyjedynkować go + float4x4 *mat = GetMatrix(); // transform submodelu + if (Vertices) + { + for (int i = 0; i < iNumVerts; ++i) + Vertices[i].Point = (*mat) * Vertices[i].Point; + (*mat)(3)[0] = (*mat)(3)[1] = (*mat)(3)[2] = + 0.0; // zerujemy przesunięcie przed obracaniem normalnych + if (eType != TP_STARS) // gwiazdki mają kolory zamiast normalnych, to ich wtedy + // nie ruszamy + for (int i = 0; i < iNumVerts; ++i) + Vertices[i].Normal = SafeNormalize((*mat) * Vertices[i].Normal); + } + mat->Identity(); // jedynkowanie transformu po przeliczeniu wierzchołków + iFlags &= ~0x8000; // transform jedynkowy + } } - } - else //jak jest jednostkowy i nie ma animacji - if (doit) - {//jeśli jest jednostkowy transform, to przeliczamy wierzchołki, a mnożenie podajemy dalej - double t; - if (Vertices) - for (int i=0;iInitialRotate(doit); // potomne ewentualnie obrócimy } - if (Child) Child->InitialRotate(doit); //potomne ewentualnie obrócimy - } - if (Next) Next->InitialRotate(doit); + if (Next) + Next->InitialRotate(doit); }; void __fastcall TSubModel::ChildAdd(TSubModel *SubModel) -{//dodanie submodelu potemnego (uzależnionego) - //Ra: zmiana kolejności, żeby kolejne móc renderować po aktualnym (było przed) - if (SubModel) SubModel->NextAdd(Child); //Ra: zmiana kolejności renderowania - Child=SubModel; +{ // dodanie submodelu potemnego (uzależnionego) + // Ra: zmiana kolejności, żeby kolejne móc renderować po aktualnym (było przed) + if (SubModel) + SubModel->NextAdd(Child); // Ra: zmiana kolejności renderowania + Child = SubModel; }; void __fastcall TSubModel::NextAdd(TSubModel *SubModel) -{//dodanie submodelu kolejnego (wspólny przodek) - if (Next) - Next->NextAdd(SubModel); - else - Next=SubModel; +{ // dodanie submodelu kolejnego (wspólny przodek) + if (Next) + Next->NextAdd(SubModel); + else + Next = SubModel; }; int __fastcall TSubModel::FlagsCheck() -{//analiza koniecznych zmian pomiędzy submodelami - //samo pomijanie glBindTexture() nie poprawi wydajności - //ale można sprawdzić, czy można w ogóle pominąć kod do tekstur (sprawdzanie replaceskin) - int i; - if (Child) - {//Child jest renderowany po danym submodelu - if (Child->TextureID) //o ile ma teksturę - if (Child->TextureID!=TextureID) //i jest ona inna niż rodzica - Child->iFlags|=0x80; //to trzeba sprawdzać, jak z teksturami jest - i=Child->FlagsCheck(); - iFlags|=0x00FF0000&((i<<16)|(i)|(i>>8)); //potomny, rodzeństwo i dzieci - if (eType==TP_TEXT) - {//wyłączenie renderowania Next dla znaków wyświetlacza tekstowego - TSubModel *p=Child; - while (p) - {p->iFlags&=0xC0FFFFFF; - p=p->Next; - } - } - } - if (Next) - {//Next jest renderowany po danym submodelu (kolejność odwrócona po wczytaniu T3D) - if (TextureID) //o ile dany ma teksturę - if ((TextureID!=Next->TextureID)||(i&0x00800000)) //a ma inną albo dzieci zmieniają - iFlags|=0x80; //to dany submodel musi sobie ją ustawiać - i=Next->FlagsCheck(); - iFlags|=0xFF000000&((i<<24)|(i<<8)|(i)); //następny, kolejne i ich dzieci - //tekstury nie ustawiamy tylko wtedy, gdy jest taka sama jak Next i jego dzieci nie zmieniają - } - return iFlags; +{ // analiza koniecznych zmian pomiędzy submodelami + // samo pomijanie glBindTexture() nie poprawi wydajności + // ale można sprawdzić, czy można w ogóle pominąć kod do tekstur (sprawdzanie replaceskin) + int i; + if (Child) + { // Child jest renderowany po danym submodelu + if (Child->TextureID) // o ile ma teksturę + if (Child->TextureID != TextureID) // i jest ona inna niż rodzica + Child->iFlags |= 0x80; // to trzeba sprawdzać, jak z teksturami jest + i = Child->FlagsCheck(); + iFlags |= 0x00FF0000 & ((i << 16) | (i) | (i >> 8)); // potomny, rodzeństwo i dzieci + if (eType == TP_TEXT) + { // wyłączenie renderowania Next dla znaków wyświetlacza tekstowego + TSubModel *p = Child; + while (p) + { + p->iFlags &= 0xC0FFFFFF; + p = p->Next; + } + } + } + if (Next) + { // Next jest renderowany po danym submodelu (kolejność odwrócona po wczytaniu T3D) + if (TextureID) // o ile dany ma teksturę + if ((TextureID != Next->TextureID) || + (i & 0x00800000)) // a ma inną albo dzieci zmieniają + iFlags |= 0x80; // to dany submodel musi sobie ją ustawiać + i = Next->FlagsCheck(); + iFlags |= 0xFF000000 & ((i << 24) | (i << 8) | (i)); // następny, kolejne i ich dzieci + // tekstury nie ustawiamy tylko wtedy, gdy jest taka sama jak Next i jego dzieci nie + // zmieniają + } + return iFlags; }; -void __fastcall TSubModel::SetRotate(float3 vNewRotateAxis,float fNewAngle) -{//obrócenie submodelu wg podanej osi (np. wskazówki w kabinie) - v_RotateAxis=vNewRotateAxis; - f_Angle=fNewAngle; - if (fNewAngle!=0.0) - {b_Anim=at_Rotate; - b_aAnim=at_Rotate; - } - iAnimOwner=iInstance; //zapamiętanie czyja jest animacja +void __fastcall TSubModel::SetRotate(float3 vNewRotateAxis, float fNewAngle) +{ // obrócenie submodelu wg podanej osi (np. wskazówki w kabinie) + v_RotateAxis = vNewRotateAxis; + f_Angle = fNewAngle; + if (fNewAngle != 0.0) + { + b_Anim = at_Rotate; + b_aAnim = at_Rotate; + } + iAnimOwner = iInstance; // zapamiętanie czyja jest animacja } void __fastcall TSubModel::SetRotateXYZ(float3 vNewAngles) -{//obrócenie submodelu o podane kąty wokół osi lokalnego układu - v_Angles=vNewAngles; - b_Anim=at_RotateXYZ; - b_aAnim=at_RotateXYZ; - iAnimOwner=iInstance; //zapamiętanie czyja jest animacja +{ // obrócenie submodelu o podane kąty wokół osi lokalnego układu + v_Angles = vNewAngles; + b_Anim = at_RotateXYZ; + b_aAnim = at_RotateXYZ; + iAnimOwner = iInstance; // zapamiętanie czyja jest animacja } void __fastcall TSubModel::SetRotateXYZ(vector3 vNewAngles) -{//obrócenie submodelu o podane kąty wokół osi lokalnego układu - v_Angles.x=vNewAngles.x; - v_Angles.y=vNewAngles.y; - v_Angles.z=vNewAngles.z; - b_Anim=at_RotateXYZ; - b_aAnim=at_RotateXYZ; - iAnimOwner=iInstance; //zapamiętanie czyja jest animacja +{ // obrócenie submodelu o podane kąty wokół osi lokalnego układu + v_Angles.x = vNewAngles.x; + v_Angles.y = vNewAngles.y; + v_Angles.z = vNewAngles.z; + b_Anim = at_RotateXYZ; + b_aAnim = at_RotateXYZ; + iAnimOwner = iInstance; // zapamiętanie czyja jest animacja } void __fastcall TSubModel::SetTranslate(float3 vNewTransVector) -{//przesunięcie submodelu (np. w kabinie) - v_TransVector=vNewTransVector; - b_Anim=at_Translate; - b_aAnim=at_Translate; - iAnimOwner=iInstance; //zapamiętanie czyja jest animacja +{ // przesunięcie submodelu (np. w kabinie) + v_TransVector = vNewTransVector; + b_Anim = at_Translate; + b_aAnim = at_Translate; + iAnimOwner = iInstance; // zapamiętanie czyja jest animacja } void __fastcall TSubModel::SetTranslate(vector3 vNewTransVector) -{//przesunięcie submodelu (np. w kabinie) - v_TransVector.x=vNewTransVector.x; - v_TransVector.y=vNewTransVector.y; - v_TransVector.z=vNewTransVector.z; - b_Anim=at_Translate; - b_aAnim=at_Translate; - iAnimOwner=iInstance; //zapamiętanie czyja jest animacja +{ // przesunięcie submodelu (np. w kabinie) + v_TransVector.x = vNewTransVector.x; + v_TransVector.y = vNewTransVector.y; + v_TransVector.z = vNewTransVector.z; + b_Anim = at_Translate; + b_aAnim = at_Translate; + iAnimOwner = iInstance; // zapamiętanie czyja jest animacja } void __fastcall TSubModel::SetRotateIK1(float3 vNewAngles) -{//obrócenie submodelu o podane kąty wokół osi lokalnego układu - v_Angles=vNewAngles; - iAnimOwner=iInstance; //zapamiętanie czyja jest animacja +{ // obrócenie submodelu o podane kąty wokół osi lokalnego układu + v_Angles = vNewAngles; + iAnimOwner = iInstance; // zapamiętanie czyja jest animacja } struct ToLower { - char operator()(char input) { return tolower(input); } + char operator()(char input) { return tolower(input); } }; -TSubModel* __fastcall TSubModel::GetFromName(AnsiString search,bool i) +TSubModel *__fastcall TSubModel::GetFromName(AnsiString search, bool i) { - return GetFromName(search.c_str(),i); + return GetFromName(search.c_str(), i); }; -TSubModel* __fastcall TSubModel::GetFromName(char *search,bool i) +TSubModel *__fastcall TSubModel::GetFromName(char *search, bool i) { - TSubModel* result; - //std::transform(search.begin(),search.end(),search.begin(),ToLower()); - //search=search.LowerCase(); - //AnsiString name=AnsiString(); - if (pName&&search) - if ((i?stricmp(pName,search):strcmp(pName,search))==0) - return this; - else - if (pName==search) - return this; //oba NULL - if (Next) - { - result=Next->GetFromName(search); - if (result) return result; - } - if (Child) - { - result=Child->GetFromName(search); - if (result) return result; - } - return NULL; + TSubModel *result; + // std::transform(search.begin(),search.end(),search.begin(),ToLower()); + // search=search.LowerCase(); + // AnsiString name=AnsiString(); + if (pName && search) + if ((i ? stricmp(pName, search) : strcmp(pName, search)) == 0) + return this; + else if (pName == search) + return this; // oba NULL + if (Next) + { + result = Next->GetFromName(search); + if (result) + return result; + } + if (Child) + { + result = Child->GetFromName(search); + if (result) + return result; + } + return NULL; }; -//WORD hbIndices[18]={3,0,1,5,4,2,1,0,4,1,5,3,2,3,5,2,4,0}; +// WORD hbIndices[18]={3,0,1,5,4,2,1,0,4,1,5,3,2,3,5,2,4,0}; void __fastcall TSubModel::RaAnimation(TAnimType a) -{//wykonanie animacji niezależnie od renderowania - switch (a) - {//korekcja położenia, jeśli submodel jest animowany - case at_Translate: //Ra: było "true" - if (iAnimOwner!=iInstance) break; //cudza animacja - glTranslatef(v_TransVector.x,v_TransVector.y,v_TransVector.z); - break; - case at_Rotate: //Ra: było "true" - if (iAnimOwner!=iInstance) break; //cudza animacja - glRotatef(f_Angle,v_RotateAxis.x,v_RotateAxis.y,v_RotateAxis.z); - break; - case at_RotateXYZ: - if (iAnimOwner!=iInstance) break; //cudza animacja - glTranslatef(v_TransVector.x,v_TransVector.y,v_TransVector.z); - glRotatef(v_Angles.x,1.0,0.0,0.0); - glRotatef(v_Angles.y,0.0,1.0,0.0); - glRotatef(v_Angles.z,0.0,0.0,1.0); - break; - case at_SecondsJump: //sekundy z przeskokiem - glRotatef(floor(GlobalTime->mr)*6.0,0.0,1.0,0.0); - break; - case at_MinutesJump: //minuty z przeskokiem - glRotatef(GlobalTime->mm*6.0,0.0,1.0,0.0); - break; - case at_HoursJump: //godziny skokowo 12h/360° - glRotatef(GlobalTime->hh*30.0*0.5,0.0,1.0,0.0); - break; - case at_Hours24Jump: //godziny skokowo 24h/360° - glRotatef(GlobalTime->hh*15.0*0.25,0.0,1.0,0.0); - break; - case at_Seconds: //sekundy płynnie - glRotatef(GlobalTime->mr*6.0,0.0,1.0,0.0); - break; - case at_Minutes: //minuty płynnie - glRotatef(GlobalTime->mm*6.0+GlobalTime->mr*0.1,0.0,1.0,0.0); - break; - case at_Hours: //godziny płynnie 12h/360° - //glRotatef(GlobalTime->hh*30.0+GlobalTime->mm*0.5+GlobalTime->mr/120.0,0.0,1.0,0.0); - glRotatef(2.0*Global::fTimeAngleDeg,0.0,1.0,0.0); - break; - case at_Hours24: //godziny płynnie 24h/360° - //glRotatef(GlobalTime->hh*15.0+GlobalTime->mm*0.25+GlobalTime->mr/240.0,0.0,1.0,0.0); - glRotatef(Global::fTimeAngleDeg,0.0,1.0,0.0); - break; - case at_Billboard: //obrót w pionie do kamery - {matrix4x4 mat; //potrzebujemy współrzędne przesunięcia środka układu współrzędnych submodelu - glGetDoublev(GL_MODELVIEW_MATRIX,mat.getArray()); //pobranie aktualnej matrycy - float3 gdzie=float3(mat[3][0],mat[3][1],mat[3][2]); //początek układu współrzędnych submodelu względem kamery - glLoadIdentity(); //macierz jedynkowa - glTranslatef(gdzie.x,gdzie.y,gdzie.z); //początek układu zostaje bez zmian - glRotated(atan2(gdzie.x,gdzie.z)*180.0/M_PI,0.0,1.0,0.0); //jedynie obracamy w pionie o kąt - } - break; - case at_Wind: //ruch pod wpływem wiatru (wiatr będziemy liczyć potem...) - glRotated(1.5*sin(M_PI*GlobalTime->mr/6.0),0.0,1.0,0.0); - break; - case at_Sky: //animacja nieba - glRotated(Global::fLatitudeDeg,1.0,0.0,0.0); //ustawienie osi OY na północ - //glRotatef(Global::fTimeAngleDeg,0.0,1.0,0.0); //obrót dobowy osi OX - glRotated(-fmod(Global::fTimeAngleDeg,360.0),0.0,1.0,0.0); //obrót dobowy osi OX - break; - case at_IK11: //ostatni element animacji szkieletowej (podudzie, stopa) - glRotatef(v_Angles.z,0.0,1.0,0.0); //obrót względem osi pionowej (azymut) - glRotatef(v_Angles.x,1.0,0.0,0.0); //obrót względem poziomu (deklinacja) - break; - case at_DigiClk: //animacja zegara cyfrowego - {//ustawienie animacji w submodelach potomnych - TSubModel *sm=ChildGet(); - do - {//pętla po submodelach potomnych i obracanie ich o kąt zależy od czasu - if (sm->pName) - {//musi mieć niepustą nazwę - if ((*sm->pName)>='0') - if ((*sm->pName)<='5') //zegarek ma 6 cyfr maksymalnie - sm->SetRotate(float3(0,1,0),-Global::fClockAngleDeg[(*sm->pName)-'0']); +{ // wykonanie animacji niezależnie od renderowania + switch (a) + { // korekcja położenia, jeśli submodel jest animowany + case at_Translate: // Ra: było "true" + if (iAnimOwner != iInstance) + break; // cudza animacja + glTranslatef(v_TransVector.x, v_TransVector.y, v_TransVector.z); + break; + case at_Rotate: // Ra: było "true" + if (iAnimOwner != iInstance) + break; // cudza animacja + glRotatef(f_Angle, v_RotateAxis.x, v_RotateAxis.y, v_RotateAxis.z); + break; + case at_RotateXYZ: + if (iAnimOwner != iInstance) + break; // cudza animacja + glTranslatef(v_TransVector.x, v_TransVector.y, v_TransVector.z); + glRotatef(v_Angles.x, 1.0, 0.0, 0.0); + glRotatef(v_Angles.y, 0.0, 1.0, 0.0); + glRotatef(v_Angles.z, 0.0, 0.0, 1.0); + break; + case at_SecondsJump: // sekundy z przeskokiem + glRotatef(floor(GlobalTime->mr) * 6.0, 0.0, 1.0, 0.0); + break; + case at_MinutesJump: // minuty z przeskokiem + glRotatef(GlobalTime->mm * 6.0, 0.0, 1.0, 0.0); + break; + case at_HoursJump: // godziny skokowo 12h/360° + glRotatef(GlobalTime->hh * 30.0 * 0.5, 0.0, 1.0, 0.0); + break; + case at_Hours24Jump: // godziny skokowo 24h/360° + glRotatef(GlobalTime->hh * 15.0 * 0.25, 0.0, 1.0, 0.0); + break; + case at_Seconds: // sekundy płynnie + glRotatef(GlobalTime->mr * 6.0, 0.0, 1.0, 0.0); + break; + case at_Minutes: // minuty płynnie + glRotatef(GlobalTime->mm * 6.0 + GlobalTime->mr * 0.1, 0.0, 1.0, 0.0); + break; + case at_Hours: // godziny płynnie 12h/360° + // glRotatef(GlobalTime->hh*30.0+GlobalTime->mm*0.5+GlobalTime->mr/120.0,0.0,1.0,0.0); + glRotatef(2.0 * Global::fTimeAngleDeg, 0.0, 1.0, 0.0); + break; + case at_Hours24: // godziny płynnie 24h/360° + // glRotatef(GlobalTime->hh*15.0+GlobalTime->mm*0.25+GlobalTime->mr/240.0,0.0,1.0,0.0); + glRotatef(Global::fTimeAngleDeg, 0.0, 1.0, 0.0); + break; + case at_Billboard: // obrót w pionie do kamery + { + matrix4x4 mat; // potrzebujemy współrzędne przesunięcia środka układu współrzędnych + // submodelu + glGetDoublev(GL_MODELVIEW_MATRIX, mat.getArray()); // pobranie aktualnej matrycy + float3 gdzie = float3(mat[3][0], mat[3][1], + mat[3][2]); // początek układu współrzędnych submodelu względem kamery + glLoadIdentity(); // macierz jedynkowa + glTranslatef(gdzie.x, gdzie.y, gdzie.z); // początek układu zostaje bez zmian + glRotated(atan2(gdzie.x, gdzie.z) * 180.0 / M_PI, 0.0, 1.0, + 0.0); // jedynie obracamy w pionie o kąt + } + break; + case at_Wind: // ruch pod wpływem wiatru (wiatr będziemy liczyć potem...) + glRotated(1.5 * sin(M_PI * GlobalTime->mr / 6.0), 0.0, 1.0, 0.0); + break; + case at_Sky: // animacja nieba + glRotated(Global::fLatitudeDeg, 1.0, 0.0, 0.0); // ustawienie osi OY na północ + // glRotatef(Global::fTimeAngleDeg,0.0,1.0,0.0); //obrót dobowy osi OX + glRotated(-fmod(Global::fTimeAngleDeg, 360.0), 0.0, 1.0, 0.0); // obrót dobowy osi OX + break; + case at_IK11: // ostatni element animacji szkieletowej (podudzie, stopa) + glRotatef(v_Angles.z, 0.0, 1.0, 0.0); // obrót względem osi pionowej (azymut) + glRotatef(v_Angles.x, 1.0, 0.0, 0.0); // obrót względem poziomu (deklinacja) + break; + case at_DigiClk: // animacja zegara cyfrowego + { // ustawienie animacji w submodelach potomnych + TSubModel *sm = ChildGet(); + do + { // pętla po submodelach potomnych i obracanie ich o kąt zależy od czasu + if (sm->pName) + { // musi mieć niepustą nazwę + if ((*sm->pName) >= '0') + if ((*sm->pName) <= '5') // zegarek ma 6 cyfr maksymalnie + sm->SetRotate(float3(0, 1, 0), -Global::fClockAngleDeg[(*sm->pName) - '0']); + } + sm = sm->NextGet(); + } while (sm); + } + break; + } + if (mAnimMatrix) // można by to dać np. do at_Translate + { + glMultMatrixf(mAnimMatrix->readArray()); + mAnimMatrix = NULL; // jak animator będzie potrzebował, to ustawi ponownie } - sm=sm->NextGet(); - } while (sm); - } - break; - } - if (mAnimMatrix) //można by to dać np. do at_Translate - {glMultMatrixf(mAnimMatrix->readArray()); - mAnimMatrix=NULL; //jak animator będzie potrzebował, to ustawi ponownie - } }; void __fastcall TSubModel::RenderDL() -{//główna procedura renderowania przez DL - if (iVisible && (fSquareDist>=fSquareMinDist) && (fSquareDistreadArray()); - if (b_Anim) RaAnimation(b_Anim); - } - if (eType= fSquareMinDist) && (fSquareDist < fSquareMaxDist)) + { + if (iFlags & 0xC000) + { + glPushMatrix(); + if (fMatrix) + glMultMatrixf(fMatrix->readArray()); + if (b_Anim) + RaAnimation(b_Anim); + } + if (eType < TP_ROTATOR) + { // renderowanie obiektów OpenGL + if (iAlpha & iFlags & 0x1F) // rysuj gdy element nieprzezroczysty + { + if (TextureID < 0) // && (ReplacableSkinId!=0)) + { // zmienialne skóry + glBindTexture(GL_TEXTURE_2D, ReplacableSkinId[-TextureID]); + // TexAlpha=!(iAlpha&1); //zmiana tylko w przypadku wymienej tekstury + } + else + glBindTexture(GL_TEXTURE_2D, TextureID); // również 0 + if (Global::fLuminance < fLight) + { + glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo + glCallList(uiDisplayList); // tylko dla siatki + glMaterialfv(GL_FRONT, GL_EMISSION, emm2); + } + else + glCallList(uiDisplayList); // tylko dla siatki + } + } + else if (eType == TP_FREESPOTLIGHT) + { // wersja DL + matrix4x4 mat; // macierz opisuje układ renderowania względem kamery + glGetDoublev(GL_MODELVIEW_MATRIX, mat.getArray()); + // kąt między kierunkiem światła a współrzędnymi kamery + vector3 gdzie = mat * vector3(0, 0, 0); // pozycja punktu świecącego względem kamery + fCosViewAngle = DotProduct(Normalize(mat * vector3(0, 0, 1) - gdzie), Normalize(gdzie)); + if (fCosViewAngle > fCosFalloffAngle) // kąt większy niż maksymalny stożek swiatła + { + double Distdimm = 1.0; + if (fCosViewAngle < fCosHotspotAngle) // zmniejszona jasność między Hotspot a + // Falloff + if (fCosFalloffAngle < fCosHotspotAngle) + Distdimm = 1.0 - + (fCosHotspotAngle - fCosViewAngle) / + (fCosHotspotAngle - fCosFalloffAngle); + glColor3f(f4Diffuse[0] * Distdimm, f4Diffuse[1] * Distdimm, + f4Diffuse[2] * Distdimm); + /* TODO: poprawic to zeby dzialalo + if (iFarAttenDecay>0) + switch (iFarAttenDecay) + { + case 1: + Distdimm=fFarDecayRadius/(1+sqrt(fSquareDist)); //dorobic od + kata + break; + case 2: + Distdimm=fFarDecayRadius/(1+fSquareDist); //dorobic od kata + break; + } + if (Distdimm>1) + Distdimm=1; + glColor3f(Diffuse[0]*Distdimm,Diffuse[1]*Distdimm,Diffuse[2]*Distdimm); + */ + // glPopMatrix(); + // return; + glCallList(uiDisplayList); // wyświetlenie warunkowe + } + } + else if (eType == TP_STARS) + { + // glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly + if (Global::fLuminance < fLight) + { + glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo + glCallList(uiDisplayList); // narysuj naraz wszystkie punkty z DL + glMaterialfv(GL_FRONT, GL_EMISSION, emm2); + } + } + if (Child != NULL) + if (iAlpha & iFlags & 0x001F0000) + Child->RenderDL(); + if (iFlags & 0xC000) + glPopMatrix(); } - else - glBindTexture(GL_TEXTURE_2D,TextureID); //również 0 - if (Global::fLuminancefCosFalloffAngle) //kąt większy niż maksymalny stożek swiatła - { - double Distdimm=1.0; - if (fCosViewAngle0) - switch (iFarAttenDecay) - { - case 1: - Distdimm=fFarDecayRadius/(1+sqrt(fSquareDist)); //dorobic od kata - break; - case 2: - Distdimm=fFarDecayRadius/(1+fSquareDist); //dorobic od kata - break; - } - if (Distdimm>1) - Distdimm=1; - glColor3f(Diffuse[0]*Distdimm,Diffuse[1]*Distdimm,Diffuse[2]*Distdimm); -*/ - // glPopMatrix(); - // return; - glCallList(uiDisplayList); //wyświetlenie warunkowe - } - } - else if (eType==TP_STARS) - { - //glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly - if (Global::fLuminanceRenderDL(); - if (iFlags&0xC000) - glPopMatrix(); - } - if (b_AnimRenderDL(); //dalsze rekurencyjnie -}; //Render + if (b_Anim < at_SecondsJump) + b_Anim = at_None; // wyłączenie animacji dla kolejnego użycia subm + if (Next) + if (iAlpha & iFlags & 0x1F000000) + Next->RenderDL(); // dalsze rekurencyjnie +}; // Render void __fastcall TSubModel::RenderAlphaDL() -{//renderowanie przezroczystych przez DL - if (iVisible && (fSquareDist>=fSquareMinDist) && (fSquareDistreadArray()); - if (b_aAnim) RaAnimation(b_aAnim); - } - if (eTypeLength(); - TSubModel *p; - char c; - if (!smLetter) - {//jeśli nie ma tablicy, to ją stworzyć; miejsce nieodpowiednie, ale tymczasowo może być - smLetter=new TSubModel*[256]; //tablica wskaźników submodeli dla wyświetlania tekstu - ZeroMemory(smLetter,256*sizeof(TSubModel*)); //wypełnianie zerami - p=Child; - while (p) - { - smLetter[*p->pName]=p; - p=p->Next; //kolejny znak - } - } - for (i=1;i<=j;++i) +{ // renderowanie przezroczystych przez DL + if (iVisible && (fSquareDist >= fSquareMinDist) && (fSquareDist < fSquareMaxDist)) { - p=smLetter[(*pasText)[i]]; //znak do wyświetlenia - if (p) - {//na razie tylko jako przezroczyste - p->RenderAlphaDL(); - if (p->fMatrix) glMultMatrixf(p->fMatrix->readArray()); //przesuwanie widoku - } + if (iFlags & 0xC000) + { + glPushMatrix(); + if (fMatrix) + glMultMatrixf(fMatrix->readArray()); + if (b_aAnim) + RaAnimation(b_aAnim); + } + if (eType < TP_ROTATOR) + { // renderowanie obiektów OpenGL + if (iAlpha & iFlags & 0x2F) // rysuj gdy element przezroczysty + { + if (TextureID < 0) // && (ReplacableSkinId!=0)) + { // zmienialne skóry + glBindTexture(GL_TEXTURE_2D, ReplacableSkinId[-TextureID]); + // TexAlpha=iAlpha&1; //zmiana tylko w przypadku wymienej tekstury + } + else + glBindTexture(GL_TEXTURE_2D, TextureID); // również 0 + if (Global::fLuminance < fLight) + { + glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo + glCallList(uiDisplayList); // tylko dla siatki + glMaterialfv(GL_FRONT, GL_EMISSION, emm2); + } + else + glCallList(uiDisplayList); // tylko dla siatki + } + } + else if (eType == TP_FREESPOTLIGHT) + { + // dorobić aureolę! + } + if (Child != NULL) + if (eType == TP_TEXT) + { // tekst renderujemy w specjalny sposób, zamiast submodeli z łańcucha Child + int i, j = pasText->Length(); + TSubModel *p; + char c; + if (!smLetter) + { // jeśli nie ma tablicy, to ją stworzyć; miejsce nieodpowiednie, ale tymczasowo + // może być + smLetter = new TSubModel *[256]; // tablica wskaźników submodeli dla + // wyświetlania tekstu + ZeroMemory(smLetter, 256 * sizeof(TSubModel *)); // wypełnianie zerami + p = Child; + while (p) + { + smLetter[*p->pName] = p; + p = p->Next; // kolejny znak + } + } + for (i = 1; i <= j; ++i) + { + p = smLetter[(*pasText)[i]]; // znak do wyświetlenia + if (p) + { // na razie tylko jako przezroczyste + p->RenderAlphaDL(); + if (p->fMatrix) + glMultMatrixf(p->fMatrix->readArray()); // przesuwanie widoku + } + } + } + else if (iAlpha & iFlags & 0x002F0000) + Child->RenderAlphaDL(); + if (iFlags & 0xC000) + glPopMatrix(); } - } - else - if (iAlpha&iFlags&0x002F0000) - Child->RenderAlphaDL(); - if (iFlags&0xC000) - glPopMatrix(); - } - if (b_aAnimRenderAlphaDL(); -}; //RenderAlpha + if (b_aAnim < at_SecondsJump) + b_aAnim = at_None; // wyłączenie animacji dla kolejnego użycia submodelu + if (Next != NULL) + if (iAlpha & iFlags & 0x2F000000) + Next->RenderAlphaDL(); +}; // RenderAlpha void __fastcall TSubModel::RenderVBO() -{//główna procedura renderowania przez VBO - if (iVisible && (fSquareDist>=fSquareMinDist) && (fSquareDistreadArray()); - if (b_Anim) RaAnimation(b_Anim); - } - if (eTypefCosFalloffAngle) //kąt większy niż maksymalny stożek swiatła - { - double Distdimm=1.0; - if (fCosViewAngle.DecayRadius -- The distance over which the decay occurs. - - if (iFarAttenDecay>0) - switch (iFarAttenDecay) - { - case 1: - Distdimm=fFarDecayRadius/(1+sqrt(fSquareDist)); //dorobic od kata - break; - case 2: - Distdimm=fFarDecayRadius/(1+fSquareDist); //dorobic od kata - break; - } - if (Distdimm>1) - Distdimm=1; - -*/ - glBindTexture(GL_TEXTURE_2D,0); //nie teksturować - //glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]); - //glColorMaterial(GL_FRONT,GL_EMISSION); - float color[4]={f4Diffuse[0]*Distdimm,f4Diffuse[1]*Distdimm,f4Diffuse[2]*Distdimm,0}; - //glColor3f(f4Diffuse[0]*Distdimm,f4Diffuse[1]*Distdimm,f4Diffuse[2]*Distdimm); - glColorMaterial(GL_FRONT,GL_EMISSION); - glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly - glColor3fv(color); //inaczej są białe - glMaterialfv(GL_FRONT,GL_EMISSION,color); - glDrawArrays(GL_POINTS,iVboPtr,iNumVerts); //narysuj wierzchołek z VBO - glEnable(GL_LIGHTING); - glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); //co ma ustawiać glColor - glMaterialfv(GL_FRONT,GL_EMISSION,emm2); //bez tego słupy się świecą - } - } - else if (eType==TP_STARS) - { - //glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly - if (Global::fLuminanceEndVBO(); //Ra: to też nie jest zbyt ładne - if (pRoot->StartColorVBO()) - {//wyświetlanie kolorowych punktów zamiast trójkątów - glBindTexture(GL_TEXTURE_2D,0); //tekstury nie ma - glColorMaterial(GL_FRONT,GL_EMISSION); - glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly - //glMaterialfv(GL_FRONT,GL_EMISSION,f4Diffuse); //zeby swiecilo na kolorowo - glDrawArrays(GL_POINTS,iVboPtr,iNumVerts); //narysuj naraz wszystkie punkty z VBO - glEnable(GL_LIGHTING); - glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); - //glMaterialfv(GL_FRONT,GL_EMISSION,emm2); - pRoot->EndVBO(); - pRoot->StartVBO(); - } - } - } -/*Ra: tu coś jest bez sensu... - else +{ // główna procedura renderowania przez VBO + if (iVisible && (fSquareDist >= fSquareMinDist) && (fSquareDist < fSquareMaxDist)) { - glBindTexture(GL_TEXTURE_2D, 0); -// if (eType==smt_FreeSpotLight) -// { -// if (iFarAttenDecay==0) -// glColor3f(Diffuse[0],Diffuse[1],Diffuse[2]); -// } -// else -//TODO: poprawic zeby dzialalo - glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]); - glColorMaterial(GL_FRONT,GL_EMISSION); - glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly - //glBegin(GL_POINTS); - glDrawArrays(GL_POINTS,iVboPtr,iNumVerts); //narysuj wierzchołek z VBO - // glVertex3f(0,0,0); - //glEnd(); - glEnable(GL_LIGHTING); - glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); - glMaterialfv(GL_FRONT,GL_EMISSION,emm2); - //glEndList(); + if (iFlags & 0xC000) + { + glPushMatrix(); + if (fMatrix) + glMultMatrixf(fMatrix->readArray()); + if (b_Anim) + RaAnimation(b_Anim); + } + if (eType < TP_ROTATOR) + { // renderowanie obiektów OpenGL + if (iAlpha & iFlags & 0x1F) // rysuj gdy element nieprzezroczysty + { + if (TextureID < 0) // && (ReplacableSkinId!=0)) + { // zmienialne skóry + glBindTexture(GL_TEXTURE_2D, ReplacableSkinId[-TextureID]); + // TexAlpha=!(iAlpha&1); //zmiana tylko w przypadku wymienej tekstury + } + else + glBindTexture(GL_TEXTURE_2D, TextureID); // również 0 + glColor3fv(f4Diffuse); // McZapkie-240702: zamiast ub + // glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,f4Diffuse); //to samo, co glColor + if (Global::fLuminance < fLight) + { + glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo + glDrawArrays(eType, iVboPtr, + iNumVerts); // narysuj naraz wszystkie trójkąty z VBO + glMaterialfv(GL_FRONT, GL_EMISSION, emm2); + } + else + glDrawArrays(eType, iVboPtr, + iNumVerts); // narysuj naraz wszystkie trójkąty z VBO + } + } + else if (eType == TP_FREESPOTLIGHT) + { // wersja VBO + matrix4x4 mat; // macierz opisuje układ renderowania względem kamery + glGetDoublev(GL_MODELVIEW_MATRIX, mat.getArray()); + // kąt między kierunkiem światła a współrzędnymi kamery + vector3 gdzie = mat * vector3(0, 0, 0); // pozycja punktu świecącego względem kamery + fCosViewAngle = DotProduct(Normalize(mat * vector3(0, 0, 1) - gdzie), Normalize(gdzie)); + if (fCosViewAngle > fCosFalloffAngle) // kąt większy niż maksymalny stożek swiatła + { + double Distdimm = 1.0; + if (fCosViewAngle < fCosHotspotAngle) // zmniejszona jasność między Hotspot a + // Falloff + if (fCosFalloffAngle < fCosHotspotAngle) + Distdimm = 1.0 - + (fCosHotspotAngle - fCosViewAngle) / + (fCosHotspotAngle - fCosFalloffAngle); + + /* TODO: poprawic to zeby dzialalo + + 2- Inverse (Applies inverse decay. The formula is luminance=R0/R, where R0 is + the radial source of the light if no attenuation is used, or the Near End + value of the light if Attenuation is used. R is the radial distance of the + illuminated surface from R0.) + + 3- Inverse Square (Applies inverse-square decay. The formula for this is (R0/R)^2. + This is actually the "real-world" decay of light, but you might find it too dim + in the world of computer graphics.) + + .DecayRadius -- The distance over which the decay occurs. + + if (iFarAttenDecay>0) + switch (iFarAttenDecay) + { + case 1: + Distdimm=fFarDecayRadius/(1+sqrt(fSquareDist)); //dorobic od + kata + break; + case 2: + Distdimm=fFarDecayRadius/(1+fSquareDist); //dorobic od kata + break; + } + if (Distdimm>1) + Distdimm=1; + + */ + glBindTexture(GL_TEXTURE_2D, 0); // nie teksturować + // glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]); + // glColorMaterial(GL_FRONT,GL_EMISSION); + float color[4] = {f4Diffuse[0] * Distdimm, f4Diffuse[1] * Distdimm, + f4Diffuse[2] * Distdimm, 0}; + // glColor3f(f4Diffuse[0]*Distdimm,f4Diffuse[1]*Distdimm,f4Diffuse[2]*Distdimm); + glColorMaterial(GL_FRONT, GL_EMISSION); + glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie blendowaly + glColor3fv(color); // inaczej są białe + glMaterialfv(GL_FRONT, GL_EMISSION, color); + glDrawArrays(GL_POINTS, iVboPtr, iNumVerts); // narysuj wierzchołek z VBO + glEnable(GL_LIGHTING); + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // co ma ustawiać glColor + glMaterialfv(GL_FRONT, GL_EMISSION, emm2); // bez tego słupy się świecą + } + } + else if (eType == TP_STARS) + { + // glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly + if (Global::fLuminance < fLight) + { // Ra: pewnie można by to zrobić lepiej, bez powtarzania StartVBO() + pRoot->EndVBO(); // Ra: to też nie jest zbyt ładne + if (pRoot->StartColorVBO()) + { // wyświetlanie kolorowych punktów zamiast trójkątów + glBindTexture(GL_TEXTURE_2D, 0); // tekstury nie ma + glColorMaterial(GL_FRONT, GL_EMISSION); + glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie blendowaly + // glMaterialfv(GL_FRONT,GL_EMISSION,f4Diffuse); //zeby swiecilo na kolorowo + glDrawArrays(GL_POINTS, iVboPtr, + iNumVerts); // narysuj naraz wszystkie punkty z VBO + glEnable(GL_LIGHTING); + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + // glMaterialfv(GL_FRONT,GL_EMISSION,emm2); + pRoot->EndVBO(); + pRoot->StartVBO(); + } + } + } + /*Ra: tu coś jest bez sensu... + else + { + glBindTexture(GL_TEXTURE_2D, 0); + // if (eType==smt_FreeSpotLight) + // { + // if (iFarAttenDecay==0) + // glColor3f(Diffuse[0],Diffuse[1],Diffuse[2]); + // } + // else + //TODO: poprawic zeby dzialalo + glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]); + glColorMaterial(GL_FRONT,GL_EMISSION); + glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly + //glBegin(GL_POINTS); + glDrawArrays(GL_POINTS,iVboPtr,iNumVerts); //narysuj wierzchołek z VBO + // glVertex3f(0,0,0); + //glEnd(); + glEnable(GL_LIGHTING); + glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); + glMaterialfv(GL_FRONT,GL_EMISSION,emm2); + //glEndList(); + } + */ + if (Child != NULL) + if (iAlpha & iFlags & 0x001F0000) + Child->RenderVBO(); + if (iFlags & 0xC000) + glPopMatrix(); } -*/ - if (Child!=NULL) - if (iAlpha&iFlags&0x001F0000) - Child->RenderVBO(); - if (iFlags&0xC000) - glPopMatrix(); - } - if (b_AnimRenderVBO(); //dalsze rekurencyjnie -}; //RaRender + if (b_Anim < at_SecondsJump) + b_Anim = at_None; // wyłączenie animacji dla kolejnego użycia submodelu + if (Next) + if (iAlpha & iFlags & 0x1F000000) + Next->RenderVBO(); // dalsze rekurencyjnie +}; // RaRender void __fastcall TSubModel::RenderAlphaVBO() -{//renderowanie przezroczystych przez VBO - if (iVisible && (fSquareDist>=fSquareMinDist) && (fSquareDistreadArray()); - if (b_aAnim) RaAnimation(b_aAnim); - } - glColor3fv(f4Diffuse); - if (eType= fSquareMinDist) && (fSquareDist < fSquareMaxDist)) + { + if (iFlags & 0xC000) + { + glPushMatrix(); // zapamiętanie matrycy + if (fMatrix) + glMultMatrixf(fMatrix->readArray()); + if (b_aAnim) + RaAnimation(b_aAnim); + } + glColor3fv(f4Diffuse); + if (eType < TP_ROTATOR) + { // renderowanie obiektów OpenGL + if (iAlpha & iFlags & 0x2F) // rysuj gdy element przezroczysty + { + if (TextureID < 0) // && (ReplacableSkinId!=0)) + { // zmienialne skory + glBindTexture(GL_TEXTURE_2D, ReplacableSkinId[-TextureID]); + // TexAlpha=iAlpha&1; //zmiana tylko w przypadku wymienej tekstury + } + else + glBindTexture(GL_TEXTURE_2D, TextureID); // również 0 + if (Global::fLuminance < fLight) + { + glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo + glDrawArrays(eType, iVboPtr, + iNumVerts); // narysuj naraz wszystkie trójkąty z VBO + glMaterialfv(GL_FRONT, GL_EMISSION, emm2); + } + else + glDrawArrays(eType, iVboPtr, + iNumVerts); // narysuj naraz wszystkie trójkąty z VBO + } + } + else if (eType == TP_FREESPOTLIGHT) + { + // dorobić aureolę! + } + if (Child) + if (iAlpha & iFlags & 0x002F0000) + Child->RenderAlphaVBO(); + if (iFlags & 0xC000) + glPopMatrix(); } - else - glBindTexture(GL_TEXTURE_2D,TextureID); //również 0 - if (Global::fLuminanceRenderAlphaVBO(); - if (iFlags&0xC000) - glPopMatrix(); - } - if (b_aAnimRenderAlphaVBO(); -}; //RaRenderAlpha + if (b_aAnim < at_SecondsJump) + b_aAnim = at_None; // wyłączenie animacji dla kolejnego użycia submodelu + if (Next) + if (iAlpha & iFlags & 0x2F000000) + Next->RenderAlphaVBO(); +}; // RaRenderAlpha //--------------------------------------------------------------------------- -void __fastcall TSubModel::RaArrayFill(CVertNormTex *Vert) -{//wypełnianie tablic VBO - if (Child) Child->RaArrayFill(Vert); - if ((eTypeRaArrayFill(Vert); +void __fastcall TSubModel::RaArrayFill(CVertNormTex *Vert) +{ // wypełnianie tablic VBO + if (Child) + Child->RaArrayFill(Vert); + if ((eType < TP_ROTATOR) || (eType == TP_STARS)) + for (int i = 0; i < iNumVerts; ++i) + { + Vert[iVboPtr + i].x = Vertices[i].Point.x; + Vert[iVboPtr + i].y = Vertices[i].Point.y; + Vert[iVboPtr + i].z = Vertices[i].Point.z; + Vert[iVboPtr + i].nx = Vertices[i].Normal.x; + Vert[iVboPtr + i].ny = Vertices[i].Normal.y; + Vert[iVboPtr + i].nz = Vertices[i].Normal.z; + Vert[iVboPtr + i].u = Vertices[i].tu; + Vert[iVboPtr + i].v = Vertices[i].tv; + } + else if (eType == TP_FREESPOTLIGHT) + Vert[iVboPtr].x = Vert[iVboPtr].y = Vert[iVboPtr].z = 0.0; + if (Next) + Next->RaArrayFill(Vert); }; void __fastcall TSubModel::Info() -{//zapisanie informacji o submodelu do obiektu pomocniczego - TSubModelInfo *info=TSubModelInfo::pTable+TSubModelInfo::iCurrent; - info->pSubModel=this; - if (fMatrix&&(iFlags&0x8000)) //ma matrycę i jest ona niejednostkowa - info->iTransform=info->iTotalTransforms++; - if (TextureID>0) - {//jeśli ma teksturę niewymienną - for (int i=0;iiCurrent;++i) - if (TextureID==info->pTable[i].pSubModel->TextureID) //porównanie z wcześniejszym - {info->iTexture=info->pTable[i].iTexture; //taki jaki już był - break; //koniec sprawdzania - } - if (info->iTexture<0) //jeśli nie znaleziono we wcześniejszych - {info->iTexture=++info->iTotalTextures; //przydzielenie numeru tekstury w pliku (od 1) - AnsiString t=AnsiString(pTexture); - if (t.SubString(t.Length()-3,4)==".tga") - t.Delete(t.Length()-3,4); - else if (t.SubString(t.Length()-3,4)==".dds") - t.Delete(t.Length()-3,4); - if (t!=AnsiString(pTexture)) - {//jeśli się zmieniło - //pName=new char[token.length()+1]; //nie ma sensu skracać tabeli - strcpy(pTexture,t.c_str()); - } - info->iTextureLen=t.Length()+1; //przygotowanie do zapisania, z zerem na końcu - } - } - else info->iTexture=TextureID; //nie ma albo wymienna - //if (asName.Length()) - if (pName) - {info->iName=info->iTotalNames++; //przydzielenie numeru nazwy w pliku (od 0) - info->iNameLen=strlen(pName)+1; //z zerem na końcu - } - ++info->iCurrent; //przejście do kolejnego obiektu pomocniczego - if (Child) - {info->iChild=info->iCurrent; - Child->Info(); - } - if (Next) - {info->iNext=info->iCurrent; - Next->Info(); - } +{ // zapisanie informacji o submodelu do obiektu pomocniczego + TSubModelInfo *info = TSubModelInfo::pTable + TSubModelInfo::iCurrent; + info->pSubModel = this; + if (fMatrix && (iFlags & 0x8000)) // ma matrycę i jest ona niejednostkowa + info->iTransform = info->iTotalTransforms++; + if (TextureID > 0) + { // jeśli ma teksturę niewymienną + for (int i = 0; i < info->iCurrent; ++i) + if (TextureID == info->pTable[i].pSubModel->TextureID) // porównanie z wcześniejszym + { + info->iTexture = info->pTable[i].iTexture; // taki jaki już był + break; // koniec sprawdzania + } + if (info->iTexture < 0) // jeśli nie znaleziono we wcześniejszych + { + info->iTexture = ++info->iTotalTextures; // przydzielenie numeru tekstury w pliku (od 1) + AnsiString t = AnsiString(pTexture); + if (t.SubString(t.Length() - 3, 4) == ".tga") + t.Delete(t.Length() - 3, 4); + else if (t.SubString(t.Length() - 3, 4) == ".dds") + t.Delete(t.Length() - 3, 4); + if (t != AnsiString(pTexture)) + { // jeśli się zmieniło + // pName=new char[token.length()+1]; //nie ma sensu skracać tabeli + strcpy(pTexture, t.c_str()); + } + info->iTextureLen = t.Length() + 1; // przygotowanie do zapisania, z zerem na końcu + } + } + else + info->iTexture = TextureID; // nie ma albo wymienna + // if (asName.Length()) + if (pName) + { + info->iName = info->iTotalNames++; // przydzielenie numeru nazwy w pliku (od 0) + info->iNameLen = strlen(pName) + 1; // z zerem na końcu + } + ++info->iCurrent; // przejście do kolejnego obiektu pomocniczego + if (Child) + { + info->iChild = info->iCurrent; + Child->Info(); + } + if (Next) + { + info->iNext = info->iCurrent; + Next->Info(); + } }; void __fastcall TSubModel::InfoSet(TSubModelInfo *info) -{//ustawienie danych wg obiektu pomocniczego do zapisania w pliku - int ile=(char*)&uiDisplayList-(char*)&eType; //ilość bajtów pomiędzy tymi zmiennymi - ZeroMemory(this,sizeof(TSubModel)); //zerowaie całości - CopyMemory(this,info->pSubModel,ile); //skopiowanie pamięci 1:1 - iTexture=info->iTexture;//numer nazwy tekstury, a nie numer w OpenGL - TextureID=info->iTexture;//numer tekstury w OpenGL - iName=info->iName; //numer nazwy w obszarze nazw - iMatrix=info->iTransform; //numer macierzy - Next=(TSubModel*)info->iNext; //numer następnego - Child=(TSubModel*)info->iChild; //numer potomnego - iFlags&=~0x200; //nie jest wczytany z tekstowego - //asTexture=asName=""; - pTexture=pName=NULL; +{ // ustawienie danych wg obiektu pomocniczego do zapisania w pliku + int ile = (char *)&uiDisplayList - (char *)&eType; // ilość bajtów pomiędzy tymi zmiennymi + ZeroMemory(this, sizeof(TSubModel)); // zerowaie całości + CopyMemory(this, info->pSubModel, ile); // skopiowanie pamięci 1:1 + iTexture = info->iTexture; // numer nazwy tekstury, a nie numer w OpenGL + TextureID = info->iTexture; // numer tekstury w OpenGL + iName = info->iName; // numer nazwy w obszarze nazw + iMatrix = info->iTransform; // numer macierzy + Next = (TSubModel *)info->iNext; // numer następnego + Child = (TSubModel *)info->iChild; // numer potomnego + iFlags &= ~0x200; // nie jest wczytany z tekstowego + // asTexture=asName=""; + pTexture = pName = NULL; }; -void __fastcall TSubModel::BinInit(TSubModel *s,float4x4 *m,float8 *v,TStringPack *t,TStringPack *n,bool dynamic) -{//ustawienie wskaźników w submodelu - iVisible=1; //tymczasowo używane - Child=((int)Child>0)?s+(int)Child:NULL; //zerowy nie może być potomnym - Next=((int)Next>0)?s+(int)Next:NULL; //zerowy nie może być następnym - fMatrix=((iMatrix>=0)&&m)?m+iMatrix:NULL; - //if (n&&(iName>=0)) asName=AnsiString(n->String(iName)); else asName=""; - if (n&&(iName>=0)) - {pName=n->String(iName); - AnsiString s=AnsiString(pName); - if (!s.IsEmpty()) - {//jeśli dany submodel jest zgaszonym światłem, to domyślnie go ukrywamy - if (s.SubString(1,8)=="Light_On") //jeśli jest światłem numerowanym - iVisible=0; //to domyślnie wyłączyć, żeby się nie nakładało z obiektem "Light_Off" - else if (dynamic) //inaczej wyłączało smugę w latarniach - if (s.SubString(s.Length()-2,3)=="_on") //jeśli jest kontrolką w stanie zapalonym - iVisible=0; //to domyślnie wyłączyć, żeby się nie nakładało z obiektem "_off" - } - } - else - pName=NULL; - if (iTexture>0) - {//obsługa stałej tekstury - //TextureID=TTexturesManager::GetTextureID(t->String(TextureID)); - //asTexture=AnsiString(t->String(iTexture)); - pTexture=t->String(iTexture); - AnsiString t=AnsiString(pTexture); - if (t.LastDelimiter("/\\")==0) - t.Insert(Global::asCurrentTexturePath,1); - TextureID=TTexturesManager::GetTextureID(szTexturePath,Global::asCurrentTexturePath.c_str(),t.c_str()); - //TexAlpha=TTexturesManager::GetAlpha(TextureID); //zmienna robocza - //ustawienie cyklu przezroczyste/nieprzezroczyste zależnie od własności stałej tekstury - //iFlags=(iFlags&~0x30)|(TTexturesManager::GetAlpha(TextureID)?0x20:0x10); //0x10-nieprzezroczysta, 0x20-przezroczysta - if (Opacity<1.0) //przezroczystość z tekstury brana tylko dla Opacity 0! - iFlags|=TTexturesManager::GetAlpha(TextureID)?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta - else - iFlags|=0x10; //normalnie nieprzezroczyste - } - b_aAnim=b_Anim; //skopiowanie animacji do drugiego cyklu - iFlags&=~0x0200; //wczytano z pliku binarnego (nie jest właścicielem tablic) - Vertices=v+iVboPtr; - //if (!iNumVerts) eType=-1; //tymczasowo zmiana typu, żeby się nie renderowało na siłę +void __fastcall TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v, TStringPack *t, + TStringPack *n, bool dynamic) +{ // ustawienie wskaźników w submodelu + iVisible = 1; // tymczasowo używane + Child = ((int)Child > 0) ? s + (int)Child : NULL; // zerowy nie może być potomnym + Next = ((int)Next > 0) ? s + (int)Next : NULL; // zerowy nie może być następnym + fMatrix = ((iMatrix >= 0) && m) ? m + iMatrix : NULL; + // if (n&&(iName>=0)) asName=AnsiString(n->String(iName)); else asName=""; + if (n && (iName >= 0)) + { + pName = n->String(iName); + AnsiString s = AnsiString(pName); + if (!s.IsEmpty()) + { // jeśli dany submodel jest zgaszonym światłem, to domyślnie go ukrywamy + if (s.SubString(1, 8) == "Light_On") // jeśli jest światłem numerowanym + iVisible = 0; // to domyślnie wyłączyć, żeby się nie nakładało z obiektem + // "Light_Off" + else if (dynamic) // inaczej wyłączało smugę w latarniach + if (s.SubString(s.Length() - 2, 3) == + "_on") // jeśli jest kontrolką w stanie zapalonym + iVisible = 0; // to domyślnie wyłączyć, żeby się nie nakładało z obiektem "_off" + } + } + else + pName = NULL; + if (iTexture > 0) + { // obsługa stałej tekstury + // TextureID=TTexturesManager::GetTextureID(t->String(TextureID)); + // asTexture=AnsiString(t->String(iTexture)); + pTexture = t->String(iTexture); + AnsiString t = AnsiString(pTexture); + if (t.LastDelimiter("/\\") == 0) + t.Insert(Global::asCurrentTexturePath, 1); + TextureID = TTexturesManager::GetTextureID(szTexturePath, + Global::asCurrentTexturePath.c_str(), t.c_str()); + // TexAlpha=TTexturesManager::GetAlpha(TextureID); //zmienna robocza + // ustawienie cyklu przezroczyste/nieprzezroczyste zależnie od własności stałej tekstury + // iFlags=(iFlags&~0x30)|(TTexturesManager::GetAlpha(TextureID)?0x20:0x10); + // //0x10-nieprzezroczysta, 0x20-przezroczysta + if (Opacity < 1.0) // przezroczystość z tekstury brana tylko dla Opacity 0! + iFlags |= TTexturesManager::GetAlpha(TextureID) ? + 0x20 : + 0x10; // 0x10-nieprzezroczysta, 0x20-przezroczysta + else + iFlags |= 0x10; // normalnie nieprzezroczyste + } + b_aAnim = b_Anim; // skopiowanie animacji do drugiego cyklu + iFlags &= ~0x0200; // wczytano z pliku binarnego (nie jest właścicielem tablic) + Vertices = v + iVboPtr; + // if (!iNumVerts) eType=-1; //tymczasowo zmiana typu, żeby się nie renderowało na siłę }; void __fastcall TSubModel::AdjustDist() -{//aktualizacja odległości faz LoD, zależna od rozdzielczości pionowej oraz multisamplingu - if (fSquareMaxDist>0.0) fSquareMaxDist*=Global::fDistanceFactor; - if (fSquareMinDist>0.0) fSquareMinDist*=Global::fDistanceFactor; - //if (fNearAttenStart>0.0) fNearAttenStart*=Global::fDistanceFactor; - //if (fNearAttenEnd>0.0) fNearAttenEnd*=Global::fDistanceFactor; - if (Child) Child->AdjustDist(); - if (Next) Next->AdjustDist(); +{ // aktualizacja odległości faz LoD, zależna od rozdzielczości pionowej oraz multisamplingu + if (fSquareMaxDist > 0.0) + fSquareMaxDist *= Global::fDistanceFactor; + if (fSquareMinDist > 0.0) + fSquareMinDist *= Global::fDistanceFactor; + // if (fNearAttenStart>0.0) fNearAttenStart*=Global::fDistanceFactor; + // if (fNearAttenEnd>0.0) fNearAttenEnd*=Global::fDistanceFactor; + if (Child) + Child->AdjustDist(); + if (Next) + Next->AdjustDist(); }; -void __fastcall TSubModel::ColorsSet(int *a,int *d,int*s) -{//ustawienie kolorów dla modelu terenu - int i; - if (a) for (i=0;i<4;++i) f4Ambient[i]=a[i]/255.0; - if (d) for (i=0;i<4;++i) f4Diffuse[i]=d[i]/255.0; - if (s) for (i=0;i<4;++i) f4Specular[i]=s[i]/255.0; +void __fastcall TSubModel::ColorsSet(int *a, int *d, int *s) +{ // ustawienie kolorów dla modelu terenu + int i; + if (a) + for (i = 0; i < 4; ++i) + f4Ambient[i] = a[i] / 255.0; + if (d) + for (i = 0; i < 4; ++i) + f4Diffuse[i] = d[i] / 255.0; + if (s) + for (i = 0; i < 4; ++i) + f4Specular[i] = s[i] / 255.0; }; void __fastcall TSubModel::ParentMatrix(float4x4 *m) -{//pobranie transformacji względem wstawienia modelu - //jeśli nie zostało wykonane Init() (tzn. zaraz po wczytaniu T3D), to dodatkowy obrót - //obrót T3D jest wymagany np. do policzenia wysokości pantografów - *m=float4x4(*fMatrix); //skopiowanie, bo będziemy mnożyć - //m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak) - TSubModel *sm=this; - while (sm->Parent) - {//przenieść tę funkcję do modelu - if (sm->Parent->GetMatrix()) - *m=*sm->Parent->GetMatrix()**m; - sm=sm->Parent; - } - //dla ostatniego może być potrzebny dodatkowy obrót, jeśli wczytano z T3D, a nie obrócono jeszcze +{ // pobranie transformacji względem wstawienia modelu + // jeśli nie zostało wykonane Init() (tzn. zaraz po wczytaniu T3D), to dodatkowy obrót + // obrót T3D jest wymagany np. do policzenia wysokości pantografów + *m = float4x4(*fMatrix); // skopiowanie, bo będziemy mnożyć + // m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak) + TSubModel *sm = this; + while (sm->Parent) + { // przenieść tę funkcję do modelu + if (sm->Parent->GetMatrix()) + *m = *sm->Parent->GetMatrix() * *m; + sm = sm->Parent; + } + // dla ostatniego może być potrzebny dodatkowy obrót, jeśli wczytano z T3D, a nie obrócono + // jeszcze }; float __fastcall TSubModel::MaxY(const float4x4 &m) -{//obliczenie maksymalnej wysokości, na początek ślizgu w pantografie - if (eType!=4) return 0; //tylko dla trójkątów liczymy - if (iNumVerts<1) return 0; - if (!Vertices) return 0; - float y,my=m[0][1]*Vertices[0].Point.x+m[1][1]*Vertices[0].Point.y+m[2][1]*Vertices[0].Point.z+m[3][1]; - for (int i=1;iChildAdd(SubModel); - } - else - {//jeśli nie znaleziony, podczepiamy do łańcucha głównego - SubModel->NextAdd(Root); //Ra: zmiana kolejności renderowania wymusza zmianę tu - Root=SubModel; - } - ++iSubModelsCount; //teraz jest o 1 submodel więcej - iFlags|=0x0200; //submodele są oddzielne +void __fastcall TModel3d::AddTo(TSubModel *tmp, TSubModel *SubModel) +{ // jedyny poprawny sposób dodawania submodeli, inaczej mogą zginąć przy zapisie E3D + if (tmp) + { // jeśli znaleziony, podłączamy mu jako potomny + tmp->ChildAdd(SubModel); + } + else + { // jeśli nie znaleziony, podczepiamy do łańcucha głównego + SubModel->NextAdd(Root); // Ra: zmiana kolejności renderowania wymusza zmianę tu + Root = SubModel; + } + ++iSubModelsCount; // teraz jest o 1 submodel więcej + iFlags |= 0x0200; // submodele są oddzielne }; -TSubModel* __fastcall TModel3d::GetFromName(const char *sName) -{//wyszukanie submodelu po nazwie - if (!sName) return Root; //potrzebne do terenu z E3D - if (iFlags&0x0200) //wczytany z pliku tekstowego, wyszukiwanie rekurencyjne - return Root?Root->GetFromName(sName):NULL; - else //wczytano z pliku binarnego, można wyszukać iteracyjnie - { - //for (int i=0;iGetFromName(sName):NULL; - } +TSubModel *__fastcall TModel3d::GetFromName(const char *sName) +{ // wyszukanie submodelu po nazwie + if (!sName) + return Root; // potrzebne do terenu z E3D + if (iFlags & 0x0200) // wczytany z pliku tekstowego, wyszukiwanie rekurencyjne + return Root ? Root->GetFromName(sName) : NULL; + else // wczytano z pliku binarnego, można wyszukać iteracyjnie + { + // for (int i=0;iGetFromName(sName) : NULL; + } }; /* @@ -1563,281 +1716,303 @@ TMaterial* __fastcall TModel3d::GetMaterialFromName(char *sName) } */ -bool __fastcall TModel3d::LoadFromFile(char *FileName,bool dynamic) -{//wczytanie modelu z pliku - AnsiString name=AnsiString(FileName).LowerCase(); - int i=name.LastDelimiter("."); - if (i) - if (name.SubString(i,name.Length()-i+1)==".t3d") - name.Delete(i,4); - asBinary=name+".e3d"; - if (FileExists(asBinary)) - {LoadFromBinFile(asBinary.c_str(),dynamic); - asBinary=""; //wyłączenie zapisu - Init(); - } - else - {if (FileExists(name+".t3d")) - {LoadFromTextFile(FileName,dynamic); //wczytanie tekstowego - if (!dynamic) //pojazdy dopiero po ustawieniu animacji - Init(); //generowanie siatek i zapis E3D - } - } - return Root?(iSubModelsCount>0):false; //brak pliku albo problem z wczytaniem -}; - -void __fastcall TModel3d::LoadFromBinFile(char *FileName,bool dynamic) -{//wczytanie modelu z pliku binarnego - WriteLog("Loading - binary model: "+AnsiString(FileName)); - int i=0,j,k,ch,size; - TFileStream *fs=new TFileStream(AnsiString(FileName),fmOpenRead); - size=fs->Size>>2; - iModel=new int[size]; //ten wskaźnik musi być w modelu, aby zwolnić pamięć - fs->Read(iModel,fs->Size); //wczytanie pliku - delete fs; - float4x4 *m=NULL; //transformy - //zestaw kromek: - while ((i<<2)>2); //początek następnej kromki - if (ch=='E3D0') //główna: 'E3D0',len,pod-kromki - {//tylko tę kromkę znamy, może kiedyś jeszcze DOF się zrobi - i+=2; - while (i>2); //długość aktualnej kromki - switch (ch) - {case 'MDL0': //zmienne modelu: 'E3D0',len,(informacje o modelu) - break; - case 'VNT0': //wierzchołki: 'VNT0',len,(32 bajty na wierzchołek) - iNumVerts=(k-2)>>3; - m_nVertexCount=iNumVerts; - m_pVNT=(CVertNormTex*)(iModel+i+2); - break; - case 'SUB0': //submodele: 'SUB0',len,(256 bajtów na submodel) - iSubModelsCount=(k-2)/64; - Root=(TSubModel*)(iModel+i+2); //numery na wskaźniki przetworzymy później - break; - case 'SUB1': //submodele: 'SUB1',len,(320 bajtów na submodel) - iSubModelsCount=(k-2)/80; - Root=(TSubModel*)(iModel+i+2); //numery na wskaźniki przetworzymy później - for (ch=1;ch>1);++ch) - *(((float*)m)+ch)=*(((double*)m)+ch); //przepisanie double do float - break; - case 'IDX1': //indeksy 1B: 'IDX2',len,(po bajcie na numer wierzchołka) - break; - case 'IDX2': //indeksy 2B: 'IDX2',len,(po 2 bajty na numer wierzchołka) - break; - case 'IDX4': //indeksy 4B: 'IDX4',len,(po 4 bajty na numer wierzchołka) - break; - case 'TEX0': //tekstury: 'TEX0',len,(łańcuchy zakończone zerem - pliki tekstur) - Textures.Init((char*)(iModel+i)); //łącznie z nagłówkiem - break; - case 'TIX0': //indeks nazw tekstur - Textures.InitIndex((int*)(iModel+i)); //łącznie z nagłówkiem - break; - case 'NAM0': //nazwy: 'NAM0',len,(łańcuchy zakończone zerem - nazwy submodeli) - Names.Init((char*)(iModel+i)); //łącznie z nagłówkiem - break; - case 'NIX0': //indeks nazw submodeli - Names.InitIndex((int*)(iModel+i)); //łącznie z nagłówkiem - break; +bool __fastcall TModel3d::LoadFromFile(char *FileName, bool dynamic) +{ // wczytanie modelu z pliku + AnsiString name = AnsiString(FileName).LowerCase(); + int i = name.LastDelimiter("."); + if (i) + if (name.SubString(i, name.Length() - i + 1) == ".t3d") + name.Delete(i, 4); + asBinary = name + ".e3d"; + if (FileExists(asBinary)) + { + LoadFromBinFile(asBinary.c_str(), dynamic); + asBinary = ""; // wyłączenie zapisu + Init(); } - i+=k; //przejście do kolejnej kromki - } - } - i=j; - } - for (i=0;iParent=Root+i; //wpisanie wskaźnika nadrzędnego do potmnego - if (Root[i].NextGet()) - Root[i].NextGet()->Parent=Root[i].Parent; //skopiowanie wskaźnika nadrzędnego do kolejnego - } - iFlags&=~0x0200; - return; + else + { + if (FileExists(name + ".t3d")) + { + LoadFromTextFile(FileName, dynamic); // wczytanie tekstowego + if (!dynamic) // pojazdy dopiero po ustawieniu animacji + Init(); // generowanie siatek i zapis E3D + } + } + return Root ? (iSubModelsCount > 0) : false; // brak pliku albo problem z wczytaniem }; -void __fastcall TModel3d::LoadFromTextFile(char *FileName,bool dynamic) -{//wczytanie submodelu z pliku tekstowego - WriteLog("Loading - text model: "+AnsiString(FileName)); - iFlags|=0x0200; //wczytano z pliku tekstowego (właścicielami tablic są submodle) - cParser parser(FileName,cParser::buffer_FILE); //Ra: tu powinno być "models\\"... - TSubModel *SubModel; - std::string token; - parser.getToken(token); - iNumVerts=0; //w konstruktorze to jest - while (token!="" || parser.eof()) - { - std::string parent; - //parser.getToken(parent); - parser.getTokens(1,false); //nazwa submodelu nadrzędnego bez zmieny na małe - parser >> parent; - if (parent=="") break; - SubModel=new TSubModel(); - iNumVerts+=SubModel->Load(parser,this,iNumVerts,dynamic); - SubModel->Parent=AddToNamed(parent.c_str(),SubModel); //będzie potrzebne do wyliczenia pozycji, np. pantografu - //iSubModelsCount++; - parser.getToken(token); - } - //Ra: od wersji 334 przechylany jest cały model, a nie tylko pierwszy submodel - //ale bujanie kabiny nadal używa bananów :( od 393 przywrócone, ale z dodatkowym warunkiem - if (Global::iConvertModels&4) - {//automatyczne banany czasem psuły przechylanie kabin... - if (dynamic&&Root) - {if (Root->NextGet()) //jeśli ma jakiekolwiek kolejne - {//dynamic musi mieć "banana", bo tylko pierwszy obiekt jest animowany, a następne nie - SubModel=new TSubModel(); //utworzenie pustego - SubModel->ChildAdd(Root); - Root=SubModel; - ++iSubModelsCount; - } - Root->WillBeAnimated(); //bo z tym jest dużo problemów - } - } +void __fastcall TModel3d::LoadFromBinFile(char *FileName, bool dynamic) +{ // wczytanie modelu z pliku binarnego + WriteLog("Loading - binary model: " + AnsiString(FileName)); + int i = 0, j, k, ch, size; + TFileStream *fs = new TFileStream(AnsiString(FileName), fmOpenRead); + size = fs->Size >> 2; + iModel = new int[size]; // ten wskaźnik musi być w modelu, aby zwolnić pamięć + fs->Read(iModel, fs->Size); // wczytanie pliku + delete fs; + float4x4 *m = NULL; // transformy + // zestaw kromek: + while ((i << 2) < size) // w pliku może być kilka modeli + { + ch = iModel[i]; // nazwa kromki + j = i + (iModel[i + 1] >> 2); // początek następnej kromki + if (ch == 'E3D0') // główna: 'E3D0',len,pod-kromki + { // tylko tę kromkę znamy, może kiedyś jeszcze DOF się zrobi + i += 2; + while (i < j) + { // przetwarzanie kromek wewnętrznych + ch = iModel[i]; // nazwa kromki + k = (iModel[i + 1] >> 2); // długość aktualnej kromki + switch (ch) + { + case 'MDL0': // zmienne modelu: 'E3D0',len,(informacje o modelu) + break; + case 'VNT0': // wierzchołki: 'VNT0',len,(32 bajty na wierzchołek) + iNumVerts = (k - 2) >> 3; + m_nVertexCount = iNumVerts; + m_pVNT = (CVertNormTex *)(iModel + i + 2); + break; + case 'SUB0': // submodele: 'SUB0',len,(256 bajtów na submodel) + iSubModelsCount = (k - 2) / 64; + Root = (TSubModel *)(iModel + i + 2); // numery na wskaźniki przetworzymy + // później + break; + case 'SUB1': // submodele: 'SUB1',len,(320 bajtów na submodel) + iSubModelsCount = (k - 2) / 80; + Root = (TSubModel *)(iModel + i + 2); // numery na wskaźniki przetworzymy + // później + for (ch = 1; ch < iSubModelsCount; + ++ch) // trzeba przesunąć bliżej, bo 256 wystarczy + MoveMemory(((char *)Root) + 256 * ch, ((char *)Root) + 320 * ch, 256); + break; + case 'TRA0': // transformy: 'TRA0',len,(64 bajty na transform) + m = (float4x4 *)(iModel + i + 2); // tabela transformów + break; + case 'TRA1': // transformy: 'TRA1',len,(128 bajtów na transform) + m = (float4x4 *)(iModel + i + 2); // tabela transformów + for (ch = 0; ch < ((k - 2) >> 1); ++ch) + *(((float *)m) + ch) = *(((double *)m) + ch); // przepisanie double do float + break; + case 'IDX1': // indeksy 1B: 'IDX2',len,(po bajcie na numer wierzchołka) + break; + case 'IDX2': // indeksy 2B: 'IDX2',len,(po 2 bajty na numer wierzchołka) + break; + case 'IDX4': // indeksy 4B: 'IDX4',len,(po 4 bajty na numer wierzchołka) + break; + case 'TEX0': // tekstury: 'TEX0',len,(łańcuchy zakończone zerem - pliki tekstur) + Textures.Init((char *)(iModel + i)); //łącznie z nagłówkiem + break; + case 'TIX0': // indeks nazw tekstur + Textures.InitIndex((int *)(iModel + i)); //łącznie z nagłówkiem + break; + case 'NAM0': // nazwy: 'NAM0',len,(łańcuchy zakończone zerem - nazwy submodeli) + Names.Init((char *)(iModel + i)); //łącznie z nagłówkiem + break; + case 'NIX0': // indeks nazw submodeli + Names.InitIndex((int *)(iModel + i)); //łącznie z nagłówkiem + break; + } + i += k; // przejście do kolejnej kromki + } + } + i = j; + } + for (i = 0; i < iSubModelsCount; ++i) + { // aktualizacja wskaźników w submodelach + Root[i].BinInit(Root, m, (float8 *)m_pVNT, &Textures, &Names, dynamic); + if (Root[i].ChildGet()) + Root[i].ChildGet()->Parent = Root + i; // wpisanie wskaźnika nadrzędnego do potmnego + if (Root[i].NextGet()) + Root[i].NextGet()->Parent = + Root[i].Parent; // skopiowanie wskaźnika nadrzędnego do kolejnego + } + iFlags &= ~0x0200; + return; +}; + +void __fastcall TModel3d::LoadFromTextFile(char *FileName, bool dynamic) +{ // wczytanie submodelu z pliku tekstowego + WriteLog("Loading - text model: " + AnsiString(FileName)); + iFlags |= 0x0200; // wczytano z pliku tekstowego (właścicielami tablic są submodle) + cParser parser(FileName, cParser::buffer_FILE); // Ra: tu powinno być "models\\"... + TSubModel *SubModel; + std::string token; + parser.getToken(token); + iNumVerts = 0; // w konstruktorze to jest + while (token != "" || parser.eof()) + { + std::string parent; + // parser.getToken(parent); + parser.getTokens(1, false); // nazwa submodelu nadrzędnego bez zmieny na małe + parser >> parent; + if (parent == "") + break; + SubModel = new TSubModel(); + iNumVerts += SubModel->Load(parser, this, iNumVerts, dynamic); + SubModel->Parent = AddToNamed( + parent.c_str(), SubModel); // będzie potrzebne do wyliczenia pozycji, np. pantografu + // iSubModelsCount++; + parser.getToken(token); + } + // Ra: od wersji 334 przechylany jest cały model, a nie tylko pierwszy submodel + // ale bujanie kabiny nadal używa bananów :( od 393 przywrócone, ale z dodatkowym warunkiem + if (Global::iConvertModels & 4) + { // automatyczne banany czasem psuły przechylanie kabin... + if (dynamic && Root) + { + if (Root->NextGet()) // jeśli ma jakiekolwiek kolejne + { // dynamic musi mieć "banana", bo tylko pierwszy obiekt jest animowany, a następne nie + SubModel = new TSubModel(); // utworzenie pustego + SubModel->ChildAdd(Root); + Root = SubModel; + ++iSubModelsCount; + } + Root->WillBeAnimated(); // bo z tym jest dużo problemów + } + } } void __fastcall TModel3d::Init() -{//obrócenie początkowe układu współrzędnych, dla pojazdów wykonywane po analizie animacji - if (iFlags&0x8000) return; //operacje zostały już wykonane - if (Root) - {if (iFlags&0x0200) //jeśli wczytano z pliku tekstowego - {//jest jakiś dziwny błąd, że obkręcany ma być tylko ostatni submodel głównego łańcucha - //TSubModel *p=Root; - //do - //{p->InitialRotate(true); //ostatniemu należy się konwersja układu współrzędnych - // p=p->NextGet(); - //} - //while (p->NextGet()) - //Root->InitialRotate(false); //a poprzednim tylko optymalizacja - Root->InitialRotate(true); //argumet określa, czy wykonać pierwotny obrót - } - iFlags|=Root->FlagsCheck()|0x8000; //flagi całego modelu - if (!asBinary.IsEmpty()) //jeśli jest podana nazwa - {if (Global::iConvertModels) //i włączony zapis - SaveToBinFile(asBinary.c_str()); //utworzy tablicę (m_pVNT) - asBinary=""; //zablokowanie powtórnego zapisu - } - if (iNumVerts) - { - if (Global::fDistanceFactor!=1.0) //trochę zaoszczędzi czasu na modelach z wieloma submocelami - Root->AdjustDist(); //aktualizacja odległości faz LoD, zależnie od rozdzielczości pionowej oraz multisamplingu - if (Global::bUseVBO) - {if (!m_pVNT) //jeśli nie ma jeszcze tablicy (wczytano z pliku tekstowego) - {//tworzenie tymczasowej tablicy z wierzchołkami całego modelu - MakeArray(iNumVerts); //tworzenie tablic dla VBO - Root->RaArrayFill(m_pVNT); //wypełnianie tablicy - BuildVBOs(); //tworzenie VBO i usuwanie tablicy z pamięci +{ // obrócenie początkowe układu współrzędnych, dla pojazdów wykonywane po analizie animacji + if (iFlags & 0x8000) + return; // operacje zostały już wykonane + if (Root) + { + if (iFlags & 0x0200) // jeśli wczytano z pliku tekstowego + { // jest jakiś dziwny błąd, że obkręcany ma być tylko ostatni submodel głównego łańcucha + // TSubModel *p=Root; + // do + //{p->InitialRotate(true); //ostatniemu należy się konwersja układu współrzędnych + // p=p->NextGet(); + //} + // while (p->NextGet()) + // Root->InitialRotate(false); //a poprzednim tylko optymalizacja + Root->InitialRotate(true); // argumet określa, czy wykonać pierwotny obrót + } + iFlags |= Root->FlagsCheck() | 0x8000; // flagi całego modelu + if (!asBinary.IsEmpty()) // jeśli jest podana nazwa + { + if (Global::iConvertModels) // i włączony zapis + SaveToBinFile(asBinary.c_str()); // utworzy tablicę (m_pVNT) + asBinary = ""; // zablokowanie powtórnego zapisu + } + if (iNumVerts) + { + if (Global::fDistanceFactor != + 1.0) // trochę zaoszczędzi czasu na modelach z wieloma submocelami + Root->AdjustDist(); // aktualizacja odległości faz LoD, zależnie od rozdzielczości + // pionowej oraz multisamplingu + if (Global::bUseVBO) + { + if (!m_pVNT) // jeśli nie ma jeszcze tablicy (wczytano z pliku tekstowego) + { // tworzenie tymczasowej tablicy z wierzchołkami całego modelu + MakeArray(iNumVerts); // tworzenie tablic dla VBO + Root->RaArrayFill(m_pVNT); // wypełnianie tablicy + BuildVBOs(); // tworzenie VBO i usuwanie tablicy z pamięci + } + else + BuildVBOs(false); // tworzenie VBO bez usuwania tablicy z pamięci + } + else + { // przygotowanie skompilowanych siatek dla DisplayLists + Root->DisplayLists(); // tworzenie skompilowanej listy dla submodelu + } + // if (Root->TextureID) //o ile ma teksturę + // Root->iFlags|=0x80; //konieczność ustawienia tekstury + } } - else - BuildVBOs(false); //tworzenie VBO bez usuwania tablicy z pamięci - } - else - {//przygotowanie skompilowanych siatek dla DisplayLists - Root->DisplayLists(); //tworzenie skompilowanej listy dla submodelu - } - //if (Root->TextureID) //o ile ma teksturę - // Root->iFlags|=0x80; //konieczność ustawienia tekstury - } - } }; void __fastcall TModel3d::SaveToBinFile(char *FileName) -{//zapis modelu binarnego - WriteLog("Saving E3D binary model."); - int i,zero=0; - TSubModelInfo *info=new TSubModelInfo[iSubModelsCount]; - info->Reset(); - Root->Info(); //zebranie informacji o submodelach - int len; //łączna długość pliku - int sub; //ilość submodeli (w bajtach) - int tra; //wielkość obszaru transformów - int vnt; //wielkość obszaru wierzchołków - int tex=0; //wielkość obszaru nazw tekstur - int nam=0; //wielkość obszaru nazw submodeli - sub=8+sizeof(TSubModel)*iSubModelsCount; - tra=info->iTotalTransforms?8+64*info->iTotalTransforms:0; - vnt=8+32*iNumVerts; - for (i=0;iasName,*asT=&roboczy->asTexture; - //roboczy->FirstInit(); //żeby delete nie usuwało czego nie powinno - TFileStream *fs=new TFileStream(AnsiString(FileName),fmCreate); - fs->Write("E3D0",4); //kromka główna - fs->Write(&len,4); - {fs->Write("SUB0",4); //dane submodeli - fs->Write(&sub,4); - for (i=0;iInfoSet(info+i); - fs->Write(roboczy,sizeof(TSubModel)); //zapis jednego submodelu - } - } - if (tra) - {//zapis transformów - fs->Write("TRA0",4); //transformy - fs->Write(&tra,4); - for (i=0;i=0) - fs->Write(info[i].pSubModel->GetMatrix(),16*4); - } - {//zapis wierzchołków - MakeArray(iNumVerts); //tworzenie tablic dla VBO - Root->RaArrayFill(m_pVNT); //wypełnianie tablicy - fs->Write("VNT0",4); //wierzchołki - fs->Write(&vnt,4); - fs->Write(m_pVNT,32*iNumVerts); - } - if (tex) //może być jeden submodel ze zmienną teksturą i nazwy nie będzie - {//zapis nazw tekstur - fs->Write("TEX0",4); //nazwy tekstur - i=(tex+3)&~3; //zaokrąglenie w górę - fs->Write(&i,4); - fs->Write(&zero,1); //ciąg o numerze zero nie jest używany, ma tylko znacznik końca - for (i=0;iWrite(info[i].pSubModel->pTexture,info[i].iTextureLen); - if ((-tex)&3) fs->Write(&zero,((-tex)&3)); //wyrównanie do wielokrotności 4 bajtów - } - if (nam) //może być jeden anonimowy submodel w modelu - {//zapis nazw submodeli - fs->Write("NAM0",4); //nazwy submodeli - i=(nam+3)&~3; //zaokrąglenie w górę - fs->Write(&i,4); - for (i=0;iWrite(info[i].pSubModel->pName,info[i].iNameLen); - if ((-nam)&3) fs->Write(&zero,((-nam)&3)); //wyrównanie do wielokrotności 4 bajtów - } - delete fs; - //roboczy->FirstInit(); //żeby delete nie usuwało czego nie powinno - //roboczy->iFlags=0; //żeby delete nie usuwało czego nie powinno - //roboczy->asName)=asN; - //&roboczy->asTexture=asT; - delete roboczy; - delete[] info; +{ // zapis modelu binarnego + WriteLog("Saving E3D binary model."); + int i, zero = 0; + TSubModelInfo *info = new TSubModelInfo[iSubModelsCount]; + info->Reset(); + Root->Info(); // zebranie informacji o submodelach + int len; //łączna długość pliku + int sub; // ilość submodeli (w bajtach) + int tra; // wielkość obszaru transformów + int vnt; // wielkość obszaru wierzchołków + int tex = 0; // wielkość obszaru nazw tekstur + int nam = 0; // wielkość obszaru nazw submodeli + sub = 8 + sizeof(TSubModel) * iSubModelsCount; + tra = info->iTotalTransforms ? 8 + 64 * info->iTotalTransforms : 0; + vnt = 8 + 32 * iNumVerts; + for (i = 0; i < iSubModelsCount; ++i) + { + tex += info[i].iTextureLen; + nam += info[i].iNameLen; + } + if (tex) + tex += 9; // 8 na nagłówek i jeden ciąg pusty (tylko znacznik końca) + if (nam) + nam += 8; + len = 8 + sub + tra + vnt + tex + ((-tex) & 3) + nam + ((-nam) & 3); + TSubModel *roboczy = new TSubModel(); // bufor używany do zapisywania + // AnsiString *asN=&roboczy->asName,*asT=&roboczy->asTexture; + // roboczy->FirstInit(); //żeby delete nie usuwało czego nie powinno + TFileStream *fs = new TFileStream(AnsiString(FileName), fmCreate); + fs->Write("E3D0", 4); // kromka główna + fs->Write(&len, 4); + { + fs->Write("SUB0", 4); // dane submodeli + fs->Write(&sub, 4); + for (i = 0; i < iSubModelsCount; ++i) + { + roboczy->InfoSet(info + i); + fs->Write(roboczy, sizeof(TSubModel)); // zapis jednego submodelu + } + } + if (tra) + { // zapis transformów + fs->Write("TRA0", 4); // transformy + fs->Write(&tra, 4); + for (i = 0; i < iSubModelsCount; ++i) + if (info[i].iTransform >= 0) + fs->Write(info[i].pSubModel->GetMatrix(), 16 * 4); + } + { // zapis wierzchołków + MakeArray(iNumVerts); // tworzenie tablic dla VBO + Root->RaArrayFill(m_pVNT); // wypełnianie tablicy + fs->Write("VNT0", 4); // wierzchołki + fs->Write(&vnt, 4); + fs->Write(m_pVNT, 32 * iNumVerts); + } + if (tex) // może być jeden submodel ze zmienną teksturą i nazwy nie będzie + { // zapis nazw tekstur + fs->Write("TEX0", 4); // nazwy tekstur + i = (tex + 3) & ~3; // zaokrąglenie w górę + fs->Write(&i, 4); + fs->Write(&zero, 1); // ciąg o numerze zero nie jest używany, ma tylko znacznik końca + for (i = 0; i < iSubModelsCount; ++i) + if (info[i].iTextureLen) + fs->Write(info[i].pSubModel->pTexture, info[i].iTextureLen); + if ((-tex) & 3) + fs->Write(&zero, ((-tex) & 3)); // wyrównanie do wielokrotności 4 bajtów + } + if (nam) // może być jeden anonimowy submodel w modelu + { // zapis nazw submodeli + fs->Write("NAM0", 4); // nazwy submodeli + i = (nam + 3) & ~3; // zaokrąglenie w górę + fs->Write(&i, 4); + for (i = 0; i < iSubModelsCount; ++i) + if (info[i].iNameLen) + fs->Write(info[i].pSubModel->pName, info[i].iNameLen); + if ((-nam) & 3) + fs->Write(&zero, ((-nam) & 3)); // wyrównanie do wielokrotności 4 bajtów + } + delete fs; + // roboczy->FirstInit(); //żeby delete nie usuwało czego nie powinno + // roboczy->iFlags=0; //żeby delete nie usuwało czego nie powinno + // roboczy->asName)=asN; + //&roboczy->asTexture=asT; + delete roboczy; + delete[] info; }; -void __fastcall TModel3d::BreakHierarhy() -{ - Error("Not implemented yet :("); -}; +void __fastcall TModel3d::BreakHierarhy() { Error("Not implemented yet :("); }; /* void __fastcall TModel3d::Render(vector3 pPosition,double fAngle,GLuint ReplacableSkinId,int iAlpha) @@ -1871,28 +2046,30 @@ void __fastcall TModel3d::Render(vector3 pPosition,double fAngle,GLuint Replacab }; */ -void __fastcall TModel3d::Render(double fSquareDistance,GLuint *ReplacableSkinId,int iAlpha) +void __fastcall TModel3d::Render(double fSquareDistance, GLuint *ReplacableSkinId, int iAlpha) { - iAlpha^=0x0F0F000F; //odwrócenie flag tekstur, aby wyłapać nieprzezroczyste - if (iAlpha&iFlags&0x1F1F001F) //czy w ogóle jest co robić w tym cyklu? - {TSubModel::fSquareDist=fSquareDistance; //zmienna globalna! - Root->ReplacableSet(ReplacableSkinId,iAlpha); - Root->RenderDL(); - } + iAlpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste + if (iAlpha & iFlags & 0x1F1F001F) // czy w ogóle jest co robić w tym cyklu? + { + TSubModel::fSquareDist = fSquareDistance; // zmienna globalna! + Root->ReplacableSet(ReplacableSkinId, iAlpha); + Root->RenderDL(); + } }; -void __fastcall TModel3d::RenderAlpha(double fSquareDistance,GLuint *ReplacableSkinId,int iAlpha) +void __fastcall TModel3d::RenderAlpha(double fSquareDistance, GLuint *ReplacableSkinId, int iAlpha) { - if (iAlpha&iFlags&0x2F2F002F) - { - TSubModel::fSquareDist=fSquareDistance; //zmienna globalna! - Root->ReplacableSet(ReplacableSkinId,iAlpha); - Root->RenderAlphaDL(); - } + if (iAlpha & iFlags & 0x2F2F002F) + { + TSubModel::fSquareDist = fSquareDistance; // zmienna globalna! + Root->ReplacableSet(ReplacableSkinId, iAlpha); + Root->RenderAlphaDL(); + } }; /* -void __fastcall TModel3d::RaRender(vector3 pPosition,double fAngle,GLuint *ReplacableSkinId,int iAlpha) +void __fastcall TModel3d::RaRender(vector3 pPosition,double fAngle,GLuint *ReplacableSkinId,int +iAlpha) { // glColor3f(1.0f,1.0f,1.0f); // glColor3f(0.0f,0.0f,0.0f); @@ -1922,35 +2099,40 @@ void __fastcall TModel3d::RaRender(vector3 pPosition,double fAngle,GLuint *Repla }; */ -void __fastcall TModel3d::RaRender(double fSquareDistance,GLuint *ReplacableSkinId,int iAlpha) -{//renderowanie specjalne, np. kabiny - iAlpha^=0x0F0F000F; //odwrócenie flag tekstur, aby wyłapać nieprzezroczyste - if (iAlpha&iFlags&0x1F1F001F) //czy w ogóle jest co robić w tym cyklu? - {TSubModel::fSquareDist=fSquareDistance; //zmienna globalna! - if (StartVBO()) - {//odwrócenie flag, aby wyłapać nieprzezroczyste - Root->ReplacableSet(ReplacableSkinId,iAlpha); - Root->pRoot=this; - Root->RenderVBO(); - EndVBO(); - } - } +void __fastcall TModel3d::RaRender(double fSquareDistance, GLuint *ReplacableSkinId, int iAlpha) +{ // renderowanie specjalne, np. kabiny + iAlpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste + if (iAlpha & iFlags & 0x1F1F001F) // czy w ogóle jest co robić w tym cyklu? + { + TSubModel::fSquareDist = fSquareDistance; // zmienna globalna! + if (StartVBO()) + { // odwrócenie flag, aby wyłapać nieprzezroczyste + Root->ReplacableSet(ReplacableSkinId, iAlpha); + Root->pRoot = this; + Root->RenderVBO(); + EndVBO(); + } + } }; -void __fastcall TModel3d::RaRenderAlpha(double fSquareDistance,GLuint *ReplacableSkinId,int iAlpha) -{//renderowanie specjalne, np. kabiny - if (iAlpha&iFlags&0x2F2F002F) //czy w ogóle jest co robić w tym cyklu? - {TSubModel::fSquareDist=fSquareDistance; //zmienna globalna! - if (StartVBO()) - {Root->ReplacableSet(ReplacableSkinId,iAlpha); - Root->RenderAlphaVBO(); - EndVBO(); - } - } +void __fastcall TModel3d::RaRenderAlpha(double fSquareDistance, GLuint *ReplacableSkinId, + int iAlpha) +{ // renderowanie specjalne, np. kabiny + if (iAlpha & iFlags & 0x2F2F002F) // czy w ogóle jest co robić w tym cyklu? + { + TSubModel::fSquareDist = fSquareDistance; // zmienna globalna! + if (StartVBO()) + { + Root->ReplacableSet(ReplacableSkinId, iAlpha); + Root->RenderAlphaVBO(); + EndVBO(); + } + } }; /* -void __fastcall TModel3d::RaRenderAlpha(vector3 pPosition,double fAngle,GLuint *ReplacableSkinId,int iAlpha) +void __fastcall TModel3d::RaRenderAlpha(vector3 pPosition,double fAngle,GLuint *ReplacableSkinId,int +iAlpha) { glPushMatrix(); glTranslatef(pPosition.x,pPosition.y,pPosition.z); @@ -1967,111 +2149,135 @@ void __fastcall TModel3d::RaRenderAlpha(vector3 pPosition,double fAngle,GLuint * */ //----------------------------------------------------------------------------- -//2011-03-16 cztery nowe funkcje renderowania z możliwością pochylania obiektów +// 2011-03-16 cztery nowe funkcje renderowania z możliwością pochylania obiektów //----------------------------------------------------------------------------- -void __fastcall TModel3d::Render(vector3 *vPosition,vector3 *vAngle,GLuint *ReplacableSkinId,int iAlpha) -{//nieprzezroczyste, Display List - glPushMatrix(); - glTranslated(vPosition->x,vPosition->y,vPosition->z); - if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0); - if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0); - if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0); - TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna globalna! - //odwrócenie flag, aby wyłapać nieprzezroczyste - Root->ReplacableSet(ReplacableSkinId,iAlpha^0x0F0F000F); - Root->RenderDL(); - glPopMatrix(); +void __fastcall TModel3d::Render(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId, + int iAlpha) +{ // nieprzezroczyste, Display List + glPushMatrix(); + glTranslated(vPosition->x, vPosition->y, vPosition->z); + if (vAngle->y != 0.0) + glRotated(vAngle->y, 0.0, 1.0, 0.0); + if (vAngle->x != 0.0) + glRotated(vAngle->x, 1.0, 0.0, 0.0); + if (vAngle->z != 0.0) + glRotated(vAngle->z, 0.0, 0.0, 1.0); + TSubModel::fSquareDist = + SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna! + // odwrócenie flag, aby wyłapać nieprzezroczyste + Root->ReplacableSet(ReplacableSkinId, iAlpha ^ 0x0F0F000F); + Root->RenderDL(); + glPopMatrix(); }; -void __fastcall TModel3d::RenderAlpha(vector3* vPosition,vector3* vAngle,GLuint *ReplacableSkinId,int iAlpha) -{//przezroczyste, Display List - glPushMatrix(); - glTranslated(vPosition->x,vPosition->y,vPosition->z); - if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0); - if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0); - if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0); - TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna globalna! - Root->ReplacableSet(ReplacableSkinId,iAlpha); - Root->RenderAlphaDL(); - glPopMatrix(); +void __fastcall TModel3d::RenderAlpha(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId, + int iAlpha) +{ // przezroczyste, Display List + glPushMatrix(); + glTranslated(vPosition->x, vPosition->y, vPosition->z); + if (vAngle->y != 0.0) + glRotated(vAngle->y, 0.0, 1.0, 0.0); + if (vAngle->x != 0.0) + glRotated(vAngle->x, 1.0, 0.0, 0.0); + if (vAngle->z != 0.0) + glRotated(vAngle->z, 0.0, 0.0, 1.0); + TSubModel::fSquareDist = + SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna! + Root->ReplacableSet(ReplacableSkinId, iAlpha); + Root->RenderAlphaDL(); + glPopMatrix(); }; -void __fastcall TModel3d::RaRender(vector3* vPosition,vector3* vAngle,GLuint *ReplacableSkinId,int iAlpha) -{//nieprzezroczyste, VBO - glPushMatrix(); - glTranslated(vPosition->x,vPosition->y,vPosition->z); - if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0); - if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0); - if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0); - TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna globalna! - if (StartVBO()) - {//odwrócenie flag, aby wyłapać nieprzezroczyste - Root->ReplacableSet(ReplacableSkinId,iAlpha^0x0F0F000F); - Root->RenderVBO(); - EndVBO(); - } - glPopMatrix(); +void __fastcall TModel3d::RaRender(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId, + int iAlpha) +{ // nieprzezroczyste, VBO + glPushMatrix(); + glTranslated(vPosition->x, vPosition->y, vPosition->z); + if (vAngle->y != 0.0) + glRotated(vAngle->y, 0.0, 1.0, 0.0); + if (vAngle->x != 0.0) + glRotated(vAngle->x, 1.0, 0.0, 0.0); + if (vAngle->z != 0.0) + glRotated(vAngle->z, 0.0, 0.0, 1.0); + TSubModel::fSquareDist = + SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna! + if (StartVBO()) + { // odwrócenie flag, aby wyłapać nieprzezroczyste + Root->ReplacableSet(ReplacableSkinId, iAlpha ^ 0x0F0F000F); + Root->RenderVBO(); + EndVBO(); + } + glPopMatrix(); }; -void __fastcall TModel3d::RaRenderAlpha(vector3* vPosition,vector3* vAngle,GLuint *ReplacableSkinId,int iAlpha) -{//przezroczyste, VBO - glPushMatrix(); - glTranslated(vPosition->x,vPosition->y,vPosition->z); - if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0); - if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0); - if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0); - TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna globalna! - if (StartVBO()) - {Root->ReplacableSet(ReplacableSkinId,iAlpha); - Root->RenderAlphaVBO(); - EndVBO(); - } - glPopMatrix(); +void __fastcall TModel3d::RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, + GLuint *ReplacableSkinId, int iAlpha) +{ // przezroczyste, VBO + glPushMatrix(); + glTranslated(vPosition->x, vPosition->y, vPosition->z); + if (vAngle->y != 0.0) + glRotated(vAngle->y, 0.0, 1.0, 0.0); + if (vAngle->x != 0.0) + glRotated(vAngle->x, 1.0, 0.0, 0.0); + if (vAngle->z != 0.0) + glRotated(vAngle->z, 0.0, 0.0, 1.0); + TSubModel::fSquareDist = + SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna! + if (StartVBO()) + { + Root->ReplacableSet(ReplacableSkinId, iAlpha); + Root->RenderAlphaVBO(); + EndVBO(); + } + glPopMatrix(); }; //----------------------------------------------------------------------------- -//2012-02 funkcje do tworzenia terenu z E3D +// 2012-02 funkcje do tworzenia terenu z E3D //----------------------------------------------------------------------------- int __fastcall TModel3d::TerrainCount() -{//zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy - int i=0; - TSubModel *r=Root; - while (r) - {r=r->NextGet(); - ++i; - } - return i; +{ // zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy + int i = 0; + TSubModel *r = Root; + while (r) + { + r = r->NextGet(); + ++i; + } + return i; }; -TSubModel* __fastcall TModel3d::TerrainSquare(int n) -{//pobieranie wskaźnika do submodelu (n) - int i=0; - TSubModel *r=Root; - while (iNextGet(); - ++i; - } - r->UnFlagNext(); //blokowanie wyświetlania po Next głównej listy - return r; +TSubModel *__fastcall TModel3d::TerrainSquare(int n) +{ // pobieranie wskaźnika do submodelu (n) + int i = 0; + TSubModel *r = Root; + while (i < n) + { + r = r->NextGet(); + ++i; + } + r->UnFlagNext(); // blokowanie wyświetlania po Next głównej listy + return r; }; void __fastcall TModel3d::TerrainRenderVBO(int n) -{//renderowanie terenu z VBO - glPushMatrix(); - //glTranslated(vPosition->x,vPosition->y,vPosition->z); - //if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0); - //if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0); - //if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0); - //TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna globalna! - if (StartVBO()) - {//odwrócenie flag, aby wyłapać nieprzezroczyste - //Root->ReplacableSet(ReplacableSkinId,iAlpha^0x0F0F000F); - TSubModel *r=Root; - while (r) - { - if (r->iVisible==n) //tylko jeśli ma być widoczny w danej ramce (problem dla 0==false) - r->RenderVBO(); //sub kolejne (Next) się nie wyrenderują - r=r->NextGet(); - } - EndVBO(); - } - glPopMatrix(); +{ // renderowanie terenu z VBO + glPushMatrix(); + // glTranslated(vPosition->x,vPosition->y,vPosition->z); + // if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0); + // if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0); + // if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0); + // TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna + // globalna! + if (StartVBO()) + { // odwrócenie flag, aby wyłapać nieprzezroczyste + // Root->ReplacableSet(ReplacableSkinId,iAlpha^0x0F0F000F); + TSubModel *r = Root; + while (r) + { + if (r->iVisible == n) // tylko jeśli ma być widoczny w danej ramce (problem dla + // 0==false) + r->RenderVBO(); // sub kolejne (Next) się nie wyrenderują + r = r->NextGet(); + } + EndVBO(); + } + glPopMatrix(); }; - diff --git a/Model3d.h b/Model3d.h index 287bd2ff..d785dc3b 100644 --- a/Model3d.h +++ b/Model3d.h @@ -11,44 +11,47 @@ using namespace Math3D; struct GLVERTEX { - vector3 Point; - vector3 Normal; - float tu,tv; + vector3 Point; + vector3 Normal; + float tu, tv; }; class TStringPack { - char *data; - //+0 - 4 bajty: typ kromki - //+4 - 4 bajty: długość łącznie z nagłówkiem - //+8 - obszar łańcuchów znakowych, każdy zakończony zerem - int *index; - //+0 - 4 bajty: typ kromki - //+4 - 4 bajty: długość łącznie z nagłówkiem - //+8 - tabela indeksów -public: - char* String(int n); - char* StringAt(int n) {return data+9+n;}; - __fastcall TStringPack() {data=NULL; index=NULL;}; - void __fastcall Init(char *d) {data=d;}; - void __fastcall InitIndex(int *i) {index=i;}; + char *data; + //+0 - 4 bajty: typ kromki + //+4 - 4 bajty: długość łącznie z nagłówkiem + //+8 - obszar łańcuchów znakowych, każdy zakończony zerem + int *index; + //+0 - 4 bajty: typ kromki + //+4 - 4 bajty: długość łącznie z nagłówkiem + //+8 - tabela indeksów + public: + char *String(int n); + char *StringAt(int n) { return data + 9 + n; }; + __fastcall TStringPack() + { + data = NULL; + index = NULL; + }; + void __fastcall Init(char *d) { data = d; }; + void __fastcall InitIndex(int *i) { index = i; }; }; class TMaterialColor { -public: - __fastcall TMaterialColor() {}; - __fastcall TMaterialColor(char V) - { - r=g=b=V; - }; - // __fastcall TMaterialColor(double R, double G, double B) + public: + __fastcall TMaterialColor(){}; + __fastcall TMaterialColor(char V) { r = g = b = V; }; + // __fastcall TMaterialColor(double R, double G, double B) __fastcall TMaterialColor(char R, char G, char B) { - r=R; g=G; b=B; + r = R; + g = G; + b = B; }; - char r,g,b; + char r, g, b; }; /* @@ -56,7 +59,8 @@ struct TMaterial { int ID; AnsiString Name; -//McZapkie-240702: lepiej uzywac wartosci float do opisu koloru bo funkcje opengl chyba tego na ogol uzywaja +//McZapkie-240702: lepiej uzywac wartosci float do opisu koloru bo funkcje opengl chyba tego na ogol +uzywaja float Ambient[4]; float Diffuse[4]; float Specular[4]; @@ -100,265 +104,298 @@ typedef enum smt_Stars //wiele punktów świetlnych } TSubModelType; */ -//Ra: specjalne typy submodeli, poza tym GL_TRIANGLES itp. -const int TP_ROTATOR=256; -const int TP_FREESPOTLIGHT=257; -const int TP_STARS=258; -const int TP_TEXT=259; +// Ra: specjalne typy submodeli, poza tym GL_TRIANGLES itp. +const int TP_ROTATOR = 256; +const int TP_FREESPOTLIGHT = 257; +const int TP_STARS = 258; +const int TP_TEXT = 259; -enum TAnimType //rodzaj animacji -{at_None, //brak - at_Rotate, //obrót względem wektora o kąt - at_RotateXYZ, //obrót względem osi o kąty - at_Translate, //przesunięcie - at_SecondsJump, //sekundy z przeskokiem - at_MinutesJump, //minuty z przeskokiem - at_HoursJump, //godziny z przeskokiem 12h/360° - at_Hours24Jump, //godziny z przeskokiem 24h/360° - at_Seconds, //sekundy płynnie - at_Minutes, //minuty płynnie - at_Hours, //godziny płynnie 12h/360° - at_Hours24, //godziny płynnie 24h/360° - at_Billboard, //obrót w pionie do kamery - at_Wind, //ruch pod wpływem wiatru - at_Sky, //animacja nieba - at_IK=0x100, //odwrotna kinematyka - submodel sterujący (np. staw skokowy) - at_IK11=0x101, //odwrotna kinematyka - submodel nadrzędny do sterowango (np. stopa) - at_IK21=0x102, //odwrotna kinematyka - submodel nadrzędny do sterowango (np. podudzie) - at_IK22=0x103, //odwrotna kinematyka - submodel nadrzędny do nadrzędnego sterowango (np. udo) - at_Digital=0x200, //dziesięciocyfrowy licznik mechaniczny (z cylindrami) - at_DigiClk=0x201, //zegar cyfrowy jako licznik na dziesięciościanach - at_Undefined=0x800000FF //animacja chwilowo nieokreślona +enum TAnimType // rodzaj animacji +{ + at_None, // brak + at_Rotate, // obrót względem wektora o kąt + at_RotateXYZ, // obrót względem osi o kąty + at_Translate, // przesunięcie + at_SecondsJump, // sekundy z przeskokiem + at_MinutesJump, // minuty z przeskokiem + at_HoursJump, // godziny z przeskokiem 12h/360° + at_Hours24Jump, // godziny z przeskokiem 24h/360° + at_Seconds, // sekundy płynnie + at_Minutes, // minuty płynnie + at_Hours, // godziny płynnie 12h/360° + at_Hours24, // godziny płynnie 24h/360° + at_Billboard, // obrót w pionie do kamery + at_Wind, // ruch pod wpływem wiatru + at_Sky, // animacja nieba + at_IK = 0x100, // odwrotna kinematyka - submodel sterujący (np. staw skokowy) + at_IK11 = 0x101, // odwrotna kinematyka - submodel nadrzędny do sterowango (np. stopa) + at_IK21 = 0x102, // odwrotna kinematyka - submodel nadrzędny do sterowango (np. podudzie) + at_IK22 = 0x103, // odwrotna kinematyka - submodel nadrzędny do nadrzędnego sterowango (np. udo) + at_Digital = 0x200, // dziesięciocyfrowy licznik mechaniczny (z cylindrami) + at_DigiClk = 0x201, // zegar cyfrowy jako licznik na dziesięciościanach + at_Undefined = 0x800000FF // animacja chwilowo nieokreślona }; class TModel3d; class TSubModelInfo; class TSubModel -{//klasa submodelu - pojedyncza siatka, punkt świetlny albo grupa punktów - //Ra: ta klasa ma mieć wielkość 256 bajtów, aby pokryła się z formatem binarnym - //Ra: nie przestawiać zmiennych, bo wczytują się z pliku binarnego! -private: - TSubModel *Next; - TSubModel *Child; - int eType; //Ra: modele binarne dają więcej możliwości niż mesh złożony z trójkątów - int iName; //numer łańcucha z nazwą submodelu, albo -1 gdy anonimowy -public: //chwilowo - TAnimType b_Anim; -private: - int iFlags; //flagi informacyjne: - //bit 0: =1 faza rysowania zależy od wymiennej tekstury 0 - //bit 1: =1 faza rysowania zależy od wymiennej tekstury 1 - //bit 2: =1 faza rysowania zależy od wymiennej tekstury 2 - //bit 3: =1 faza rysowania zależy od wymiennej tekstury 3 - //bit 4: =1 rysowany w fazie nieprzezroczystych (stała tekstura albo brak) - //bit 5: =1 rysowany w fazie przezroczystych (stała tekstura) - //bit 7: =1 ta sama tekstura, co poprzedni albo nadrzędny - //bit 8: =1 wierzchołki wyświetlane z indeksów - //bit 9: =1 wczytano z pliku tekstowego (jest właścicielem tablic) - //bit 13: =1 wystarczy przesunięcie zamiast mnożenia macierzy (trzy jedynki) - //bit 14: =1 wymagane przechowanie macierzy (animacje) - //bit 15: =1 wymagane przechowanie macierzy (transform niejedynkowy) - union - {//transform, nie każdy submodel musi mieć - float4x4 *fMatrix; //pojedyncza precyzja wystarcza - //matrix4x4 *dMatrix; //do testu macierz podwójnej precyzji - int iMatrix; //w pliku binarnym jest numer matrycy - }; - int iNumVerts; //ilość wierzchołków (1 dla FreeSpotLight) - int iVboPtr; //początek na liście wierzchołków albo indeksów - int iTexture; //numer nazwy tekstury, -1 wymienna, 0 brak - float fVisible; //próg jasności światła do załączenia submodelu - float fLight; //próg jasności światła do zadziałania selfillum - float f4Ambient[4]; - float f4Diffuse[4]; //float ze względu na glMaterialfv() - float f4Specular[4]; - float f4Emision[4]; - float fWireSize; //nie używane, ale wczytywane - float fSquareMaxDist; - float fSquareMinDist; - //McZapkie-050702: parametry dla swiatla: - float fNearAttenStart; - float fNearAttenEnd; - int bUseNearAtten; //te 3 zmienne okreslaja rysowanie aureoli wokol zrodla swiatla - int iFarAttenDecay; //ta zmienna okresla typ zaniku natezenia swiatla (0:brak, 1,2: potega 1/R) - float fFarDecayRadius; //normalizacja j.w. - float fCosFalloffAngle; //cosinus kąta stożka pod którym widać światło - float fCosHotspotAngle; //cosinus kąta stożka pod którym widać aureolę i zwiększone natężenie światła - float fCosViewAngle; //cos kata pod jakim sie teraz patrzy - //Ra: dalej są zmienne robocze, można je przestawiać z zachowaniem rozmiaru klasy - int TextureID; //numer tekstury, -1 wymienna, 0 brak - int bWire; //nie używane, ale wczytywane - //short TexAlpha; //Ra: nie używane już - GLuint uiDisplayList; //roboczy numer listy wyświetlania - float Opacity; //nie używane, ale wczytywane - //ABu: te same zmienne, ale zdublowane dla Render i RenderAlpha, - //bo sie chrzanilo przemieszczanie obiektow. - //Ra: już się nie chrzani - float f_Angle; - float3 v_RotateAxis; - float3 v_Angles; -public: //chwilowo - float3 v_TransVector; - float8 *Vertices; //roboczy wskaźnik - wczytanie T3D do VBO - int iAnimOwner; //roboczy numer egzemplarza, który ustawił animację - TAnimType b_aAnim; //kody animacji oddzielnie, bo zerowane -public: - float4x4 *mAnimMatrix; //macierz do animacji kwaternionowych (należy do AnimContainer) - char space[8]; //wolne miejsce na przyszłe zmienne (zmniejszyć w miarę potrzeby) -public: - TSubModel **smLetter; //wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D) - TSubModel *Parent; //nadrzędny, np. do wymnażania macierzy - int iVisible; //roboczy stan widoczności - //AnsiString asTexture; //robocza nazwa tekstury do zapisania w pliku binarnym - //AnsiString asName; //robocza nazwa - char *pTexture; //robocza nazwa tekstury do zapisania w pliku binarnym - char *pName; //robocza nazwa -private: - //int __fastcall SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 *pt,GLVERTEX *Vertices); - int __fastcall SeekFaceNormal(DWORD *Masks,int f,DWORD dwMask,float3 *pt,float8 *Vertices); - void __fastcall RaAnimation(TAnimType a); -public: - static int iInstance; //identyfikator egzemplarza, który aktualnie renderuje model - static GLuint *ReplacableSkinId; - static int iAlpha; //maska bitowa dla danego przebiegu - static double fSquareDist; - static TModel3d* pRoot; - static AnsiString* pasText; //tekst dla wyświetlacza (!!!! do przemyślenia) - __fastcall TSubModel(); - __fastcall ~TSubModel(); - void __fastcall FirstInit(); - int __fastcall Load(cParser& Parser, TModel3d *Model,int Pos,bool dynamic); - void __fastcall ChildAdd(TSubModel *SubModel); - void __fastcall NextAdd(TSubModel *SubModel); - TSubModel* __fastcall NextGet() {return Next;}; - TSubModel* __fastcall ChildGet() {return Child;}; - int __fastcall TriangleAdd(TModel3d *m,int tex,int tri); - float8* __fastcall TrianglePtr(int tex,int pos,int *la,int *ld,int*ls); - //float8* __fastcall TrianglePtr(const char *tex,int tri); - //void __fastcall SetRotate(vector3 vNewRotateAxis,float fNewAngle); - void __fastcall SetRotate(float3 vNewRotateAxis,float fNewAngle); - void __fastcall SetRotateXYZ(vector3 vNewAngles); - void __fastcall SetRotateXYZ(float3 vNewAngles); - void __fastcall SetTranslate(vector3 vNewTransVector); - void __fastcall SetTranslate(float3 vNewTransVector); - void __fastcall SetRotateIK1(float3 vNewAngles); - TSubModel* __fastcall GetFromName(AnsiString search,bool i=true); - TSubModel* __fastcall GetFromName(char *search,bool i=true); - void __fastcall RenderDL(); - void __fastcall RenderAlphaDL(); - void __fastcall RenderVBO(); - void __fastcall RenderAlphaVBO(); - //inline matrix4x4* __fastcall GetMatrix() {return dMatrix;}; - inline float4x4* __fastcall GetMatrix() {return fMatrix;}; - //matrix4x4* __fastcall GetTransform() {return Matrix;}; - inline void __fastcall Hide() {iVisible=0;}; - void __fastcall RaArrayFill(CVertNormTex *Vert); - //void __fastcall Render(); - int __fastcall FlagsCheck(); - void __fastcall WillBeAnimated() {if (this) iFlags|=0x4000;}; - void __fastcall InitialRotate(bool doit); - void __fastcall DisplayLists(); - void __fastcall Info(); - void __fastcall InfoSet(TSubModelInfo *info); - void __fastcall BinInit(TSubModel *s,float4x4 *m,float8 *v,TStringPack *t,TStringPack *n=NULL,bool dynamic=false); - void __fastcall ReplacableSet(GLuint *r,int a) - {ReplacableSkinId=r; iAlpha=a;}; - void __fastcall TextureNameSet(const char *n); - void __fastcall NameSet(const char *n); - //Ra: funkcje do budowania terenu z E3D - int __fastcall Flags() {return iFlags;}; - void __fastcall UnFlagNext() {iFlags&=0x00FFFFFF;}; - void __fastcall ColorsSet(int *a,int *d,int*s); - inline float3 Translation1Get() - {return fMatrix?*(fMatrix->TranslationGet())+v_TransVector:v_TransVector;} - inline float3 Translation2Get() - {return *(fMatrix->TranslationGet())+Child->Translation1Get();} - void __fastcall ParentMatrix(float4x4 *m); - float __fastcall MaxY(const float4x4 &m); - void __fastcall AdjustDist(); +{ // klasa submodelu - pojedyncza siatka, punkt świetlny albo grupa punktów + // Ra: ta klasa ma mieć wielkość 256 bajtów, aby pokryła się z formatem binarnym + // Ra: nie przestawiać zmiennych, bo wczytują się z pliku binarnego! + private: + TSubModel *Next; + TSubModel *Child; + int eType; // Ra: modele binarne dają więcej możliwości niż mesh złożony z trójkątów + int iName; // numer łańcucha z nazwą submodelu, albo -1 gdy anonimowy + public: // chwilowo + TAnimType b_Anim; + + private: + int iFlags; // flagi informacyjne: + // bit 0: =1 faza rysowania zależy od wymiennej tekstury 0 + // bit 1: =1 faza rysowania zależy od wymiennej tekstury 1 + // bit 2: =1 faza rysowania zależy od wymiennej tekstury 2 + // bit 3: =1 faza rysowania zależy od wymiennej tekstury 3 + // bit 4: =1 rysowany w fazie nieprzezroczystych (stała tekstura albo brak) + // bit 5: =1 rysowany w fazie przezroczystych (stała tekstura) + // bit 7: =1 ta sama tekstura, co poprzedni albo nadrzędny + // bit 8: =1 wierzchołki wyświetlane z indeksów + // bit 9: =1 wczytano z pliku tekstowego (jest właścicielem tablic) + // bit 13: =1 wystarczy przesunięcie zamiast mnożenia macierzy (trzy jedynki) + // bit 14: =1 wymagane przechowanie macierzy (animacje) + // bit 15: =1 wymagane przechowanie macierzy (transform niejedynkowy) + union + { // transform, nie każdy submodel musi mieć + float4x4 *fMatrix; // pojedyncza precyzja wystarcza + // matrix4x4 *dMatrix; //do testu macierz podwójnej precyzji + int iMatrix; // w pliku binarnym jest numer matrycy + }; + int iNumVerts; // ilość wierzchołków (1 dla FreeSpotLight) + int iVboPtr; // początek na liście wierzchołków albo indeksów + int iTexture; // numer nazwy tekstury, -1 wymienna, 0 brak + float fVisible; // próg jasności światła do załączenia submodelu + float fLight; // próg jasności światła do zadziałania selfillum + float f4Ambient[4]; + float f4Diffuse[4]; // float ze względu na glMaterialfv() + float f4Specular[4]; + float f4Emision[4]; + float fWireSize; // nie używane, ale wczytywane + float fSquareMaxDist; + float fSquareMinDist; + // McZapkie-050702: parametry dla swiatla: + float fNearAttenStart; + float fNearAttenEnd; + int bUseNearAtten; // te 3 zmienne okreslaja rysowanie aureoli wokol zrodla swiatla + int iFarAttenDecay; // ta zmienna okresla typ zaniku natezenia swiatla (0:brak, 1,2: potega 1/R) + float fFarDecayRadius; // normalizacja j.w. + float fCosFalloffAngle; // cosinus kąta stożka pod którym widać światło + float fCosHotspotAngle; // cosinus kąta stożka pod którym widać aureolę i zwiększone natężenie + // światła + float fCosViewAngle; // cos kata pod jakim sie teraz patrzy + // Ra: dalej są zmienne robocze, można je przestawiać z zachowaniem rozmiaru klasy + int TextureID; // numer tekstury, -1 wymienna, 0 brak + int bWire; // nie używane, ale wczytywane + // short TexAlpha; //Ra: nie używane już + GLuint uiDisplayList; // roboczy numer listy wyświetlania + float Opacity; // nie używane, ale wczytywane + // ABu: te same zmienne, ale zdublowane dla Render i RenderAlpha, + // bo sie chrzanilo przemieszczanie obiektow. + // Ra: już się nie chrzani + float f_Angle; + float3 v_RotateAxis; + float3 v_Angles; + + public: // chwilowo + float3 v_TransVector; + float8 *Vertices; // roboczy wskaźnik - wczytanie T3D do VBO + int iAnimOwner; // roboczy numer egzemplarza, który ustawił animację + TAnimType b_aAnim; // kody animacji oddzielnie, bo zerowane + public: + float4x4 *mAnimMatrix; // macierz do animacji kwaternionowych (należy do AnimContainer) + char space[8]; // wolne miejsce na przyszłe zmienne (zmniejszyć w miarę potrzeby) + public: + TSubModel ** + smLetter; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D) + TSubModel *Parent; // nadrzędny, np. do wymnażania macierzy + int iVisible; // roboczy stan widoczności + // AnsiString asTexture; //robocza nazwa tekstury do zapisania w pliku binarnym + // AnsiString asName; //robocza nazwa + char *pTexture; // robocza nazwa tekstury do zapisania w pliku binarnym + char *pName; // robocza nazwa + private: + // int __fastcall SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 *pt,GLVERTEX + // *Vertices); + int __fastcall SeekFaceNormal(DWORD *Masks, int f, DWORD dwMask, float3 *pt, float8 *Vertices); + void __fastcall RaAnimation(TAnimType a); + + public: + static int iInstance; // identyfikator egzemplarza, który aktualnie renderuje model + static GLuint *ReplacableSkinId; + static int iAlpha; // maska bitowa dla danego przebiegu + static double fSquareDist; + static TModel3d *pRoot; + static AnsiString *pasText; // tekst dla wyświetlacza (!!!! do przemyślenia) + __fastcall TSubModel(); + __fastcall ~TSubModel(); + void __fastcall FirstInit(); + int __fastcall Load(cParser &Parser, TModel3d *Model, int Pos, bool dynamic); + void __fastcall ChildAdd(TSubModel *SubModel); + void __fastcall NextAdd(TSubModel *SubModel); + TSubModel *__fastcall NextGet() { return Next; }; + TSubModel *__fastcall ChildGet() { return Child; }; + int __fastcall TriangleAdd(TModel3d *m, int tex, int tri); + float8 *__fastcall TrianglePtr(int tex, int pos, int *la, int *ld, int *ls); + // float8* __fastcall TrianglePtr(const char *tex,int tri); + // void __fastcall SetRotate(vector3 vNewRotateAxis,float fNewAngle); + void __fastcall SetRotate(float3 vNewRotateAxis, float fNewAngle); + void __fastcall SetRotateXYZ(vector3 vNewAngles); + void __fastcall SetRotateXYZ(float3 vNewAngles); + void __fastcall SetTranslate(vector3 vNewTransVector); + void __fastcall SetTranslate(float3 vNewTransVector); + void __fastcall SetRotateIK1(float3 vNewAngles); + TSubModel *__fastcall GetFromName(AnsiString search, bool i = true); + TSubModel *__fastcall GetFromName(char *search, bool i = true); + void __fastcall RenderDL(); + void __fastcall RenderAlphaDL(); + void __fastcall RenderVBO(); + void __fastcall RenderAlphaVBO(); + // inline matrix4x4* __fastcall GetMatrix() {return dMatrix;}; + inline float4x4 *__fastcall GetMatrix() { return fMatrix; }; + // matrix4x4* __fastcall GetTransform() {return Matrix;}; + inline void __fastcall Hide() { iVisible = 0; }; + void __fastcall RaArrayFill(CVertNormTex *Vert); + // void __fastcall Render(); + int __fastcall FlagsCheck(); + void __fastcall WillBeAnimated() + { + if (this) + iFlags |= 0x4000; + }; + void __fastcall InitialRotate(bool doit); + void __fastcall DisplayLists(); + void __fastcall Info(); + void __fastcall InfoSet(TSubModelInfo *info); + void __fastcall BinInit(TSubModel *s, float4x4 *m, float8 *v, TStringPack *t, + TStringPack *n = NULL, bool dynamic = false); + void __fastcall ReplacableSet(GLuint *r, int a) + { + ReplacableSkinId = r; + iAlpha = a; + }; + void __fastcall TextureNameSet(const char *n); + void __fastcall NameSet(const char *n); + // Ra: funkcje do budowania terenu z E3D + int __fastcall Flags() { return iFlags; }; + void __fastcall UnFlagNext() { iFlags &= 0x00FFFFFF; }; + void __fastcall ColorsSet(int *a, int *d, int *s); + inline float3 Translation1Get() + { + return fMatrix ? *(fMatrix->TranslationGet()) + v_TransVector : v_TransVector; + } + inline float3 Translation2Get() + { + return *(fMatrix->TranslationGet()) + Child->Translation1Get(); + } + void __fastcall ParentMatrix(float4x4 *m); + float __fastcall MaxY(const float4x4 &m); + void __fastcall AdjustDist(); }; class TSubModelInfo -{//klasa z informacjami o submodelach, do tworzenia pliku binarnego -public: - TSubModel *pSubModel; //wskaźnik na submodel - int iTransform; //numer transformu (-1 gdy brak) - int iName; //numer nazwy - int iTexture; //numer tekstury - int iNameLen; //długość nazwy - int iTextureLen; //długość tekstury - int iNext,iChild; //numer następnego i potomnego - static int iTotalTransforms; //ilość transformów - static int iTotalNames; //ilość nazw - static int iTotalTextures; //ilość tekstur - static int iCurrent; //aktualny obiekt - static TSubModelInfo* pTable; //tabele obiektów pomocniczych - __fastcall TSubModelInfo() - {pSubModel=NULL; - iTransform=iName=iTexture=iNext=iChild=-1; //nie ma - iNameLen=iTextureLen=0; - } - void __fastcall Reset() - {pTable=this; //ustawienie wskaźnika tabeli obiektów - iTotalTransforms=iTotalNames=iTotalTextures=iCurrent=0; //zerowanie liczników - } - __fastcall ~TSubModelInfo() {}; +{ // klasa z informacjami o submodelach, do tworzenia pliku binarnego + public: + TSubModel *pSubModel; // wskaźnik na submodel + int iTransform; // numer transformu (-1 gdy brak) + int iName; // numer nazwy + int iTexture; // numer tekstury + int iNameLen; // długość nazwy + int iTextureLen; // długość tekstury + int iNext, iChild; // numer następnego i potomnego + static int iTotalTransforms; // ilość transformów + static int iTotalNames; // ilość nazw + static int iTotalTextures; // ilość tekstur + static int iCurrent; // aktualny obiekt + static TSubModelInfo *pTable; // tabele obiektów pomocniczych + __fastcall TSubModelInfo() + { + pSubModel = NULL; + iTransform = iName = iTexture = iNext = iChild = -1; // nie ma + iNameLen = iTextureLen = 0; + } + void __fastcall Reset() + { + pTable = this; // ustawienie wskaźnika tabeli obiektów + iTotalTransforms = iTotalNames = iTotalTextures = iCurrent = 0; // zerowanie liczników + } + __fastcall ~TSubModelInfo(){}; }; class TModel3d : public CMesh { -private: - //TMaterial *Materials; - //int MaterialsCount; //Ra: nie używane - //bool TractionPart; //Ra: nie używane - TSubModel *Root; //drzewo submodeli - int iFlags; //Ra: czy submodele mają przezroczyste tekstury -public: //Ra: tymczasowo - int iNumVerts; //ilość wierzchołków (gdy nie ma VBO, to m_nVertexCount=0) -private: - TStringPack Textures; //nazwy tekstur - TStringPack Names; //nazwy submodeli - int *iModel; //zawartość pliku binarnego - int iSubModelsCount; //Ra: używane do tworzenia binarnych - AnsiString asBinary; //nazwa pod którą zapisać model binarny -public: - inline TSubModel* __fastcall GetSMRoot() {return(Root);}; - //double Radius; //Ra: nie używane - __fastcall TModel3d(); - __fastcall TModel3d(char *FileName); - __fastcall ~TModel3d(); - TSubModel* __fastcall GetFromName(const char *sName); - //TMaterial* __fastcall GetMaterialFromName(char *sName); - TSubModel* __fastcall AddToNamed(const char *Name, TSubModel *SubModel); - void __fastcall AddTo(TSubModel *tmp,TSubModel *SubModel); - void __fastcall LoadFromTextFile(char *FileName,bool dynamic); - void __fastcall LoadFromBinFile(char *FileName,bool dynamic); - bool __fastcall LoadFromFile(char *FileName,bool dynamic); - void __fastcall SaveToBinFile(char *FileName); - void __fastcall BreakHierarhy(); - //renderowanie specjalne - void __fastcall Render(double fSquareDistance,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - void __fastcall RenderAlpha(double fSquareDistance,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - void __fastcall RaRender(double fSquareDistance,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - void __fastcall RaRenderAlpha(double fSquareDistance,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - //jeden kąt obrotu - void __fastcall Render(vector3 pPosition,double fAngle=0,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - void __fastcall RenderAlpha(vector3 pPosition,double fAngle=0,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - void __fastcall RaRender(vector3 pPosition,double fAngle=0,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - void __fastcall RaRenderAlpha(vector3 pPosition,double fAngle=0,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - //trzy kąty obrotu - void __fastcall Render(vector3* vPosition,vector3* vAngle,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - void __fastcall RenderAlpha(vector3* vPosition,vector3* vAngle,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - void __fastcall RaRender(vector3* vPosition,vector3* vAngle,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - void __fastcall RaRenderAlpha(vector3* vPosition,vector3* vAngle,GLuint *ReplacableSkinId=NULL,int iAlpha=0x30300030); - //inline int __fastcall GetSubModelsCount() { return (SubModelsCount); }; - int __fastcall Flags() {return iFlags;}; - void __fastcall Init(); - char* __fastcall NameGet() {return Root?Root->pName:NULL;}; - int __fastcall TerrainCount(); - TSubModel* __fastcall TerrainSquare(int n); - void __fastcall TerrainRenderVBO(int n); + private: + // TMaterial *Materials; + // int MaterialsCount; //Ra: nie używane + // bool TractionPart; //Ra: nie używane + TSubModel *Root; // drzewo submodeli + int iFlags; // Ra: czy submodele mają przezroczyste tekstury + public: // Ra: tymczasowo + int iNumVerts; // ilość wierzchołków (gdy nie ma VBO, to m_nVertexCount=0) + private: + TStringPack Textures; // nazwy tekstur + TStringPack Names; // nazwy submodeli + int *iModel; // zawartość pliku binarnego + int iSubModelsCount; // Ra: używane do tworzenia binarnych + AnsiString asBinary; // nazwa pod którą zapisać model binarny + public: + inline TSubModel *__fastcall GetSMRoot() { return (Root); }; + // double Radius; //Ra: nie używane + __fastcall TModel3d(); + __fastcall TModel3d(char *FileName); + __fastcall ~TModel3d(); + TSubModel *__fastcall GetFromName(const char *sName); + // TMaterial* __fastcall GetMaterialFromName(char *sName); + TSubModel *__fastcall AddToNamed(const char *Name, TSubModel *SubModel); + void __fastcall AddTo(TSubModel *tmp, TSubModel *SubModel); + void __fastcall LoadFromTextFile(char *FileName, bool dynamic); + void __fastcall LoadFromBinFile(char *FileName, bool dynamic); + bool __fastcall LoadFromFile(char *FileName, bool dynamic); + void __fastcall SaveToBinFile(char *FileName); + void __fastcall BreakHierarhy(); + // renderowanie specjalne + void __fastcall Render(double fSquareDistance, GLuint *ReplacableSkinId = NULL, + int iAlpha = 0x30300030); + void __fastcall RenderAlpha(double fSquareDistance, GLuint *ReplacableSkinId = NULL, + int iAlpha = 0x30300030); + void __fastcall RaRender(double fSquareDistance, GLuint *ReplacableSkinId = NULL, + int iAlpha = 0x30300030); + void __fastcall RaRenderAlpha(double fSquareDistance, GLuint *ReplacableSkinId = NULL, + int iAlpha = 0x30300030); + // jeden kąt obrotu + void __fastcall Render(vector3 pPosition, double fAngle = 0, GLuint *ReplacableSkinId = NULL, + int iAlpha = 0x30300030); + void __fastcall RenderAlpha(vector3 pPosition, double fAngle = 0, + GLuint *ReplacableSkinId = NULL, int iAlpha = 0x30300030); + void __fastcall RaRender(vector3 pPosition, double fAngle = 0, GLuint *ReplacableSkinId = NULL, + int iAlpha = 0x30300030); + void __fastcall RaRenderAlpha(vector3 pPosition, double fAngle = 0, + GLuint *ReplacableSkinId = NULL, int iAlpha = 0x30300030); + // trzy kąty obrotu + void __fastcall Render(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId = NULL, + int iAlpha = 0x30300030); + void __fastcall RenderAlpha(vector3 *vPosition, vector3 *vAngle, + GLuint *ReplacableSkinId = NULL, int iAlpha = 0x30300030); + void __fastcall RaRender(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId = NULL, + int iAlpha = 0x30300030); + void __fastcall RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, + GLuint *ReplacableSkinId = NULL, int iAlpha = 0x30300030); + // inline int __fastcall GetSubModelsCount() { return (SubModelsCount); }; + int __fastcall Flags() { return iFlags; }; + void __fastcall Init(); + char *__fastcall NameGet() { return Root ? Root->pName : NULL; }; + int __fastcall TerrainCount(); + TSubModel *__fastcall TerrainSquare(int n); + void __fastcall TerrainRenderVBO(int n); }; //--------------------------------------------------------------------------- diff --git a/Mover.cpp b/Mover.cpp index 8cb7811d..74dee9bf 100644 --- a/Mover.cpp +++ b/Mover.cpp @@ -7,367 +7,425 @@ // Jeśli jakieś zmienne nie są używane w mover.pas, też można je przenosić. // Przeniesienie wszystkiego na raz zrobiło by zbyt wielki chaos do ogarnięcia. -const dEpsilon=0.01; //1cm (zależy od typu sprzęgu...) +const dEpsilon = 0.01; // 1cm (zależy od typu sprzęgu...) -__fastcall TMoverParameters::TMoverParameters(double VelInitial,AnsiString TypeNameInit,AnsiString NameInit, - int LoadInitial,AnsiString LoadTypeInitial,int Cab) - : T_MoverParameters(VelInitial,TypeNameInit,NameInit,LoadInitial,LoadTypeInitial,Cab) -{//główny konstruktor - DimHalf.x=0.5*Dim.W; //połowa szerokości, OX jest w bok? - DimHalf.y=0.5*Dim.L; //połowa długości, OY jest do przodu? - DimHalf.z=0.5*Dim.H; //połowa wysokości, OZ jest w górę? - //BrakeLevelSet(-2); //Pascal ustawia na 0, przestawimy na odcięcie (CHK jest jeszcze nie wczytane!) - bPantKurek3=true; //domyślnie zbiornik pantografu połączony jest ze zbiornikiem głównym - iProblem=0; //pojazd w pełni gotowy do ruchu - iLights[0]=iLights[1]=0; //światła zgaszone +__fastcall TMoverParameters::TMoverParameters(double VelInitial, AnsiString TypeNameInit, + AnsiString NameInit, int LoadInitial, + AnsiString LoadTypeInitial, int Cab) + : T_MoverParameters(VelInitial, TypeNameInit, NameInit, LoadInitial, LoadTypeInitial, Cab) +{ // główny konstruktor + DimHalf.x = 0.5 * Dim.W; // połowa szerokości, OX jest w bok? + DimHalf.y = 0.5 * Dim.L; // połowa długości, OY jest do przodu? + DimHalf.z = 0.5 * Dim.H; // połowa wysokości, OZ jest w górę? + // BrakeLevelSet(-2); //Pascal ustawia na 0, przestawimy na odcięcie (CHK jest jeszcze nie + // wczytane!) + bPantKurek3 = true; // domyślnie zbiornik pantografu połączony jest ze zbiornikiem głównym + iProblem = 0; // pojazd w pełni gotowy do ruchu + iLights[0] = iLights[1] = 0; //światła zgaszone }; - -double __fastcall TMoverParameters::Distance(const TLocation &Loc1,const TLocation &Loc2,const TDimension &Dim1,const TDimension &Dim2) -{//zwraca odległość pomiędzy pojazdami (Loc1) i (Loc2) z uwzględnieneim ich długości (kule!) - return hypot(Loc2.X-Loc1.X,Loc1.Y-Loc2.Y)-0.5*(Dim2.L+Dim1.L); +double __fastcall TMoverParameters::Distance(const TLocation &Loc1, const TLocation &Loc2, + const TDimension &Dim1, const TDimension &Dim2) +{ // zwraca odległość pomiędzy pojazdami (Loc1) i (Loc2) z uwzględnieneim ich długości (kule!) + return hypot(Loc2.X - Loc1.X, Loc1.Y - Loc2.Y) - 0.5 * (Dim2.L + Dim1.L); }; -double __fastcall TMoverParameters::Distance(const vector3 &s1, const vector3 &s2, const vector3 &d1, const vector3 &d2) -{//obliczenie odległości prostopadłościanów o środkach (s1) i (s2) i wymiarach (d1) i (d2) - //return 0.0; //będzie zgłaszać warning - funkcja do usunięcia, chyba że się przyda... +double __fastcall TMoverParameters::Distance(const vector3 &s1, const vector3 &s2, + const vector3 &d1, const vector3 &d2){ + // obliczenie odległości prostopadłościanów o środkach (s1) i (s2) i wymiarach (d1) i (d2) + // return 0.0; //będzie zgłaszać warning - funkcja do usunięcia, chyba że się przyda... }; double __fastcall TMoverParameters::CouplerDist(Byte Coupler) -{//obliczenie odległości pomiędzy sprzęgami (kula!) - return Couplers[Coupler].CoupleDist=Distance(Loc,Couplers[Coupler].Connected->Loc,Dim,Couplers[Coupler].Connected->Dim); //odległość pomiędzy sprzęgami (kula!) +{ // obliczenie odległości pomiędzy sprzęgami (kula!) + return Couplers[Coupler].CoupleDist = + Distance(Loc, Couplers[Coupler].Connected->Loc, Dim, + Couplers[Coupler].Connected->Dim); // odległość pomiędzy sprzęgami (kula!) }; -bool __fastcall TMoverParameters::Attach(Byte ConnectNo,Byte ConnectToNr,TMoverParameters *ConnectTo,Byte CouplingType,bool Forced) -{//łączenie do swojego sprzęgu (ConnectNo) pojazdu (ConnectTo) stroną (ConnectToNr) - //Ra: zwykle wykonywane dwukrotnie, dla każdego pojazdu oddzielnie - //Ra: trzeba by odróżnić wymóg dociśnięcia od uszkodzenia sprzęgu przy podczepianiu AI do składu - if (ConnectTo) //jeśli nie pusty - { - if (ConnectToNr!=2) Couplers[ConnectNo].ConnectedNr=ConnectToNr; //2=nic nie podłączone - TCouplerType ct=ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].CouplerType; //typ sprzęgu podłączanego pojazdu - Couplers[ConnectNo].Connected=ConnectTo; //tak podpiąć (do siebie) zawsze można, najwyżej będzie wirtualny - CouplerDist(ConnectNo); //przeliczenie odległości pomiędzy sprzęgami - if (CouplingType==ctrain_virtual) return false; //wirtualny więcej nic nie robi - if (Forced?true:((Couplers[ConnectNo].CoupleDist<=dEpsilon)&&(Couplers[ConnectNo].CouplerType!=NoCoupler)&&(Couplers[ConnectNo].CouplerType==ct))) - {//stykaja sie zderzaki i kompatybilne typy sprzegow, chyba że łączenie na starcie - if (Couplers[ConnectNo].CouplingFlag==ctrain_virtual) //jeśli wcześniej nie było połączone - {//ustalenie z której strony rysować sprzęg - Couplers[ConnectNo].Render=true; //tego rysować - ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].Render=false; //a tego nie - }; - Couplers[ConnectNo].CouplingFlag=CouplingType; //ustawienie typu sprzęgu - //if (CouplingType!=ctrain_virtual) //Ra: wirtualnego nie łączymy zwrotnie! - //{//jeśli łączenie sprzęgiem niewirtualnym, ustawiamy połączenie zwrotne - ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag=CouplingType; - ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].Connected=this; - ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].CoupleDist=Couplers[ConnectNo].CoupleDist; - return true; - //} - //podłączenie nie udało się - jest wirtualne - } - } - return false; //brak podłączanego pojazdu, zbyt duża odległość, niezgodny typ sprzęgu, brak sprzęgu, brak haka +bool __fastcall TMoverParameters::Attach(Byte ConnectNo, Byte ConnectToNr, + TMoverParameters *ConnectTo, Byte CouplingType, + bool Forced) +{ //łączenie do swojego sprzęgu (ConnectNo) pojazdu (ConnectTo) stroną (ConnectToNr) + // Ra: zwykle wykonywane dwukrotnie, dla każdego pojazdu oddzielnie + // Ra: trzeba by odróżnić wymóg dociśnięcia od uszkodzenia sprzęgu przy podczepianiu AI do + // składu + if (ConnectTo) // jeśli nie pusty + { + if (ConnectToNr != 2) + Couplers[ConnectNo].ConnectedNr = ConnectToNr; // 2=nic nie podłączone + TCouplerType ct = ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr] + .CouplerType; // typ sprzęgu podłączanego pojazdu + Couplers[ConnectNo].Connected = + ConnectTo; // tak podpiąć (do siebie) zawsze można, najwyżej będzie wirtualny + CouplerDist(ConnectNo); // przeliczenie odległości pomiędzy sprzęgami + if (CouplingType == ctrain_virtual) + return false; // wirtualny więcej nic nie robi + if (Forced ? true : ((Couplers[ConnectNo].CoupleDist <= dEpsilon) && + (Couplers[ConnectNo].CouplerType != NoCoupler) && + (Couplers[ConnectNo].CouplerType == ct))) + { // stykaja sie zderzaki i kompatybilne typy sprzegow, chyba że łączenie na starcie + if (Couplers[ConnectNo].CouplingFlag == + ctrain_virtual) // jeśli wcześniej nie było połączone + { // ustalenie z której strony rysować sprzęg + Couplers[ConnectNo].Render = true; // tego rysować + ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].Render = false; // a tego nie + }; + Couplers[ConnectNo].CouplingFlag = CouplingType; // ustawienie typu sprzęgu + // if (CouplingType!=ctrain_virtual) //Ra: wirtualnego nie łączymy zwrotnie! + //{//jeśli łączenie sprzęgiem niewirtualnym, ustawiamy połączenie zwrotne + ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag = CouplingType; + ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].Connected = this; + ConnectTo->Couplers[Couplers[ConnectNo].ConnectedNr].CoupleDist = + Couplers[ConnectNo].CoupleDist; + return true; + //} + // podłączenie nie udało się - jest wirtualne + } + } + return false; // brak podłączanego pojazdu, zbyt duża odległość, niezgodny typ sprzęgu, brak + // sprzęgu, brak haka }; -bool __fastcall TMoverParameters::Attach(Byte ConnectNo,Byte ConnectToNr,T_MoverParameters *ConnectTo,Byte CouplingType,bool Forced) -{//łączenie do (ConnectNo) pojazdu (ConnectTo) stroną (ConnectToNr) - return Attach(ConnectNo,ConnectToNr,(TMoverParameters*)ConnectTo,CouplingType,Forced); +bool __fastcall TMoverParameters::Attach(Byte ConnectNo, Byte ConnectToNr, + T_MoverParameters *ConnectTo, Byte CouplingType, + bool Forced) +{ //łączenie do (ConnectNo) pojazdu (ConnectTo) stroną (ConnectToNr) + return Attach(ConnectNo, ConnectToNr, (TMoverParameters *)ConnectTo, CouplingType, Forced); }; int __fastcall TMoverParameters::DettachStatus(Byte ConnectNo) -{//Ra: sprawdzenie, czy odległość jest dobra do rozłączania - //powinny być 3 informacje: =0 sprzęg już rozłączony, <0 da się rozłączyć. >0 nie da się rozłączyć - if (!Couplers[ConnectNo].Connected) - return 0; //nie ma nic, to rozłączanie jest OK - if ((Couplers[ConnectNo].CouplingFlag&ctrain_coupler)==0) - return -Couplers[ConnectNo].CouplingFlag; //hak nie połączony - rozłączanie jest OK - if (TestFlag(DamageFlag,dtrain_coupling)) - return -Couplers[ConnectNo].CouplingFlag; //hak urwany - rozłączanie jest OK - //ABu021104: zakomentowane 'and (CouplerType<>Articulated)' w warunku, nie wiem co to bylo, ale za to teraz dziala odczepianie... :) } - //if (CouplerType==Articulated) return false; //sprzęg nie do rozpięcia - może być tylko urwany - //Couplers[ConnectNo].CoupleDist=Distance(Loc,Couplers[ConnectNo].Connected->Loc,Dim,Couplers[ConnectNo].Connected->Dim); - CouplerDist(ConnectNo); - if (Couplers[ConnectNo].CouplerType==Screw?Couplers[ConnectNo].CoupleDist<0.0:true) - return -Couplers[ConnectNo].CouplingFlag; //można rozłączać, jeśli dociśnięty - return (Couplers[ConnectNo].CoupleDist>0.2)?-Couplers[ConnectNo].CouplingFlag:Couplers[ConnectNo].CouplingFlag; +{ // Ra: sprawdzenie, czy odległość jest dobra do rozłączania + // powinny być 3 informacje: =0 sprzęg już rozłączony, <0 da się rozłączyć. >0 nie da się + // rozłączyć + if (!Couplers[ConnectNo].Connected) + return 0; // nie ma nic, to rozłączanie jest OK + if ((Couplers[ConnectNo].CouplingFlag & ctrain_coupler) == 0) + return -Couplers[ConnectNo].CouplingFlag; // hak nie połączony - rozłączanie jest OK + if (TestFlag(DamageFlag, dtrain_coupling)) + return -Couplers[ConnectNo].CouplingFlag; // hak urwany - rozłączanie jest OK + // ABu021104: zakomentowane 'and (CouplerType<>Articulated)' w warunku, nie wiem co to bylo, ale + // za to teraz dziala odczepianie... :) } + // if (CouplerType==Articulated) return false; //sprzęg nie do rozpięcia - może być tylko urwany + // Couplers[ConnectNo].CoupleDist=Distance(Loc,Couplers[ConnectNo].Connected->Loc,Dim,Couplers[ConnectNo].Connected->Dim); + CouplerDist(ConnectNo); + if (Couplers[ConnectNo].CouplerType == Screw ? Couplers[ConnectNo].CoupleDist < 0.0 : true) + return -Couplers[ConnectNo].CouplingFlag; // można rozłączać, jeśli dociśnięty + return (Couplers[ConnectNo].CoupleDist > 0.2) ? -Couplers[ConnectNo].CouplingFlag : + Couplers[ConnectNo].CouplingFlag; }; bool __fastcall TMoverParameters::Dettach(Byte ConnectNo) -{//rozlaczanie - if (!Couplers[ConnectNo].Connected) return true; //nie ma nic, to odczepiono - //with Couplers[ConnectNo] do - int i=DettachStatus(ConnectNo); //stan sprzęgu - if (i<0) - {//gdy scisniete zderzaki, chyba ze zerwany sprzeg (wirtualnego nie odpinamy z drugiej strony) - //Couplers[ConnectNo].Connected=NULL; //lepiej zostawic bo przeciez trzeba kontrolowac zderzenia odczepionych - Couplers[ConnectNo].Connected->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag=0; //pozostaje sprzęg wirtualny - Couplers[ConnectNo].CouplingFlag=0; //pozostaje sprzęg wirtualny - return true; - } - else if (i>0) - {//odłączamy węże i resztę, pozostaje sprzęg fizyczny, który wymaga dociśnięcia (z wirtualnym nic) - Couplers[ConnectNo].CouplingFlag&=ctrain_coupler; - Couplers[ConnectNo].Connected->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag=Couplers[ConnectNo].CouplingFlag; - } - return false; //jeszcze nie rozłączony +{ // rozlaczanie + if (!Couplers[ConnectNo].Connected) + return true; // nie ma nic, to odczepiono + // with Couplers[ConnectNo] do + int i = DettachStatus(ConnectNo); // stan sprzęgu + if (i < 0) + { // gdy scisniete zderzaki, chyba ze zerwany sprzeg (wirtualnego nie odpinamy z drugiej strony) + // Couplers[ConnectNo].Connected=NULL; //lepiej zostawic bo przeciez trzeba kontrolowac + // zderzenia odczepionych + Couplers[ConnectNo].Connected->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag = + 0; // pozostaje sprzęg wirtualny + Couplers[ConnectNo].CouplingFlag = 0; // pozostaje sprzęg wirtualny + return true; + } + else if (i > 0) + { // odłączamy węże i resztę, pozostaje sprzęg fizyczny, który wymaga dociśnięcia (z wirtualnym + // nic) + Couplers[ConnectNo].CouplingFlag &= ctrain_coupler; + Couplers[ConnectNo].Connected->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag = + Couplers[ConnectNo].CouplingFlag; + } + return false; // jeszcze nie rozłączony }; void __fastcall TMoverParameters::SetCoupleDist() -{//przeliczenie odległości sprzęgów - if (Couplers[0].Connected) - { - CouplerDist(0); - if (CategoryFlag&2) - {//Ra: dla samochodów zderzanie kul to za mało - } - } - if (Couplers[1].Connected) - { - CouplerDist(1); - if (CategoryFlag&2) - {//Ra: dla samochodów zderzanie kul to za mało - } - } +{ // przeliczenie odległości sprzęgów + if (Couplers[0].Connected) + { + CouplerDist(0); + if (CategoryFlag & 2) + { // Ra: dla samochodów zderzanie kul to za mało + } + } + if (Couplers[1].Connected) + { + CouplerDist(1); + if (CategoryFlag & 2) + { // Ra: dla samochodów zderzanie kul to za mało + } + } }; bool __fastcall TMoverParameters::DirectionForward() { - if ((MainCtrlPosNo>0)&&(ActiveDir<1)&&(MainCtrlPos==0)) - { - ++ActiveDir; - DirAbsolute=ActiveDir*CabNo; - if (DirAbsolute) - if (Battery) //jeśli bateria jest już załączona - BatterySwitch(true); //to w ten oto durny sposób aktywuje się CA/SHP - SendCtrlToNext("Direction",ActiveDir,CabNo); - return true; - } - else if ((ActiveDir==1)&&(MainCtrlPos==0)&&(TrainType==dt_EZT)) - return MinCurrentSwitch(true); //"wysoki rozruch" EN57 - return false; + if ((MainCtrlPosNo > 0) && (ActiveDir < 1) && (MainCtrlPos == 0)) + { + ++ActiveDir; + DirAbsolute = ActiveDir * CabNo; + if (DirAbsolute) + if (Battery) // jeśli bateria jest już załączona + BatterySwitch(true); // to w ten oto durny sposób aktywuje się CA/SHP + SendCtrlToNext("Direction", ActiveDir, CabNo); + return true; + } + else if ((ActiveDir == 1) && (MainCtrlPos == 0) && (TrainType == dt_EZT)) + return MinCurrentSwitch(true); //"wysoki rozruch" EN57 + return false; }; // Nastawianie hamulców void __fastcall TMoverParameters::BrakeLevelSet(double b) -{//ustawienie pozycji hamulca na wartość (b) w zakresie od -2 do BrakeCtrlPosNo - //jedyny dopuszczalny sposób przestawienia hamulca zasadniczego - if (fBrakeCtrlPos==b) return; //nie przeliczać, jak nie ma zmiany - fBrakeCtrlPos=b; - BrakeCtrlPosR=b; - if (fBrakeCtrlPosGetPos(bh_MIN)) - fBrakeCtrlPos=Handle->GetPos(bh_MIN); //odcięcie - else - if (fBrakeCtrlPos>Handle->GetPos(bh_MAX)) - fBrakeCtrlPos=Handle->GetPos(bh_MAX); - int x=floor(fBrakeCtrlPos); //jeśli odwołujemy się do BrakeCtrlPos w pośrednich, to musi być obcięte a nie zaokrągone - while ((x>BrakeCtrlPos)&&(BrakeCtrlPos=-1)) //jeśli zmniejszyło się o 1 - if (!T_MoverParameters::DecBrakeLevelOld()) break; - BrakePressureActual=BrakePressureTable[BrakeCtrlPos+2]; //skopiowanie pozycji -/* -//youBy: obawiam sie, ze tutaj to nie dziala :P -//Ra 2014-03: było tak zrobione, że działało - po każdej zmianie pozycji była wywoływana ta funkcja -// if (BrakeSystem==Pneumatic?BrakeSubsystem==Oerlikon:false) //tylko Oerlikon akceptuje ułamki - if(false) - if (fBrakeCtrlPos>0.0) - {//wartości pośrednie wyliczamy tylko dla hamowania - double u=fBrakeCtrlPos-double(x); //ułamek ponad wartość całkowitą - if (u>0.0) - {//wyliczamy wartości ważone - BrakePressureActual.PipePressureVal+=-u*BrakePressureActual.PipePressureVal+u*BrakePressureTable[BrakeCtrlPos+1+2].PipePressureVal; - //BrakePressureActual.BrakePressureVal+=-u*BrakePressureActual.BrakePressureVal+u*BrakePressureTable[BrakeCtrlPos+1].BrakePressureVal; //to chyba nie będzie tak działać, zwłaszcza w EN57 - BrakePressureActual.FlowSpeedVal+=-u*BrakePressureActual.FlowSpeedVal+u*BrakePressureTable[BrakeCtrlPos+1+2].FlowSpeedVal; - } - } -*/ +{ // ustawienie pozycji hamulca na wartość (b) w zakresie od -2 do BrakeCtrlPosNo + // jedyny dopuszczalny sposób przestawienia hamulca zasadniczego + if (fBrakeCtrlPos == b) + return; // nie przeliczać, jak nie ma zmiany + fBrakeCtrlPos = b; + BrakeCtrlPosR = b; + if (fBrakeCtrlPos < Handle->GetPos(bh_MIN)) + fBrakeCtrlPos = Handle->GetPos(bh_MIN); // odcięcie + else if (fBrakeCtrlPos > Handle->GetPos(bh_MAX)) + fBrakeCtrlPos = Handle->GetPos(bh_MAX); + int x = floor(fBrakeCtrlPos); // jeśli odwołujemy się do BrakeCtrlPos w pośrednich, to musi być + // obcięte a nie zaokrągone + while ((x > BrakeCtrlPos) && (BrakeCtrlPos < BrakeCtrlPosNo)) // jeśli zwiększyło się o 1 + if (!T_MoverParameters::IncBrakeLevelOld()) + break; // wyjście awaryjne + while ((x < BrakeCtrlPos) && (BrakeCtrlPos >= -1)) // jeśli zmniejszyło się o 1 + if (!T_MoverParameters::DecBrakeLevelOld()) + break; + BrakePressureActual = BrakePressureTable[BrakeCtrlPos + 2]; // skopiowanie pozycji + /* + //youBy: obawiam sie, ze tutaj to nie dziala :P + //Ra 2014-03: było tak zrobione, że działało - po każdej zmianie pozycji była wywoływana ta + funkcja + // if (BrakeSystem==Pneumatic?BrakeSubsystem==Oerlikon:false) //tylko Oerlikon akceptuje ułamki + if(false) + if (fBrakeCtrlPos>0.0) + {//wartości pośrednie wyliczamy tylko dla hamowania + double u=fBrakeCtrlPos-double(x); //ułamek ponad wartość całkowitą + if (u>0.0) + {//wyliczamy wartości ważone + BrakePressureActual.PipePressureVal+=-u*BrakePressureActual.PipePressureVal+u*BrakePressureTable[BrakeCtrlPos+1+2].PipePressureVal; + //BrakePressureActual.BrakePressureVal+=-u*BrakePressureActual.BrakePressureVal+u*BrakePressureTable[BrakeCtrlPos+1].BrakePressureVal; + //to chyba nie będzie tak działać, zwłaszcza w EN57 + BrakePressureActual.FlowSpeedVal+=-u*BrakePressureActual.FlowSpeedVal+u*BrakePressureTable[BrakeCtrlPos+1+2].FlowSpeedVal; + } + } + */ }; bool __fastcall TMoverParameters::BrakeLevelAdd(double b) -{//dodanie wartości (b) do pozycji hamulca (w tym ujemnej) - //zwraca false, gdy po dodaniu było by poza zakresem - BrakeLevelSet(fBrakeCtrlPos+b); - return b>0.0?(fBrakeCtrlPos-1.0); //true, jeśli można kontynuować +{ // dodanie wartości (b) do pozycji hamulca (w tym ujemnej) + // zwraca false, gdy po dodaniu było by poza zakresem + BrakeLevelSet(fBrakeCtrlPos + b); + return b > 0.0 ? (fBrakeCtrlPos < BrakeCtrlPosNo) : + (BrakeCtrlPos > -1.0); // true, jeśli można kontynuować }; bool __fastcall TMoverParameters::IncBrakeLevel() -{//nowa wersja na użytek AI, false gdy osiągnięto pozycję BrakeCtrlPosNo - return BrakeLevelAdd(1.0); -}; +{ // nowa wersja na użytek AI, false gdy osiągnięto pozycję BrakeCtrlPosNo + return BrakeLevelAdd(1.0); }; bool __fastcall TMoverParameters::DecBrakeLevel() -{//nowa wersja na użytek AI, false gdy osiągnięto pozycję -1 - return BrakeLevelAdd(-1.0); -}; +{ // nowa wersja na użytek AI, false gdy osiągnięto pozycję -1 return BrakeLevelAdd(-1.0); }; bool __fastcall TMoverParameters::ChangeCab(int direction) -{//zmiana kabiny i resetowanie ustawien - if (abs(ActiveCab+direction)<2) - { -// if (ActiveCab+direction=0) then LastCab:=ActiveCab; - ActiveCab=ActiveCab+direction; - if ((BrakeSystem==Pneumatic)&&(BrakeCtrlPosNo>0)) - { -// if (BrakeHandle==FV4a) //!!!POBIERAĆ WARTOŚĆ Z KLASY ZAWORU!!! -// BrakeLevelSet(-2); //BrakeCtrlPos=-2; -// else if ((BrakeHandle==FVel6)||(BrakeHandle==St113)) -// BrakeLevelSet(2); -// else -// BrakeLevelSet(1); - BrakeLevelSet(Handle->GetPos(bh_NP)); - LimPipePress=PipePress; - ActFlowSpeed=0; - } - else - //if (TrainType=dt_EZT) and (BrakeCtrlPosNo>0) then - // BrakeCtrlPos:=5; //z Megapacka - //else -// BrakeLevelSet(0); //BrakeCtrlPos=0; - BrakeLevelSet(Handle->GetPos(bh_NP)); -// if not TestFlag(BrakeStatus,b_dmg) then -// BrakeStatus:=b_off; //z Megapacka - MainCtrlPos=0; - ScndCtrlPos=0; - //Ra: to poniżej jest bez sensu - można przejść nie wyłączając - //if ((EngineType!=DieselEngine)&&(EngineType!=DieselElectric)) - //{ - // Mains=false; - // CompressorAllow=false; - // ConverterAllow=false; - //} - //ActiveDir=0; - //DirAbsolute=0; - return true; - } - return false; +{ // zmiana kabiny i resetowanie ustawien + if (abs(ActiveCab + direction) < 2) + { + // if (ActiveCab+direction=0) then LastCab:=ActiveCab; + ActiveCab = ActiveCab + direction; + if ((BrakeSystem == Pneumatic) && (BrakeCtrlPosNo > 0)) + { + // if (BrakeHandle==FV4a) //!!!POBIERAĆ WARTOŚĆ Z KLASY ZAWORU!!! + // BrakeLevelSet(-2); //BrakeCtrlPos=-2; + // else if ((BrakeHandle==FVel6)||(BrakeHandle==St113)) + // BrakeLevelSet(2); + // else + // BrakeLevelSet(1); + BrakeLevelSet(Handle->GetPos(bh_NP)); + LimPipePress = PipePress; + ActFlowSpeed = 0; + } + else + // if (TrainType=dt_EZT) and (BrakeCtrlPosNo>0) then + // BrakeCtrlPos:=5; //z Megapacka + // else + // BrakeLevelSet(0); //BrakeCtrlPos=0; + BrakeLevelSet(Handle->GetPos(bh_NP)); + // if not TestFlag(BrakeStatus,b_dmg) then + // BrakeStatus:=b_off; //z Megapacka + MainCtrlPos = 0; + ScndCtrlPos = 0; + // Ra: to poniżej jest bez sensu - można przejść nie wyłączając + // if ((EngineType!=DieselEngine)&&(EngineType!=DieselElectric)) + //{ + // Mains=false; + // CompressorAllow=false; + // ConverterAllow=false; + //} + // ActiveDir=0; + // DirAbsolute=0; + return true; + } + return false; }; bool __fastcall TMoverParameters::CurrentSwitch(int direction) -{//rozruch wysoki (true) albo niski (false) - //Ra: przeniosłem z Train.cpp, nie wiem czy ma to sens - if (MaxCurrentSwitch(direction)) - {if (TrainType!=dt_EZT) - return (MinCurrentSwitch(direction)); - } - if (EngineType==DieselEngine) //dla 2Ls150 - if (ShuntModeAllow) - if (ActiveDir==0) //przed ustawieniem kierunku - ShuntMode=direction; - return false; +{ // rozruch wysoki (true) albo niski (false) + // Ra: przeniosłem z Train.cpp, nie wiem czy ma to sens + if (MaxCurrentSwitch(direction)) + { + if (TrainType != dt_EZT) + return (MinCurrentSwitch(direction)); + } + if (EngineType == DieselEngine) // dla 2Ls150 + if (ShuntModeAllow) + if (ActiveDir == 0) // przed ustawieniem kierunku + ShuntMode = direction; + return false; }; void __fastcall TMoverParameters::UpdatePantVolume(double dt) -{//KURS90 - sprężarka pantografów; Ra 2014-07: teraz jest to zbiornik rozrządu, chociaż to jeszcze nie tak - if (EnginePowerSource.SourceType==CurrentCollector) //tylko jeśli pantografujący - { - //Ra 2014-07: zasadniczo, to istnieje zbiornik rozrządu i zbiornik pantografów - na razie mamy razem - //Ra 2014-07: kurek trójdrogowy łączy spr.pom. z pantografami i wyłącznikiem ciśnieniowym WS - //Ra 2014-07: zbiornika rozrządu nie pompuje się tu, tylko pantografy; potem można zamknąć WS i odpalić resztę - if ((TrainType==dt_EZT)?(PantPressScndPipePress) PantPress=ScndPipePress; //oraz do ScndPipePress - PantVolume=(PantPress+1)*0.1; //objętość, na wypadek odcięcia kurkiem - } - else - {//zbiornik główny odcięty, można pompować pantografy - if (PantCompFlag&&Battery) //włączona bateria i mała sprężarka - PantVolume+=dt*(TrainType==dt_EZT?0.003:0.005)*(2*0.45-((0.1/PantVolume/10)-0.1))/0.45; //napełnianie zbiornika pantografów - //Ra 2013-12: Niebugocław mówi, że w EZT nabija 1.5 raz wolniej niż jak było 0.005 - PantPress=(10.0*PantVolume)-1.0; //tu by się przydała objętość zbiornika - } - if (!PantCompFlag&&(PantVolume>0.1)) - PantVolume-=dt*0.0003; //nieszczelności: 0.0003=0.3l/s - if (Mains) //nie wchodzić w funkcję bez potrzeby - if (EngineType==ElectricSeriesMotor) //nie dotyczy... czego właściwie? - if (PantPressPantVolumePantVolume=PantVolume; //przekazanie ciśnienia do sąsiedniego członu - //czy np. w ET40, ET41, ET42 pantografy członów mają połączenie pneumatyczne? - //Ra 2014-07: raczej nie - najpierw się załącza jeden człon, a potem można podnieść w drugim - } - else - {//a tu coś dla SM42 i SM31, aby pokazywać na manometrze - PantPress=CntrlPipePress; - } +{ // KURS90 - sprężarka pantografów; Ra 2014-07: teraz jest to zbiornik rozrządu, chociaż to jeszcze + // nie tak + if (EnginePowerSource.SourceType == CurrentCollector) // tylko jeśli pantografujący + { + // Ra 2014-07: zasadniczo, to istnieje zbiornik rozrządu i zbiornik pantografów - na razie + // mamy razem + // Ra 2014-07: kurek trójdrogowy łączy spr.pom. z pantografami i wyłącznikiem ciśnieniowym + // WS + // Ra 2014-07: zbiornika rozrządu nie pompuje się tu, tylko pantografy; potem można zamknąć + // WS i odpalić resztę + if ((TrainType == dt_EZT) ? (PantPress < ScndPipePress) : + bPantKurek3) // kurek zamyka połączenie z ZG + { // zbiornik pantografu połączony ze zbiornikiem głównym - małą sprężarką się tego nie + // napompuje + // Ra 2013-12: Niebugocław mówi, że w EZT nie ma potrzeby odcinać kurkiem + PantPress = EnginePowerSource.CollectorParameters + .MaxPress; // ograniczenie ciśnienia do MaxPress (tylko w pantografach!) + if (PantPress > ScndPipePress) + PantPress = ScndPipePress; // oraz do ScndPipePress + PantVolume = (PantPress + 1) * 0.1; // objętość, na wypadek odcięcia kurkiem + } + else + { // zbiornik główny odcięty, można pompować pantografy + if (PantCompFlag && Battery) // włączona bateria i mała sprężarka + PantVolume += dt * (TrainType == dt_EZT ? 0.003 : 0.005) * + (2 * 0.45 - ((0.1 / PantVolume / 10) - 0.1)) / + 0.45; // napełnianie zbiornika pantografów + // Ra 2013-12: Niebugocław mówi, że w EZT nabija 1.5 raz wolniej niż jak było 0.005 + PantPress = (10.0 * PantVolume) - 1.0; // tu by się przydała objętość zbiornika + } + if (!PantCompFlag && (PantVolume > 0.1)) + PantVolume -= dt * 0.0003; // nieszczelności: 0.0003=0.3l/s + if (Mains) // nie wchodzić w funkcję bez potrzeby + if (EngineType == ElectricSeriesMotor) // nie dotyczy... czego właściwie? + if (PantPress < EnginePowerSource.CollectorParameters.MinPress) + if ((TrainType & (dt_EZT | dt_ET40 | dt_ET41 | dt_ET42)) ? + (GetTrainsetVoltage() < EnginePowerSource.CollectorParameters.MinV) : + true) // to jest trochę proteza; zasilanie członu może być przez sprzęg + // WN + if (MainSwitch(false)) + EventFlag = true; // wywalenie szybkiego z powodu niskiego ciśnienia + if (TrainType != dt_EZT) // w EN57 pompuje się tylko w silnikowym + // pierwotnie w CHK pantografy miały również rozrządcze EZT + for (int b = 0; b <= 1; ++b) + if (TestFlag(Couplers[b].CouplingFlag, ctrain_controll)) + if (Couplers[b].Connected->PantVolume < + PantVolume) // bo inaczej trzeba w obydwu członach przestawiać + Couplers[b].Connected->PantVolume = + PantVolume; // przekazanie ciśnienia do sąsiedniego członu + // czy np. w ET40, ET41, ET42 pantografy członów mają połączenie pneumatyczne? + // Ra 2014-07: raczej nie - najpierw się załącza jeden człon, a potem można podnieść w + // drugim + } + else + { // a tu coś dla SM42 i SM31, aby pokazywać na manometrze + PantPress = CntrlPipePress; + } }; void __fastcall TMoverParameters::UpdateBatteryVoltage(double dt) -{//przeliczenie obciążenia baterii - double sn1,sn2,sn3,sn4,sn5; //Ra: zrobić z tego amperomierz NN - if ((BatteryVoltage>0)&&(EngineType!=DieselEngine)&&(EngineType!=WheelsDriven)&&(NominalBatteryVoltage>0)) - { - if ((NominalBatteryVoltage/BatteryVoltage<1.22)&&Battery) - {//110V - if (!ConverterFlag) - sn1=(dt*2.0); //szybki spadek do ok 90V - else sn1=0; - if (ConverterFlag) - sn2=-(dt*2.0); //szybki wzrost do 110V - else sn2=0; - if (Mains) - sn3=(dt*0.05); - else sn3=0; - if (iLights[0]&63) //64=blachy, nie ciągną prądu //rozpisać na poszczególne żarówki... - sn4=dt*0.003; - else sn4=0; - if (iLights[1]&63) //64=blachy, nie ciągną prądu - sn5=dt*0.001; - else sn5=0; - }; - if ((NominalBatteryVoltage/BatteryVoltage>=1.22)&&Battery) - {//90V - if (PantCompFlag) - sn1=(dt*0.0046); - else sn1=0; - if (ConverterFlag) - sn2=-(dt*50); //szybki wzrost do 110V - else sn2=0; - if (Mains) - sn3=(dt*0.001); - else sn3=0; - if (iLights[0]&63) //64=blachy, nie ciągną prądu - sn4=(dt*0.0030); - else sn4=0; - if (iLights[1]&63) //64=blachy, nie ciągną prądu - sn5=(dt*0.0010); - else sn5=0; - }; - if (!Battery) - { - if (NominalBatteryVoltage/BatteryVoltage<1.22) - sn1=dt*50; - else - sn1=0; - sn2=dt*0.000001; - sn3=dt*0.000001; - sn4=dt*0.000001; - sn5=dt*0.000001; //bardzo powolny spadek przy wyłączonych bateriach - }; - BatteryVoltage-=(sn1+sn2+sn3+sn4+sn5); - if (NominalBatteryVoltage/BatteryVoltage>1.57) - if (MainSwitch(false)&&(EngineType!=DieselEngine)&&(EngineType!=WheelsDriven)) - EventFlag=true; //wywalanie szybkiego z powodu zbyt niskiego napiecia - if (BatteryVoltage>NominalBatteryVoltage) - BatteryVoltage=NominalBatteryVoltage; //wstrzymanie ładowania pow. 110V - if (BatteryVoltage<0.01) - BatteryVoltage=0.01; - } - else - if (NominalBatteryVoltage==0) - BatteryVoltage=0; - else - BatteryVoltage=90; +{ // przeliczenie obciążenia baterii + double sn1, sn2, sn3, sn4, sn5; // Ra: zrobić z tego amperomierz NN + if ((BatteryVoltage > 0) && (EngineType != DieselEngine) && (EngineType != WheelsDriven) && + (NominalBatteryVoltage > 0)) + { + if ((NominalBatteryVoltage / BatteryVoltage < 1.22) && Battery) + { // 110V + if (!ConverterFlag) + sn1 = (dt * 2.0); // szybki spadek do ok 90V + else + sn1 = 0; + if (ConverterFlag) + sn2 = -(dt * 2.0); // szybki wzrost do 110V + else + sn2 = 0; + if (Mains) + sn3 = (dt * 0.05); + else + sn3 = 0; + if (iLights[0] & 63) // 64=blachy, nie ciągną prądu //rozpisać na poszczególne + // żarówki... + sn4 = dt * 0.003; + else + sn4 = 0; + if (iLights[1] & 63) // 64=blachy, nie ciągną prądu + sn5 = dt * 0.001; + else + sn5 = 0; + }; + if ((NominalBatteryVoltage / BatteryVoltage >= 1.22) && Battery) + { // 90V + if (PantCompFlag) + sn1 = (dt * 0.0046); + else + sn1 = 0; + if (ConverterFlag) + sn2 = -(dt * 50); // szybki wzrost do 110V + else + sn2 = 0; + if (Mains) + sn3 = (dt * 0.001); + else + sn3 = 0; + if (iLights[0] & 63) // 64=blachy, nie ciągną prądu + sn4 = (dt * 0.0030); + else + sn4 = 0; + if (iLights[1] & 63) // 64=blachy, nie ciągną prądu + sn5 = (dt * 0.0010); + else + sn5 = 0; + }; + if (!Battery) + { + if (NominalBatteryVoltage / BatteryVoltage < 1.22) + sn1 = dt * 50; + else + sn1 = 0; + sn2 = dt * 0.000001; + sn3 = dt * 0.000001; + sn4 = dt * 0.000001; + sn5 = dt * 0.000001; // bardzo powolny spadek przy wyłączonych bateriach + }; + BatteryVoltage -= (sn1 + sn2 + sn3 + sn4 + sn5); + if (NominalBatteryVoltage / BatteryVoltage > 1.57) + if (MainSwitch(false) && (EngineType != DieselEngine) && (EngineType != WheelsDriven)) + EventFlag = true; // wywalanie szybkiego z powodu zbyt niskiego napiecia + if (BatteryVoltage > NominalBatteryVoltage) + BatteryVoltage = NominalBatteryVoltage; // wstrzymanie ładowania pow. 110V + if (BatteryVoltage < 0.01) + BatteryVoltage = 0.01; + } + else if (NominalBatteryVoltage == 0) + BatteryVoltage = 0; + else + BatteryVoltage = 90; }; /* Ukrotnienie EN57: @@ -409,182 +467,183 @@ void __fastcall TMoverParameters::UpdateBatteryVoltage(double dt) ZN //masa */ -double __fastcall TMoverParameters::ComputeMovement -(double dt,double dt1, - const TTrackShape &Shape,TTrackParam &Track,TTractionParam &ElectricTraction, - const TLocation &NewLoc,TRotation &NewRot -) -{//trzeba po mału przenosić tu tę funkcję - double d; - T_MoverParameters::ComputeMovement(dt,dt1,Shape,Track,ElectricTraction,NewLoc,NewRot); - if (Power>1.0) //w rozrządczym nie (jest błąd w FIZ!) - Ra 2014-07: teraz we wszystkich - UpdatePantVolume(dt); //Ra 2014-07: obsługa zbiornika rozrządu oraz pantografów +double __fastcall TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShape &Shape, + TTrackParam &Track, + TTractionParam &ElectricTraction, + const TLocation &NewLoc, TRotation &NewRot) +{ // trzeba po mału przenosić tu tę funkcję + double d; + T_MoverParameters::ComputeMovement(dt, dt1, Shape, Track, ElectricTraction, NewLoc, NewRot); + if (Power > 1.0) // w rozrządczym nie (jest błąd w FIZ!) - Ra 2014-07: teraz we wszystkich + UpdatePantVolume(dt); // Ra 2014-07: obsługa zbiornika rozrządu oraz pantografów - if (EngineType==WheelsDriven) - d=CabNo*dL; //na chwile dla testu - else - d=dL; - DistCounter=DistCounter+fabs(dL)/1000.0; - dL=0; + if (EngineType == WheelsDriven) + d = CabNo * dL; // na chwile dla testu + else + d = dL; + DistCounter = DistCounter + fabs(dL) / 1000.0; + dL = 0; - //koniec procedury, tu nastepuja dodatkowe procedury pomocnicze + // koniec procedury, tu nastepuja dodatkowe procedury pomocnicze - //sprawdzanie i ewentualnie wykonywanie->kasowanie poleceń - if (LoadStatus>0) //czas doliczamy tylko jeśli trwa (roz)ładowanie - LastLoadChangeTime=LastLoadChangeTime+dt; //czas (roz)ładunku - RunInternalCommand(); - //automatyczny rozruch - if (EngineType==ElectricSeriesMotor) - if (AutoRelayCheck()) - SetFlag(SoundFlag,sound_relay); -/* - else {McZapkie-041003: aby slychac bylo przelaczniki w sterowniczym} - if (EngineType=None) and (MainCtrlPosNo>0) then - for b:=0 to 1 do - with Couplers[b] do - if TestFlag(CouplingFlag,ctrain_controll) then - if Connected^.Power>0.01 then - SoundFlag:=SoundFlag or Connected^.SoundFlag; -*/ - if (EngineType==DieselEngine) - if (dizel_Update(dt)) - SetFlag(SoundFlag,sound_relay); - //uklady hamulcowe: - if (VeselVolume>0) - Compressor=CompressedVolume/VeselVolume; - else - { - Compressor=0; - CompressorFlag=false; - }; - ConverterCheck(); - if (CompressorSpeed>0.0) //sprężarka musi mieć jakąś niezerową wydajność - CompressorCheck(dt); //żeby rozważać jej załączenie i pracę - UpdateBrakePressure(dt); - UpdatePipePressure(dt); - UpdateBatteryVoltage(dt); - UpdateScndPipePressure(dt); // druga rurka, youBy - //hamulec antypoślizgowy - wyłączanie - if ((BrakeSlippingTimer>0.8)&&(ASBType!=128)) //ASBSpeed=0.8 - Hamulec->ASB(0); - //SetFlag(BrakeStatus,-b_antislip); - BrakeSlippingTimer=BrakeSlippingTimer+dt; - //sypanie piasku - wyłączone i piasek się nie kończy - błędy AI - //if AIControllFlag then - // if SandDose then - // if Sand>0 then - // begin - // Sand:=Sand-NPoweredAxles*SandSpeed*dt; - // if Random
10) and (not DebugmodeFlag) then - if (!DebugModeFlag) - SecuritySystemCheck(dt1); - return d; + // sprawdzanie i ewentualnie wykonywanie->kasowanie poleceń + if (LoadStatus > 0) // czas doliczamy tylko jeśli trwa (roz)ładowanie + LastLoadChangeTime = LastLoadChangeTime + dt; // czas (roz)ładunku + RunInternalCommand(); + // automatyczny rozruch + if (EngineType == ElectricSeriesMotor) + if (AutoRelayCheck()) + SetFlag(SoundFlag, sound_relay); + /* + else {McZapkie-041003: aby slychac bylo przelaczniki w sterowniczym} + if (EngineType=None) and (MainCtrlPosNo>0) then + for b:=0 to 1 do + with Couplers[b] do + if TestFlag(CouplingFlag,ctrain_controll) then + if Connected^.Power>0.01 then + SoundFlag:=SoundFlag or Connected^.SoundFlag; + */ + if (EngineType == DieselEngine) + if (dizel_Update(dt)) + SetFlag(SoundFlag, sound_relay); + // uklady hamulcowe: + if (VeselVolume > 0) + Compressor = CompressedVolume / VeselVolume; + else + { + Compressor = 0; + CompressorFlag = false; + }; + ConverterCheck(); + if (CompressorSpeed > 0.0) // sprężarka musi mieć jakąś niezerową wydajność + CompressorCheck(dt); //żeby rozważać jej załączenie i pracę + UpdateBrakePressure(dt); + UpdatePipePressure(dt); + UpdateBatteryVoltage(dt); + UpdateScndPipePressure(dt); // druga rurka, youBy + // hamulec antypoślizgowy - wyłączanie + if ((BrakeSlippingTimer > 0.8) && (ASBType != 128)) // ASBSpeed=0.8 + Hamulec->ASB(0); + // SetFlag(BrakeStatus,-b_antislip); + BrakeSlippingTimer = BrakeSlippingTimer + dt; + // sypanie piasku - wyłączone i piasek się nie kończy - błędy AI + // if AIControllFlag then + // if SandDose then + // if Sand>0 then + // begin + // Sand:=Sand-NPoweredAxles*SandSpeed*dt; + // if Random
10) and (not DebugmodeFlag) then + if (!DebugModeFlag) + SecuritySystemCheck(dt1); + return d; }; -double __fastcall TMoverParameters::FastComputeMovement -(double dt, - const TTrackShape &Shape,TTrackParam &Track, - const TLocation &NewLoc,TRotation &NewRot -) -{//trzeba po mału przenosić tu tę funkcję - double d; - T_MoverParameters::FastComputeMovement(dt,Shape,Track,NewLoc,NewRot); - if (Power>1.0) //w rozrządczym nie (jest błąd w FIZ!) - UpdatePantVolume(dt); //Ra 2014-07: obsługa zbiornika rozrządu oraz pantografów - if (EngineType==WheelsDriven) - d=CabNo*dL; //na chwile dla testu - else - d=dL; - DistCounter=DistCounter+fabs(dL)/1000.0; - dL=0; +double __fastcall TMoverParameters::FastComputeMovement(double dt, const TTrackShape &Shape, + TTrackParam &Track, const TLocation &NewLoc, + TRotation &NewRot) +{ // trzeba po mału przenosić tu tę funkcję + double d; + T_MoverParameters::FastComputeMovement(dt, Shape, Track, NewLoc, NewRot); + if (Power > 1.0) // w rozrządczym nie (jest błąd w FIZ!) + UpdatePantVolume(dt); // Ra 2014-07: obsługa zbiornika rozrządu oraz pantografów + if (EngineType == WheelsDriven) + d = CabNo * dL; // na chwile dla testu + else + d = dL; + DistCounter = DistCounter + fabs(dL) / 1000.0; + dL = 0; - //koniec procedury, tu nastepuja dodatkowe procedury pomocnicze + // koniec procedury, tu nastepuja dodatkowe procedury pomocnicze - //sprawdzanie i ewentualnie wykonywanie->kasowanie poleceń - if (LoadStatus>0) //czas doliczamy tylko jeśli trwa (roz)ładowanie - LastLoadChangeTime=LastLoadChangeTime+dt; //czas (roz)ładunku - RunInternalCommand(); - if (EngineType==DieselEngine) - if (dizel_Update(dt)) - SetFlag(SoundFlag,sound_relay); - //uklady hamulcowe: - if (VeselVolume>0) - Compressor=CompressedVolume/VeselVolume; - else - { - Compressor=0; - CompressorFlag=false; - }; - ConverterCheck(); - if (CompressorSpeed>0.0) //sprężarka musi mieć jakąś niezerową wydajność - CompressorCheck(dt); //żeby rozważać jej załączenie i pracę - UpdateBrakePressure(dt); - UpdatePipePressure(dt); - UpdateScndPipePressure(dt); // druga rurka, youBy - UpdateBatteryVoltage(dt); - //hamulec antyposlizgowy - wyłączanie - if ((BrakeSlippingTimer>0.8)&&(ASBType!=128)) //ASBSpeed=0.8 - Hamulec->ASB(0); - BrakeSlippingTimer=BrakeSlippingTimer+dt; - return d; + // sprawdzanie i ewentualnie wykonywanie->kasowanie poleceń + if (LoadStatus > 0) // czas doliczamy tylko jeśli trwa (roz)ładowanie + LastLoadChangeTime = LastLoadChangeTime + dt; // czas (roz)ładunku + RunInternalCommand(); + if (EngineType == DieselEngine) + if (dizel_Update(dt)) + SetFlag(SoundFlag, sound_relay); + // uklady hamulcowe: + if (VeselVolume > 0) + Compressor = CompressedVolume / VeselVolume; + else + { + Compressor = 0; + CompressorFlag = false; + }; + ConverterCheck(); + if (CompressorSpeed > 0.0) // sprężarka musi mieć jakąś niezerową wydajność + CompressorCheck(dt); //żeby rozważać jej załączenie i pracę + UpdateBrakePressure(dt); + UpdatePipePressure(dt); + UpdateScndPipePressure(dt); // druga rurka, youBy + UpdateBatteryVoltage(dt); + // hamulec antyposlizgowy - wyłączanie + if ((BrakeSlippingTimer > 0.8) && (ASBType != 128)) // ASBSpeed=0.8 + Hamulec->ASB(0); + BrakeSlippingTimer = BrakeSlippingTimer + dt; + return d; }; double __fastcall TMoverParameters::ShowEngineRotation(int VehN) -{//pokazywanie obrotów silnika, również dwóch dalszych pojazdów (3×SN61) - int b; - switch (VehN) - {//numer obrotomierza - case 1: - return fabs(enrot); - case 2: - for (b=0;b<=1;++b) - if (TestFlag(Couplers[b].CouplingFlag,ctrain_controll)) - if (Couplers[b].Connected->Power>0.01) - return fabs(Couplers[b].Connected->enrot); - break; - case 3: //to nie uwzględnia ewentualnego odwrócenia pojazdu w środku - for (b=0;b<=1;++b) - if (TestFlag(Couplers[b].CouplingFlag,ctrain_controll)) - if (Couplers[b].Connected->Power>0.01) - if (TestFlag(Couplers[b].Connected->Couplers[b].CouplingFlag,ctrain_controll)) - if (Couplers[b].Connected->Couplers[b].Connected->Power>0.01) - return fabs(Couplers[b].Connected->Couplers[b].Connected->enrot); - break; - }; - return 0.0; +{ // pokazywanie obrotów silnika, również dwóch dalszych pojazdów (3×SN61) + int b; + switch (VehN) + { // numer obrotomierza + case 1: + return fabs(enrot); + case 2: + for (b = 0; b <= 1; ++b) + if (TestFlag(Couplers[b].CouplingFlag, ctrain_controll)) + if (Couplers[b].Connected->Power > 0.01) + return fabs(Couplers[b].Connected->enrot); + break; + case 3: // to nie uwzględnia ewentualnego odwrócenia pojazdu w środku + for (b = 0; b <= 1; ++b) + if (TestFlag(Couplers[b].CouplingFlag, ctrain_controll)) + if (Couplers[b].Connected->Power > 0.01) + if (TestFlag(Couplers[b].Connected->Couplers[b].CouplingFlag, ctrain_controll)) + if (Couplers[b].Connected->Couplers[b].Connected->Power > 0.01) + return fabs(Couplers[b].Connected->Couplers[b].Connected->enrot); + break; + }; + return 0.0; }; void __fastcall TMoverParameters::ConverterCheck() -{//sprawdzanie przetwornicy - if (ConverterAllow&&Mains) - ConverterFlag=true; - else - ConverterFlag=false; +{ // sprawdzanie przetwornicy + if (ConverterAllow && Mains) + ConverterFlag = true; + else + ConverterFlag = false; }; int __fastcall TMoverParameters::ShowCurrent(Byte AmpN) -{//odczyt amperażu - switch (EngineType) - {case ElectricInductionMotor: - switch (AmpN) - {//do asynchronicznych - case 1: return WindingRes*Mm/Vadd; - case 2: return dizel_fill*WindingRes; - default: return T_MoverParameters::ShowCurrent(AmpN); - } - break; - case DieselElectric: - return fabs(Im); - break; - default: - return T_MoverParameters::ShowCurrent(AmpN); - } +{ // odczyt amperażu + switch (EngineType) + { + case ElectricInductionMotor: + switch (AmpN) + { // do asynchronicznych + case 1: + return WindingRes * Mm / Vadd; + case 2: + return dizel_fill * WindingRes; + default: + return T_MoverParameters::ShowCurrent(AmpN); + } + break; + case DieselElectric: + return fabs(Im); + break; + default: + return T_MoverParameters::ShowCurrent(AmpN); + } }; diff --git a/Mover.h b/Mover.h index b6fe77a9..51bebf3a 100644 --- a/Mover.h +++ b/Mover.h @@ -13,161 +13,167 @@ #include "dumb3d.h" using namespace Math3D; -enum TProblem //lista problemów taboru, które uniemożliwiają jazdę -{//flagi bitowe - pr_Hamuje=1, //pojazd ma załączony hamulec lub zatarte osie - pr_Pantografy=2, //pojazd wymaga napompowania pantografów - pr_Ostatni=0x80000000 //ostatnia flaga bitowa +enum TProblem // lista problemów taboru, które uniemożliwiają jazdę +{ // flagi bitowe + pr_Hamuje = 1, // pojazd ma załączony hamulec lub zatarte osie + pr_Pantografy = 2, // pojazd wymaga napompowania pantografów + pr_Ostatni = 0x80000000 // ostatnia flaga bitowa }; class TMoverParameters : public T_MoverParameters -{//Ra: wrapper na kod pascalowy, przejmujący jego funkcje -public: - vector3 vCoulpler[2]; //powtórzenie współrzędnych sprzęgów z DynObj :/ - vector3 DimHalf; //połowy rozmiarów do obliczeń geometrycznych - //int WarningSignal; //0: nie trabi, 1,2: trabi syreną o podanym numerze - unsigned char WarningSignal; //tymczasowo 8bit, ze względu na funkcje w MTools - double fBrakeCtrlPos; //płynna nastawa hamulca zespolonego - bool bPantKurek3; //kurek trójdrogowy (pantografu): true=połączenie z ZG, false=połączenie z małą sprężarką - int iProblem; //flagi problemów z taborem, aby AI nie musiało porównywać; 0=może jechać - int iLights[2]; //bity zapalonych świateł tutaj, żeby dało się liczyć pobór prądu -private: - double __fastcall CouplerDist(Byte Coupler); -public: - __fastcall TMoverParameters(double VelInitial,AnsiString TypeNameInit,AnsiString NameInit, - int LoadInitial,AnsiString LoadTypeInitial,int Cab); - //obsługa sprzęgów - double __fastcall Distance(const TLocation &Loc1,const TLocation &Loc2,const TDimension &Dim1,const TDimension &Dim2); - double __fastcall Distance(const vector3 &Loc1,const vector3 &Loc2,const vector3 &Dim1,const vector3 &Dim2); - bool __fastcall Attach(Byte ConnectNo,Byte ConnectToNr,TMoverParameters *ConnectTo,Byte CouplingType,bool Forced=false); - bool __fastcall Attach(Byte ConnectNo,Byte ConnectToNr,T_MoverParameters *ConnectTo,Byte CouplingType,bool Forced=false); - int __fastcall DettachStatus(Byte ConnectNo); - bool __fastcall Dettach(Byte ConnectNo); - void __fastcall SetCoupleDist(); - bool __fastcall DirectionForward(); - void __fastcall BrakeLevelSet(double b); - bool __fastcall BrakeLevelAdd(double b); - bool __fastcall IncBrakeLevel(); //wersja na użytek AI - bool __fastcall DecBrakeLevel(); - bool __fastcall ChangeCab(int direction); - bool __fastcall CurrentSwitch(int direction); - void __fastcall UpdateBatteryVoltage(double dt); - double __fastcall ComputeMovement - (double dt,double dt1, - const TTrackShape &Shape,TTrackParam &Track,TTractionParam &ElectricTraction, - const TLocation &NewLoc,TRotation &NewRot - ); - double __fastcall FastComputeMovement - (double dt, - const TTrackShape &Shape,TTrackParam &Track, - const TLocation &NewLoc,TRotation &NewRot - ); - double __fastcall ShowEngineRotation(int VehN); - //double __fastcall GetTrainsetVoltage(void); - //bool __fastcall Physic_ReActivation(void); - //double __fastcall LocalBrakeRatio(void); - //double __fastcall ManualBrakeRatio(void); - //double __fastcall PipeRatio(void); - //double __fastcall RealPipeRatio(void); - //double __fastcall BrakeVP(void); - //bool __fastcall DynamicBrakeSwitch(bool Switch); - //bool __fastcall SendCtrlBroadcast(AnsiString CtrlCommand, double ctrlvalue); - //bool __fastcall SendCtrlToNext(AnsiString CtrlCommand, double ctrlvalue, double dir); - //bool __fastcall CabActivisation(void); - //bool __fastcall CabDeactivisation(void); - //bool __fastcall IncMainCtrl(int CtrlSpeed); - //bool __fastcall DecMainCtrl(int CtrlSpeed); - //bool __fastcall IncScndCtrl(int CtrlSpeed); - //bool __fastcall DecScndCtrl(int CtrlSpeed); - //bool __fastcall AddPulseForce(int Multipler); - //bool __fastcall SandDoseOn(void); - //bool __fastcall SecuritySystemReset(void); - //void __fastcall SecuritySystemCheck(double dt); - //bool __fastcall BatterySwitch(bool State); - //bool __fastcall EpFuseSwitch(bool State); - //bool __fastcall IncBrakeLevelOld(void); - //bool __fastcall DecBrakeLevelOld(void); - //bool __fastcall IncLocalBrakeLevel(Byte CtrlSpeed); - //bool __fastcall DecLocalBrakeLevel(Byte CtrlSpeed); - //bool __fastcall IncLocalBrakeLevelFAST(void); - //bool __fastcall DecLocalBrakeLevelFAST(void); - //bool __fastcall IncManualBrakeLevel(Byte CtrlSpeed); - //bool __fastcall DecManualBrakeLevel(Byte CtrlSpeed); - //bool __fastcall EmergencyBrakeSwitch(bool Switch); - //bool __fastcall AntiSlippingBrake(void); - //bool __fastcall BrakeReleaser(Byte state); - //bool __fastcall SwitchEPBrake(Byte state); - //bool __fastcall AntiSlippingButton(void); - //bool __fastcall IncBrakePress(double &brake, double PressLimit, double dp); - //bool __fastcall DecBrakePress(double &brake, double PressLimit, double dp); - //bool __fastcall BrakeDelaySwitch(Byte BDS); - //bool __fastcall IncBrakeMult(void); - //bool __fastcall DecBrakeMult(void); - //void __fastcall UpdateBrakePressure(double dt); - //void __fastcall UpdatePipePressure(double dt); - //void __fastcall CompressorCheck(double dt); - void __fastcall UpdatePantVolume(double dt); - //void __fastcall UpdateScndPipePressure(double dt); - //void __fastcall UpdateBatteryVoltage(double dt); - //double __fastcall GetDVc(double dt); - //void __fastcall ComputeConstans(void); - //double __fastcall ComputeMass(void); - //double __fastcall Adhesive(double staticfriction); - //double __fastcall TractionForce(double dt); - //double __fastcall FrictionForce(double R, Byte TDamage); - //double __fastcall BrakeForce(const TTrackParam &Track); - //double __fastcall CouplerForce(Byte CouplerN, double dt); - //void __fastcall CollisionDetect(Byte CouplerN, double dt); - //double __fastcall ComputeRotatingWheel(double WForce, double dt, double n); - //bool __fastcall SetInternalCommand(AnsiString NewCommand, double NewValue1, double NewValue2); - //double __fastcall GetExternalCommand(AnsiString &Command); - //bool __fastcall RunCommand(AnsiString command, double CValue1, double CValue2); - //bool __fastcall RunInternalCommand(void); - //void __fastcall PutCommand(AnsiString NewCommand, double NewValue1, double NewValue2, const TLocation - // &NewLocation); - //bool __fastcall DirectionBackward(void); - //bool __fastcall MainSwitch(bool State); - //bool __fastcall ConverterSwitch(bool State); - //bool __fastcall CompressorSwitch(bool State); - void __fastcall ConverterCheck(); - //bool __fastcall FuseOn(void); - //bool __fastcall FuseFlagCheck(void); - //void __fastcall FuseOff(void); - int __fastcall ShowCurrent(Byte AmpN); - //double __fastcall v2n(void); - //double __fastcall current(double n, double U); - //double __fastcall Momentum(double I); - //double __fastcall MomentumF(double I, double Iw, Byte SCP); - //bool __fastcall CutOffEngine(void); - //bool __fastcall MaxCurrentSwitch(bool State); - //bool __fastcall ResistorsFlagCheck(void); - //bool __fastcall MinCurrentSwitch(bool State); - //bool __fastcall AutoRelaySwitch(bool State); - //bool __fastcall AutoRelayCheck(void); - //bool __fastcall dizel_EngageSwitch(double state); - //bool __fastcall dizel_EngageChange(double dt); - //bool __fastcall dizel_AutoGearCheck(void); - //double __fastcall dizel_fillcheck(Byte mcp); - //double __fastcall dizel_Momentum(double dizel_fill, double n, double dt); - //bool __fastcall dizel_Update(double dt); - //bool __fastcall LoadingDone(double LSpeed, AnsiString LoadInit); - //void __fastcall ComputeTotalForce(double dt, double dt1, bool FullVer); - //double __fastcall ComputeMovement(double dt, double dt1, const TTrackShape &Shape, TTrackParam &Track - // , TTractionParam &ElectricTraction, const TLocation &NewLoc, TRotation &NewRot); - //double __fastcall FastComputeMovement(double dt, const TTrackShape &Shape, TTrackParam &Track, const - // TLocation &NewLoc, TRotation &NewRot); - //bool __fastcall ChangeOffsetH(double DeltaOffset); - //__fastcall T_MoverParameters(double VelInitial, AnsiString TypeNameInit, AnsiString NameInit, int LoadInitial - // , AnsiString LoadTypeInitial, int Cab); - //bool __fastcall LoadChkFile(AnsiString chkpath); - //bool __fastcall CheckLocomotiveParameters(bool ReadyFlag, int Dir); - //AnsiString __fastcall EngineDescription(int what); - //bool __fastcall DoorLeft(bool State); - //bool __fastcall DoorRight(bool State); - //bool __fastcall DoorBlockedFlag(void); - //bool __fastcall PantFront(bool State); - //bool __fastcall PantRear(bool State); - // +{ // Ra: wrapper na kod pascalowy, przejmujący jego funkcje + public: + vector3 vCoulpler[2]; // powtórzenie współrzędnych sprzęgów z DynObj :/ + vector3 DimHalf; // połowy rozmiarów do obliczeń geometrycznych + // int WarningSignal; //0: nie trabi, 1,2: trabi syreną o podanym numerze + unsigned char WarningSignal; // tymczasowo 8bit, ze względu na funkcje w MTools + double fBrakeCtrlPos; // płynna nastawa hamulca zespolonego + bool bPantKurek3; // kurek trójdrogowy (pantografu): true=połączenie z ZG, false=połączenie z + // małą sprężarką + int iProblem; // flagi problemów z taborem, aby AI nie musiało porównywać; 0=może jechać + int iLights[2]; // bity zapalonych świateł tutaj, żeby dało się liczyć pobór prądu + private: + double __fastcall CouplerDist(Byte Coupler); + + public: + __fastcall TMoverParameters(double VelInitial, AnsiString TypeNameInit, AnsiString NameInit, + int LoadInitial, AnsiString LoadTypeInitial, int Cab); + // obsługa sprzęgów + double __fastcall Distance(const TLocation &Loc1, const TLocation &Loc2, const TDimension &Dim1, + const TDimension &Dim2); + double __fastcall Distance(const vector3 &Loc1, const vector3 &Loc2, const vector3 &Dim1, + const vector3 &Dim2); + bool __fastcall Attach(Byte ConnectNo, Byte ConnectToNr, TMoverParameters *ConnectTo, + Byte CouplingType, bool Forced = false); + bool __fastcall Attach(Byte ConnectNo, Byte ConnectToNr, T_MoverParameters *ConnectTo, + Byte CouplingType, bool Forced = false); + int __fastcall DettachStatus(Byte ConnectNo); + bool __fastcall Dettach(Byte ConnectNo); + void __fastcall SetCoupleDist(); + bool __fastcall DirectionForward(); + void __fastcall BrakeLevelSet(double b); + bool __fastcall BrakeLevelAdd(double b); + bool __fastcall IncBrakeLevel(); // wersja na użytek AI + bool __fastcall DecBrakeLevel(); + bool __fastcall ChangeCab(int direction); + bool __fastcall CurrentSwitch(int direction); + void __fastcall UpdateBatteryVoltage(double dt); + double __fastcall ComputeMovement(double dt, double dt1, const TTrackShape &Shape, + TTrackParam &Track, TTractionParam &ElectricTraction, + const TLocation &NewLoc, TRotation &NewRot); + double __fastcall FastComputeMovement(double dt, const TTrackShape &Shape, TTrackParam &Track, + const TLocation &NewLoc, TRotation &NewRot); + double __fastcall ShowEngineRotation(int VehN); + // double __fastcall GetTrainsetVoltage(void); + // bool __fastcall Physic_ReActivation(void); + // double __fastcall LocalBrakeRatio(void); + // double __fastcall ManualBrakeRatio(void); + // double __fastcall PipeRatio(void); + // double __fastcall RealPipeRatio(void); + // double __fastcall BrakeVP(void); + // bool __fastcall DynamicBrakeSwitch(bool Switch); + // bool __fastcall SendCtrlBroadcast(AnsiString CtrlCommand, double ctrlvalue); + // bool __fastcall SendCtrlToNext(AnsiString CtrlCommand, double ctrlvalue, double dir); + // bool __fastcall CabActivisation(void); + // bool __fastcall CabDeactivisation(void); + // bool __fastcall IncMainCtrl(int CtrlSpeed); + // bool __fastcall DecMainCtrl(int CtrlSpeed); + // bool __fastcall IncScndCtrl(int CtrlSpeed); + // bool __fastcall DecScndCtrl(int CtrlSpeed); + // bool __fastcall AddPulseForce(int Multipler); + // bool __fastcall SandDoseOn(void); + // bool __fastcall SecuritySystemReset(void); + // void __fastcall SecuritySystemCheck(double dt); + // bool __fastcall BatterySwitch(bool State); + // bool __fastcall EpFuseSwitch(bool State); + // bool __fastcall IncBrakeLevelOld(void); + // bool __fastcall DecBrakeLevelOld(void); + // bool __fastcall IncLocalBrakeLevel(Byte CtrlSpeed); + // bool __fastcall DecLocalBrakeLevel(Byte CtrlSpeed); + // bool __fastcall IncLocalBrakeLevelFAST(void); + // bool __fastcall DecLocalBrakeLevelFAST(void); + // bool __fastcall IncManualBrakeLevel(Byte CtrlSpeed); + // bool __fastcall DecManualBrakeLevel(Byte CtrlSpeed); + // bool __fastcall EmergencyBrakeSwitch(bool Switch); + // bool __fastcall AntiSlippingBrake(void); + // bool __fastcall BrakeReleaser(Byte state); + // bool __fastcall SwitchEPBrake(Byte state); + // bool __fastcall AntiSlippingButton(void); + // bool __fastcall IncBrakePress(double &brake, double PressLimit, double dp); + // bool __fastcall DecBrakePress(double &brake, double PressLimit, double dp); + // bool __fastcall BrakeDelaySwitch(Byte BDS); + // bool __fastcall IncBrakeMult(void); + // bool __fastcall DecBrakeMult(void); + // void __fastcall UpdateBrakePressure(double dt); + // void __fastcall UpdatePipePressure(double dt); + // void __fastcall CompressorCheck(double dt); + void __fastcall UpdatePantVolume(double dt); + // void __fastcall UpdateScndPipePressure(double dt); + // void __fastcall UpdateBatteryVoltage(double dt); + // double __fastcall GetDVc(double dt); + // void __fastcall ComputeConstans(void); + // double __fastcall ComputeMass(void); + // double __fastcall Adhesive(double staticfriction); + // double __fastcall TractionForce(double dt); + // double __fastcall FrictionForce(double R, Byte TDamage); + // double __fastcall BrakeForce(const TTrackParam &Track); + // double __fastcall CouplerForce(Byte CouplerN, double dt); + // void __fastcall CollisionDetect(Byte CouplerN, double dt); + // double __fastcall ComputeRotatingWheel(double WForce, double dt, double n); + // bool __fastcall SetInternalCommand(AnsiString NewCommand, double NewValue1, double + // NewValue2); + // double __fastcall GetExternalCommand(AnsiString &Command); + // bool __fastcall RunCommand(AnsiString command, double CValue1, double CValue2); + // bool __fastcall RunInternalCommand(void); + // void __fastcall PutCommand(AnsiString NewCommand, double NewValue1, double NewValue2, const + // TLocation + // &NewLocation); + // bool __fastcall DirectionBackward(void); + // bool __fastcall MainSwitch(bool State); + // bool __fastcall ConverterSwitch(bool State); + // bool __fastcall CompressorSwitch(bool State); + void __fastcall ConverterCheck(); + // bool __fastcall FuseOn(void); + // bool __fastcall FuseFlagCheck(void); + // void __fastcall FuseOff(void); + int __fastcall ShowCurrent(Byte AmpN); + // double __fastcall v2n(void); + // double __fastcall current(double n, double U); + // double __fastcall Momentum(double I); + // double __fastcall MomentumF(double I, double Iw, Byte SCP); + // bool __fastcall CutOffEngine(void); + // bool __fastcall MaxCurrentSwitch(bool State); + // bool __fastcall ResistorsFlagCheck(void); + // bool __fastcall MinCurrentSwitch(bool State); + // bool __fastcall AutoRelaySwitch(bool State); + // bool __fastcall AutoRelayCheck(void); + // bool __fastcall dizel_EngageSwitch(double state); + // bool __fastcall dizel_EngageChange(double dt); + // bool __fastcall dizel_AutoGearCheck(void); + // double __fastcall dizel_fillcheck(Byte mcp); + // double __fastcall dizel_Momentum(double dizel_fill, double n, double dt); + // bool __fastcall dizel_Update(double dt); + // bool __fastcall LoadingDone(double LSpeed, AnsiString LoadInit); + // void __fastcall ComputeTotalForce(double dt, double dt1, bool FullVer); + // double __fastcall ComputeMovement(double dt, double dt1, const TTrackShape &Shape, + // TTrackParam &Track + // , TTractionParam &ElectricTraction, const TLocation &NewLoc, TRotation &NewRot); + // double __fastcall FastComputeMovement(double dt, const TTrackShape &Shape, TTrackParam + // &Track, const + // TLocation &NewLoc, TRotation &NewRot); + // bool __fastcall ChangeOffsetH(double DeltaOffset); + //__fastcall T_MoverParameters(double VelInitial, AnsiString TypeNameInit, AnsiString NameInit, + //int LoadInitial + // , AnsiString LoadTypeInitial, int Cab); + // bool __fastcall LoadChkFile(AnsiString chkpath); + // bool __fastcall CheckLocomotiveParameters(bool ReadyFlag, int Dir); + // AnsiString __fastcall EngineDescription(int what); + // bool __fastcall DoorLeft(bool State); + // bool __fastcall DoorRight(bool State); + // bool __fastcall DoorBlockedFlag(void); + // bool __fastcall PantFront(bool State); + // bool __fastcall PantRear(bool State); + // }; #endif diff --git a/Names.cpp b/Names.cpp index 07da8552..3a4a3105 100644 --- a/Names.cpp +++ b/Names.cpp @@ -31,137 +31,146 @@ Obiekty sortowane wg nazw, mo */ -void __fastcall ItemRecord::TreeAdd(ItemRecord *r,int c) -{//dodanie rekordu do drzewa - ustalenie w której gałęzi - //zapisać w (iFlags) ile znaków jest zgodnych z nadrzędnym, żeby nie sprawdzać wszystkich od zera - if ((cName[c]&&r->cName[c])?cName[c]==r->cName[c]:false) - TreeAdd(r,c+1); //ustawić wg kolejnego znaku, chyba że zero - else - if ((unsigned char)(cName[c])<(unsigned char)(r->cName[c])) - {//zero jest najmniejsze - doczepiamy jako (rNext) - if (!rNext) rNext=r; - else rNext->TreeAdd(r,0); //doczepić do tej gałęzi - } - else - { - if (!rPrev) rPrev=r; - else rPrev->TreeAdd(r,0); //doczepić do tej gałęzi - } +void __fastcall ItemRecord::TreeAdd(ItemRecord *r, int c) +{ // dodanie rekordu do drzewa - ustalenie w której gałęzi + // zapisać w (iFlags) ile znaków jest zgodnych z nadrzędnym, żeby nie sprawdzać wszystkich od + // zera + if ((cName[c] && r->cName[c]) ? cName[c] == r->cName[c] : false) + TreeAdd(r, c + 1); // ustawić wg kolejnego znaku, chyba że zero + else if ((unsigned char)(cName[c]) < (unsigned char)(r->cName[c])) + { // zero jest najmniejsze - doczepiamy jako (rNext) + if (!rNext) + rNext = r; + else + rNext->TreeAdd(r, 0); // doczepić do tej gałęzi + } + else + { + if (!rPrev) + rPrev = r; + else + rPrev->TreeAdd(r, 0); // doczepić do tej gałęzi + } }; -void __fastcall ItemRecord::ListGet(ItemRecord *r,int*&n) -{//rekurencyjne wypełnianie posortowanej listy na podstawie drzewa - if (rPrev) rPrev->ListGet(r,n); //dodanie wszystkich wcześniejszych - *n++=this-r; //dodanie swojego indeksu do tabeli - if (rNext) rNext->ListGet(r,n); //dodanie wszystkich późniejszych +void __fastcall ItemRecord::ListGet(ItemRecord *r, int *&n) +{ // rekurencyjne wypełnianie posortowanej listy na podstawie drzewa + if (rPrev) + rPrev->ListGet(r, n); // dodanie wszystkich wcześniejszych + *n++ = this - r; // dodanie swojego indeksu do tabeli + if (rNext) + rNext->ListGet(r, n); // dodanie wszystkich późniejszych }; -void* __fastcall ItemRecord::TreeFind(const char *n) -{//wyszukanie ciągu (n) - ItemRecord *r=TreeFindRecord(n); - return r?r->pData:NULL; +void *__fastcall ItemRecord::TreeFind(const char *n) +{ // wyszukanie ciągu (n) + ItemRecord *r = TreeFindRecord(n); + return r ? r->pData : NULL; }; -ItemRecord* __fastcall ItemRecord::TreeFindRecord(const char *n) -{//wyszukanie ciągu (n) - ItemRecord *r=this; //żeby nie robić rekurencji - int i=0; - do - { - if (!n[i]) if (!r->cName[i]) return r; //znaleziony - if (n[i]==r->cName[i]) - ++i; //porównać kolejny znak - else - if ((unsigned char)(n[i])<(unsigned char)(r->cName[i])) - { - i=0; //porównywać od nowa - r=r->rPrev; //wcześniejsza gałąź drzewa - } - else - { - i=0; //porównywać od nowa - r=r->rNext; //późniejsza gałąź drzewa - } - } while (r); - return NULL; +ItemRecord *__fastcall ItemRecord::TreeFindRecord(const char *n) +{ // wyszukanie ciągu (n) + ItemRecord *r = this; //żeby nie robić rekurencji + int i = 0; + do + { + if (!n[i]) + if (!r->cName[i]) + return r; // znaleziony + if (n[i] == r->cName[i]) + ++i; // porównać kolejny znak + else if ((unsigned char)(n[i]) < (unsigned char)(r->cName[i])) + { + i = 0; // porównywać od nowa + r = r->rPrev; // wcześniejsza gałąź drzewa + } + else + { + i = 0; // porównywać od nowa + r = r->rNext; // późniejsza gałąź drzewa + } + } while (r); + return NULL; }; __fastcall TNames::TNames() -{//tworzenie bufora - iSize=16*1024*1024; //rozmiar bufora w bajtach - cBuffer=new char[iSize]; - ZeroMemory(cBuffer,iSize); //nie trzymać jakiś starych śmieci - rRecords=(ItemRecord*)cBuffer; - cLast=cBuffer+iSize; //bajt za buforem - iLast=-1; - ZeroMemory(rTypes,20*sizeof(ItemRecord*)); +{ // tworzenie bufora + iSize = 16 * 1024 * 1024; // rozmiar bufora w bajtach + cBuffer = new char[iSize]; + ZeroMemory(cBuffer, iSize); // nie trzymać jakiś starych śmieci + rRecords = (ItemRecord *)cBuffer; + cLast = cBuffer + iSize; // bajt za buforem + iLast = -1; + ZeroMemory(rTypes, 20 * sizeof(ItemRecord *)); }; -int __fastcall TNames::Add(int t,const char *n) -{//dodanie obiektu typu (t) o nazwie (n) - int len=strlen(n)+1; //ze znacznikiem końca - cLast-=len; //rezerwacja miejsca - memcpy(cLast,n,len); //przekopiowanie tekstu do bufora - //cLast[len-1]='\0'; - rRecords[++iLast].cName=cLast; //połączenie nazwy z rekordem - rRecords[iLast].iFlags=t; - if (!rTypes[t]) - rTypes[t]=rRecords+iLast; //korzeń drzewa, bo nie było wcześniej - else - rTypes[t]->TreeAdd(rRecords+iLast,0); //doczepienie jako gałąź - //rTypes[t]=Sort(t); //sortowanie uruchamiać ręcznie - if ((iLast&0x3F)==0) //nie za często, bo sortowania zajmą więcej czasu niż wyszukiwania - Sort(t); //optymalizacja drzewa co jakiś czas - return iLast; +int __fastcall TNames::Add(int t, const char *n) +{ // dodanie obiektu typu (t) o nazwie (n) + int len = strlen(n) + 1; // ze znacznikiem końca + cLast -= len; // rezerwacja miejsca + memcpy(cLast, n, len); // przekopiowanie tekstu do bufora + // cLast[len-1]='\0'; + rRecords[++iLast].cName = cLast; // połączenie nazwy z rekordem + rRecords[iLast].iFlags = t; + if (!rTypes[t]) + rTypes[t] = rRecords + iLast; // korzeń drzewa, bo nie było wcześniej + else + rTypes[t]->TreeAdd(rRecords + iLast, 0); // doczepienie jako gałąź + // rTypes[t]=Sort(t); //sortowanie uruchamiać ręcznie + if ((iLast & 0x3F) == 0) // nie za często, bo sortowania zajmą więcej czasu niż wyszukiwania + Sort(t); // optymalizacja drzewa co jakiś czas + return iLast; } -int __fastcall TNames::Add(int t,const char *n,void *d) +int __fastcall TNames::Add(int t, const char *n, void *d) { - int i=Add(t,n); - rRecords[iLast].pData=d; - return i; + int i = Add(t, n); + rRecords[iLast].pData = d; + return i; }; -bool __fastcall TNames::Update(int t,const char *n,void *d) -{//dodanie jeśli nie ma, wymiana (d), gdy jest - ItemRecord *r=FindRecord(t,n); //najpierw sprawdzić, czy już jest - if (r) - {//przy zdublowaniu nazwy podmieniać w drzewku na późniejszy - r->pData=d; - return true; //duplikat - } - //Add(t,n,d); //nazwa unikalna - return false; //został dodany nowy +bool __fastcall TNames::Update(int t, const char *n, void *d) +{ // dodanie jeśli nie ma, wymiana (d), gdy jest + ItemRecord *r = FindRecord(t, n); // najpierw sprawdzić, czy już jest + if (r) + { // przy zdublowaniu nazwy podmieniać w drzewku na późniejszy + r->pData = d; + return true; // duplikat + } + // Add(t,n,d); //nazwa unikalna + return false; // został dodany nowy }; -ItemRecord* __fastcall TNames::TreeSet(int *n,int d,int u) -{//rekurencyjne wypełnianie drzewa pozycjami od (d) do (u) - if (d==u) - { - rRecords[n[d]].rPrev=rRecords[n[d]].rNext=NULL; - return rRecords+n[d]; //tej gałęzi nie ma - } - else if (d>u) return NULL; - int p=(u+d)>>1; //połowa - rRecords[n[p]].rPrev=TreeSet(n,d,p-1); //zapisanie wcześniejszych gałęzi - rRecords[n[p]].rNext=TreeSet(n,p+1,u); //zapisanie późniejszych gałęzi - return rRecords+n[p]; +ItemRecord *__fastcall TNames::TreeSet(int *n, int d, int u) +{ // rekurencyjne wypełnianie drzewa pozycjami od (d) do (u) + if (d == u) + { + rRecords[n[d]].rPrev = rRecords[n[d]].rNext = NULL; + return rRecords + n[d]; // tej gałęzi nie ma + } + else if (d > u) + return NULL; + int p = (u + d) >> 1; // połowa + rRecords[n[p]].rPrev = TreeSet(n, d, p - 1); // zapisanie wcześniejszych gałęzi + rRecords[n[p]].rNext = TreeSet(n, p + 1, u); // zapisanie późniejszych gałęzi + return rRecords + n[p]; }; void __fastcall TNames::Sort(int t) -{//przebudowa drzewa typu (t), zwraca wierzchołek drzewa - if (iLast<3) return; //jak jest mało, to nie ma sensu sortować - if (rTypes[t]) //jeśli jest jakiś rekord danego typu - {int *r=new int[iLast+1]; //robocza tablica indeksów - numery posortowanych rekordów - int *q=r; //wskaźnik roboczy, przekazywany przez referencję - rTypes[t]->ListGet(rRecords,q); //drzewo jest już posortowane - zamienić je na listę - rTypes[t]=TreeSet(r,0,(q-r)-1); - delete[] r; - } - return; +{ // przebudowa drzewa typu (t), zwraca wierzchołek drzewa + if (iLast < 3) + return; // jak jest mało, to nie ma sensu sortować + if (rTypes[t]) // jeśli jest jakiś rekord danego typu + { + int *r = new int[iLast + 1]; // robocza tablica indeksów - numery posortowanych rekordów + int *q = r; // wskaźnik roboczy, przekazywany przez referencję + rTypes[t]->ListGet(rRecords, q); // drzewo jest już posortowane - zamienić je na listę + rTypes[t] = TreeSet(r, 0, (q - r) - 1); + delete[] r; + } + return; }; -ItemRecord* __fastcall TNames::FindRecord(const int t,const char *n) -{//poszukiwanie rekordu w celu np. zmiany wskaźnika - return rTypes[t]?rTypes[t]->TreeFindRecord(n):NULL; +ItemRecord *__fastcall TNames::FindRecord(const int t, const char *n) +{ // poszukiwanie rekordu w celu np. zmiany wskaźnika + return rTypes[t] ? rTypes[t]->TreeFindRecord(n) : NULL; }; - diff --git a/Names.h b/Names.h index 03db8c9c..beeaa938 100644 --- a/Names.h +++ b/Names.h @@ -4,50 +4,53 @@ #define NamesH //--------------------------------------------------------------------------- class ItemRecord -{//rekord opisujący obiekt; raz utworzony nie przemieszcza się - //rozmiar rekordu można zmienić w razie potrzeby -public: - char *cName; //wskaźnik do nazwy umieszczonej w buforze - int iFlags; //flagi bitowe - ItemRecord *rPrev,*rNext; //posortowane drzewo (przebudowywane w razie potrzeby) - union - {void *pData; //wskaźnik do obiektu - int iData; //albo numer obiektu (tekstury) - unsigned int uData; - }; - //typedef - void __fastcall ListGet(ItemRecord *r,int*&n); - void __fastcall TreeAdd(ItemRecord *r,int c); - template inline TOut* DataGet() {return (TOut*)pData;}; - template inline void DataSet(TOut *x) {pData=(void*)x;}; - void* __fastcall TreeFind(const char *n); - ItemRecord* __fastcall TreeFindRecord(const char *n); +{ // rekord opisujący obiekt; raz utworzony nie przemieszcza się + // rozmiar rekordu można zmienić w razie potrzeby + public: + char *cName; // wskaźnik do nazwy umieszczonej w buforze + int iFlags; // flagi bitowe + ItemRecord *rPrev, *rNext; // posortowane drzewo (przebudowywane w razie potrzeby) + union + { + void *pData; // wskaźnik do obiektu + int iData; // albo numer obiektu (tekstury) + unsigned int uData; + }; + // typedef + void __fastcall ListGet(ItemRecord *r, int *&n); + void __fastcall TreeAdd(ItemRecord *r, int c); + template inline TOut *DataGet() { return (TOut *)pData; }; + template inline void DataSet(TOut *x) { pData = (void *)x; }; + void *__fastcall TreeFind(const char *n); + ItemRecord *__fastcall TreeFindRecord(const char *n); }; class TNames { -public: - int iSize; //rozmiar bufora - char *cBuffer; //bufor dla rekordów (na początku) i nazw (na końcu) - ItemRecord *rRecords; //rekordy na początku bufora - char *cLast; //ostatni użyty bajt na nazwy - ItemRecord *rTypes[20]; //rożne typy obiektów (początek drzewa) - int iLast; //ostatnio użyty rekord -public: - __fastcall TNames(); - int __fastcall Add(int t,const char *n); //dodanie obiektu typu (t) - int __fastcall Add(int t,const char *n,void *d); //dodanie obiektu z wskaźnikiem - int __fastcall Add(int t,const char *n,int d); //dodanie obiektu z numerem - bool __fastcall Update(int t,const char *n,void *d); //dodanie jeśli nie ma, wymiana (d), gdy jest - void __fastcall TreeSet(); - ItemRecord* __fastcall TreeSet(int *n,int d,int u); - void __fastcall Sort(int t); //przebudowa drzewa typu (t) - ItemRecord* __fastcall Item(int n); //rekord o numerze (n) - inline void* Find(const int t,const char *n) - {return rTypes[t]?rTypes[t]->TreeFind(n):NULL;}; - ItemRecord* __fastcall FindRecord(const int t,const char *n); - //template inline TOut* Find(const int t,const char *n) - //{return (TOut*)(rTypes[t]->TreeFind(n));}; + public: + int iSize; // rozmiar bufora + char *cBuffer; // bufor dla rekordów (na początku) i nazw (na końcu) + ItemRecord *rRecords; // rekordy na początku bufora + char *cLast; // ostatni użyty bajt na nazwy + ItemRecord *rTypes[20]; // rożne typy obiektów (początek drzewa) + int iLast; // ostatnio użyty rekord + public: + __fastcall TNames(); + int __fastcall Add(int t, const char *n); // dodanie obiektu typu (t) + int __fastcall Add(int t, const char *n, void *d); // dodanie obiektu z wskaźnikiem + int __fastcall Add(int t, const char *n, int d); // dodanie obiektu z numerem + bool __fastcall Update(int t, const char *n, + void *d); // dodanie jeśli nie ma, wymiana (d), gdy jest + void __fastcall TreeSet(); + ItemRecord *__fastcall TreeSet(int *n, int d, int u); + void __fastcall Sort(int t); // przebudowa drzewa typu (t) + ItemRecord *__fastcall Item(int n); // rekord o numerze (n) + inline void *Find(const int t, const char *n) + { + return rTypes[t] ? rTypes[t]->TreeFind(n) : NULL; + }; + ItemRecord *__fastcall FindRecord(const int t, const char *n); + // template inline TOut* Find(const int t,const char *n) + //{return (TOut*)(rTypes[t]->TreeFind(n));}; }; #endif - diff --git a/RealSound.cpp b/RealSound.cpp index 73e4cdfd..0a723a51 100644 --- a/RealSound.cpp +++ b/RealSound.cpp @@ -5,8 +5,8 @@ */ -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "math.h" @@ -18,260 +18,273 @@ __fastcall TRealSound::TRealSound() { - pSound=NULL; - dSoundAtt=-1; - AM=0.0; - AA=0.0; - FM=0.0; - FA=0.0; - vSoundPosition.x=0; - vSoundPosition.y=0; - vSoundPosition.z=0; - fDistance=fPreviousDistance=0.0; - fFrequency=22050.0; //częstotliwość samplowania pliku - iDoppler=0; //normlanie jest załączony; !=0 - modyfikacje - bLoopPlay=false; //dźwięk wyłączony + pSound = NULL; + dSoundAtt = -1; + AM = 0.0; + AA = 0.0; + FM = 0.0; + FA = 0.0; + vSoundPosition.x = 0; + vSoundPosition.y = 0; + vSoundPosition.z = 0; + fDistance = fPreviousDistance = 0.0; + fFrequency = 22050.0; // częstotliwość samplowania pliku + iDoppler = 0; // normlanie jest załączony; !=0 - modyfikacje + bLoopPlay = false; // dźwięk wyłączony } __fastcall TRealSound::~TRealSound() { - //if (this) if (pSound) pSound->Stop(); + // if (this) if (pSound) pSound->Stop(); } -void __fastcall TRealSound::Free() -{ -} +void __fastcall TRealSound::Free() {} -void __fastcall TRealSound::Init(char *SoundName, double DistanceAttenuation, double X, double Y, double Z,bool Dynamic,bool freqmod,double rmin) +void __fastcall TRealSound::Init(char *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); - if (pSound) - { - if (freqmod) - if (fFrequency!=22050.0) - {//dla modulowanych nie może być zmiany mnożnika, bo częstotliwość w nagłówku byłą ignorowana, a mogła być inna niż 22050 - fFrequency=22050.0; - ErrorLog("Bad sound: "+AnsiString(SoundName)+", as modulated, should have 22.05kHz in header"); - } - AM=1.0; - pSound->SetVolume(DSBVOLUME_MIN); - } - else - {//nie ma dźwięku, to jest wysyp - AM=0; - ErrorLog("Missed sound: "+AnsiString(SoundName)); - } - if (DistanceAttenuation>0.0) - { - dSoundAtt=DistanceAttenuation*DistanceAttenuation; - vSoundPosition.x=X; - vSoundPosition.y=Y; - vSoundPosition.z=Z; - if (rmin<0) iDoppler=1; //wyłączenie efektu Dopplera, np. dla dźwięku ptaków - } - else - dSoundAtt=-1; + // Nazwa=SoundName; //to tak raczej nie zadziała, (SoundName) jest tymczasowe + pSound = TSoundsManager::GetFromName(SoundName, Dynamic, &fFrequency); + if (pSound) + { + if (freqmod) + if (fFrequency != 22050.0) + { // dla modulowanych nie może być zmiany mnożnika, bo częstotliwość w nagłówku byłą + // ignorowana, a mogła być inna niż 22050 + fFrequency = 22050.0; + ErrorLog("Bad sound: " + AnsiString(SoundName) + + ", as modulated, should have 22.05kHz in header"); + } + AM = 1.0; + pSound->SetVolume(DSBVOLUME_MIN); + } + else + { // nie ma dźwięku, to jest wysyp + AM = 0; + ErrorLog("Missed sound: " + AnsiString(SoundName)); + } + if (DistanceAttenuation > 0.0) + { + dSoundAtt = DistanceAttenuation * DistanceAttenuation; + vSoundPosition.x = X; + vSoundPosition.y = Y; + vSoundPosition.z = Z; + if (rmin < 0) + iDoppler = 1; // wyłączenie efektu Dopplera, np. dla dźwięku ptaków + } + else + dSoundAtt = -1; }; - double __fastcall TRealSound::ListenerDistance(vector3 ListenerPosition) { - if (dSoundAtt==-1) - { return 0.0; } - else - { return SquareMagnitude(ListenerPosition-vSoundPosition); } + if (dSoundAtt == -1) + { + return 0.0; + } + else + { + return SquareMagnitude(ListenerPosition - vSoundPosition); + } } -void __fastcall TRealSound::Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition) +void __fastcall TRealSound::Play(double Volume, int Looping, bool ListenerInside, + vector3 NewPosition) { - if (!pSound) return; - long int vol; - double dS; -// double Distance; - DWORD stat; - if ((Global::bSoundEnabled)&&(AM!=0)) - { - if (Volume>1.0) - Volume=1.0; - fPreviousDistance=fDistance; - fDistance=0.0; //?? - if (dSoundAtt>0.0) - { - vSoundPosition=NewPosition; - dS=dSoundAtt; //*dSoundAtt; //bo odleglosc podawana w kwadracie - fDistance=ListenerDistance(Global::pCameraPosition); - if (ListenerInside) //osłabianie dźwięków z odległością - Volume=Volume*dS/(dS+fDistance); - else - Volume=Volume*dS/(dS+2*fDistance); //podwójne dla ListenerInside=false - } - if (iDoppler) // - {//Ra 2014-07: efekt Dopplera nie zawsze jest wskazany - //if (FreeFlyModeFlag) //gdy swobodne latanie - nie sprawdza się to - fPreviousDistance=fDistance; //to efektu Dopplera nie będzie - } - if (Looping) //dźwięk zapętlony można wyłączyć i zostanie włączony w miarę potrzeby - bLoopPlay=true; //dźwięk wyłączony - //McZapkie-010302 - babranie tylko z niezbyt odleglymi dźwiękami - if ((dSoundAtt==-1)||(fDistance<20.0*dS)) - { -// vol=2*Volume+1; -// if (vol<1) vol=1; -// vol=10000*(log(vol)-1); -// vol=10000*(vol-1); - //int glos=1; - //Volume=Volume*glos; //Ra: whatta hella is this - if (Volume<0.0) Volume=0.0; - vol=-5000.0+5000.0*Volume; - if (vol>=0) - vol=-1; - if (Timer::GetSoundTimer()||!Looping) //Ra: po co to jest? - pSound->SetVolume(vol); //Attenuation, in hundredths of a decibel (dB). - pSound->GetStatus(&stat); - if (!(stat&DSBSTATUS_PLAYING)) - pSound->Play(0,0,Looping); - } - else //wylacz dzwiek bo daleko - {//Ra 2014-09: oddalanie się nie może być powodem do wyłączenie dźwięku -/* -// Ra: stara wersja, ale podobno lepsza - pSound->GetStatus(&stat); - if (bLoopPlay) //jeśli zapętlony, to zostanie ponownie włączony, o ile znajdzie się bliżej - if (stat&DSBSTATUS_PLAYING) - pSound->Stop(); -// Ra: wyłączyłem, bo podobno jest gorzej niż wcześniej - //ZiomalCl: dźwięk po wyłączeniu sam się nie włączy, gdy wrócimy w rejon odtwarzania - pSound->SetVolume(DSBVOLUME_MIN); //dlatego lepiej go wyciszyć na czas oddalenia się - pSound->GetStatus(&stat); - if (!(stat&DSBSTATUS_PLAYING)) - pSound->Play(0,0,Looping); //ZiomalCl: włączenie odtwarzania rownież i tu, gdyż jesli uruchamiamy dźwięk poza promieniem, nie uruchomi się on w ogóle -*/ - } - } + if (!pSound) + return; + long int vol; + double dS; + // double Distance; + DWORD stat; + if ((Global::bSoundEnabled) && (AM != 0)) + { + if (Volume > 1.0) + Volume = 1.0; + fPreviousDistance = fDistance; + fDistance = 0.0; //?? + if (dSoundAtt > 0.0) + { + vSoundPosition = NewPosition; + dS = dSoundAtt; //*dSoundAtt; //bo odleglosc podawana w kwadracie + fDistance = ListenerDistance(Global::pCameraPosition); + if (ListenerInside) // osłabianie dźwięków z odległością + Volume = Volume * dS / (dS + fDistance); + else + Volume = Volume * dS / (dS + 2 * fDistance); // podwójne dla ListenerInside=false + } + if (iDoppler) // + { // Ra 2014-07: efekt Dopplera nie zawsze jest wskazany + // if (FreeFlyModeFlag) //gdy swobodne latanie - nie sprawdza się to + fPreviousDistance = fDistance; // to efektu Dopplera nie będzie + } + if (Looping) // dźwięk zapętlony można wyłączyć i zostanie włączony w miarę potrzeby + bLoopPlay = true; // dźwięk wyłączony + // McZapkie-010302 - babranie tylko z niezbyt odleglymi dźwiękami + if ((dSoundAtt == -1) || (fDistance < 20.0 * dS)) + { + // vol=2*Volume+1; + // if (vol<1) vol=1; + // vol=10000*(log(vol)-1); + // vol=10000*(vol-1); + // int glos=1; + // Volume=Volume*glos; //Ra: whatta hella is this + if (Volume < 0.0) + Volume = 0.0; + vol = -5000.0 + 5000.0 * Volume; + if (vol >= 0) + vol = -1; + if (Timer::GetSoundTimer() || !Looping) // Ra: po co to jest? + pSound->SetVolume(vol); // Attenuation, in hundredths of a decibel (dB). + pSound->GetStatus(&stat); + if (!(stat & DSBSTATUS_PLAYING)) + pSound->Play(0, 0, Looping); + } + else // wylacz dzwiek bo daleko + { // Ra 2014-09: oddalanie się nie może być powodem do wyłączenie dźwięku + /* + // Ra: stara wersja, ale podobno lepsza + pSound->GetStatus(&stat); + if (bLoopPlay) //jeśli zapętlony, to zostanie ponownie włączony, o ile znajdzie się + bliżej + if (stat&DSBSTATUS_PLAYING) + pSound->Stop(); + // Ra: wyłączyłem, bo podobno jest gorzej niż wcześniej + //ZiomalCl: dźwięk po wyłączeniu sam się nie włączy, gdy wrócimy w rejon odtwarzania + pSound->SetVolume(DSBVOLUME_MIN); //dlatego lepiej go wyciszyć na czas oddalenia się + pSound->GetStatus(&stat); + if (!(stat&DSBSTATUS_PLAYING)) + pSound->Play(0,0,Looping); //ZiomalCl: włączenie odtwarzania rownież i tu, gdyż + jesli uruchamiamy dźwięk poza promieniem, nie uruchomi się on w ogóle + */ + } + } }; -void __fastcall TRealSound::Start() -{//włączenie dźwięku +void __fastcall TRealSound::Start(){// włączenie dźwięku }; void __fastcall TRealSound::Stop() { - DWORD stat; - if (pSound) - if ((Global::bSoundEnabled)&&(AM!=0)) - { - bLoopPlay=false; //dźwięk wyłączony - pSound->GetStatus(&stat); - if (stat&DSBSTATUS_PLAYING) - pSound->Stop(); - } + DWORD stat; + if (pSound) + if ((Global::bSoundEnabled) && (AM != 0)) + { + bLoopPlay = false; // dźwięk wyłączony + pSound->GetStatus(&stat); + if (stat & DSBSTATUS_PLAYING) + pSound->Stop(); + } }; -void __fastcall TRealSound::AdjFreq(double Freq, double dt) //McZapkie TODO: dorobic tu efekt Dopplera -//Freq moze byc liczba dodatnia mniejsza od 1 lub wieksza od 1 +void __fastcall TRealSound::AdjFreq(double Freq, + double dt) // McZapkie TODO: dorobic tu efekt Dopplera +// Freq moze byc liczba dodatnia mniejsza od 1 lub wieksza od 1 { - float df, Vlist, Vsrc; - if ((Global::bSoundEnabled) && (AM!=0)) - { - if (dt>0) -//efekt Dopplera + float df, Vlist, Vsrc; + if ((Global::bSoundEnabled) && (AM != 0)) { - Vlist=(sqrt(fPreviousDistance)-sqrt(fDistance))/dt; - df= Freq*(1+Vlist/299.8); + if (dt > 0) + // efekt Dopplera + { + Vlist = (sqrt(fPreviousDistance) - sqrt(fDistance)) / dt; + df = Freq * (1 + Vlist / 299.8); + } + else + df = Freq; + if (Timer::GetSoundTimer()) + { + df = fFrequency * df; // TODO - brac czestotliwosc probkowania z wav + pSound->SetFrequency((df < DSBFREQUENCY_MIN ? + DSBFREQUENCY_MIN : + (df > DSBFREQUENCY_MAX ? DSBFREQUENCY_MAX : df))); + } } - else - df=Freq; - if (Timer::GetSoundTimer()) - { - df=fFrequency*df; //TODO - brac czestotliwosc probkowania z wav - pSound->SetFrequency(( dfDSBFREQUENCY_MAX ? DSBFREQUENCY_MAX : df) ) ); - } - } } -double TRealSound::GetWaveTime() //McZapkie: na razie tylko dla 22KHz/8bps -{//używana do pomiaru czasu dla dźwięków z początkiem i końcem - if (!pSound) return 0.0; - double WaveTime; - DSBCAPS caps; - caps.dwSize=sizeof(caps); - pSound->GetCaps(&caps); - WaveTime=caps.dwBufferBytes; - return WaveTime/fFrequency; //(pSound->); // wielkosc w bajtach przez czestotliwosc probkowania +double TRealSound::GetWaveTime() // McZapkie: na razie tylko dla 22KHz/8bps +{ // używana do pomiaru czasu dla dźwięków z początkiem i końcem + if (!pSound) + return 0.0; + double WaveTime; + DSBCAPS caps; + caps.dwSize = sizeof(caps); + pSound->GetCaps(&caps); + WaveTime = caps.dwBufferBytes; + return WaveTime / + fFrequency; //(pSound->); // wielkosc w bajtach przez czestotliwosc probkowania } -void __fastcall TRealSound::SetPan(int Pan) -{ - pSound->SetPan(Pan); -} +void __fastcall TRealSound::SetPan(int Pan) { pSound->SetPan(Pan); } int TRealSound::GetStatus() { -DWORD stat; - if ((Global::bSoundEnabled) && (AM!=0)) - { - pSound->GetStatus(&stat); - return stat; - } - else - return 0; + DWORD stat; + if ((Global::bSoundEnabled) && (AM != 0)) + { + pSound->GetStatus(&stat); + return stat; + } + else + return 0; } void __fastcall TRealSound::ResetPosition() { - if (pSound) //Ra: znowu jakiś badziew! - pSound->SetCurrentPosition(0); + if (pSound) // Ra: znowu jakiś badziew! + pSound->SetCurrentPosition(0); } -void __fastcall TTextSound::Init(char *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(); - AnsiString txt=AnsiString(SoundName); - txt.Delete(txt.Length()-3,4); //obcięcie rozszerzenia - for (int i=txt.Length();i>0;--i) - if (txt[i]=='/') txt[i]='\\'; //bo nie rozumi - txt+="-"+Global::asLang+".txt"; //już może być w różnych językach - if (!FileExists(txt)) - 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; - } -}; -void __fastcall TTextSound::Play(double Volume,int Looping,bool ListenerInside,vector3 NewPosition) -{ - if (!asText.IsEmpty()) - {//jeśli ma powiązany tekst - DWORD stat; - pSound->GetStatus(&stat); - if (!(stat&DSBSTATUS_PLAYING)) //jeśli nie jest aktualnie odgrywany - { - int i; - AnsiString t=asText; - do - {//na razie zrobione jakkolwiek, docelowo przenieść teksty do tablicy nazw - i=t.Pos("\r"); //znak nowej linii - if (!i) - Global::tranTexts.Add(t.c_str(),fTime,true); - else - { - Global::tranTexts.Add(t.SubString(1,i-1).c_str(),fTime,true); - t.Delete(1,i); - while (t.IsEmpty()?false:(unsigned char)(t[1])<33) - t.Delete(1,1); +void __fastcall TTextSound::Init(char *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(); + AnsiString txt = AnsiString(SoundName); + txt.Delete(txt.Length() - 3, 4); // obcięcie rozszerzenia + for (int i = txt.Length(); i > 0; --i) + if (txt[i] == '/') + txt[i] = '\\'; // bo nie rozumi + txt += "-" + Global::asLang + ".txt"; // już może być w różnych językach + if (!FileExists(txt)) + 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; } - } while (i>0); - } - } - TRealSound::Play(Volume,Looping,ListenerInside,NewPosition); +}; +void __fastcall TTextSound::Play(double Volume, int Looping, bool ListenerInside, + vector3 NewPosition) +{ + if (!asText.IsEmpty()) + { // jeśli ma powiązany tekst + DWORD stat; + pSound->GetStatus(&stat); + if (!(stat & DSBSTATUS_PLAYING)) // jeśli nie jest aktualnie odgrywany + { + int i; + AnsiString t = asText; + do + { // na razie zrobione jakkolwiek, docelowo przenieść teksty do tablicy nazw + i = t.Pos("\r"); // znak nowej linii + if (!i) + Global::tranTexts.Add(t.c_str(), fTime, true); + else + { + Global::tranTexts.Add(t.SubString(1, i - 1).c_str(), fTime, true); + t.Delete(1, i); + while (t.IsEmpty() ? false : (unsigned char)(t[1]) < 33) + t.Delete(1, 1); + } + } while (i > 0); + } + } + TRealSound::Play(Volume, Looping, ListenerInside, NewPosition); }; //--------------------------------------------------------------------------- #pragma package(smart_init) - diff --git a/RealSound.h b/RealSound.h index 90d6d3e5..bf5f2cbb 100644 --- a/RealSound.h +++ b/RealSound.h @@ -7,60 +7,62 @@ class TRealSound { -protected: - PSound pSound; - char* Nazwa; //dla celow odwszawiania - double fDistance,fPreviousDistance; //dla liczenia Dopplera - float fFrequency; //częstotliwość samplowania pliku - int iDoppler; //Ra 2014-07: możliwość wyłączenia efektu Dopplera np. dla śpiewu ptaków -public: - vector3 vSoundPosition; //polozenie zrodla dzwieku - double dSoundAtt; //odleglosc polowicznego zaniku dzwieku - double AM; //mnoznik amplitudy - double AA; //offset amplitudy - double FM; //mnoznik czestotliwosci - double FA; //offset czestotliwosci - bool bLoopPlay; //czy zapętlony dźwięk jest odtwarzany - __fastcall TRealSound(); - __fastcall ~TRealSound(); - void __fastcall Free(); - void __fastcall Init(char *SoundName,double SoundAttenuation,double X,double Y,double Z,bool Dynamic,bool freqmod=false,double rmin=0.0); - double __fastcall ListenerDistance(vector3 ListenerPosition); - void __fastcall Play(double Volume,int Looping,bool ListenerInside,vector3 NewPosition); - void __fastcall Start(); - void __fastcall Stop(); - void __fastcall AdjFreq(double Freq,double dt); - void __fastcall SetPan(int Pan); - double GetWaveTime(); //McZapkie TODO: dorobic dla roznych bps - int GetStatus(); - void __fastcall ResetPosition(); - //void __fastcall FreqReset(float f=22050.0) {fFrequency=f;}; + protected: + PSound pSound; + char *Nazwa; // dla celow odwszawiania + double fDistance, fPreviousDistance; // dla liczenia Dopplera + float fFrequency; // częstotliwość samplowania pliku + int iDoppler; // Ra 2014-07: możliwość wyłączenia efektu Dopplera np. dla śpiewu ptaków + public: + vector3 vSoundPosition; // polozenie zrodla dzwieku + double dSoundAtt; // odleglosc polowicznego zaniku dzwieku + double AM; // mnoznik amplitudy + double AA; // offset amplitudy + double FM; // mnoznik czestotliwosci + double FA; // offset czestotliwosci + bool bLoopPlay; // czy zapętlony dźwięk jest odtwarzany + __fastcall TRealSound(); + __fastcall ~TRealSound(); + void __fastcall Free(); + void __fastcall Init(char *SoundName, double SoundAttenuation, double X, double Y, double Z, + bool Dynamic, bool freqmod = false, double rmin = 0.0); + double __fastcall ListenerDistance(vector3 ListenerPosition); + void __fastcall Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition); + void __fastcall Start(); + void __fastcall Stop(); + void __fastcall AdjFreq(double Freq, double dt); + void __fastcall SetPan(int Pan); + double GetWaveTime(); // McZapkie TODO: dorobic dla roznych bps + int GetStatus(); + void __fastcall ResetPosition(); + // void __fastcall FreqReset(float f=22050.0) {fFrequency=f;}; }; class TTextSound : public TRealSound -{//dźwięk ze stenogramem - AnsiString asText; - float fTime; //czas trwania -public: - void __fastcall Init(char *SoundName,double SoundAttenuation,double X,double Y,double Z,bool Dynamic,bool freqmod=false,double rmin=0.0); - void __fastcall Play(double Volume,int Looping,bool ListenerInside,vector3 NewPosition); +{ // dźwięk ze stenogramem + AnsiString asText; + float fTime; // czas trwania + public: + void __fastcall Init(char *SoundName, double SoundAttenuation, double X, double Y, double Z, + bool Dynamic, bool freqmod = false, double rmin = 0.0); + void __fastcall Play(double Volume, int Looping, bool ListenerInside, 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 - //0..9 - cyfry 0..9 - //10..19 - liczby 10..19 - //21..29 - dziesiątki (*21==*10?) - //31..39 - setki 100,200,...,800,900 - //40 - "tysiąc" - //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 - //a może zamiast wielu plików/dźwięków zrobić jeden połączony plik i posługiwać się czasem od..do? +{ // 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 + // 0..9 - cyfry 0..9 + // 10..19 - liczby 10..19 + // 21..29 - dziesiątki (*21==*10?) + // 31..39 - setki 100,200,...,800,900 + // 40 - "tysiąc" + // 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 + // a może zamiast wielu plików/dźwięków zrobić jeden połączony plik i posługiwać się czasem + // od..do? }; - //--------------------------------------------------------------------------- #endif diff --git a/ResourceManager.cpp b/ResourceManager.cpp index 20e1b927..9f8c6ad4 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -8,16 +8,13 @@ double ResourceManager::_expiry = 5.0f; double ResourceManager::_lastUpdate = 0.0f; double ResourceManager::_lastReport = 0.0f; -void ResourceManager::Register(Resource* resource) -{ - _resources.push_back(resource); -}; +void ResourceManager::Register(Resource *resource) { _resources.push_back(resource); }; -void ResourceManager::Unregister(Resource* resource) +void ResourceManager::Unregister(Resource *resource) { Resources::iterator iter = std::find(_resources.begin(), _resources.end(), resource); - if(iter != _resources.end()) + if (iter != _resources.end()) _resources.erase(iter); resource->Release(); @@ -25,35 +22,33 @@ void ResourceManager::Unregister(Resource* resource) class ResourceExpired { -public: - ResourceExpired(double time): _time(time) { }; - bool operator()(Resource* resource) - { - return (resource->GetLastUsage() < _time); - } + public: + ResourceExpired(double time) : _time(time){}; + bool operator()(Resource *resource) { return (resource->GetLastUsage() < _time); } -private: + private: double _time; }; void ResourceManager::Sweep(double currentTime) { - if(currentTime - _lastUpdate < _expiry) + if (currentTime - _lastUpdate < _expiry) return; - Resources::iterator begin = std::remove_if(_resources.begin(), _resources.end(), ResourceExpired(currentTime - _expiry)); + Resources::iterator begin = std::remove_if(_resources.begin(), _resources.end(), + ResourceExpired(currentTime - _expiry)); #ifdef RESOURCE_REPORTING - if(begin != _resources.end()) + if (begin != _resources.end()) WriteLog("Releasing resources"); #endif - for(Resources::iterator iter = begin; iter != _resources.end(); iter++) + for (Resources::iterator iter = begin; iter != _resources.end(); iter++) (*iter)->Release(); #ifdef RESOURCE_REPORTING - if(begin != _resources.end()) + if (begin != _resources.end()) { std::ostringstream msg; msg << "Released " << (_resources.end() - begin) << " resources"; @@ -64,7 +59,7 @@ void ResourceManager::Sweep(double currentTime) _resources.erase(begin, _resources.end()); #ifdef RESOURCE_REPORTING - if(currentTime - _lastReport > 30.0f) + if (currentTime - _lastReport > 30.0f) { std::ostringstream msg; msg << "Resources count: " << _resources.size(); @@ -74,5 +69,4 @@ void ResourceManager::Sweep(double currentTime) #endif _lastUpdate = currentTime; - }; diff --git a/ResourceManager.h b/ResourceManager.h index 5a16a008..49df9c4f 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -9,37 +9,35 @@ class Resource { -public: + public: virtual void Release() = 0; double GetLastUsage() const { return _lastUsage; } -protected: + protected: void SetLastUsage(double lastUsage) { _lastUsage = lastUsage; } -private: + private: double _lastUsage; - }; class ResourceManager { -public: - static void Register(Resource* resource); - static void Unregister(Resource* resource); + public: + static void Register(Resource *resource); + static void Unregister(Resource *resource); static void Sweep(double currentTime); static void SetExpiry(double expiry) { _expiry = expiry; } -private: - typedef std::vector Resources; + private: + typedef std::vector Resources; static double _expiry; static double _lastUpdate; static double _lastReport; - - static Resources _resources; + static Resources _resources; }; #endif diff --git a/Segment.cpp b/Segment.cpp index 77081a84..9b1edf1e 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -15,149 +15,145 @@ #pragma package(smart_init) //--------------------------------------------------------------------------- -//101206 Ra: trapezoidalne drogi -//110806 Ra: odwrócone mapowanie wzdłuż - Point1 == 1.0 +// 101206 Ra: trapezoidalne drogi +// 110806 Ra: odwrócone mapowanie wzdłuż - Point1 == 1.0 AnsiString __fastcall Where(vector3 p) -{//zamiana współrzędnych na tekst, używana w błędach - return AnsiString(p.x)+" "+AnsiString(p.y)+" "+AnsiString(p.z); +{ // zamiana współrzędnych na tekst, używana w błędach + return AnsiString(p.x) + " " + AnsiString(p.y) + " " + AnsiString(p.z); }; __fastcall TSegment::TSegment(TTrack *owner) { - Point1=CPointOut=CPointIn=Point2=vector3(0.0f,0.0f,0.0f); - fLength=0; - fRoll1=0; - fRoll2=0; - fTsBuffer=NULL; - fStep=0; - pOwner=owner; + Point1 = CPointOut = CPointIn = Point2 = vector3(0.0f, 0.0f, 0.0f); + fLength = 0; + fRoll1 = 0; + fRoll2 = 0; + fTsBuffer = NULL; + fStep = 0; + pOwner = owner; }; -__fastcall TSegment::~TSegment() -{ - SafeDeleteArray(fTsBuffer); +__fastcall TSegment::~TSegment() { SafeDeleteArray(fTsBuffer); }; + +bool __fastcall TSegment::Init(vector3 NewPoint1, vector3 NewPoint2, double fNewStep, + double fNewRoll1, double fNewRoll2) +{ // wersja dla prostego - wyliczanie punktów kontrolnych + vector3 dir; + if (fNewRoll1 == fNewRoll2) + { // faktyczny prosty + dir = Normalize(NewPoint2 - NewPoint1); // wektor kierunku o długości 1 + return TSegment::Init(NewPoint1, dir, -dir, NewPoint2, fNewStep, fNewRoll1, fNewRoll2, + false); + } + else + { // prosty ze zmienną przechyłką musi być segmentowany jak krzywe + dir = (NewPoint2 - NewPoint1) / 3.0; // punkty kontrolne prostego są w 1/3 długości + return TSegment::Init(NewPoint1, NewPoint1 + dir, NewPoint2 - dir, NewPoint2, fNewStep, + fNewRoll1, fNewRoll2, true); + } }; -bool __fastcall TSegment::Init( - vector3 NewPoint1,vector3 NewPoint2,double fNewStep, - double fNewRoll1,double fNewRoll2) -{//wersja dla prostego - wyliczanie punktów kontrolnych - vector3 dir; - if (fNewRoll1==fNewRoll2) - {//faktyczny prosty - dir=Normalize(NewPoint2-NewPoint1); //wektor kierunku o długości 1 - return TSegment::Init( - NewPoint1,dir,-dir,NewPoint2, - fNewStep,fNewRoll1,fNewRoll2, - false); - } - else - {//prosty ze zmienną przechyłką musi być segmentowany jak krzywe - dir=(NewPoint2-NewPoint1)/3.0; //punkty kontrolne prostego są w 1/3 długości - return TSegment::Init( - NewPoint1,NewPoint1+dir,NewPoint2-dir,NewPoint2, - fNewStep,fNewRoll1,fNewRoll2, - true); - } -}; - -bool __fastcall TSegment::Init( - vector3 &NewPoint1,vector3 NewCPointOut,vector3 NewCPointIn,vector3 &NewPoint2, - double fNewStep,double fNewRoll1, double fNewRoll2, bool bIsCurve) -{//wersja uniwersalna (dla krzywej i prostego) - Point1=NewPoint1; - CPointOut=NewCPointOut; - CPointIn=NewCPointIn; - Point2=NewPoint2; - //poprawienie przechyłki - fRoll1=DegToRad(fNewRoll1); //Ra: przeliczone jest bardziej przydatne do obliczeń - fRoll2=DegToRad(fNewRoll2); - if (Global::bRollFix) - {//Ra: poprawianie przechyłki - // Przechyłka powinna być na środku wewnętrznej szyny, a standardowo jest w osi - // toru. Dlatego trzeba podnieść tor oraz odpowiednio podwyższyć podsypkę. - // Nie wykonywać tej funkcji, jeśli podwyższenie zostało uwzględnione w edytorze. - // Problematyczne mogą byc rozjazdy na przechyłce - lepiej je modelować w edytorze. - // Na razie wszystkie scenerie powinny być poprawiane. - // Jedynie problem będzie z podwójną rampą przechyłkową, która w środku będzie - // mieć moment wypoziomowania, ale musi on być również podniesiony. - if (fRoll1!=0.0) - {//tylko jeśli jest przechyłka - double w1=fabs(sin(fRoll1)*0.75); //0.5*w2+0.0325; //0.75m dla 1.435 - Point1.y+=w1; //modyfikacja musi być przed policzeniem dalszych parametrów - if (bCurve) CPointOut.y+=w1; //prosty ma wektory jednostkowe - pOwner->MovedUp1(w1);//zwrócić trzeba informację o podwyższeniu podsypki - } - if (fRoll2!=0.0) - { - double w2=fabs(sin(fRoll2)*0.75); //0.5*w2+0.0325; //0.75m dla 1.435 - Point2.y+=w2; //modyfikacja musi być przed policzeniem dalszych parametrów - if (bCurve) CPointIn.y+=w2; //prosty ma wektory jednostkowe - //zwrócić trzeba informację o podwyższeniu podsypki - } - } - //Ra: ten kąt jeszcze do przemyślenia jest - fDirection=-atan2(Point2.x-Point1.x,Point2.z-Point1.z); //kąt w planie, żeby nie liczyć wielokrotnie - bCurve=bIsCurve; - if (bCurve) - {//przeliczenie współczynników wielomianu, będzie mniej mnożeń i można policzyć pochodne - vC=3.0*(CPointOut-Point1); //t^1 - vB=3.0*(CPointIn-CPointOut)-vC; //t^2 - vA=Point2-Point1-vC-vB; //t^3 - fLength=ComputeLength(); - } - else - fLength=(Point1-Point2).Length(); - fStep=fNewStep; - if (fLength<=0) - { - ErrorLog("Bad geometry: Length <= 0 in TSegment::Init at "+Where(Point1)); - //MessageBox(0,"Length<=0","TSegment::Init",MB_OK); - return false; //zerowe nie mogą być - } - fStoop=atan2((Point2.y-Point1.y),fLength); //pochylenie toru prostego, żeby nie liczyć wielokrotnie - SafeDeleteArray(fTsBuffer); - if ((bCurve) && (fStep>0)) - {//Ra: prosty dostanie podział, jak ma różną przechyłkę na końcach - double s=0; - int i=0; - iSegCount=ceil(fLength/fStep); //potrzebne do VBO - //fStep=fLength/(double)(iSegCount-1); //wyrównanie podziału - fTsBuffer=new double[iSegCount+1]; - fTsBuffer[0]=0; /* TODO : fix fTsBuffer */ - while (sfLength) s=fLength; - fTsBuffer[i]=GetTFromS(s); - } - } - if (fLength>500) - {//tor ma pojemność 40 pojazdów, więc nie może być za długi - ErrorLog("Bad geometry: Length > 500m at "+Where(Point1)); - //MessageBox(0,"Length>500","TSegment::Init",MB_OK); - return false; - } - return true; +bool __fastcall TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointIn, + vector3 &NewPoint2, double fNewStep, double fNewRoll1, + double fNewRoll2, bool bIsCurve) +{ // wersja uniwersalna (dla krzywej i prostego) + Point1 = NewPoint1; + CPointOut = NewCPointOut; + CPointIn = NewCPointIn; + Point2 = NewPoint2; + // poprawienie przechyłki + fRoll1 = DegToRad(fNewRoll1); // Ra: przeliczone jest bardziej przydatne do obliczeń + fRoll2 = DegToRad(fNewRoll2); + if (Global::bRollFix) + { // Ra: poprawianie przechyłki + // Przechyłka powinna być na środku wewnętrznej szyny, a standardowo jest w osi + // toru. Dlatego trzeba podnieść tor oraz odpowiednio podwyższyć podsypkę. + // Nie wykonywać tej funkcji, jeśli podwyższenie zostało uwzględnione w edytorze. + // Problematyczne mogą byc rozjazdy na przechyłce - lepiej je modelować w edytorze. + // Na razie wszystkie scenerie powinny być poprawiane. + // Jedynie problem będzie z podwójną rampą przechyłkową, która w środku będzie + // mieć moment wypoziomowania, ale musi on być również podniesiony. + if (fRoll1 != 0.0) + { // tylko jeśli jest przechyłka + double w1 = fabs(sin(fRoll1) * 0.75); // 0.5*w2+0.0325; //0.75m dla 1.435 + Point1.y += w1; // modyfikacja musi być przed policzeniem dalszych parametrów + if (bCurve) + CPointOut.y += w1; // prosty ma wektory jednostkowe + pOwner->MovedUp1(w1); // zwrócić trzeba informację o podwyższeniu podsypki + } + if (fRoll2 != 0.0) + { + double w2 = fabs(sin(fRoll2) * 0.75); // 0.5*w2+0.0325; //0.75m dla 1.435 + Point2.y += w2; // modyfikacja musi być przed policzeniem dalszych parametrów + if (bCurve) + CPointIn.y += w2; // prosty ma wektory jednostkowe + // zwrócić trzeba informację o podwyższeniu podsypki + } + } + // Ra: ten kąt jeszcze do przemyślenia jest + fDirection = -atan2(Point2.x - Point1.x, + Point2.z - Point1.z); // kąt w planie, żeby nie liczyć wielokrotnie + bCurve = bIsCurve; + if (bCurve) + { // przeliczenie współczynników wielomianu, będzie mniej mnożeń i można policzyć pochodne + vC = 3.0 * (CPointOut - Point1); // t^1 + vB = 3.0 * (CPointIn - CPointOut) - vC; // t^2 + vA = Point2 - Point1 - vC - vB; // t^3 + fLength = ComputeLength(); + } + else + fLength = (Point1 - Point2).Length(); + fStep = fNewStep; + if (fLength <= 0) + { + ErrorLog("Bad geometry: Length <= 0 in TSegment::Init at " + Where(Point1)); + // MessageBox(0,"Length<=0","TSegment::Init",MB_OK); + return false; // zerowe nie mogą być + } + fStoop = atan2((Point2.y - Point1.y), + fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie + SafeDeleteArray(fTsBuffer); + if ((bCurve) && (fStep > 0)) + { // Ra: prosty dostanie podział, jak ma różną przechyłkę na końcach + double s = 0; + int i = 0; + iSegCount = ceil(fLength / fStep); // potrzebne do VBO + // fStep=fLength/(double)(iSegCount-1); //wyrównanie podziału + fTsBuffer = new double[iSegCount + 1]; + fTsBuffer[0] = 0; /* TODO : fix fTsBuffer */ + while (s < fLength) + { + i++; + s += fStep; + if (s > fLength) + s = fLength; + fTsBuffer[i] = GetTFromS(s); + } + } + if (fLength > 500) + { // tor ma pojemność 40 pojazdów, więc nie może być za długi + ErrorLog("Bad geometry: Length > 500m at " + Where(Point1)); + // MessageBox(0,"Length>500","TSegment::Init",MB_OK); + return false; + } + return true; } - vector3 __fastcall TSegment::GetFirstDerivative(double fTime) { double fOmTime = 1.0 - fTime; double fPowTime = fTime; - vector3 kResult = fOmTime*(CPointOut-Point1); + vector3 kResult = fOmTime * (CPointOut - Point1); - //int iDegreeM1 = 3 - 1; + // int iDegreeM1 = 3 - 1; - double fCoeff = 2*fPowTime; - kResult = (kResult+fCoeff*(CPointIn-CPointOut))*fOmTime; + double fCoeff = 2 * fPowTime; + kResult = (kResult + fCoeff * (CPointIn - CPointOut)) * fOmTime; fPowTime *= fTime; - kResult += fPowTime*(Point2-CPointIn); + kResult += fPowTime * (Point2 - CPointIn); kResult *= 3; return kResult; @@ -167,752 +163,828 @@ double __fastcall TSegment::RombergIntegral(double fA, double fB) { double fH = fB - fA; - const int ms_iOrder= 5; + const int ms_iOrder = 5; double ms_apfRom[2][ms_iOrder]; - ms_apfRom[0][0] = 0.5*fH*((GetFirstDerivative(fA).Length())+(GetFirstDerivative(fB).Length())); + ms_apfRom[0][0] = + 0.5 * fH * ((GetFirstDerivative(fA).Length()) + (GetFirstDerivative(fB).Length())); for (int i0 = 2, iP0 = 1; i0 <= ms_iOrder; i0++, iP0 *= 2, fH *= 0.5) { // approximations via the trapezoid rule double fSum = 0.0; int i1; for (i1 = 1; i1 <= iP0; i1++) - fSum += (GetFirstDerivative(fA + fH*(i1-0.5)).Length()); + fSum += (GetFirstDerivative(fA + fH * (i1 - 0.5)).Length()); // Richardson extrapolation - ms_apfRom[1][0] = 0.5*(ms_apfRom[0][0] + fH*fSum); + ms_apfRom[1][0] = 0.5 * (ms_apfRom[0][0] + fH * fSum); for (int i2 = 1, iP2 = 4; i2 < i0; i2++, iP2 *= 4) { - ms_apfRom[1][i2] = - (iP2*ms_apfRom[1][i2-1] - ms_apfRom[0][i2-1])/(iP2-1); + ms_apfRom[1][i2] = (iP2 * ms_apfRom[1][i2 - 1] - ms_apfRom[0][i2 - 1]) / (iP2 - 1); } for (i1 = 0; i1 < i0; i1++) ms_apfRom[0][i1] = ms_apfRom[1][i1]; } - return ms_apfRom[0][ms_iOrder-1]; + return ms_apfRom[0][ms_iOrder - 1]; } double __fastcall TSegment::GetTFromS(double s) { // initial guess for Newton's method - int it=0; - double fTolerance= 0.001; - double fRatio = s/RombergIntegral(0,1); + int it = 0; + double fTolerance = 0.001; + double fRatio = s / RombergIntegral(0, 1); double fOmRatio = 1.0 - fRatio; - double fTime = fOmRatio*0 + fRatio*1; + double fTime = fOmRatio * 0 + fRatio * 1; -// for (int i = 0; i < iIterations; i++) + // for (int i = 0; i < iIterations; i++) while (true) { it++; - if (it>10) + if (it > 10) { - ErrorLog("Bad geometry: Too many iterations at "+Where(Point1)); - //MessageBox(0,"Too many iterations","GetTFromS",MB_OK); - return fTime; + ErrorLog("Bad geometry: Too many iterations at " + Where(Point1)); + // MessageBox(0,"Too many iterations","GetTFromS",MB_OK); + return fTime; } - double fDifference = RombergIntegral(0,fTime) - s; - if ( ( fDifference>0 ? fDifference : -fDifference) < fTolerance ) + double fDifference = RombergIntegral(0, fTime) - s; + if ((fDifference > 0 ? fDifference : -fDifference) < fTolerance) return fTime; - fTime -= fDifference/GetFirstDerivative(fTime).Length(); + fTime -= fDifference / GetFirstDerivative(fTime).Length(); } // Newton's method failed. If this happens, increase iterations or // tolerance or integration accuracy. - //return -1; //Ra: tu nigdy nie dojdzie - + // return -1; //Ra: tu nigdy nie dojdzie }; vector3 __fastcall TSegment::RaInterpolate(double t) -{//wyliczenie XYZ na krzywej Beziera z użyciem współczynników - return t*(t*(t*vA+vB)+vC)+Point1; //9 mnożeń, 9 dodawań +{ // wyliczenie XYZ na krzywej Beziera z użyciem współczynników + return t * (t * (t * vA + vB) + vC) + Point1; // 9 mnożeń, 9 dodawań }; vector3 __fastcall TSegment::RaInterpolate0(double t) -{//wyliczenie XYZ na krzywej Beziera, na użytek liczenia długości nie jest dodawane Point1 - return t*(t*(t*vA+vB)+vC); //9 mnożeń, 6 dodawań +{ // wyliczenie XYZ na krzywej Beziera, na użytek liczenia długości nie jest dodawane Point1 + return t * (t * (t * vA + vB) + vC); // 9 mnożeń, 6 dodawań }; -double __fastcall TSegment::ComputeLength() //McZapkie-150503: dlugosc miedzy punktami krzywej -{//obliczenie długości krzywej Beziera za pomocą interpolacji odcinkami - //Ra: zamienić na liczenie rekurencyjne średniej z cięciwy i łamanej po kontrolnych - //Ra: koniec rekurencji jeśli po podziale suma długości nie różni się więcej niż 0.5mm od poprzedniej - //Ra: ewentualnie rozpoznać łuk okręgu płaskiego i liczyć ze wzoru na długość łuku - double t,l=0; - vector3 last=vector3(0,0,0); //długość liczona po przesunięciu odcinka do początku układu - vector3 tmp=Point2-Point1; - int m=20.0*tmp.Length(); //było zawsze do 10000, teraz jest liczone odcinkami po około 5cm - for (int i=1;i<=m;i++) - { - t=double(i)/double(m); //wyznaczenie parametru na krzywej z przedziału (0,1> - //tmp=Interpolate(t,p1,cp1,cp2,p2); - tmp=RaInterpolate0(t); //obliczenie punktu dla tego parametru - t=vector3(tmp-last).Length(); //obliczenie długości wektora - l+=t; //zwiększenie wyliczanej długości - last=tmp; - } - return (l); +double __fastcall TSegment::ComputeLength() // McZapkie-150503: dlugosc miedzy punktami krzywej +{ // obliczenie długości krzywej Beziera za pomocą interpolacji odcinkami + // Ra: zamienić na liczenie rekurencyjne średniej z cięciwy i łamanej po kontrolnych + // Ra: koniec rekurencji jeśli po podziale suma długości nie różni się więcej niż 0.5mm od + // poprzedniej + // Ra: ewentualnie rozpoznać łuk okręgu płaskiego i liczyć ze wzoru na długość łuku + double t, l = 0; + vector3 last = vector3(0, 0, 0); // długość liczona po przesunięciu odcinka do początku układu + vector3 tmp = Point2 - Point1; + int m = 20.0 * tmp.Length(); // było zawsze do 10000, teraz jest liczone odcinkami po około 5cm + for (int i = 1; i <= m; i++) + { + t = double(i) / double(m); // wyznaczenie parametru na krzywej z przedziału (0,1> + // tmp=Interpolate(t,p1,cp1,cp2,p2); + tmp = RaInterpolate0(t); // obliczenie punktu dla tego parametru + t = vector3(tmp - last).Length(); // obliczenie długości wektora + l += t; // zwiększenie wyliczanej długości + last = tmp; + } + return (l); } -const double fDirectionOffset=0.1; //długość wektora do wyliczenia kierunku +const double fDirectionOffset = 0.1; // długość wektora do wyliczenia kierunku vector3 __fastcall TSegment::GetDirection(double fDistance) -{//takie toporne liczenie pochodnej dla podanego dystansu od Point1 - double t1=GetTFromS(fDistance-fDirectionOffset); - if (t1<=0.0) - return (CPointOut-Point1); //na zewnątrz jako prosta - double t2=GetTFromS(fDistance+fDirectionOffset); - if (t2>=1.0) - return (Point1-CPointIn); //na zewnątrz jako prosta - return (FastGetPoint(t2)-FastGetPoint(t1)); +{ // takie toporne liczenie pochodnej dla podanego dystansu od Point1 + double t1 = GetTFromS(fDistance - fDirectionOffset); + if (t1 <= 0.0) + return (CPointOut - Point1); // na zewnątrz jako prosta + double t2 = GetTFromS(fDistance + fDirectionOffset); + if (t2 >= 1.0) + return (Point1 - CPointIn); // na zewnątrz jako prosta + return (FastGetPoint(t2) - FastGetPoint(t1)); } vector3 __fastcall TSegment::FastGetDirection(double fDistance, double fOffset) -{//takie toporne liczenie pochodnej dla parametru 0.0÷1.0 - double t1=fDistance-fOffset; - if (t1<=0.0) - return (CPointOut-Point1); //wektor na początku jest stały - double t2=fDistance+fOffset; - if (t2>=1.0) - return (Point2-CPointIn); //wektor na końcu jest stały - return (FastGetPoint(t2)-FastGetPoint(t1)); +{ // takie toporne liczenie pochodnej dla parametru 0.0÷1.0 + double t1 = fDistance - fOffset; + if (t1 <= 0.0) + return (CPointOut - Point1); // wektor na początku jest stały + double t2 = fDistance + fOffset; + if (t2 >= 1.0) + return (Point2 - CPointIn); // wektor na końcu jest stały + return (FastGetPoint(t2) - FastGetPoint(t1)); } vector3 __fastcall TSegment::GetPoint(double fDistance) -{//wyliczenie współrzędnych XYZ na torze w odległości (fDistance) od Point1 - if (bCurve) - {//można by wprowadzić uproszczony wzór dla okręgów płaskich - double t=GetTFromS(fDistance); //aproksymacja dystansu na krzywej Beziera - //return Interpolate(t,Point1,CPointOut,CPointIn,Point2); - return RaInterpolate(t); - } - else - {//wyliczenie dla odcinka prostego jest prostsze - double t=fDistance/fLength; //zerowych torów nie ma - return ((1.0-t)*Point1+(t)*Point2); - } +{ // wyliczenie współrzędnych XYZ na torze w odległości (fDistance) od Point1 + if (bCurve) + { // można by wprowadzić uproszczony wzór dla okręgów płaskich + double t = GetTFromS(fDistance); // aproksymacja dystansu na krzywej Beziera + // return Interpolate(t,Point1,CPointOut,CPointIn,Point2); + return RaInterpolate(t); + } + else + { // wyliczenie dla odcinka prostego jest prostsze + double t = fDistance / fLength; // zerowych torów nie ma + return ((1.0 - t) * Point1 + (t)*Point2); + } }; -void __fastcall TSegment::RaPositionGet(double fDistance,vector3 &p,vector3 &a) -{//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) - //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 - } - 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) - a.y=fStoop; //pochylenie toru prostego - a.z=fDirection; //kierunek toru w planie - } +void __fastcall TSegment::RaPositionGet(double fDistance, vector3 &p, vector3 &a) +{ // 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) + // 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 + } + 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) + a.y = fStoop; // pochylenie toru prostego + a.z = fDirection; // kierunek toru w planie + } }; - vector3 __fastcall TSegment::FastGetPoint(double t) { - //return (bCurve?Interpolate(t,Point1,CPointOut,CPointIn,Point2):((1.0-t)*Point1+(t)*Point2)); - return (bCurve?RaInterpolate(t):((1.0-t)*Point1+(t)*Point2)); + // return (bCurve?Interpolate(t,Point1,CPointOut,CPointIn,Point2):((1.0-t)*Point1+(t)*Point2)); + return (bCurve ? RaInterpolate(t) : ((1.0 - t) * Point1 + (t)*Point2)); } void __fastcall TSegment::RenderLoft(const vector6 *ShapePoints, int iNumShapePoints, - double fTextureLength, int iSkip, int iQualityFactor,vector3 **p,bool bRender) -{//generowanie trójkątów dla odcinka trajektorii ruchu - //standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku - //po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli - // podany jest przekrój końcowy - //podsypka toru jest robiona za pomocą 6 punktów, szyna 12, drogi i rzeki na 3+2+3 - if (iQualityFactor<1) iQualityFactor= 1; //co który segment ma być uwzględniony - vector3 pos1,pos2,dir,parallel1,parallel2,pt,norm; - double s,step,fOffset,tv1,tv2,t; - int i,j ; - bool trapez=iNumShapePoints<0; //sygnalizacja trapezowatości - iNumShapePoints=abs(iNumShapePoints); - if (bCurve) - { - double m1,jmm1,m2,jmm2; //pozycje względne na odcinku 0...1 (ale nie parametr Beziera) - tv1=1.0; //Ra: to by można było wyliczać dla odcinka, wyglądało by lepiej - step=fStep*iQualityFactor; - s=fStep*iSkip; //iSkip - ile odcinków z początku pominąć - i=iSkip; //domyślnie 0 - if (!fTsBuffer) - return; //prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę - if (i>iSegCount) - return; //prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę - t=fTsBuffer[i]; //tabela watości t dla segmentów - fOffset=0.1/fLength; //pierwsze 10cm - pos1=FastGetPoint(t); //wektor początku segmentu - dir=FastGetDirection(t,fOffset); //wektor kierunku - //parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); //wektor poprzeczny - parallel1=Normalize(vector3(-dir.z,0.0,dir.x)); //wektor poprzeczny - m2=s/fLength; jmm2=1.0-m2; - while (sfLength-0.5) //Ra: -0.5 żeby nie robiło cieniasa na końcu - {//gdy przekroczyliśmy koniec - stąd dziury w torach... - step-=(s-fLength); //jeszcze do wyliczenia mapowania potrzebny - s=fLength; - i=iSegCount; //20/5 ma dawać 4 - m2=1.0; jmm2=0.0; - } - while (tv1<0.0) tv1+=1.0; //przestawienie mapowania - tv2=tv1-step/fTextureLength; //mapowanie na końcu segmentu - t=fTsBuffer[i]; //szybsze od GetTFromS(s); - pos2=FastGetPoint(t); - dir=FastGetDirection(t,fOffset); //nowy wektor kierunku - //parallel2=CrossProduct(dir,vector3(0,1,0)); //wektor poprzeczny - parallel2=Normalize(vector3(-dir.z,0.0,dir.x)); //wektor poprzeczny - glBegin(GL_TRIANGLE_STRIP); - if (trapez) - for (j=0;j iSegCount) + return; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę + t = fTsBuffer[i]; // tabela watości t dla segmentów + fOffset = 0.1 / fLength; // pierwsze 10cm + pos1 = FastGetPoint(t); // wektor początku segmentu + dir = FastGetDirection(t, fOffset); // wektor kierunku + // parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); //wektor poprzeczny + parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny + m2 = s / fLength; + jmm2 = 1.0 - m2; + while (s < fLength) + { + // step=SquareMagnitude(Global::GetCameraPosition()+pos); + i += iQualityFactor; // kolejny punkt łamanej + s += step; // końcowa pozycja segmentu [m] + m1 = m2; + jmm1 = jmm2; // stara pozycja + m2 = s / fLength; + jmm2 = 1.0 - m2; // nowa pozycja + if (s > fLength - 0.5) // Ra: -0.5 żeby nie robiło cieniasa na końcu + { // gdy przekroczyliśmy koniec - stąd dziury w torach... + step -= (s - fLength); // jeszcze do wyliczenia mapowania potrzebny + s = fLength; + i = iSegCount; // 20/5 ma dawać 4 + m2 = 1.0; + jmm2 = 0.0; + } + while (tv1 < 0.0) + tv1 += 1.0; // przestawienie mapowania + tv2 = tv1 - step / fTextureLength; // mapowanie na końcu segmentu + t = fTsBuffer[i]; // szybsze od GetTFromS(s); + pos2 = FastGetPoint(t); + dir = FastGetDirection(t, fOffset); // nowy wektor kierunku + // parallel2=CrossProduct(dir,vector3(0,1,0)); //wektor poprzeczny + parallel2 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny + glBegin(GL_TRIANGLE_STRIP); + if (trapez) + for (j = 0; j < iNumShapePoints; j++) + { + norm = (jmm1 * ShapePoints[j].n.x + m1 * ShapePoints[j + iNumShapePoints].n.x) * + parallel1; + norm.y += jmm1 * ShapePoints[j].n.y + m1 * ShapePoints[j + iNumShapePoints].n.y; + pt = parallel1 * + (jmm1 * ShapePoints[j].x + m1 * ShapePoints[j + iNumShapePoints].x) + + pos1; + pt.y += jmm1 * ShapePoints[j].y + m1 * ShapePoints[j + iNumShapePoints].y; + if (bRender) + { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale + // potrzebować punktów + glNormal3f(norm.x, norm.y, norm.z); + glTexCoord2f( + jmm1 * ShapePoints[j].z + m1 * ShapePoints[j + iNumShapePoints].z, tv1); + glVertex3f(pt.x, pt.y, pt.z); // pt nie mamy gdzie zapamiętać? + } + if (p) // jeśli jest wskaźnik do tablicy + if (*p) + if (!j) // to dla pierwszego punktu + { + *(*p) = pt; + (*p)++; + } // zapamiętanie brzegu jezdni + // dla trapezu drugi koniec ma inne współrzędne + norm = (jmm1 * ShapePoints[j].n.x + m1 * ShapePoints[j + iNumShapePoints].n.x) * + parallel2; + norm.y += jmm1 * ShapePoints[j].n.y + m1 * ShapePoints[j + iNumShapePoints].n.y; + pt = parallel2 * + (jmm2 * ShapePoints[j].x + m2 * ShapePoints[j + iNumShapePoints].x) + + pos2; + pt.y += jmm2 * ShapePoints[j].y + m2 * ShapePoints[j + iNumShapePoints].y; + if (bRender) + { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale + // potrzebować punktów + glNormal3f(norm.x, norm.y, norm.z); + glTexCoord2f( + jmm2 * ShapePoints[j].z + m2 * ShapePoints[j + iNumShapePoints].z, tv2); + glVertex3f(pt.x, pt.y, pt.z); + } + if (p) // jeśli jest wskaźnik do tablicy + if (*p) + if (!j) // to dla pierwszego punktu + if (i == iSegCount) + { + *(*p) = pt; + (*p)++; + } // zapamiętanie brzegu jezdni + } + else + for (j = 0; j < iNumShapePoints; j++) + { //łuk z jednym profilem + norm = ShapePoints[j].n.x * parallel1; + norm.y += ShapePoints[j].n.y; + pt = parallel1 * ShapePoints[j].x + pos1; + pt.y += ShapePoints[j].y; + glNormal3f(norm.x, norm.y, norm.z); + glTexCoord2f(ShapePoints[j].z, tv1); + glVertex3f(pt.x, pt.y, pt.z); // punkt na początku odcinka + norm = ShapePoints[j].n.x * parallel2; + norm.y += ShapePoints[j].n.y; + pt = parallel2 * ShapePoints[j].x + pos2; + pt.y += ShapePoints[j].y; + glNormal3f(norm.x, norm.y, norm.z); + glTexCoord2f(ShapePoints[j].z, tv2); + glVertex3f(pt.x, pt.y, pt.z); // punkt na końcu odcinka + } + glEnd(); + pos1 = pos2; + parallel1 = parallel2; + tv1 = tv2; + } } - else - for (j=0;j fLength) { -// step= SquareMagnitude(Global::GetCameraPosition()+pos); - //t2= oldt2+t2step; - i++; - s+= step; - - if (s>fLength) - { - step-= (s-fLength); - s= fLength; - } - - while (tv1<0.0) tv1+=1.0; - tv2=tv1-step/fTextureLength; - - t= fTsBuffer[i]; - pos2= FastGetPoint( t ); - dir=FastGetDirection(t,offset); - //parallel2=Normalize(CrossProduct(dir,vector3(0,1,0))); - parallel2=Normalize(vector3(-dir.z,0.0,dir.x)); //wektor poprzeczny - - a2= double(i)/(iSkip); - glBegin(GL_TRIANGLE_STRIP); - for (j=0; j fLength) { -// step= SquareMagnitude(Global::GetCameraPosition()+pos); - i++; - s+= step; - - if (s>fLength) - { - step-= (s-fLength); - s= fLength; - } - - while (tv1<0.0) tv1+=1.0; - - tv2=tv1-step/fTextureLength; - - t= s/fLength; - pos2= FastGetPoint( t ); - - a2= double(i)/(iSkip); - glBegin(GL_TRIANGLE_STRIP); - for (j=0; jnx=norm.x; //niekoniecznie tak - Vert->ny=norm.y; - Vert->nz=norm.z; - Vert->u=jmm1*ShapePoints[j].z+m1*ShapePoints[j+iNumShapePoints].z; - Vert->v=tv1; - Vert->x=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na początku odcinka - Vert++; - //dla trapezu drugi koniec ma inne współrzędne względne - norm=(jmm1*ShapePoints[j].n.x+m1*ShapePoints[j+iNumShapePoints].n.x)*parallel2; - norm.y+=jmm1*ShapePoints[j].n.y+m1*ShapePoints[j+iNumShapePoints].n.y; - pt=parallel2*(jmm2*(ShapePoints[j].x-fOffsetX)+m2*ShapePoints[j+iNumShapePoints].x)+pos2; - pt.y+=jmm2*ShapePoints[j].y+m2*ShapePoints[j+iNumShapePoints].y; - Vert->nx=norm.x; //niekoniecznie tak - Vert->ny=norm.y; - Vert->nz=norm.z; - Vert->u=jmm2*ShapePoints[j].z+m2*ShapePoints[j+iNumShapePoints].z; - Vert->v=tv2; - Vert->x=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na końcu odcinka - Vert++; - } - else - for (j=0;jnx=norm.x; //niekoniecznie tak - Vert->ny=norm.y; - Vert->nz=norm.z; - Vert->u=ShapePoints[j].z; - Vert->v=tv1; - Vert->x=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na początku odcinka - Vert++; - norm=ShapePoints[j].n.x*parallel2; - norm.y+=ShapePoints[j].n.y; - pt=parallel2*ShapePoints[j].x+pos2; - pt.y+=ShapePoints[j].y; - Vert->nx=norm.x; //niekoniecznie tak - Vert->ny=norm.y; - Vert->nz=norm.z; - Vert->u=ShapePoints[j].z; - Vert->v=tv2; - Vert->x=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na końcu odcinka - Vert++; +void __fastcall TSegment::RaRenderLoft(CVertNormTex *&Vert, const vector6 *ShapePoints, + int iNumShapePoints, double fTextureLength, int iSkip, + int iEnd, double fOffsetX) +{ // generowanie trójkątów dla odcinka trajektorii ruchu + // standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku + // po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli + // podany jest przekrój końcowy + // podsypka toru jest robiona za pomocą 6 punktów, szyna 12, drogi i rzeki na 3+2+3 + // na użytek VBO strip dla łuków jest tworzony wzdłuż + // dla skróconego odcinka (iEndnx = norm.x; // niekoniecznie tak + Vert->ny = norm.y; + Vert->nz = norm.z; + Vert->u = jmm1 * ShapePoints[j].z + m1 * ShapePoints[j + iNumShapePoints].z; + Vert->v = tv1; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na początku odcinka + Vert++; + // dla trapezu drugi koniec ma inne współrzędne względne + norm = (jmm1 * ShapePoints[j].n.x + m1 * ShapePoints[j + iNumShapePoints].n.x) * + parallel2; + norm.y += jmm1 * ShapePoints[j].n.y + m1 * ShapePoints[j + iNumShapePoints].n.y; + pt = parallel2 * (jmm2 * (ShapePoints[j].x - fOffsetX) + + m2 * ShapePoints[j + iNumShapePoints].x) + + pos2; + pt.y += jmm2 * ShapePoints[j].y + m2 * ShapePoints[j + iNumShapePoints].y; + Vert->nx = norm.x; // niekoniecznie tak + Vert->ny = norm.y; + Vert->nz = norm.z; + Vert->u = jmm2 * ShapePoints[j].z + m2 * ShapePoints[j + iNumShapePoints].z; + Vert->v = tv2; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na końcu odcinka + Vert++; + } + else + for (j = 0; j < iNumShapePoints; j++) + { // współrzędne początku + norm = ShapePoints[j].n.x * parallel1; + norm.y += ShapePoints[j].n.y; + pt = parallel1 * (ShapePoints[j].x - fOffsetX) + pos1; + pt.y += ShapePoints[j].y; + Vert->nx = norm.x; // niekoniecznie tak + Vert->ny = norm.y; + Vert->nz = norm.z; + Vert->u = ShapePoints[j].z; + Vert->v = tv1; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na początku odcinka + Vert++; + norm = ShapePoints[j].n.x * parallel2; + norm.y += ShapePoints[j].n.y; + pt = parallel2 * ShapePoints[j].x + pos2; + pt.y += ShapePoints[j].y; + Vert->nx = norm.x; // niekoniecznie tak + Vert->ny = norm.y; + Vert->nz = norm.z; + Vert->u = ShapePoints[j].z; + Vert->v = tv2; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na końcu odcinka + Vert++; + } + pos1 = pos2; + parallel1 = parallel2; + tv1 = tv2; + } + } + else + { // gdy prosty + pos1 = FastGetPoint((fStep * iSkip) / fLength); + pos2 = FastGetPoint_1(); + dir = GetDirection(); + // parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); + parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny + if (trapez) + for (j = 0; j < iNumShapePoints; j++) + { + norm = ShapePoints[j].n.x * parallel1; + norm.y += ShapePoints[j].n.y; + pt = parallel1 * (ShapePoints[j].x - fOffsetX) + pos1; + pt.y += ShapePoints[j].y; + Vert->nx = norm.x; // niekoniecznie tak + Vert->ny = norm.y; + Vert->nz = norm.z; + Vert->u = ShapePoints[j].z; + Vert->v = 0; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na początku odcinka + Vert++; + // dla trapezu drugi koniec ma inne współrzędne + norm = ShapePoints[j + iNumShapePoints].n.x * parallel1; + norm.y += ShapePoints[j + iNumShapePoints].n.y; + pt = parallel1 * (ShapePoints[j + iNumShapePoints].x - fOffsetX) + + pos2; // odsunięcie + pt.y += ShapePoints[j + iNumShapePoints].y; // wysokość + Vert->nx = norm.x; // niekoniecznie tak + Vert->ny = norm.y; + Vert->nz = norm.z; + Vert->u = ShapePoints[j + iNumShapePoints].z; + Vert->v = fLength / fTextureLength; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na końcu odcinka + Vert++; + } + else + for (j = 0; j < iNumShapePoints; j++) + { + norm = ShapePoints[j].n.x * parallel1; + norm.y += ShapePoints[j].n.y; + pt = parallel1 * (ShapePoints[j].x - fOffsetX) + pos1; + pt.y += ShapePoints[j].y; + Vert->nx = norm.x; // niekoniecznie tak + Vert->ny = norm.y; + Vert->nz = norm.z; + Vert->u = ShapePoints[j].z; + Vert->v = 0; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na początku odcinka + Vert++; + pt = parallel1 * (ShapePoints[j].x - fOffsetX) + pos2; + pt.y += ShapePoints[j].y; + Vert->nx = norm.x; // niekoniecznie tak + Vert->ny = norm.y; + Vert->nz = norm.z; + Vert->u = ShapePoints[j].z; + Vert->v = fLength / fTextureLength; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na końcu odcinka + Vert++; + } } - pos1=pos2; - parallel1=parallel2; - tv1=tv2; - } - } - else - {//gdy prosty - pos1=FastGetPoint((fStep*iSkip)/fLength); - pos2=FastGetPoint_1(); - dir=GetDirection(); - //parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); - parallel1=Normalize(vector3(-dir.z,0.0,dir.x)); //wektor poprzeczny - if (trapez) - for (j=0;jnx=norm.x; //niekoniecznie tak - Vert->ny=norm.y; - Vert->nz=norm.z; - Vert->u=ShapePoints[j].z; - Vert->v=0; - Vert->x=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na początku odcinka - Vert++; - //dla trapezu drugi koniec ma inne współrzędne - norm=ShapePoints[j+iNumShapePoints].n.x*parallel1; - norm.y+=ShapePoints[j+iNumShapePoints].n.y; - pt=parallel1*(ShapePoints[j+iNumShapePoints].x-fOffsetX)+pos2; //odsunięcie - pt.y+=ShapePoints[j+iNumShapePoints].y; //wysokość - Vert->nx=norm.x; //niekoniecznie tak - Vert->ny=norm.y; - Vert->nz=norm.z; - Vert->u=ShapePoints[j+iNumShapePoints].z; - Vert->v=fLength/fTextureLength; - Vert->x=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na końcu odcinka - Vert++; - } - else - for (j=0;jnx=norm.x; //niekoniecznie tak - Vert->ny=norm.y; - Vert->nz=norm.z; - Vert->u=ShapePoints[j].z; - Vert->v=0; - Vert->x=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na początku odcinka - Vert++; - pt=parallel1*(ShapePoints[j].x-fOffsetX)+pos2; - pt.y+=ShapePoints[j].y; - Vert->nx=norm.x; //niekoniecznie tak - Vert->ny=norm.y; - Vert->nz=norm.z; - Vert->u=ShapePoints[j].z; - Vert->v=fLength/fTextureLength; - Vert->x=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na końcu odcinka - Vert++; - } - } }; -void __fastcall TSegment::RaAnimate( - CVertNormTex* &Vert,const vector6 *ShapePoints, - int iNumShapePoints,double fTextureLength,int iSkip,int iEnd,double fOffsetX) -{//jak wyżej, tylko z pominięciem mapowania i braku trapezowania - vector3 pos1,pos2,dir,parallel1,parallel2,pt; - double s,step,fOffset,t,fEnd; - int i,j ; - bool trapez=iNumShapePoints<0; //sygnalizacja trapezowatości - iNumShapePoints=abs(iNumShapePoints); - if (bCurve) - { - double m1,jmm1,m2,jmm2; //pozycje względne na odcinku 0...1 (ale nie parametr Beziera) - step=fStep; - s=fStep*iSkip; //iSkip - ile odcinków z początku pominąć - i=iSkip; //domyślnie 0 - t=fTsBuffer[i]; //tabela wattości t dla segmentów - fOffset=0.1/fLength; //pierwsze 10cm - pos1=FastGetPoint(t); //wektor początku segmentu - dir=FastGetDirection(t,fOffset); //wektor kierunku - //parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); //wektor prostopadły - parallel1=Normalize(vector3(-dir.z,0.0,dir.x)); //wektor poprzeczny - if (iEnd==0) iEnd=iSegCount; - fEnd=fLength*double(iEnd)/double(iSegCount); - m2=s/fEnd; jmm2=1.0-m2; - while (ix=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na początku odcinka - Vert++; - //dla trapezu drugi koniec ma inne współrzędne - pt=parallel2*(jmm2*(ShapePoints[j].x-fOffsetX)+m2*ShapePoints[j+iNumShapePoints].x)+pos2; - pt.y+=jmm2*ShapePoints[j].y+m2*ShapePoints[j+iNumShapePoints].y; - Vert->x=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na końcu odcinka - Vert++; - } - pos1=pos2; - parallel1=parallel2; - } - } - else - {//gdy prosty - pos1=FastGetPoint((fStep*iSkip)/fLength); - pos2=FastGetPoint_1(); - dir=GetDirection(); - //parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); - parallel1=Normalize(vector3(-dir.z,0.0,dir.x)); //wektor poprzeczny - if (trapez) - for (j=0;jx=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na początku odcinka - Vert++; - pt=parallel1*(ShapePoints[j+iNumShapePoints].x-fOffsetX)+pos2; //odsunięcie - pt.y+=ShapePoints[j+iNumShapePoints].y; //wysokość - Vert->x=pt.x; Vert->y=pt.y; Vert->z=pt.z; //punkt na końcu odcinka - Vert++; - } - } +void __fastcall TSegment::RaAnimate(CVertNormTex *&Vert, const vector6 *ShapePoints, + int iNumShapePoints, double fTextureLength, int iSkip, int iEnd, + double fOffsetX) +{ // jak wyżej, tylko z pominięciem mapowania i braku trapezowania + vector3 pos1, pos2, dir, parallel1, parallel2, pt; + double s, step, fOffset, t, fEnd; + int i, j; + bool trapez = iNumShapePoints < 0; // sygnalizacja trapezowatości + iNumShapePoints = abs(iNumShapePoints); + if (bCurve) + { + double m1, jmm1, m2, jmm2; // pozycje względne na odcinku 0...1 (ale nie parametr Beziera) + step = fStep; + s = fStep * iSkip; // iSkip - ile odcinków z początku pominąć + i = iSkip; // domyślnie 0 + t = fTsBuffer[i]; // tabela wattości t dla segmentów + fOffset = 0.1 / fLength; // pierwsze 10cm + pos1 = FastGetPoint(t); // wektor początku segmentu + dir = FastGetDirection(t, fOffset); // wektor kierunku + // parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); //wektor prostopadły + parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny + if (iEnd == 0) + iEnd = iSegCount; + fEnd = fLength * double(iEnd) / double(iSegCount); + m2 = s / fEnd; + jmm2 = 1.0 - m2; + while (i < iEnd) + { + ++i; // kolejny punkt łamanej + s += step; // końcowa pozycja segmentu [m] + m1 = m2; + jmm1 = jmm2; // stara pozycja + m2 = s / fEnd; + jmm2 = 1.0 - m2; // nowa pozycja + if (i == iEnd) + { // gdy przekroczyliśmy koniec - stąd dziury w torach... + step -= (s - fEnd); // jeszcze do wyliczenia mapowania potrzebny + s = fEnd; + // i=iEnd; //20/5 ma dawać 4 + m2 = 1.0; + jmm2 = 0.0; + } + t = fTsBuffer[i]; // szybsze od GetTFromS(s); + pos2 = FastGetPoint(t); + dir = FastGetDirection(t, fOffset); // nowy wektor kierunku + // parallel2=Normalize(CrossProduct(dir,vector3(0,1,0))); + parallel2 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny + if (trapez) + for (j = 0; j < iNumShapePoints; j++) + { // współrzędne początku + pt = parallel1 * (jmm1 * (ShapePoints[j].x - fOffsetX) + + m1 * ShapePoints[j + iNumShapePoints].x) + + pos1; + pt.y += jmm1 * ShapePoints[j].y + m1 * ShapePoints[j + iNumShapePoints].y; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na początku odcinka + Vert++; + // dla trapezu drugi koniec ma inne współrzędne + pt = parallel2 * (jmm2 * (ShapePoints[j].x - fOffsetX) + + m2 * ShapePoints[j + iNumShapePoints].x) + + pos2; + pt.y += jmm2 * ShapePoints[j].y + m2 * ShapePoints[j + iNumShapePoints].y; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na końcu odcinka + Vert++; + } + pos1 = pos2; + parallel1 = parallel2; + } + } + else + { // gdy prosty + pos1 = FastGetPoint((fStep * iSkip) / fLength); + pos2 = FastGetPoint_1(); + dir = GetDirection(); + // parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); + parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny + if (trapez) + for (j = 0; j < iNumShapePoints; j++) + { + pt = parallel1 * (ShapePoints[j].x - fOffsetX) + pos1; + pt.y += ShapePoints[j].y; + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na początku odcinka + Vert++; + pt = parallel1 * (ShapePoints[j + iNumShapePoints].x - fOffsetX) + + pos2; // odsunięcie + pt.y += ShapePoints[j + iNumShapePoints].y; // wysokość + Vert->x = pt.x; + Vert->y = pt.y; + Vert->z = pt.z; // punkt na końcu odcinka + Vert++; + } + } }; //--------------------------------------------------------------------------- - - diff --git a/Segment.h b/Segment.h index 1e64e24f..59a12071 100644 --- a/Segment.h +++ b/Segment.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------- #ifndef SegmentH -#define SegmentH +#define SegmentH #include "VBO.h" #include "dumb3d.h" @@ -9,95 +9,120 @@ using namespace Math3D; -//110405 Ra: klasa punktów przekroju z normalnymi +// 110405 Ra: klasa punktów przekroju z normalnymi class vector6 : public vector3 -{//punkt przekroju wraz z wektorem normalnym -public: - vector3 n; - __fastcall vector6() - {x=y=z=n.x=n.z=0.0; n.y=1.0;}; - __fastcall vector6(double a,double b,double c,double d,double e,double f) - //{x=a; y=b; z=c; n.x=d; n.y=e; n.z=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 - __fastcall 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;}; +{ // punkt przekroju wraz z wektorem normalnym + public: + vector3 n; + __fastcall vector6() + { + x = y = z = n.x = n.z = 0.0; + n.y = 1.0; + }; + __fastcall vector6(double a, double b, double c, double d, double e, double f) + //{x=a; y=b; z=c; n.x=d; n.y=e; n.z=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 + __fastcall 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: - vector3 Point1,CPointOut,CPointIn,Point2; - double fRoll1,fRoll2; //przechyłka na końcach - double fLength; //długość policzona - double *fTsBuffer; //wartości parametru krzywej dla równych odcinków - double fStep; - int iSegCount; //ilość odcinków do rysowania krzywej - double fDirection; //Ra: kąt prostego w planie; dla łuku kąt od Point1 - double fStoop; //Ra: kąt wzniesienia; dla łuku od Point1 - vector3 vA,vB,vC; //współczynniki wielomianów trzeciego stopnia vD==Point1 - //TSegment *pPrev; //odcinek od strony punktu 1 - w segmencie, żeby nie skakać na zwrotnicach - //TSegment *pNext; //odcinek od strony punktu 2 - TTrack *pOwner; //wskaźnik na właściciela - double fAngle[2]; //kąty zakończenia drogi na przejazdach - vector3 __fastcall GetFirstDerivative(double fTime); - double __fastcall RombergIntegral(double fA, double fB); - double __fastcall GetTFromS(double s); - vector3 __fastcall RaInterpolate(double t); - vector3 __fastcall RaInterpolate0(double t); - //TSegment *segNeightbour[2]; //sąsiednie odcinki - musi być przeniesione z Track - //int iNeightbour[2]; //do którego końca doczepiony -public: - bool bCurve; - //int iShape; //Ra: flagi kształtu dadzą więcej możliwości optymalizacji (0-Bezier,1-prosty,2/3-łuk w lewo/prawo,6/7-przejściowa w lewo/prawo) - __fastcall TSegment(TTrack *owner); - __fastcall ~TSegment(); - bool __fastcall Init(vector3 NewPoint1,vector3 NewPoint2,double fNewStep, - double fNewRoll1=0,double fNewRoll2=0); - bool __fastcall Init(vector3 &NewPoint1,vector3 NewCPointOut, - vector3 NewCPointIn,vector3 &NewPoint2,double fNewStep, - double fNewRoll1=0,double fNewRoll2=0,bool bIsCurve=true); - inline double __fastcall ComputeLength(); //McZapkie-150503 - inline vector3 __fastcall GetDirection1() {return bCurve?CPointOut-Point1:CPointOut;}; - inline vector3 __fastcall GetDirection2() {return bCurve?CPointIn-Point2:CPointIn;}; - vector3 __fastcall GetDirection(double fDistance); - vector3 __fastcall GetDirection() {return CPointOut;}; - vector3 __fastcall FastGetDirection(double fDistance,double fOffset); - vector3 __fastcall GetPoint(double fDistance); - void __fastcall RaPositionGet(double fDistance,vector3 &p,vector3 &a); - vector3 __fastcall FastGetPoint(double t); - inline vector3 __fastcall FastGetPoint_0() {return Point1;}; - inline vector3 __fastcall FastGetPoint_1() {return Point2;}; - inline double __fastcall GetRoll(double s) - { - s/=fLength; - return ((1.0-s)*fRoll1+s*fRoll2); - } - void __fastcall GetRolls(double &r1,double &r2) - {//pobranie przechyłek (do generowania trójkątów) - r1=fRoll1; r2=fRoll2; - } - void __fastcall RenderLoft(const vector6 *ShapePoints,int iNumShapePoints, - double fTextureLength,int iSkip=0,int iQualityFactor=1,vector3 **p=NULL,bool bRender=true); - void __fastcall RenderSwitchRail(const vector6 *ShapePoints1,const vector6 *ShapePoints2, - int iNumShapePoints,double fTextureLength,int iSkip=0,double fOffsetX=0.0f); - void __fastcall Render(); - inline double __fastcall GetLength() {return fLength;}; - void __fastcall MoveMe(vector3 pPosition) - {Point1+=pPosition; - Point2+=pPosition; - if (bCurve) - {CPointIn+=pPosition; - CPointOut+=pPosition; - } - } - int __fastcall RaSegCount() {return fTsBuffer?iSegCount:1;}; - void __fastcall RaRenderLoft(CVertNormTex* &Vert,const vector6 *ShapePoints,int iNumShapePoints, - double fTextureLength,int iSkip=0,int iEnd=0,double fOffsetX=0.0); - void __fastcall RaAnimate(CVertNormTex* &Vert,const vector6 *ShapePoints,int iNumShapePoints, - double fTextureLength,int iSkip=0,int iEnd=0,double fOffsetX=0.0); - void __fastcall AngleSet(int i,double a) {fAngle[i]=a;}; - void __fastcall Rollment(double w1,double w2); //poprawianie przechyłki +{ // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny) + private: + vector3 Point1, CPointOut, CPointIn, Point2; + double fRoll1, fRoll2; // przechyłka na końcach + double fLength; // długość policzona + double *fTsBuffer; // wartości parametru krzywej dla równych odcinków + double fStep; + int iSegCount; // ilość odcinków do rysowania krzywej + double fDirection; // Ra: kąt prostego w planie; dla łuku kąt od Point1 + double fStoop; // Ra: kąt wzniesienia; dla łuku od Point1 + vector3 vA, vB, vC; // współczynniki wielomianów trzeciego stopnia vD==Point1 + // TSegment *pPrev; //odcinek od strony punktu 1 - w segmencie, żeby nie skakać na zwrotnicach + // TSegment *pNext; //odcinek od strony punktu 2 + TTrack *pOwner; // wskaźnik na właściciela + double fAngle[2]; // kąty zakończenia drogi na przejazdach + vector3 __fastcall GetFirstDerivative(double fTime); + double __fastcall RombergIntegral(double fA, double fB); + double __fastcall GetTFromS(double s); + vector3 __fastcall RaInterpolate(double t); + vector3 __fastcall RaInterpolate0(double t); + // TSegment *segNeightbour[2]; //sąsiednie odcinki - musi być przeniesione z Track + // int iNeightbour[2]; //do którego końca doczepiony + public: + bool bCurve; + // int iShape; //Ra: flagi kształtu dadzą więcej możliwości optymalizacji + // (0-Bezier,1-prosty,2/3-łuk w lewo/prawo,6/7-przejściowa w lewo/prawo) + __fastcall TSegment(TTrack *owner); + __fastcall ~TSegment(); + bool __fastcall Init(vector3 NewPoint1, vector3 NewPoint2, double fNewStep, + double fNewRoll1 = 0, double fNewRoll2 = 0); + bool __fastcall Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointIn, + vector3 &NewPoint2, double fNewStep, double fNewRoll1 = 0, + double fNewRoll2 = 0, bool bIsCurve = true); + inline double __fastcall ComputeLength(); // McZapkie-150503 + inline vector3 __fastcall GetDirection1() { return bCurve ? CPointOut - Point1 : CPointOut; }; + inline vector3 __fastcall GetDirection2() { return bCurve ? CPointIn - Point2 : CPointIn; }; + vector3 __fastcall GetDirection(double fDistance); + vector3 __fastcall GetDirection() { return CPointOut; }; + vector3 __fastcall FastGetDirection(double fDistance, double fOffset); + vector3 __fastcall GetPoint(double fDistance); + void __fastcall RaPositionGet(double fDistance, vector3 &p, vector3 &a); + vector3 __fastcall FastGetPoint(double t); + inline vector3 __fastcall FastGetPoint_0() { return Point1; }; + inline vector3 __fastcall FastGetPoint_1() { return Point2; }; + inline double __fastcall GetRoll(double s) + { + s /= fLength; + return ((1.0 - s) * fRoll1 + s * fRoll2); + } + void __fastcall GetRolls(double &r1, double &r2) + { // pobranie przechyłek (do generowania trójkątów) + r1 = fRoll1; + r2 = fRoll2; + } + void __fastcall RenderLoft(const vector6 *ShapePoints, int iNumShapePoints, + double fTextureLength, int iSkip = 0, int iQualityFactor = 1, + vector3 **p = NULL, bool bRender = true); + void __fastcall RenderSwitchRail(const vector6 *ShapePoints1, const vector6 *ShapePoints2, + int iNumShapePoints, double fTextureLength, int iSkip = 0, + double fOffsetX = 0.0f); + void __fastcall Render(); + inline double __fastcall GetLength() { return fLength; }; + void __fastcall MoveMe(vector3 pPosition) + { + Point1 += pPosition; + Point2 += pPosition; + if (bCurve) + { + CPointIn += pPosition; + CPointOut += pPosition; + } + } + int __fastcall RaSegCount() { return fTsBuffer ? iSegCount : 1; }; + void __fastcall RaRenderLoft(CVertNormTex *&Vert, const vector6 *ShapePoints, + int iNumShapePoints, double fTextureLength, int iSkip = 0, + int iEnd = 0, double fOffsetX = 0.0); + void __fastcall RaAnimate(CVertNormTex *&Vert, const vector6 *ShapePoints, int iNumShapePoints, + double fTextureLength, int iSkip = 0, int iEnd = 0, + double fOffsetX = 0.0); + void __fastcall AngleSet(int i, double a) { fAngle[i] = a; }; + void __fastcall Rollment(double w1, double w2); // poprawianie przechyłki }; //--------------------------------------------------------------------------- diff --git a/Sound.cpp b/Sound.cpp index edc2290c..9c48a06f 100644 --- a/Sound.cpp +++ b/Sound.cpp @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------- -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #define STRICT @@ -9,114 +9,115 @@ #include "Usefull.h" #include "Globals.h" //#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } -#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } +#define SAFE_RELEASE(p) \ + { \ + if (p) \ + { \ + (p)->Release(); \ + (p) = NULL; \ + } \ + } -char Directory[]= "sounds\\"; +char Directory[] = "sounds\\"; -LPDIRECTSOUND TSoundsManager::pDS; +LPDIRECTSOUND TSoundsManager::pDS; LPDIRECTSOUNDNOTIFY TSoundsManager::pDSNotify; -int TSoundsManager::Count= 0; -TSoundContainer *TSoundsManager::First=NULL; +int TSoundsManager::Count = 0; +TSoundContainer *TSoundsManager::First = NULL; +__fastcall TSoundContainer::TSoundContainer(LPDIRECTSOUND pDS, char *Directory, char *strFileName, + int NConcurrent) +{ // wczytanie pliku dźwiękowego + int hr = 111; + DSBuffer = NULL; // na początek, gdyby uruchomić dźwięków się nie udało -__fastcall TSoundContainer::TSoundContainer( LPDIRECTSOUND pDS, char *Directory, char *strFileName, int NConcurrent) -{//wczytanie pliku dźwiękowego - int hr= 111; - DSBuffer=NULL; //na początek, gdyby uruchomić dźwięków się nie udało + Concurrent = NConcurrent; - Concurrent= NConcurrent; + Oldest = 0; + // strcpy(Name, strFileName); - Oldest= 0; -// strcpy(Name, strFileName); - - strcpy(Name,Directory); - strcat(Name,strFileName); - - CWaveSoundRead* pWaveSoundRead; + strcpy(Name, Directory); + strcat(Name, strFileName); + CWaveSoundRead *pWaveSoundRead; // Create a new wave file class pWaveSoundRead = new CWaveSoundRead(); // Load the wave file if (FAILED(pWaveSoundRead->Open(Name))) - if(FAILED(pWaveSoundRead->Open(strFileName))) - { -// SetFileUI( hDlg, TEXT("Bad wave file.") ); - return; - ErrorLog("Missed sound: "+AnsiString(strFileName)); - } + if (FAILED(pWaveSoundRead->Open(strFileName))) + { + // SetFileUI( hDlg, TEXT("Bad wave file.") ); + return; + ErrorLog("Missed sound: " + AnsiString(strFileName)); + } - strcpy(Name,AnsiString(strFileName).LowerCase().c_str()); + strcpy(Name, AnsiString(strFileName).LowerCase().c_str()); // Set up the direct sound buffer, and only request the flags needed // since each requires some overhead and limits if the buffer can // be hardware accelerated DSBUFFERDESC dsbd; - ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) ); - dsbd.dwSize = sizeof(DSBUFFERDESC); - dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; - if (!Global::bInactivePause) //jeśli przełączony w tło ma nadal działać - dsbd.dwFlags|=DSBCAPS_GLOBALFOCUS; //to dźwięki mają być również słyszalne + ZeroMemory(&dsbd, sizeof(DSBUFFERDESC)); + dsbd.dwSize = sizeof(DSBUFFERDESC); + dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + if (!Global::bInactivePause) // jeśli przełączony w tło ma nadal działać + dsbd.dwFlags |= DSBCAPS_GLOBALFOCUS; // to dźwięki mają być również słyszalne dsbd.dwBufferBytes = pWaveSoundRead->m_ckIn.cksize; - dsbd.lpwfxFormat = pWaveSoundRead->m_pwfx; - fSamplingRate=pWaveSoundRead->m_pwfx->nSamplesPerSec; - iBitsPerSample=pWaveSoundRead->m_pwfx->wBitsPerSample; + dsbd.lpwfxFormat = pWaveSoundRead->m_pwfx; + fSamplingRate = pWaveSoundRead->m_pwfx->nSamplesPerSec; + iBitsPerSample = pWaveSoundRead->m_pwfx->wBitsPerSample; -// pDSBuffer= (LPDIRECTSOUNDBUFFER*) malloc(Concurrent*sizeof(LPDIRECTSOUNDBUFFER)); -// for (int i=0; iCreateSoundBuffer( &dsbd, &(DSBuffer), NULL ) ) ) - //if (FAILED(pDS->CreateSoundBuffer(&dsbd,&(DSBuffer),NULL))) - return; + if (FAILED(hr = pDS->CreateSoundBuffer(&dsbd, &(DSBuffer), NULL))) + // if (FAILED(pDS->CreateSoundBuffer(&dsbd,&(DSBuffer),NULL))) + return; // Remember how big the buffer is DWORD dwBufferBytes; dwBufferBytes = dsbd.dwBufferBytes; - //---------------------------------------------------------- - - BYTE* pbWavData; // Pointer to actual wav data - UINT cbWavSize; // Size of data - VOID* pbData = NULL; - VOID* pbData2 = NULL; - DWORD dwLength; - DWORD dwLength2; + BYTE *pbWavData; // Pointer to actual wav data + UINT cbWavSize; // Size of data + VOID *pbData = NULL; + VOID *pbData2 = NULL; + DWORD dwLength; + DWORD dwLength2; // The size of wave data is in pWaveFileSound->m_ckIn INT nWaveFileSize = pWaveSoundRead->m_ckIn.cksize; // Allocate that buffer. - pbWavData = new BYTE[ nWaveFileSize ]; - if( NULL == pbWavData ) - return ;//E_OUTOFMEMORY; + pbWavData = new BYTE[nWaveFileSize]; + if (NULL == pbWavData) + return; // E_OUTOFMEMORY; - //if (FAILED(hr=pWaveSoundRead->Read( nWaveFileSize,pbWavData,&cbWavSize))) - if( FAILED( hr = pWaveSoundRead->Read( nWaveFileSize, - pbWavData, - &cbWavSize ) ) ) - return ; + // if (FAILED(hr=pWaveSoundRead->Read( nWaveFileSize,pbWavData,&cbWavSize))) + if (FAILED(hr = pWaveSoundRead->Read(nWaveFileSize, pbWavData, &cbWavSize))) + return; // Reset the file to the beginning pWaveSoundRead->Reset(); // Lock the buffer down - //if (FAILED(hr=DSBuffer->Lock(0,dwBufferBytes,&pbData,&dwLength,&pbData2,&dwLength2,0))) - if( FAILED( hr = DSBuffer->Lock( 0, dwBufferBytes, &pbData, &dwLength, - &pbData2, &dwLength2, 0L ) ) ) - return ; + // if (FAILED(hr=DSBuffer->Lock(0,dwBufferBytes,&pbData,&dwLength,&pbData2,&dwLength2,0))) + if (FAILED(hr = DSBuffer->Lock(0, dwBufferBytes, &pbData, &dwLength, &pbData2, &dwLength2, 0L))) + return; // Copy the memory to it. - memcpy( pbData, pbWavData, dwBufferBytes ); + memcpy(pbData, pbWavData, dwBufferBytes); // Unlock the buffer, we don't need it anymore. - DSBuffer->Unlock( pbData, dwBufferBytes, NULL, 0 ); + DSBuffer->Unlock(pbData, dwBufferBytes, NULL, 0); pbData = NULL; // We dont need the wav file data buffer anymore, so delete it @@ -126,154 +127,149 @@ __fastcall TSoundContainer::TSoundContainer( LPDIRECTSOUND pDS, char *Directory, DSBuffers.push(DSBuffer); -/* - for (int i=1; iDuplicateSoundBuffer(pDSBuffer[0],&(pDSBuffer[i])))) + /* + for (int i=1; iDuplicateSoundBuffer(pDSBuffer[0],&(pDSBuffer[i])))) + { + Concurrent= i; + break; + }; - };*/ - + };*/ }; __fastcall TSoundContainer::~TSoundContainer() { -// for (int i=Concurrent-1; i>=0; i--) -// SAFE_RELEASE( pDSBuffer[i] ); -// free(pDSBuffer); + // for (int i=Concurrent-1; i>=0; i--) + // SAFE_RELEASE( pDSBuffer[i] ); + // free(pDSBuffer); while (!DSBuffers.empty()) { SAFE_RELEASE(DSBuffers.top()); DSBuffers.pop(); } - SafeDelete( Next ); + SafeDelete(Next); }; LPDIRECTSOUNDBUFFER __fastcall TSoundContainer::GetUnique(LPDIRECTSOUND pDS) { - if (!DSBuffer) return NULL; - //jeśli się dobrze zainicjowało - LPDIRECTSOUNDBUFFER buff; - pDS->DuplicateSoundBuffer(DSBuffer,&buff); - if (buff) DSBuffers.push(buff); - return DSBuffers.top(); + if (!DSBuffer) + return NULL; + // jeśli się dobrze zainicjowało + LPDIRECTSOUNDBUFFER buff; + pDS->DuplicateSoundBuffer(DSBuffer, &buff); + if (buff) + DSBuffers.push(buff); + return DSBuffers.top(); }; - - -__fastcall TSoundsManager::~TSoundsManager() -{ - - Free(); -}; +__fastcall TSoundsManager::~TSoundsManager() { Free(); }; void __fastcall TSoundsManager::Free() { - SafeDelete( First ); - SAFE_RELEASE( pDS ); + SafeDelete(First); + SAFE_RELEASE(pDS); }; - -TSoundContainer* __fastcall TSoundsManager::LoadFromFile(char *Dir,char *Name,int Concurrent) +TSoundContainer *__fastcall TSoundsManager::LoadFromFile(char *Dir, char *Name, int Concurrent) { - TSoundContainer *Tmp=First; - First=new TSoundContainer(pDS,Dir,Name,Concurrent); - First->Next=Tmp; - Count++; - return First; //albo NULL, jak nie wyjdzie (na razie zawsze wychodzi) + TSoundContainer *Tmp = First; + First = new TSoundContainer(pDS, Dir, Name, Concurrent); + First->Next = Tmp; + Count++; + return First; // albo NULL, jak nie wyjdzie (na razie zawsze wychodzi) }; void __fastcall TSoundsManager::LoadSounds(char *Directory) -{//wczytanie wszystkich plików z katalogu - mało elastyczne - WIN32_FIND_DATA FindFileData; - HANDLE handle=FindFirstFile("sounds\\*.wav",&FindFileData); - if (handle!=INVALID_HANDLE_VALUE) - do - { - LoadFromFile(Directory,FindFileData.cFileName,1); - } while (FindNextFile(handle,&FindFileData)); - FindClose(handle); +{ // wczytanie wszystkich plików z katalogu - mało elastyczne + WIN32_FIND_DATA FindFileData; + HANDLE handle = FindFirstFile("sounds\\*.wav", &FindFileData); + if (handle != INVALID_HANDLE_VALUE) + do + { + LoadFromFile(Directory, FindFileData.cFileName, 1); + } while (FindNextFile(handle, &FindFileData)); + FindClose(handle); }; -LPDIRECTSOUNDBUFFER __fastcall TSoundsManager::GetFromName(char *Name,bool Dynamic,float *fSamplingRate) -{//wyszukanie dźwięku w pamięci albo wczytanie z pliku - AnsiString file; - if (Dynamic) - {//próba wczytania z katalogu pojazdu - file=Global::asCurrentDynamicPath+AnsiString(Name); - if (FileExists(file)) - Name=file.c_str(); //nowa nazwa - else - Dynamic=false; //wczytanie z "sounds/" - } - TSoundContainer *Next=First; - DWORD dwStatus; - for (int i=0;iName)==0) - { - if (fSamplingRate) - *fSamplingRate=Next->fSamplingRate; //częstotliwość - return (Next->GetUnique(pDS)); -// DSBuffers. - /* - Next->pDSBuffer[Next->Oldest]->Stop(); - Next->pDSBuffer[Next->Oldest]->SetCurrentPosition(0); - if (Next->OldestConcurrent-1) - { - Next->Oldest++; - return (Next->pDSBuffer[Next->Oldest-1]); - } - else - { - Next->Oldest= 0; - return (Next->pDSBuffer[Next->Concurrent-1]); - }; +LPDIRECTSOUNDBUFFER __fastcall TSoundsManager::GetFromName(char *Name, bool Dynamic, + float *fSamplingRate) +{ // wyszukanie dźwięku w pamięci albo wczytanie z pliku + AnsiString file; + if (Dynamic) + { // próba wczytania z katalogu pojazdu + file = Global::asCurrentDynamicPath + AnsiString(Name); + if (FileExists(file)) + Name = file.c_str(); // nowa nazwa + else + Dynamic = false; // wczytanie z "sounds/" + } + TSoundContainer *Next = First; + DWORD dwStatus; + for (int i = 0; i < Count; i++) + { + if (strcmp(Name, Next->Name) == 0) + { + if (fSamplingRate) + *fSamplingRate = Next->fSamplingRate; // częstotliwość + return (Next->GetUnique(pDS)); + // DSBuffers. + /* + Next->pDSBuffer[Next->Oldest]->Stop(); + Next->pDSBuffer[Next->Oldest]->SetCurrentPosition(0); + if (Next->OldestConcurrent-1) + { + Next->Oldest++; + return (Next->pDSBuffer[Next->Oldest-1]); + } + else + { + Next->Oldest= 0; + return (Next->pDSBuffer[Next->Concurrent-1]); + }; -/* for (int j=0; jConcurrent; j++) - { + /* for (int j=0; jConcurrent; j++) + { - Next->pDSBuffer[j]->GetStatus(&dwStatus); - if ((dwStatus & DSBSTATUS_PLAYING) != DSBSTATUS_PLAYING) - return (Next->pDSBuffer[j]); - } */ - } - else - Next=Next->Next; - }; - if (Dynamic) //wczytanie z katalogu pojazdu - Next=LoadFromFile("",Name,1); - else - Next=LoadFromFile(Directory,Name,1); - if (Next) - {// - if (fSamplingRate) - *fSamplingRate=Next->fSamplingRate; //częstotliwość - return Next->GetUnique(pDS); - } - ErrorLog("Missed sound: "+AnsiString(Name)); - return (NULL); + Next->pDSBuffer[j]->GetStatus(&dwStatus); + if ((dwStatus & DSBSTATUS_PLAYING) != DSBSTATUS_PLAYING) + return (Next->pDSBuffer[j]); + } */ + } + else + Next = Next->Next; + }; + if (Dynamic) // wczytanie z katalogu pojazdu + Next = LoadFromFile("", Name, 1); + else + Next = LoadFromFile(Directory, Name, 1); + if (Next) + { // + if (fSamplingRate) + *fSamplingRate = Next->fSamplingRate; // częstotliwość + return Next->GetUnique(pDS); + } + ErrorLog("Missed sound: " + AnsiString(Name)); + return (NULL); }; void __fastcall TSoundsManager::RestoreAll() { - TSoundContainer *Next= First; + TSoundContainer *Next = First; HRESULT hr; DWORD dwStatus; - for (int i=0; iDSBuffer->GetStatus(&dwStatus))) + ; + // return hr; - if( FAILED( hr = Next->DSBuffer->GetStatus( &dwStatus ) ) ); - // return hr; - - if( dwStatus & DSBSTATUS_BUFFERLOST ) + if (dwStatus & DSBSTATUS_BUFFERLOST) { // Since the app could have just been activated, then // DirectSound may not be giving us control yet, so @@ -282,96 +278,91 @@ void __fastcall TSoundsManager::RestoreAll() do { hr = Next->DSBuffer->Restore(); - if( hr == DSERR_BUFFERLOST ) - Sleep( 10 ); - } - while ((hr=Next->DSBuffer->Restore())!=NULL); + if (hr == DSERR_BUFFERLOST) + Sleep(10); + } while ((hr = Next->DSBuffer->Restore()) != NULL); -// char *Name= Next->Name; -// int cc= Next->Concurrent; -// delete Next; -// Next= new TSoundContainer(pDS, Directory, Name, cc); -// if( FAILED( hr = FillBuffer() ) ); -// return hr; + // char *Name= Next->Name; + // int cc= Next->Concurrent; + // delete Next; + // Next= new TSoundContainer(pDS, Directory, Name, cc); + // if( FAILED( hr = FillBuffer() ) ); + // return hr; }; - Next= Next->Next; + Next = Next->Next; }; - }; - -//void __fastcall TSoundsManager::Init(char *Name, int Concurrent) +// void __fastcall TSoundsManager::Init(char *Name, int Concurrent) //__fastcall TSoundsManager::TSoundsManager(HWND hWnd) -//void __fastcall TSoundsManager::Init(HWND hWnd, char *NDirectory) +// void __fastcall TSoundsManager::Init(HWND hWnd, char *NDirectory) void __fastcall TSoundsManager::Init(HWND hWnd) { - First= NULL; - Count= 0; - pDS= NULL; - pDSNotify= NULL; + First = NULL; + Count = 0; + pDS = NULL; + pDSNotify = NULL; - HRESULT hr; //=222; + HRESULT hr; //=222; LPDIRECTSOUNDBUFFER pDSBPrimary = NULL; -// strcpy(Directory, NDirectory); + // strcpy(Directory, NDirectory); // Create IDirectSound using the primary sound device - hr = DirectSoundCreate( NULL, &pDS, NULL ); - if( hr!=DS_OK ) + hr = DirectSoundCreate(NULL, &pDS, NULL); + if (hr != DS_OK) { -if (hr==DSERR_ALLOCATED) - return; -if (hr==DSERR_INVALIDPARAM) - return; -if (hr==DSERR_NOAGGREGATION) - return; -if (hr==DSERR_NODRIVER) - return; -if (hr==DSERR_OUTOFMEMORY) - return; + if (hr == DSERR_ALLOCATED) + return; + if (hr == DSERR_INVALIDPARAM) + return; + if (hr == DSERR_NOAGGREGATION) + return; + if (hr == DSERR_NODRIVER) + return; + if (hr == DSERR_OUTOFMEMORY) + return; -// hr=0; + // hr=0; }; -// return ; + // return ; // Set coop level to DSSCL_PRIORITY -// if( FAILED( hr = pDS->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ) ) ); - // return ; - pDS->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ); + // if( FAILED( hr = pDS->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ) ) ); + // return ; + pDS->SetCooperativeLevel(hWnd, DSSCL_PRIORITY); // Get the primary buffer DSBUFFERDESC dsbd; - ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) ); - dsbd.dwSize = sizeof(DSBUFFERDESC); - dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; - if (!Global::bInactivePause) //jeśli przełączony w tło ma nadal działać - dsbd.dwFlags|=DSBCAPS_GLOBALFOCUS; //to dźwięki mają być również słyszalne + ZeroMemory(&dsbd, sizeof(DSBUFFERDESC)); + dsbd.dwSize = sizeof(DSBUFFERDESC); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + if (!Global::bInactivePause) // jeśli przełączony w tło ma nadal działać + dsbd.dwFlags |= DSBCAPS_GLOBALFOCUS; // to dźwięki mają być również słyszalne dsbd.dwBufferBytes = 0; - dsbd.lpwfxFormat = NULL; + dsbd.lpwfxFormat = NULL; - if( FAILED( hr = pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) ) - return ; + if (FAILED(hr = pDS->CreateSoundBuffer(&dsbd, &pDSBPrimary, NULL))) + return; // Set primary buffer format to 22kHz and 16-bit output. WAVEFORMATEX wfx; - ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = 2; - wfx.nSamplesPerSec = 44100; - wfx.wBitsPerSample = 16; - wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; + ZeroMemory(&wfx, sizeof(WAVEFORMATEX)); + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = 2; + wfx.nSamplesPerSec = 44100; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; - if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) ) - return ; - - SAFE_RELEASE( pDSBPrimary ); + if (FAILED(hr = pDSBPrimary->SetFormat(&wfx))) + return; + SAFE_RELEASE(pDSBPrimary); }; - //--------------------------------------------------------------------------- #pragma package(smart_init) diff --git a/Sound.h b/Sound.h index 9bdd240c..a82a52aa 100644 --- a/Sound.h +++ b/Sound.h @@ -14,47 +14,49 @@ typedef LPDIRECTSOUNDBUFFER PSound; -//inline __fastcall Playing(PSound Sound) +// inline __fastcall Playing(PSound Sound) //{ //} class TSoundContainer { -public: - int Concurrent; - int Oldest; - char Name[80]; - LPDIRECTSOUNDBUFFER DSBuffer; - float fSamplingRate; //częstotliwość odczytana z pliku - int iBitsPerSample; //ile bitów na próbkę - TSoundContainer *Next; - std::stack< LPDIRECTSOUNDBUFFER > DSBuffers; - LPDIRECTSOUNDBUFFER __fastcall GetUnique(LPDIRECTSOUND pDS); - __fastcall TSoundContainer(LPDIRECTSOUND pDS, char *Directory, char *strFileName, int NConcurrent); - __fastcall ~TSoundContainer(); + public: + int Concurrent; + int Oldest; + char Name[80]; + LPDIRECTSOUNDBUFFER DSBuffer; + float fSamplingRate; // częstotliwość odczytana z pliku + int iBitsPerSample; // ile bitów na próbkę + TSoundContainer *Next; + std::stack DSBuffers; + LPDIRECTSOUNDBUFFER __fastcall GetUnique(LPDIRECTSOUND pDS); + __fastcall TSoundContainer(LPDIRECTSOUND pDS, char *Directory, char *strFileName, + int NConcurrent); + __fastcall ~TSoundContainer(); }; - class TSoundsManager { -private: - static LPDIRECTSOUND pDS; - static LPDIRECTSOUNDNOTIFY pDSNotify; -// static char Directory[80]; - static int Count; - static TSoundContainer *First; - static TSoundContainer* __fastcall LoadFromFile(char *Dir,char *Name,int Concurrent); -public: -// __fastcall TSoundsManager(HWND hWnd); -// static void __fastcall Init(HWND hWnd, char *NDirectory); - static void __fastcall Init(HWND hWnd); - __fastcall ~TSoundsManager(); - static void __fastcall Free(); - static void __fastcall Init(char *Name, int Concurrent); - static void __fastcall LoadSounds(char *Directory); - static LPDIRECTSOUNDBUFFER __fastcall GetFromName(char *Name,bool Dynamic,float *fSamplingRate=NULL); - static void __fastcall RestoreAll(); + private: + static LPDIRECTSOUND pDS; + static LPDIRECTSOUNDNOTIFY pDSNotify; + // static char Directory[80]; + static int Count; + static TSoundContainer *First; + static TSoundContainer *__fastcall LoadFromFile(char *Dir, char *Name, int Concurrent); + + public: + // __fastcall TSoundsManager(HWND hWnd); + // static void __fastcall Init(HWND hWnd, char *NDirectory); + static void __fastcall Init(HWND hWnd); + __fastcall ~TSoundsManager(); + static void __fastcall Free(); + static void __fastcall Init(char *Name, int Concurrent); + static void __fastcall LoadSounds(char *Directory); + static LPDIRECTSOUNDBUFFER __fastcall GetFromName(char *Name, bool Dynamic, + float *fSamplingRate = NULL); + static void __fastcall RestoreAll(); }; //--------------------------------------------------------------------------- diff --git a/Spline.cpp b/Spline.cpp index 4a6f1713..5b7ba785 100644 --- a/Spline.cpp +++ b/Spline.cpp @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------- -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Geometry.h" @@ -11,13 +11,12 @@ //#define asSplinesPatch AnsiString("Scenery\\") - bool __fastcall Connect(TKnot *k1, TKnot *k2) { if (k1 && k2) { - k1->Next= k2; - k2->Prev= k1; + k1->Next = k2; + k2->Prev = k1; k1->InitLength(); return true; } @@ -28,140 +27,142 @@ bool __fastcall Connect(TKnot *k1, TKnot *k2) #define Precision 10000 float __fastcall CurveLength(vector3 p1, vector3 cp1, vector3 cp2, vector3 p2) { - float t,l=0; - vector3 tmp,last= p1; - for (int i=1; i<=Precision; i++) + float t, l = 0; + vector3 tmp, last = p1; + for (int i = 1; i <= Precision; i++) { - t= float(i)/float(Precision); - tmp= Interpolate(t,p1,cp1,cp2,p2); - t= vector3(tmp-last).Length(); - l+= t; - last= tmp; + t = float(i) / float(Precision); + tmp = Interpolate(t, p1, cp1, cp2, p2); + t = vector3(tmp - last).Length(); + l += t; + last = tmp; } return (l); - } __fastcall TKnot::TKnot() { - Next=Prev= NULL; - Length= -1; - IsCurve= false; - fLengthIn=fLengthOut= 0; - fRoll= 0; - bSwitchDirectionForward= false; - bSwitchDirectionBackward= false; + Next = Prev = NULL; + Length = -1; + IsCurve = false; + fLengthIn = fLengthOut = 0; + fRoll = 0; + bSwitchDirectionForward = false; + bSwitchDirectionBackward = false; } __fastcall TKnot::TKnot(int n) { - bSwitchDirectionForward= false; - bSwitchDirectionBackward= false; - Next=Prev= NULL; - Length= -1; - IsCurve= false; - fLengthIn=fLengthOut= 0; - if (n>0) + bSwitchDirectionForward = false; + bSwitchDirectionBackward = false; + Next = Prev = NULL; + Length = -1; + IsCurve = false; + fLengthIn = fLengthOut = 0; + if (n > 0) { - Next= new TKnot(n-1); - Next->Prev= this; + Next = new TKnot(n - 1); + Next->Prev = this; } } -__fastcall TKnot::~TKnot() -{ -} +__fastcall TKnot::~TKnot() {} vector3 __fastcall TKnot::GetDirection(float t) { if (IsCurve) { - vector3 v1= CPointOut-Point; - vector3 v2= Next->Point-Next->CPointIn; //BUGBUG - return v1*(1-t)+v2*(t); + vector3 v1 = CPointOut - Point; + vector3 v2 = Next->Point - Next->CPointIn; // BUGBUG + return v1 * (1 - t) + v2 * (t); } else - return (Next->Point-Point);//Spline->Knots[KnotIndex].Point-Spline->Knots[KnotIndex].Point); + return (Next->Point - + Point); // Spline->Knots[KnotIndex].Point-Spline->Knots[KnotIndex].Point); } float __fastcall TKnot::GetTFromS(float s) { // initial guess for Newton's method - int it=0; - float fTolerance= 0.001; - float fRatio = s/RombergIntegral(0,1); - float fOmRatio = 1.0 - fRatio; - float fTime = fOmRatio*0 + fRatio*1; - -// for (int i = 0; i < iIterations; i++) - while (true) - { - it++; - if (it>10) - MessageBox(0,"Too many iterations","TSpline->GetTFromS",MB_OK); - - float fDifference = RombergIntegral(0,fTime) - s; - if ( ( fDifference>0 ? fDifference : -fDifference) < fTolerance ) - return fTime; - - fTime -= fDifference/GetFirstDerivative(fTime).Length(); - } - - // Newton's method failed. If this happens, increase iterations or - // tolerance or integration accuracy. - return -1; + int it = 0; + float fTolerance = 0.001; + float fRatio = s / RombergIntegral(0, 1); + float fOmRatio = 1.0 - fRatio; + float fTime = fOmRatio * 0 + fRatio * 1; + // for (int i = 0; i < iIterations; i++) + while (true) + { + it++; + if (it > 10) + MessageBox(0, "Too many iterations", "TSpline->GetTFromS", MB_OK); + + float fDifference = RombergIntegral(0, fTime) - s; + if ((fDifference > 0 ? fDifference : -fDifference) < fTolerance) + return fTime; + + fTime -= fDifference / GetFirstDerivative(fTime).Length(); + } + + // Newton's method failed. If this happens, increase iterations or + // tolerance or integration accuracy. + return -1; } bool __fastcall TKnot::Init(TKnot *NNext, TKnot *NPrev) { - if (NNext!=NULL) + if (NNext != NULL) { - Next= NNext; - Next->Prev= this; + Next = NNext; + Next->Prev = this; } - if (NPrev!=NULL) + if (NPrev != NULL) { - Prev= NPrev; - Prev->Next= this; + Prev = NPrev; + Prev->Next = this; } } bool __fastcall TKnot::InitCPoints() { - if (Prev!=NULL) - if (Prev->IsCurve) - if (Next!=NULL) - { - if (!IsCurve) - { - CPointIn= Point-fLengthIn*Normalize(Next->Point-Point); - } - else - CPointIn= Point-fLengthIn*(Normalize(Normalize(Next->Point-Point)+Normalize(Point-Prev->Point))); - } - else - CPointIn= Point-fLengthIn*Normalize(Point-Prev->Point); - else - CPointIn= Prev->Point; + if (Prev != NULL) + if (Prev->IsCurve) + if (Next != NULL) + { + if (!IsCurve) + { + CPointIn = Point - fLengthIn * Normalize(Next->Point - Point); + } + else + CPointIn = Point - + fLengthIn * (Normalize(Normalize(Next->Point - Point) + + Normalize(Point - Prev->Point))); + } + else + CPointIn = Point - fLengthIn * Normalize(Point - Prev->Point); + else + CPointIn = Prev->Point; - if (Next!=NULL) - if (IsCurve) - if (Prev!=NULL) - { - if (!Prev->IsCurve) - { - CPointOut= Point-fLengthOut*Normalize(Prev->Point-Point); - } - else - CPointOut= Point-fLengthOut*(Normalize(Normalize(Prev->Point-Point)+Normalize(Point-Next->Point))); - } - else; -// CPointOut= -fLengthOut*Normalize(Next->Point-Point); - else - CPointOut= Next->Point; - else - CPointOut= Point-fLengthOut*Normalize(Prev->Point-Point); + if (Next != NULL) + if (IsCurve) + if (Prev != NULL) + { + if (!Prev->IsCurve) + { + CPointOut = Point - fLengthOut * Normalize(Prev->Point - Point); + } + else + CPointOut = Point - + fLengthOut * (Normalize(Normalize(Prev->Point - Point) + + Normalize(Point - Next->Point))); + } + else + ; + // CPointOut= -fLengthOut*Normalize(Next->Point-Point); + else + CPointOut = Next->Point; + else + CPointOut = Point - fLengthOut * Normalize(Prev->Point - Point); } bool __fastcall TKnot::InitLength() @@ -169,350 +170,341 @@ bool __fastcall TKnot::InitLength() if (IsCurve) if (Next) - Length= RombergIntegral(0,1); - else; - else - if (Next) - Length= (Point-Next->Point).Length(); + Length = RombergIntegral(0, 1); + else + ; + else if (Next) + Length = (Point - Next->Point).Length(); return true; - - } vector3 TKnot::GetFirstDerivative(float fTime) { - float fOmTime = 1.0 - fTime; - float fPowTime = fTime; - vector3 kResult = fOmTime*(CPointOut-Point); - - int iDegreeM1 = 3 - 1; - - float fCoeff = 2*fPowTime; - kResult = (kResult+fCoeff*(Next->CPointIn-CPointOut))*fOmTime; - fPowTime *= fTime; - - kResult += fPowTime*(Next->Point-Next->CPointIn); - kResult *= 3; - - return kResult; + float fOmTime = 1.0 - fTime; + float fPowTime = fTime; + vector3 kResult = fOmTime * (CPointOut - Point); + + int iDegreeM1 = 3 - 1; + + float fCoeff = 2 * fPowTime; + kResult = (kResult + fCoeff * (Next->CPointIn - CPointOut)) * fOmTime; + fPowTime *= fTime; + + kResult += fPowTime * (Next->Point - Next->CPointIn); + kResult *= 3; + + return kResult; } float TKnot::RombergIntegral(float fA, float fB) { float fH = fB - fA; - const int ms_iOrder= 5; + const int ms_iOrder = 5; float ms_apfRom[2][ms_iOrder]; - - ms_apfRom[0][0] = 0.5*fH*((GetFirstDerivative(fA).Length())+(GetFirstDerivative(fB).Length())); - for (int i0 = 2, iP0 = 1; i0 <= ms_iOrder; i0++, iP0 *= 2, fH *= 0.5) - { - // approximations via the trapezoid rule - float fSum = 0.0; - int i1; - for (i1 = 1; i1 <= iP0; i1++) - fSum += (GetFirstDerivative(fA + fH*(i1-0.5)).Length()); - - // Richardson extrapolation - ms_apfRom[1][0] = 0.5*(ms_apfRom[0][0] + fH*fSum); - for (int i2 = 1, iP2 = 4; i2 < i0; i2++, iP2 *= 4) - { - ms_apfRom[1][i2] = - (iP2*ms_apfRom[1][i2-1] - ms_apfRom[0][i2-1])/(iP2-1); - } - - for (i1 = 0; i1 < i0; i1++) - ms_apfRom[0][i1] = ms_apfRom[1][i1]; - } - - return ms_apfRom[0][ms_iOrder-1]; -} + ms_apfRom[0][0] = + 0.5 * fH * ((GetFirstDerivative(fA).Length()) + (GetFirstDerivative(fB).Length())); + for (int i0 = 2, iP0 = 1; i0 <= ms_iOrder; i0++, iP0 *= 2, fH *= 0.5) + { + // approximations via the trapezoid rule + float fSum = 0.0; + int i1; + for (i1 = 1; i1 <= iP0; i1++) + fSum += (GetFirstDerivative(fA + fH * (i1 - 0.5)).Length()); + + // Richardson extrapolation + ms_apfRom[1][0] = 0.5 * (ms_apfRom[0][0] + fH * fSum); + for (int i2 = 1, iP2 = 4; i2 < i0; i2++, iP2 *= 4) + { + ms_apfRom[1][i2] = (iP2 * ms_apfRom[1][i2 - 1] - ms_apfRom[0][i2 - 1]) / (iP2 - 1); + } + + for (i1 = 0; i1 < i0; i1++) + ms_apfRom[0][i1] = ms_apfRom[1][i1]; + } + + return ms_apfRom[0][ms_iOrder - 1]; +} //----------------------------------------------------------------------------// - __fastcall TSpline::TSpline() { -// Closed= true; -// asName= "foo"; -// Knots= NULL; - RootKnot= NULL; - iNumKnots= 0; - KnotsAllocated= false; -// Next=Prev= this; + // Closed= true; + // asName= "foo"; + // Knots= NULL; + RootKnot = NULL; + iNumKnots = 0; + KnotsAllocated = false; + // Next=Prev= this; } __fastcall TSpline::TSpline(AnsiString asNName) { -// Closed= true; -// asName= asNName; -// Knots= NULL; - RootKnot= NULL; - iNumKnots= 0; - KnotsAllocated= false; -// Next=Prev= this; + // Closed= true; + // asName= asNName; + // Knots= NULL; + RootKnot = NULL; + iNumKnots = 0; + KnotsAllocated = false; + // Next=Prev= this; } __fastcall TSpline::~TSpline() { - // if (KnotsAllocated) -// SafeDeleteArray(Knots); + // if (KnotsAllocated) + // SafeDeleteArray(Knots); -// SafeDelete(RootKnot); + // SafeDelete(RootKnot); - TKnot *ck,*tk; - ck= RootKnot; + TKnot *ck, *tk; + ck = RootKnot; - for (int i=0; iNext; + tk = ck; + ck = ck->Next; SafeDelete(tk); } - } -bool __fastcall TSpline::Create( int n, AnsiString asNName ) +bool __fastcall TSpline::Create(int n, AnsiString asNName) { -/* -// asName= asNName; - iNumKnots= n; - Knots= new TKnot[iNumKnots]; - KnotsAllocated= true; - Knots[0].Prev= NULL; - Knots[iNumKnots-1].Next= NULL; - for (int i=1; iOpen(asSceneryPatch+FileName,mmRead); + TMapTextfile *tf= new TMapTextfile(); + tf->Open(asSceneryPatch+FileName,mmRead); - tf->ReadLn(buf); - - if (buf==AnsiString("\"SPLINE\"")) - { tf->ReadLn(buf); - if (FirstKnot==NULL) - Create(buf.ToInt()); - else - AssignKnots(FirstKnot,buf.ToInt()); - TKnot *CurrentKnot= Knots; -// iNumKnots= buf.ToInt(); - // Knots= new TKnot[iNumKnots];// malloc(*sizeof(TKnot)); - DecimalSeparator= '.'; - for (i=0; iReadLn(buf); CurrentKnot->Point.x= buf.ToDouble(); - tf->ReadLn(buf); CurrentKnot->Point.z= buf.ToDouble(); - tf->ReadLn(buf); CurrentKnot->Point.y= buf.ToDouble(); - tf->ReadLn(buf); CurrentKnot->CPointIn.x= buf.ToDouble(); - tf->ReadLn(buf); CurrentKnot->CPointIn.z= buf.ToDouble(); - tf->ReadLn(buf); CurrentKnot->CPointIn.y= buf.ToDouble(); - tf->ReadLn(buf); CurrentKnot->CPointOut.x= buf.ToDouble(); - tf->ReadLn(buf); CurrentKnot->CPointOut.z= buf.ToDouble(); - tf->ReadLn(buf); CurrentKnot->CPointOut.y= buf.ToDouble(); - - tf->ReadLn(buf); -// buf.Trim(); - Knots[i].IsCurve= (buf!="#line "); - CurrentKnot= CurrentKnot->Next; - - - } - DecimalSeparator= ','; - - CurrentKnot= Knots; - - for (i=0; iIsCurve) - { - - CurrentKnot->Length= CurveLength(CurrentKnot->Point,CurrentKnot->CPointOut,CurrentKnot->Next->CPointIn,CurrentKnot->Next->Point); - } + tf->ReadLn(buf); + if (FirstKnot==NULL) + Create(buf.ToInt()); else + AssignKnots(FirstKnot,buf.ToInt()); + TKnot *CurrentKnot= Knots; + // iNumKnots= buf.ToInt(); + // Knots= new TKnot[iNumKnots];// malloc(*sizeof(TKnot)); + + DecimalSeparator= '.'; + for (i=0; iCPointOut= 2*CurrentKnot->Point-CurrentKnot->CPointIn; - CurrentKnot->Next->CPointIn= CurrentKnot->Point; - CurrentKnot->Length= (CurrentKnot->Point-CurrentKnot->Next->Point).Length(); + + tf->ReadLn(buf); CurrentKnot->Point.x= buf.ToDouble(); + tf->ReadLn(buf); CurrentKnot->Point.z= buf.ToDouble(); + tf->ReadLn(buf); CurrentKnot->Point.y= buf.ToDouble(); + tf->ReadLn(buf); CurrentKnot->CPointIn.x= buf.ToDouble(); + tf->ReadLn(buf); CurrentKnot->CPointIn.z= buf.ToDouble(); + tf->ReadLn(buf); CurrentKnot->CPointIn.y= buf.ToDouble(); + tf->ReadLn(buf); CurrentKnot->CPointOut.x= buf.ToDouble(); + tf->ReadLn(buf); CurrentKnot->CPointOut.z= buf.ToDouble(); + tf->ReadLn(buf); CurrentKnot->CPointOut.y= buf.ToDouble(); + + tf->ReadLn(buf); + // buf.Trim(); + Knots[i].IsCurve= (buf!="#line "); + CurrentKnot= CurrentKnot->Next; + + } - CurrentKnot= CurrentKnot->Next; + DecimalSeparator= ','; + + CurrentKnot= Knots; + + for (i=0; iIsCurve) + { + + CurrentKnot->Length= + CurveLength(CurrentKnot->Point,CurrentKnot->CPointOut,CurrentKnot->Next->CPointIn,CurrentKnot->Next->Point); + } + else + { + CurrentKnot->CPointOut= 2*CurrentKnot->Point-CurrentKnot->CPointIn; + CurrentKnot->Next->CPointIn= CurrentKnot->Point; + CurrentKnot->Length= (CurrentKnot->Point-CurrentKnot->Next->Point).Length(); + } + CurrentKnot= CurrentKnot->Next; + } + CurrentKnot->Length= -1; } - CurrentKnot->Length= -1; - } - tf->Close(); + tf->Close(); - delete tf; + delete tf; - return (iNumKnots); - */ + return (iNumKnots); + */ } -int __fastcall TSpline::Load( TQueryParserComp *Parser, AnsiString asEndString ) +int __fastcall TSpline::Load(TQueryParserComp *Parser, AnsiString asEndString) { - TKnot *LastKnot= NULL;; - if (RootKnot!=NULL) - for (LastKnot= RootKnot; LastKnot->Next!=NULL; LastKnot= LastKnot->Next); + TKnot *LastKnot = NULL; + ; + if (RootKnot != NULL) + for (LastKnot = RootKnot; LastKnot->Next != NULL; LastKnot = LastKnot->Next) + ; TKnot *tmp; - tmp= new TKnot(0); - tmp->Prev= LastKnot; - if (LastKnot!=NULL) - LastKnot->Next= tmp; + tmp = new TKnot(0); + tmp->Prev = LastKnot; + if (LastKnot != NULL) + LastKnot->Next = tmp; else - RootKnot= tmp; + RootKnot = tmp; - LastKnot= tmp; + LastKnot = tmp; - float tf,r,pr; + float tf, r, pr; vector3 dir; -// asName= Parser->GetNextSymbol(); + // asName= Parser->GetNextSymbol(); - iNumKnots= 0; + iNumKnots = 0; do { - LastKnot->fLengthIn= Parser->GetNextSymbol().ToDouble(); - tf= Parser->GetNextSymbol().ToDouble(); - LastKnot->Point.x= tf; - tf= Parser->GetNextSymbol().ToDouble(); - LastKnot->Point.y= tf; - tf= Parser->GetNextSymbol().ToDouble(); - LastKnot->Point.z= tf; - tf= Parser->GetNextSymbol().ToDouble(); - LastKnot->fRoll= tf/180*M_PI; + LastKnot->fLengthIn = Parser->GetNextSymbol().ToDouble(); + tf = Parser->GetNextSymbol().ToDouble(); + LastKnot->Point.x = tf; + tf = Parser->GetNextSymbol().ToDouble(); + LastKnot->Point.y = tf; + tf = Parser->GetNextSymbol().ToDouble(); + LastKnot->Point.z = tf; + tf = Parser->GetNextSymbol().ToDouble(); + LastKnot->fRoll = tf / 180 * M_PI; - LastKnot->fLengthOut= Parser->GetNextSymbol().ToDouble(); + LastKnot->fLengthOut = Parser->GetNextSymbol().ToDouble(); - LastKnot->IsCurve= (LastKnot->fLengthOut!=0); + LastKnot->IsCurve = (LastKnot->fLengthOut != 0); - LastKnot->Next= new TKnot(0); - LastKnot->Next->Prev= LastKnot; - LastKnot= LastKnot->Next; + LastKnot->Next = new TKnot(0); + LastKnot->Next->Prev = LastKnot; + LastKnot = LastKnot->Next; iNumKnots++; + } while (Parser->GetNextSymbol().LowerCase() != asEndString && !Parser->EOF); - } while (Parser->GetNextSymbol().LowerCase()!=asEndString && !Parser->EOF); - - LastKnot->Prev->Next= NULL; + LastKnot->Prev->Next = NULL; delete LastKnot; - if (RootKnot!=NULL) - for (LastKnot= RootKnot; LastKnot!=NULL; LastKnot= LastKnot->Next) + if (RootKnot != NULL) + for (LastKnot = RootKnot; LastKnot != NULL; LastKnot = LastKnot->Next) LastKnot->InitCPoints(); - if (RootKnot!=NULL) - for (LastKnot= RootKnot; LastKnot!=NULL; LastKnot= LastKnot->Next) + if (RootKnot != NULL) + for (LastKnot = RootKnot; LastKnot != NULL; LastKnot = LastKnot->Next) LastKnot->InitLength(); } float __fastcall TSpline::GetLength() { - TKnot *tmp= RootKnot; - float l= 0; - for (int i=0; iLength; - tmp= tmp->Next; + l += tmp->Length; + tmp = tmp->Next; } return l; - } vector3 __fastcall TSpline::GetCenter() { - TKnot *ck,*tk; - ck= RootKnot; - vector3 pt= vector3(0,0,0); + TKnot *ck, *tk; + ck = RootKnot; + vector3 pt = vector3(0, 0, 0); - for (int i=0; iPoint; - ck= ck->Next; + pt += ck->Point; + ck = ck->Next; } - if (iNumKnots>0) - pt/= iNumKnots; - + if (iNumKnots > 0) + pt /= iNumKnots; } -TKnot* __fastcall TSpline::GetLastKnot() +TKnot *__fastcall TSpline::GetLastKnot() { TKnot *ck; - ck= RootKnot; + ck = RootKnot; - for (int i=0; iNext; + ck = ck->Next; } return ck; } - bool __fastcall TSpline::Render() { - TKnot *LastKnot= NULL;; + TKnot *LastKnot = NULL; + ; - // if (RootKnot==NULL) -// RootKnot= Knots; + // if (RootKnot==NULL) + // RootKnot= Knots; - if (RootKnot!=NULL) + if (RootKnot != NULL) { glBindTexture(GL_TEXTURE_2D, 0); glBegin(GL_LINE_STRIP); - int i=0; - for (LastKnot= RootKnot; LastKnot!=NULL && iNext, i++) -// for (LastKnot= RootKnot; LastKnot!=NULL; LastKnot= LastKnot->Next) - glVertex3f(LastKnot->Point.x,LastKnot->Point.y,LastKnot->Point.z); + int i = 0; + for (LastKnot = RootKnot; LastKnot != NULL && i < iNumKnots; LastKnot = LastKnot->Next, i++) + // for (LastKnot= RootKnot; LastKnot!=NULL; LastKnot= LastKnot->Next) + glVertex3f(LastKnot->Point.x, LastKnot->Point.y, LastKnot->Point.z); glEnd(); -/* - if (RootKnot->Prev!=NULL) - { - glBindTexture(GL_TEXTURE_2D, 0); - glBegin(GL_LINE_STRIP); - glVertex3f(RootKnot->Point.x,RootKnot->Point.y,RootKnot->Point.z); - glVertex3f(RootKnot->Prev->Point.x,RootKnot->Prev->Point.y,RootKnot->Prev->Point.z); - glEnd(); - }*/ - + /* + if (RootKnot->Prev!=NULL) + { + glBindTexture(GL_TEXTURE_2D, 0); + glBegin(GL_LINE_STRIP); + glVertex3f(RootKnot->Point.x,RootKnot->Point.y,RootKnot->Point.z); + glVertex3f(RootKnot->Prev->Point.x,RootKnot->Prev->Point.y,RootKnot->Prev->Point.z); + glEnd(); + }*/ } - } - //--------------------------------------------------------------------------- #pragma package(smart_init) diff --git a/Spline.h b/Spline.h index b8ef6017..3f3ba33e 100644 --- a/Spline.h +++ b/Spline.h @@ -6,17 +6,17 @@ #include "QueryParserComp.hpp" using namespace Math3D; -#define B1(t) (t*t*t) -#define B2(t) (3*t*t*(1-t)) -#define B3(t) (3*t*(1-t)*(1-t)) -#define B4(t) ((1-t)*(1-t)*(1-t)) -#define Interpolate(t,p1,cp1,cp2,p2) (B4(t)*p1+B3(t)*cp1+B2(t)*cp2+B1(t)*p2) +#define B1(t) (t * t * t) +#define B2(t) (3 * t * t * (1 - t)) +#define B3(t) (3 * t * (1 - t) * (1 - t)) +#define B4(t) ((1 - t) * (1 - t) * (1 - t)) +#define Interpolate(t, p1, cp1, cp2, p2) (B4(t) * p1 + B3(t) * cp1 + B2(t) * cp2 + B1(t) * p2) class TKnot { -public: -// inline bool __fastcall IsCurve() { return (!(Point==CPointIn)); }; -// inline vector3 __fastcall GetDirection() { return (CPointOut-Point); }; + public: + // inline bool __fastcall IsCurve() { return (!(Point==CPointIn)); }; + // inline vector3 __fastcall GetDirection() { return (CPointOut-Point); }; __fastcall TKnot(); __fastcall TKnot(int n); __fastcall ~TKnot(); @@ -24,63 +24,69 @@ public: { if (Next) { - s/= Length; - return ((1-s)*fRoll+(s)*Next->fRoll); + s /= Length; + return ((1 - s) * fRoll + (s)*Next->fRoll); } else return fRoll; -// (Length-s) (s-Length) + // (Length-s) (s-Length) } - vector3 __fastcall GetDirection(float t= 0); - inline vector3 __fastcall InterpolateSegm(float t) { return (Interpolate(t,Point,CPointOut,Next->CPointIn,Next->Point) ); }; + vector3 __fastcall GetDirection(float t = 0); + inline vector3 __fastcall InterpolateSegm(float t) + { + return (Interpolate(t, Point, CPointOut, Next->CPointIn, Next->Point)); + }; float __fastcall GetTFromS(float s); bool __fastcall Init(TKnot *NNext, TKnot *NPrev); bool __fastcall InitCPoints(); bool __fastcall InitLength(); - vector3 Point,CPointIn,CPointOut; + vector3 Point, CPointIn, CPointOut; float fRoll; bool IsCurve; float Length; - TKnot *Next,*Prev; - float fLengthIn,fLengthOut; + TKnot *Next, *Prev; + float fLengthIn, fLengthOut; bool bSwitchDirectionForward; bool bSwitchDirectionBackward; -private: + private: vector3 GetFirstDerivative(float fTime); - float RombergIntegral (float fA, float fB); + float RombergIntegral(float fA, float fB); }; class TSpline { -public: + public: __fastcall TSpline(); __fastcall TSpline(AnsiString asNName); __fastcall ~TSpline(); - bool __fastcall Create( int n, AnsiString asNName="foo" ); - bool __fastcall AssignKnots( TKnot *FirstKnot, int n ); - int __fastcall LoadFromFile( AnsiString FileName, TKnot *FirstKnot = NULL ); - int __fastcall Load( TQueryParserComp *Parser, AnsiString asEndString="endspline" ); + bool __fastcall Create(int n, AnsiString asNName = "foo"); + bool __fastcall AssignKnots(TKnot *FirstKnot, int n); + int __fastcall LoadFromFile(AnsiString FileName, TKnot *FirstKnot = NULL); + int __fastcall Load(TQueryParserComp *Parser, AnsiString asEndString = "endspline"); float __fastcall GetLength(); vector3 __fastcall GetCenter(); - TKnot* __fastcall GetLastKnot(); + TKnot *__fastcall GetLastKnot(); bool __fastcall Render(); -// inline int NextIndex(int n) { return (np1]; - // p2 = &system[spring->p2]; -// VectorDifference(&p1->pos,&p2->pos,&deltaP); // Vector distance - deltaP= pPosition1 - pPosition2; -// dist = VectorLength(&deltaP); // Magnitude of deltaP - dist = deltaP.Length(); - if (dist==0) + double dist, Hterm, Dterm; + vector3 springForce, deltaV, deltaP; + // p1 = &system[spring->p1]; + // p2 = &system[spring->p2]; + // VectorDifference(&p1->pos,&p2->pos,&deltaP); // Vector distance + deltaP = pPosition1 - pPosition2; + // dist = VectorLength(&deltaP); // Magnitude of + //deltaP + dist = deltaP.Length(); + if (dist == 0) { - vForce1=vForce2=vector3(0,0,0); + vForce1 = vForce2 = vector3(0, 0, 0); return false; } -// Hterm = (dist - spring->restLen) * spring->Ks; // Ks * (dist - rest) - Hterm= (dist - restLen) * Ks; // Ks * (dist - rest) + // Hterm = (dist - spring->restLen) * spring->Ks; // Ks * (dist - rest) + Hterm = (dist - restLen) * Ks; // Ks * (dist - rest) -// VectorDifference(&p1->v,&p2->v,&deltaV); // Delta Velocity Vector - deltaV= pPosition1 - pPosition2; + // VectorDifference(&p1->v,&p2->v,&deltaV); // Delta Velocity Vector + deltaV = pPosition1 - pPosition2; -// Dterm = (DotProduct(&deltaV,&deltaP) * spring->Kd) / dist; // Damping Term - //Dterm = (DotProduct(deltaV,deltaP) * Kd) / dist; - Dterm= 0; + // Dterm = (DotProduct(&deltaV,&deltaP) * spring->Kd) / dist; // Damping Term + // Dterm = (DotProduct(deltaV,deltaP) * Kd) / dist; + Dterm = 0; -// ScaleVector(&deltaP,1.0f / dist, &springForce); // Normalize Distance Vector -// ScaleVector(&springForce,-(Hterm + Dterm),&springForce); // Calc Force - springForce= deltaP/dist*(-(Hterm + Dterm)); -// VectorSum(&p1->f,&springForce,&p1->f); // Apply to Particle 1 - // VectorDifference(&p2->f,&springForce,&p2->f); // - Force on Particle 2 - vForce1= springForce; - vForce2= springForce; - - return true; -} - -void __fastcall TSpring::Render() -{ + // ScaleVector(&deltaP,1.0f / dist, &springForce); // Normalize Distance Vector + // ScaleVector(&springForce,-(Hterm + Dterm),&springForce); // Calc Force + springForce = deltaP / dist * (-(Hterm + Dterm)); + // VectorSum(&p1->f,&springForce,&p1->f); // Apply to Particle 1 + // VectorDifference(&p2->f,&springForce,&p2->f); // - Force on Particle 2 + vForce1 = springForce; + vForce2 = springForce; + return true; } +void __fastcall TSpring::Render() {} //--------------------------------------------------------------------------- diff --git a/Spring.h b/Spring.h index 3b587f67..94ade761 100644 --- a/Spring.h +++ b/Spring.h @@ -3,36 +3,35 @@ #ifndef ParticlesH #define ParticlesH +#define STATIC_THRESHOLD 0.17f +// efine STATIC_THRESHOLD 0.03f +const double m_Kd = 0.02f; // DAMPING FACTOR +const double m_Kr = 0.8f; // 1.0 = SUPERBALL BOUNCE 0.0 = DEAD WEIGHT +const double m_Ksh = 5.0f; // HOOK'S SPRING CONSTANT +const double m_Ksd = 0.1f; // SPRING DAMPING CONSTANT -#define STATIC_THRESHOLD 0.17f -//efine STATIC_THRESHOLD 0.03f -const double m_Kd = 0.02f; // DAMPING FACTOR -const double m_Kr = 0.8f; // 1.0 = SUPERBALL BOUNCE 0.0 = DEAD WEIGHT -const double m_Ksh = 5.0f; // HOOK'S SPRING CONSTANT -const double m_Ksd = 0.1f; // SPRING DAMPING CONSTANT - -const double m_Csf = 0.9f; // Default Static Friction -const double m_Ckf = 0.7f; // Default Kinetic Friction +const double m_Csf = 0.9f; // Default Static Friction +const double m_Ckf = 0.7f; // Default Kinetic Friction #include "dumb3d.h" using namespace Math3D; class TSpring { -public: + public: __fastcall TSpring(); __fastcall ~TSpring(); -// void __fastcall Init(TParticnp1, TParticle *np2, double nKs= 0.5f, double nKd= 0.002f, double nrestLen= -1.0f); - void __fastcall Init(double nrestLen, double nKs= 0.5f, double nKd= 0.002f); + // void __fastcall Init(TParticnp1, TParticle *np2, double nKs= 0.5f, double nKd= 0.002f, + // double nrestLen= -1.0f); + void __fastcall Init(double nrestLen, double nKs = 0.5f, double nKd = 0.002f); bool __fastcall ComputateForces(vector3 pPosition1, vector3 pPosition2); void __fastcall Render(); - vector3 vForce1,vForce2; - double restLen; // LENGTH OF SPRING AT REST - double Ks; // SPRING CONSTANT - double Kd; // SPRING DAMPING -private: + vector3 vForce1, vForce2; + double restLen; // LENGTH OF SPRING AT REST + double Ks; // SPRING CONSTANT + double Kd; // SPRING DAMPING + private: }; - //--------------------------------------------------------------------------- #endif diff --git a/Texture.cpp b/Texture.cpp index e6c0214f..6a655e42 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -27,213 +27,214 @@ TTexturesManager::Alphas TTexturesManager::_alphas; TTexturesManager::Names TTexturesManager::_names; -void TTexturesManager::Init() -{ -}; +void TTexturesManager::Init(){}; -TTexturesManager::Names::iterator TTexturesManager::LoadFromFile(std::string fileName,int filter) +TTexturesManager::Names::iterator TTexturesManager::LoadFromFile(std::string fileName, int filter) { std::string message("Loading - texture: "); std::string realFileName(fileName); std::ifstream file(fileName.c_str()); - //Ra: niby bez tego jest lepiej, ale działa gorzej, więc przywrócone jest oryginalne + // Ra: niby bez tego jest lepiej, ale działa gorzej, więc przywrócone jest oryginalne if (!file.is_open()) - realFileName.insert(0,szTexturePath); + realFileName.insert(0, szTexturePath); else file.close(); - //char* cFileName = const_cast(fileName.c_str()); + // char* cFileName = const_cast(fileName.c_str()); message += realFileName; - WriteLog(message.c_str()); //Ra: chybaa miało być z komunikatem z przodu, a nie tylko nazwa + WriteLog(message.c_str()); // Ra: chybaa miało być z komunikatem z przodu, a nie tylko nazwa size_t pos = fileName.rfind('.'); std::string ext(fileName, pos + 1, std::string::npos); AlphaValue texinfo; - if (ext=="tga") - texinfo=LoadTGA(realFileName,filter); - else if (ext=="tex") - texinfo=LoadTEX(realFileName); - else if (ext=="bmp") - texinfo=LoadBMP(realFileName); - else if (ext=="dds") - texinfo=LoadDDS(realFileName,filter); + if (ext == "tga") + texinfo = LoadTGA(realFileName, filter); + else if (ext == "tex") + texinfo = LoadTEX(realFileName); + else if (ext == "bmp") + texinfo = LoadBMP(realFileName); + else if (ext == "dds") + texinfo = LoadDDS(realFileName, filter); - _alphas.insert(texinfo); //zapamiętanie stanu przezroczystości tekstury - można by tylko przezroczyste + _alphas.insert( + texinfo); // zapamiętanie stanu przezroczystości tekstury - można by tylko przezroczyste std::pair ret = _names.insert(std::make_pair(fileName, texinfo.first)); if (!texinfo.first) { - WriteLog("Failed"); - ErrorLog("Missed texture: "+AnsiString(realFileName.c_str())); - return _names.end(); + WriteLog("Failed"); + ErrorLog("Missed texture: " + AnsiString(realFileName.c_str())); + return _names.end(); }; _alphas.insert(texinfo); - ret=_names.insert(std::make_pair(fileName,texinfo.first)); //dodanie tekstury do magazynu (spisu nazw) + ret = _names.insert( + std::make_pair(fileName, texinfo.first)); // dodanie tekstury do magazynu (spisu nazw) - //WriteLog("OK"); //Ra: "OK" nie potrzeba, samo "Failed" wystarczy + // WriteLog("OK"); //Ra: "OK" nie potrzeba, samo "Failed" wystarczy return ret.first; - }; struct ReplaceSlash { - const char operator()(const char input) - { - return input == '/' ? '\\' : input; - } + const char operator()(const char input) { return input == '/' ? '\\' : input; } }; -GLuint TTexturesManager::GetTextureID(char* dir,char* where,std::string fileName,int filter) -{//ustalenie numeru tekstury, wczytanie jeśli nie jeszcze takiej nie było -/* -// Ra: niby tak jest lepiej, ale działa gorzej, więc przywrócone jest oryginalne - //najpierw szukamy w katalogu, z którego wywoływana jest tekstura, potem z wyższego - //Ra: przerobić na wyszukiwanie w drzewie nazw, do którego zapisywać np. rozmiary, przezroczystość - //Ra: ustalać, które tekstury można wczytać już w trakcie symulacji - size_t pos=fileName.find(':'); //szukamy dwukropka - if (pos!=std::string::npos) //po dwukropku mogą być podane dodatkowe informacje - fileName=fileName.substr(0,pos); //niebędące nazwą tekstury - std::transform(fileName.begin(),fileName.end(),fileName.begin(),ReplaceSlash()); //zamiana "/" na "\" - //jeśli bieżaca ścieżka do tekstur nie została dodana to dodajemy domyślną - //if (fileName.find('\\')==std::string::npos) //bz sensu - // fileName.insert(0,szDefaultTexturePath); - //najpierw szukamy w podanym katalogu, potem w domyślnym - Names::iterator iter; - std::ifstream file; - if ((fileName.find('.')==fileName.npos)?true:(fileName.rfind('.')second; //znalezione! - if (dir) - {//może we wskazanym katalogu? - test=fileName; - test.insert(0,dir); //jeszcze próba z dodatkową ścieżką - test.append(Global::szDefaultExt[i]); //dodanie jednego z kilku rozszerzeń - iter=_names.find(test); //czy mamy już w magazynie? - if (iter!=_names.end()) - return iter->second; //znalezione! - } - //} - //for (int i=0;i<4;++i) - //{//w magazynie nie ma, to sprawdzamy na dysku - test=fileName; - if (where) test.insert(0,where); //ścieżka obiektu wywołującego - test.append(Global::szDefaultExt[i]); //dodanie jednego z kilku rozszerzeń - file.open(test.c_str()); - if (!file.is_open()) - {test=fileName; - if (dir) test.insert(0,dir); //próba z dodatkową ścieżką - test.append(Global::szDefaultExt[i]); //dodanie jednego z kilku rozszerzeń - file.open(test.c_str()); - } - if (file.is_open()) - {//jak znaleziony, to plik zostaje otwarty - fileName=test; //zapamiętanie znalezionego rozszerzenia - break; //wyjście z pętli na etapie danego rozszerzenia - } - } - } - else - {//gdy jest kropka, to rozszerzenie jest jawne - std::string test; //zmienna robocza - //najpierw szukamy w magazynie - test=fileName; - if (where) test.insert(0,where); //ścieżka obiektu wywołującego - iter=_names.find(test); //czy mamy już w magazynie? - if (iter!=_names.end()) - return iter->second; //znalezione! - test=fileName; - if (dir) test.insert(0,dir); //jeszcze próba z dodatkową ścieżką - iter=_names.find(test); //czy mamy już w magazynie? - if (iter!=_names.end()) - return iter->second; //znalezione! - //w magazynie nie ma, to sprawdzamy na dysku - test=fileName; - if (where) test.insert(0,where); //ścieżka obiektu wywołującego - file.open(test.c_str()); - if (!file.is_open()) - {//jak znaleziony, to plik zostaje otwarty - test=fileName; - if (dir) test.insert(0,dir); //próba z dodatkową ścieżką - file.open(test.c_str()); - if (file.is_open()) - fileName=test; //ustalenie nowej nazwy - } - } - if (file.is_open()) - {//plik pozostaje otwarty, gdy znaleziono na dysku - file.close(); //można już zamknąć - iter=LoadFromFile(fileName,filter); //doda się do magazynu i zwróci swoją pozycję - } -*/ - size_t pos=fileName.find(':'); //szukamy dwukropka - if (pos!=std::string::npos) //po dwukropku mogą być podane dodatkowe informacje - fileName=fileName.substr(0,pos); //niebędące nazwą tekstury - pos=fileName.find('|'); //szukamy separatora tekstur - if (pos!=std::string::npos) //po | może być nazwa kolejnej tekstury - fileName=fileName.substr(0,pos); //i trzeba to obciąć - std::transform(fileName.begin(),fileName.end(),fileName.begin(),ReplaceSlash()); - //jeśli bieżaca ścieżka do tekstur nie została dodana to dodajemy domyślną - if (fileName.find('\\')==std::string::npos) - fileName.insert(0,szTexturePath); - Names::iterator iter; - if (fileName.find('.')==std::string::npos) - {//Ra: wypróbowanie rozszerzeń po kolei, zaczynając od domyślnego - fileName.append("."); //kropka będze na pewno, resztę trzeba próbować - std::string test; //zmienna robocza - for (int i=0;i<4;++i) - {//najpierw szukamy w magazynie - test=fileName; - test.append(Global::szDefaultExt[i]); - iter=_names.find(fileName); //czy mamy już w magazynie? - if (iter!=_names.end()) - return iter->second; //znalezione! - test.insert(0,szTexturePath); //jeszcze próba z dodatkową ścieżką - iter=_names.find(fileName); //czy mamy już w magazynie? - if (iter!=_names.end()) - return iter->second; //znalezione! - } - for (int i=0;i<4;++i) - {//w magazynie nie ma, to sprawdzamy na dysku - test=fileName; - test.append(Global::szDefaultExt[i]); - std::ifstream file(test.c_str()); - if (!file.is_open()) - {test.insert(0,szTexturePath); - file.open(test.c_str()); - } - if (file.is_open()) - { - fileName.append(Global::szDefaultExt[i]); //dopisanie znalezionego - file.close(); - break; //wyjście z pętli na etapie danego rozszerzenia - } - } - } - iter=_names.find(fileName); //czy mamy już w magazynie - if (iter==_names.end()) - iter=LoadFromFile(fileName,filter); - return (iter!=_names.end()?iter->second:0); +GLuint TTexturesManager::GetTextureID(char *dir, char *where, std::string fileName, int filter) +{ // ustalenie numeru tekstury, wczytanie jeśli nie jeszcze takiej nie było + /* + // Ra: niby tak jest lepiej, ale działa gorzej, więc przywrócone jest oryginalne + //najpierw szukamy w katalogu, z którego wywoływana jest tekstura, potem z wyższego + //Ra: przerobić na wyszukiwanie w drzewie nazw, do którego zapisywać np. rozmiary, + przezroczystość + //Ra: ustalać, które tekstury można wczytać już w trakcie symulacji + size_t pos=fileName.find(':'); //szukamy dwukropka + if (pos!=std::string::npos) //po dwukropku mogą być podane dodatkowe informacje + fileName=fileName.substr(0,pos); //niebędące nazwą tekstury + std::transform(fileName.begin(),fileName.end(),fileName.begin(),ReplaceSlash()); //zamiana "/" + na "\" + //jeśli bieżaca ścieżka do tekstur nie została dodana to dodajemy domyślną + //if (fileName.find('\\')==std::string::npos) //bz sensu + // fileName.insert(0,szDefaultTexturePath); + //najpierw szukamy w podanym katalogu, potem w domyślnym + Names::iterator iter; + std::ifstream file; + if ((fileName.find('.')==fileName.npos)?true:(fileName.rfind('.')second; //znalezione! + if (dir) + {//może we wskazanym katalogu? + test=fileName; + test.insert(0,dir); //jeszcze próba z dodatkową ścieżką + test.append(Global::szDefaultExt[i]); //dodanie jednego z kilku rozszerzeń + iter=_names.find(test); //czy mamy już w magazynie? + if (iter!=_names.end()) + return iter->second; //znalezione! + } + //} + //for (int i=0;i<4;++i) + //{//w magazynie nie ma, to sprawdzamy na dysku + test=fileName; + if (where) test.insert(0,where); //ścieżka obiektu wywołującego + test.append(Global::szDefaultExt[i]); //dodanie jednego z kilku rozszerzeń + file.open(test.c_str()); + if (!file.is_open()) + {test=fileName; + if (dir) test.insert(0,dir); //próba z dodatkową ścieżką + test.append(Global::szDefaultExt[i]); //dodanie jednego z kilku rozszerzeń + file.open(test.c_str()); + } + if (file.is_open()) + {//jak znaleziony, to plik zostaje otwarty + fileName=test; //zapamiętanie znalezionego rozszerzenia + break; //wyjście z pętli na etapie danego rozszerzenia + } + } + } + else + {//gdy jest kropka, to rozszerzenie jest jawne + std::string test; //zmienna robocza + //najpierw szukamy w magazynie + test=fileName; + if (where) test.insert(0,where); //ścieżka obiektu wywołującego + iter=_names.find(test); //czy mamy już w magazynie? + if (iter!=_names.end()) + return iter->second; //znalezione! + test=fileName; + if (dir) test.insert(0,dir); //jeszcze próba z dodatkową ścieżką + iter=_names.find(test); //czy mamy już w magazynie? + if (iter!=_names.end()) + return iter->second; //znalezione! + //w magazynie nie ma, to sprawdzamy na dysku + test=fileName; + if (where) test.insert(0,where); //ścieżka obiektu wywołującego + file.open(test.c_str()); + if (!file.is_open()) + {//jak znaleziony, to plik zostaje otwarty + test=fileName; + if (dir) test.insert(0,dir); //próba z dodatkową ścieżką + file.open(test.c_str()); + if (file.is_open()) + fileName=test; //ustalenie nowej nazwy + } + } + if (file.is_open()) + {//plik pozostaje otwarty, gdy znaleziono na dysku + file.close(); //można już zamknąć + iter=LoadFromFile(fileName,filter); //doda się do magazynu i zwróci swoją pozycję + } + */ + size_t pos = fileName.find(':'); // szukamy dwukropka + if (pos != std::string::npos) // po dwukropku mogą być podane dodatkowe informacje + fileName = fileName.substr(0, pos); // niebędące nazwą tekstury + pos = fileName.find('|'); // szukamy separatora tekstur + if (pos != std::string::npos) // po | może być nazwa kolejnej tekstury + fileName = fileName.substr(0, pos); // i trzeba to obciąć + std::transform(fileName.begin(), fileName.end(), fileName.begin(), ReplaceSlash()); + // jeśli bieżaca ścieżka do tekstur nie została dodana to dodajemy domyślną + if (fileName.find('\\') == std::string::npos) + fileName.insert(0, szTexturePath); + Names::iterator iter; + if (fileName.find('.') == std::string::npos) + { // Ra: wypróbowanie rozszerzeń po kolei, zaczynając od domyślnego + fileName.append("."); // kropka będze na pewno, resztę trzeba próbować + std::string test; // zmienna robocza + for (int i = 0; i < 4; ++i) + { // najpierw szukamy w magazynie + test = fileName; + test.append(Global::szDefaultExt[i]); + iter = _names.find(fileName); // czy mamy już w magazynie? + if (iter != _names.end()) + return iter->second; // znalezione! + test.insert(0, szTexturePath); // jeszcze próba z dodatkową ścieżką + iter = _names.find(fileName); // czy mamy już w magazynie? + if (iter != _names.end()) + return iter->second; // znalezione! + } + for (int i = 0; i < 4; ++i) + { // w magazynie nie ma, to sprawdzamy na dysku + test = fileName; + test.append(Global::szDefaultExt[i]); + std::ifstream file(test.c_str()); + if (!file.is_open()) + { + test.insert(0, szTexturePath); + file.open(test.c_str()); + } + if (file.is_open()) + { + fileName.append(Global::szDefaultExt[i]); // dopisanie znalezionego + file.close(); + break; // wyjście z pętli na etapie danego rozszerzenia + } + } + } + iter = _names.find(fileName); // czy mamy już w magazynie + if (iter == _names.end()) + iter = LoadFromFile(fileName, filter); + return (iter != _names.end() ? iter->second : 0); }; bool TTexturesManager::GetAlpha(GLuint id) -{//atrybut przezroczystości dla tekstury o podanym numerze (id) - Alphas::iterator iter=_alphas.find(id); - return (iter!=_alphas.end()?iter->second:false); +{ // atrybut przezroczystości dla tekstury o podanym numerze (id) + Alphas::iterator iter = _alphas.find(id); + return (iter != _alphas.end() ? iter->second : false); } TTexturesManager::AlphaValue TTexturesManager::LoadBMP(std::string fileName) @@ -244,15 +245,15 @@ TTexturesManager::AlphaValue TTexturesManager::LoadBMP(std::string fileName) if (!file.is_open()) { - //file.close(); + // file.close(); return fail; }; BITMAPFILEHEADER header; size_t bytes; - file.read((char*) &header, sizeof(BITMAPFILEHEADER)); - if(file.eof()) + file.read((char *)&header, sizeof(BITMAPFILEHEADER)); + if (file.eof()) { file.close(); return fail; @@ -261,9 +262,9 @@ TTexturesManager::AlphaValue TTexturesManager::LoadBMP(std::string fileName) // Read in bitmap information structure BITMAPINFO info; long infoSize = header.bfOffBits - sizeof(BITMAPFILEHEADER); - file.read((char*) &info, infoSize); + file.read((char *)&info, infoSize); - if(file.eof()) + if (file.eof()) { file.close(); return fail; @@ -273,13 +274,13 @@ TTexturesManager::AlphaValue TTexturesManager::LoadBMP(std::string fileName) GLuint height = info.bmiHeader.biHeight; unsigned long bitSize = info.bmiHeader.biSizeImage; - if(!bitSize) + if (!bitSize) bitSize = (width * info.bmiHeader.biBitCount + 7) / 8 * height; - GLubyte* data = new GLubyte[bitSize]; - file.read((char*) data, bitSize); + GLubyte *data = new GLubyte[bitSize]; + file.read((char *)data, bitSize); - if(file.eof()) + if (file.eof()) { delete[] data; file.close(); @@ -292,10 +293,10 @@ TTexturesManager::AlphaValue TTexturesManager::LoadBMP(std::string fileName) glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // This is specific to the binary format of the data read in. glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -303,263 +304,287 @@ TTexturesManager::AlphaValue TTexturesManager::LoadBMP(std::string fileName) glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, - GL_BGR_EXT, GL_UNSIGNED_BYTE, data); + glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, data); delete[] data; return std::make_pair(id, false); - }; -TTexturesManager::AlphaValue TTexturesManager::LoadTGA(std::string fileName,int filter) +TTexturesManager::AlphaValue TTexturesManager::LoadTGA(std::string fileName, int filter) { - AlphaValue fail(0,false); - int writeback=-1; //-1 plik jest OK, >=0 - od którego bajtu zapisać poprawiony plik - GLubyte TGACompheader[]={0,0,10,0,0,0,0,0,0,0,0,0}; //uncompressed TGA header - GLubyte TGAcompare[12]; //used to compare TGA header - GLubyte header[6]; //first 6 useful bytes from the header - std::fstream file(fileName.c_str(),std::ios::binary|std::ios::in); - file.read((char*)TGAcompare,sizeof(TGAcompare)); - file.read((char*)header,sizeof(header)); - //std::cout << file.tellg() << std::endl; - if (file.eof()) - { - file.close(); - return fail; - }; - bool compressed=(memcmp(TGACompheader,TGAcompare,sizeof(TGACompheader))==0); - GLint width =header[1]*256+header[0]; //determine the TGA width (highbyte*256+lowbyte) - GLint height=header[3]*256+header[2]; //determine the TGA height (highbyte*256+lowbyte) - // check if width, height and bpp is correct - if ( !width || !height || (header[4]!=24 && header[4]!=32)) - { - WriteLog("Bad texture: "+AnsiString(fileName.c_str())+" has wrong header or bits per pixel"); - file.close(); - return fail; - }; - {//sprawdzenie prawidłowości rozmiarów - int i,j; - for (i=width,j=0;i;i>>=1) if (i&1) ++j; - if (j==1) - for (i=height,j=0;i;i>>=1) if (i&1) ++j; - if (j!=1) WriteLog("Bad texture: "+AnsiString(fileName.c_str())+" is "+AnsiString(width)+"×"+AnsiString(height)); - } - GLuint bpp=header[4]; //grab the TGA's bits per pixel (24 or 32) - GLuint bytesPerPixel=bpp/8; // divide by 8 to get the bytes per pixel - GLuint imageSize=width*height*bytesPerPixel; //calculate the memory required for the TGA data - GLubyte *imageData=new GLubyte[imageSize]; //reserve memory to hold the TGA data - if (!compressed) - {//WriteLog("Not compressed."); - file.read(imageData,imageSize); - if (file.eof()) - { - delete[] imageData; - file.close(); - return fail; - }; - } - else - {//skompresowany plik TGA - GLuint filesize; //current byte - GLuint colorbuffer[1]; // Storage for 1 pixel - file.seekg(0,ios::end); //na koniec - filesize=(int)file.tellg()-18; //rozmiar bez nagłówka - file.seekg(18,ios::beg); //ponownie za nagłówkiem - GLubyte *copyto=imageData; //gdzie wstawiać w buforze - GLubyte *copyend=imageData+imageSize; //za ostatnim bajtem bufora - GLubyte *copyfrom=imageData+imageSize-filesize; //gdzie jest początek - int chunkheader=0; //Ra: będziemy wczytywać najmłodszy bajt - if (filesizeimageSize) - {//nie ma prawa być większe - WriteLog("Compression error"); - delete[] imageData; - file.close(); - return fail; - } - //na końcu mogą być śmieci - int extraend=copyend-copyto; //długość śmieci na końcu - if (extraend>0) - {//przesuwamy bufor do końca obszaru dekompresji - WriteLog("Extra bytes: "+AnsiString(extraend)); - memmove(copyfrom+extraend,copyfrom,filesize-extraend); - copyfrom+=extraend; - file.close(); - filesize-=extraend; //to chyba nie ma znaczenia - if (Global::iModifyTGA&2) //flaga obcinania śmieci - {//najlepiej by było obciąć plik, ale fstream tego nie potrafi - int handle; - for (unsigned int i=0;i=0 - od którego bajtu zapisać poprawiony plik + GLubyte TGACompheader[] = {0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // uncompressed TGA header + GLubyte TGAcompare[12]; // used to compare TGA header + GLubyte header[6]; // first 6 useful bytes from the header + std::fstream file(fileName.c_str(), std::ios::binary | std::ios::in); + file.read((char *)TGAcompare, sizeof(TGAcompare)); + file.read((char *)header, sizeof(header)); + // std::cout << file.tellg() << std::endl; + if (file.eof()) + { + file.close(); + return fail; + }; + bool compressed = (memcmp(TGACompheader, TGAcompare, sizeof(TGACompheader)) == 0); + GLint width = header[1] * 256 + header[0]; // determine the TGA width (highbyte*256+lowbyte) + GLint height = header[3] * 256 + header[2]; // determine the TGA height (highbyte*256+lowbyte) + // check if width, height and bpp is correct + if (!width || !height || (header[4] != 24 && header[4] != 32)) + { + WriteLog("Bad texture: " + AnsiString(fileName.c_str()) + + " has wrong header or bits per pixel"); + file.close(); + return fail; + }; + { // sprawdzenie prawidłowości rozmiarów + int i, j; + for (i = width, j = 0; i; i >>= 1) + if (i & 1) + ++j; + if (j == 1) + for (i = height, j = 0; i; i >>= 1) + if (i & 1) + ++j; + if (j != 1) + WriteLog("Bad texture: " + AnsiString(fileName.c_str()) + " is " + AnsiString(width) + + "×" + AnsiString(height)); } - file.open(fileName.c_str(),std::ios::binary|std::ios::in); - } - if (chunkheader<128) //jeśli ostatnie piksele są kopiowane - copyend-=(1+chunkheader)*bytesPerPixel; //bajty kopiowane na końcu nie podlegające dekompresji - else - copyend-=bytesPerPixel; //ostatni piksel i tak się nie zmieni - copyto=imageData; //teraz będzie wypełnianie od początku obszaru - while (copytocopyfrom) - {//jeśli piksele mają być kopiowane, to możliwe jest przesunięcie ich o 1 bajt, na miejsce licznika - filesize=(imageData+imageSize-copyto)/bytesPerPixel; //ile pikseli pozostało do końca - //WriteLog("Decompression buffer overflow at pixel "+AnsiString((copyto-imageData)/bytesPerPixel)+"+"+AnsiString(filesize)); - //pozycję w pliku trzeba by zapamietać i po wczytaniu reszty pikseli starą metodą - //zapisać od niej dane od (copyto), poprzedzone bajtem o wartości (filesize-1) - writeback=imageData+imageSize+extraend-copyfrom; //ile bajtów skompresowanych zostało do końca - copyfrom=copyto; //adres piksela do zapisania - file.seekg(-writeback,ios::end); //odległość od końca (ujemna) - if ((filesize>128)||!(Global::iModifyTGA&4)) //gdy za dużo pikseli albo wyłączone - writeback=-1; //zapis możliwe jeśli ilość problematycznych pikseli nie przekaracza 128 - break; //bufor się zatkał, dalej w ten sposób się nie da - } - if (chunkheader<128) - {//dla nagłówka < 128 mamy podane ile pikseli przekopiować minus 1 - copybytes=(++chunkheader)*bytesPerPixel; //rozmiar kopiowanego obszaru - memcpy(copyto,++copyfrom,copybytes); //skopiowanie tylu bajtów - copyto+=copybytes; - copyfrom+=copybytes; + GLuint bpp = header[4]; // grab the TGA's bits per pixel (24 or 32) + GLuint bytesPerPixel = bpp / 8; // divide by 8 to get the bytes per pixel + GLuint imageSize = + width * height * bytesPerPixel; // calculate the memory required for the TGA data + GLubyte *imageData = new GLubyte[imageSize]; // reserve memory to hold the TGA data + if (!compressed) + { // WriteLog("Not compressed."); + file.read(imageData, imageSize); + if (file.eof()) + { + delete[] imageData; + file.close(); + return fail; + }; } else - {//chunkheader > 128 RLE data, next color reapeated chunkheader - 127 times - chunkheader-=127; - //copy the color into the image data as many times as dictated - if (bytesPerPixel==4) - {//przy czterech bajtach powinno być szybsze używanie int - __int32 *ptr=(__int32*)(copyto); //wskaźnik na int - __int32 bgra=*((__int32*)++copyfrom); //kolor wypełniający (4 bajty) - for (int counter=0;counter imageSize) + { // nie ma prawa być większe + WriteLog("Compression error"); + delete[] imageData; + file.close(); + return fail; + } + // na końcu mogą być śmieci + int extraend = copyend - copyto; // długość śmieci na końcu + if (extraend > 0) + { // przesuwamy bufor do końca obszaru dekompresji + WriteLog("Extra bytes: " + AnsiString(extraend)); + memmove(copyfrom + extraend, copyfrom, filesize - extraend); + copyfrom += extraend; + file.close(); + filesize -= extraend; // to chyba nie ma znaczenia + if (Global::iModifyTGA & 2) // flaga obcinania śmieci + { // najlepiej by było obciąć plik, ale fstream tego nie potrafi + int handle; + for (unsigned int i = 0; i < fileName.length(); ++i) + if (fileName[i] == '/') + fileName[i] == '\\'; // bo to Windows + WriteLog("Truncating extra bytes"); + handle = open(fileName.c_str(), O_RDWR | O_BINARY); + chsize(handle, 18 + filesize); // obcięcie śmieci + close(handle); + extraend = 0; // skoro obcięty, to się już nie liczy + } + file.open(fileName.c_str(), std::ios::binary | std::ios::in); + } + if (chunkheader < 128) // jeśli ostatnie piksele są kopiowane + copyend -= (1 + chunkheader) * + bytesPerPixel; // bajty kopiowane na końcu nie podlegające dekompresji + else + copyend -= bytesPerPixel; // ostatni piksel i tak się nie zmieni + copyto = imageData; // teraz będzie wypełnianie od początku obszaru + while (copyto < copyend) + { + chunkheader = (unsigned char)*copyfrom; // jeden bajt, pozostałe zawsze zerowe + if (copyto > copyfrom) + { // jeśli piksele mają być kopiowane, to możliwe jest przesunięcie ich o 1 bajt, na + // miejsce licznika + filesize = (imageData + imageSize - copyto) / + bytesPerPixel; // ile pikseli pozostało do końca + // WriteLog("Decompression buffer overflow at pixel + // "+AnsiString((copyto-imageData)/bytesPerPixel)+"+"+AnsiString(filesize)); + // pozycję w pliku trzeba by zapamietać i po wczytaniu reszty pikseli starą + // metodą + // zapisać od niej dane od (copyto), poprzedzone bajtem o wartości (filesize-1) + writeback = imageData + imageSize + extraend - + copyfrom; // ile bajtów skompresowanych zostało do końca + copyfrom = copyto; // adres piksela do zapisania + file.seekg(-writeback, ios::end); // odległość od końca (ujemna) + if ((filesize > 128) || + !(Global::iModifyTGA & 4)) // gdy za dużo pikseli albo wyłączone + writeback = -1; // zapis możliwe jeśli ilość problematycznych pikseli nie + // przekaracza 128 + break; // bufor się zatkał, dalej w ten sposób się nie da + } + if (chunkheader < 128) + { // dla nagłówka < 128 mamy podane ile pikseli przekopiować minus 1 + copybytes = (++chunkheader) * bytesPerPixel; // rozmiar kopiowanego obszaru + memcpy(copyto, ++copyfrom, copybytes); // skopiowanie tylu bajtów + copyto += copybytes; + copyfrom += copybytes; + } + else + { // chunkheader > 128 RLE data, next color reapeated chunkheader - 127 times + chunkheader -= 127; + // copy the color into the image data as many times as dictated + if (bytesPerPixel == 4) + { // przy czterech bajtach powinno być szybsze używanie int + __int32 *ptr = (__int32 *)(copyto); // wskaźnik na int + __int32 bgra = *((__int32 *)++copyfrom); // kolor wypełniający (4 bajty) + for (int counter = 0; counter < chunkheader; counter++) + *ptr++ = bgra; + copyto = (char *)(ptr); // rzutowanie, żeby nie dodawać + copyfrom += 4; + } + else + { + colorbuffer[0] = *((int *)(++copyfrom)); // pobranie koloru (3 bajty) + for (int counter = 0; counter < chunkheader; counter++) + { // by the header + memcpy(copyto, colorbuffer, 3); + copyto += 3; + } + copyfrom += 3; + } + } + } // while (copyto128 RLE data, next color reapeated (chunkheader-127) times + chunkheader -= 127; + file.read((char *)colorbuffer, bytesPerPixel); + // copy the color into the image data as many times as dictated + if (bytesPerPixel == 4) + { // przy czterech bajtach powinno być szybsze używanie int + __int32 *ptr = (__int32 *)(copyto), bgra = *((__int32 *)colorbuffer); + for (int counter = 0; counter < chunkheader; counter++) + *ptr++ = bgra; + copyto = (char *)(ptr); // rzutowanie, żeby nie dodawać + } + else + for (int counter = 0; counter < chunkheader; counter++) + { // by the header + memcpy(copyto, colorbuffer, bytesPerPixel); + copyto += bytesPerPixel; + } + } + } // while (copyto= 0) + { // zapisanie pliku + file.close(); // tamten zamykamy, bo był tylko do odczytu + if (writeback) + { // zapisanie samej końcówki pliku, która utrudnia dekompresję w buforze + WriteLog("Rewriting end of file..."); + chunkheader = filesize - 1; // licznik jest o 1 mniejszy + file.open(fileName.c_str(), std::ios::binary | std::ios::out | std::ios::in); + file.seekg(-writeback, ios::end); // odległość od końca (ujemna) + file.write((char *)&chunkheader, 1); // zapisanie licznika + file.write(copyfrom, filesize * bytesPerPixel); // piksele bez kompresji + } + else + { // zapisywanie całości pliku, będzie krótszy, więc trzeba usunąć go w całości + WriteLog("Writing uncompressed file..."); + TGAcompare[2] = 2; // bez kompresji + file.open(fileName.c_str(), std::ios::binary | std::ios::out | std::ios::trunc); + file.write((char *)TGAcompare, sizeof(TGAcompare)); + file.write((char *)header, sizeof(header)); + file.write(imageData, imageSize); + } + } + }; + file.close(); // plik zamykamy dopiero na samym końcu + bool alpha = (bpp == 32); + bool hash = (fileName.find('#') != std::string::npos); // true gdy w nazwie jest "#" + bool dollar = (fileName.find('$') == std::string::npos); // true gdy w nazwie nie ma "$" + size_t pos = fileName.rfind('%'); // ostatni % w nazwie + if (pos != std::string::npos) + if (pos < fileName.size()) + { + filter = (int)fileName[pos + 1] - '0'; // zamiana cyfry za % na liczbę + if ((filter < 0) || (filter > 10)) + filter = -1; // jeśli nie jest cyfrą + } + if (!alpha && !hash && dollar && (filter < 0)) + filter = Global::iDefaultFiltering; // dotyczy tekstur TGA bez kanału alfa + // ewentualne przeskalowanie tekstury do dopuszczalnego rozumiaru + GLint w = width, h = height; + if (width > Global::iMaxTextureSize) + width = Global::iMaxTextureSize; // ogranizczenie wielkości + if (height > Global::iMaxTextureSize) + height = Global::iMaxTextureSize; + if ((w != width) || (h != height)) + { // przeskalowanie tekstury, żeby się nie wyświetlała jako biała + GLubyte *imgData = new GLubyte[width * height * bytesPerPixel]; // nowy rozmiar + gluScaleImage(bytesPerPixel == 3 ? GL_RGB : GL_RGBA, w, h, GL_UNSIGNED_BYTE, imageData, + width, height, GL_UNSIGNED_BYTE, imgData); + delete imageData; // usunięcie starego + imageData = imgData; } - } //while (copyto128 RLE data, next color reapeated (chunkheader-127) times - chunkheader-=127; - file.read((char*)colorbuffer,bytesPerPixel); - //copy the color into the image data as many times as dictated - if (bytesPerPixel==4) - {//przy czterech bajtach powinno być szybsze używanie int - __int32 *ptr=(__int32*)(copyto),bgra=*((__int32*)colorbuffer); - for (int counter=0;counter=0) - {//zapisanie pliku - file.close(); //tamten zamykamy, bo był tylko do odczytu - if (writeback) - {//zapisanie samej końcówki pliku, która utrudnia dekompresję w buforze - WriteLog("Rewriting end of file..."); - chunkheader=filesize-1; //licznik jest o 1 mniejszy - file.open(fileName.c_str(),std::ios::binary|std::ios::out|std::ios::in); - file.seekg(-writeback,ios::end); //odległość od końca (ujemna) - file.write((char*)&chunkheader,1); //zapisanie licznika - file.write(copyfrom,filesize*bytesPerPixel); //piksele bez kompresji - } - else - {//zapisywanie całości pliku, będzie krótszy, więc trzeba usunąć go w całości - WriteLog("Writing uncompressed file..."); - TGAcompare[2]=2; //bez kompresji - file.open(fileName.c_str(),std::ios::binary|std::ios::out|std::ios::trunc); - file.write((char*)TGAcompare,sizeof(TGAcompare)); - file.write((char*)header,sizeof(header)); - file.write(imageData,imageSize); - } - } - }; - file.close(); //plik zamykamy dopiero na samym końcu - bool alpha = (bpp == 32); - bool hash = (fileName.find('#') != std::string::npos); //true gdy w nazwie jest "#" - bool dollar = (fileName.find('$') == std::string::npos); //true gdy w nazwie nie ma "$" - size_t pos=fileName.rfind('%'); //ostatni % w nazwie - if (pos!=std::string::npos) - if (pos10)) filter=-1; //jeśli nie jest cyfrą - } - if (!alpha&&!hash&&dollar&&(filter<0)) - filter=Global::iDefaultFiltering; //dotyczy tekstur TGA bez kanału alfa - //ewentualne przeskalowanie tekstury do dopuszczalnego rozumiaru - GLint w=width,h=height; - if (width>Global::iMaxTextureSize) width=Global::iMaxTextureSize; //ogranizczenie wielkości - if (height>Global::iMaxTextureSize) height=Global::iMaxTextureSize; - if ((w!=width)||(h!=height)) - {//przeskalowanie tekstury, żeby się nie wyświetlała jako biała - GLubyte* imgData=new GLubyte[width*height*bytesPerPixel]; //nowy rozmiar - gluScaleImage(bytesPerPixel==3?GL_RGB:GL_RGBA,w,h,GL_UNSIGNED_BYTE,imageData,width,height,GL_UNSIGNED_BYTE,imgData); - delete imageData; //usunięcie starego - imageData=imgData; - } - GLuint id=CreateTexture(imageData,(alpha?GL_BGRA:GL_BGR),width,height,alpha,hash,dollar,filter); - delete[] imageData; - ++Global::iTextures; - return std::make_pair(id,alpha); + ++Global::iTextures; + return std::make_pair(id, alpha); }; TTexturesManager::AlphaValue TTexturesManager::LoadTEX(std::string fileName) @@ -575,11 +600,11 @@ TTexturesManager::AlphaValue TTexturesManager::LoadTEX(std::string fileName) bool alpha; - if(std::string("RGB ") == head) + if (std::string("RGB ") == head) { alpha = false; } - else if(std::string("RGBA") == head) + else if (std::string("RGBA") == head) { alpha = true; } @@ -594,25 +619,24 @@ TTexturesManager::AlphaValue TTexturesManager::LoadTEX(std::string fileName) GLuint width; GLuint height; - file.read((char *) &width, sizeof(int)); - file.read((char *) &height, sizeof(int)); + file.read((char *)&width, sizeof(int)); + file.read((char *)&height, sizeof(int)); GLuint bpp = alpha ? 4 : 3; GLuint size = width * height * bpp; - GLubyte* data = new GLubyte[size]; + GLubyte *data = new GLubyte[size]; file.read(data, size); bool hash = (fileName.find('#') != std::string::npos); - GLuint id = CreateTexture(data,(alpha?GL_RGBA:GL_RGB),width,height,alpha,hash); + GLuint id = CreateTexture(data, (alpha ? GL_RGBA : GL_RGB), width, height, alpha, hash); delete[] data; return std::make_pair(id, alpha); - }; -TTexturesManager::AlphaValue TTexturesManager::LoadDDS(std::string fileName,int filter) +TTexturesManager::AlphaValue TTexturesManager::LoadDDS(std::string fileName, int filter) { AlphaValue fail(0, false); @@ -623,14 +647,14 @@ TTexturesManager::AlphaValue TTexturesManager::LoadDDS(std::string fileName,int file.read(filecode, 4); filecode[4] = 0; - if(std::string("DDS ") != filecode) + if (std::string("DDS ") != filecode) { file.close(); return fail; }; DDSURFACEDESC2 ddsd; - file.read((char*) &ddsd, sizeof(ddsd)); + file.read((char *)&ddsd, sizeof(ddsd)); DDS_IMAGE_DATA data; @@ -641,48 +665,54 @@ TTexturesManager::AlphaValue TTexturesManager::LoadDDS(std::string fileName,int GLuint factor; - switch( ddsd.ddpfPixelFormat.dwFourCC ) + switch (ddsd.ddpfPixelFormat.dwFourCC) { - case FOURCC_DXT1: - // DXT1's compression ratio is 8:1 - data.format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - factor = 2; - break; + case FOURCC_DXT1: + // DXT1's compression ratio is 8:1 + data.format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + factor = 2; + break; - case FOURCC_DXT3: - // DXT3's compression ratio is 4:1 - data.format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - factor = 4; - break; + case FOURCC_DXT3: + // DXT3's compression ratio is 4:1 + data.format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + factor = 4; + break; - case FOURCC_DXT5: - // DXT5's compression ratio is 4:1 - data.format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - factor = 4; - break; + case FOURCC_DXT5: + // DXT5's compression ratio is 4:1 + data.format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + factor = 4; + break; - default: - file.close(); - return fail; + default: + file.close(); + return fail; } GLuint bufferSize = (ddsd.dwMipMapCount > 1 ? ddsd.dwLinearSize * factor : ddsd.dwLinearSize); data.pixels = new GLubyte[bufferSize]; - file.read((char*)data.pixels,bufferSize); + file.read((char *)data.pixels, bufferSize); file.close(); - data.width = ddsd.dwWidth; - data.height = ddsd.dwHeight; + data.width = ddsd.dwWidth; + data.height = ddsd.dwHeight; data.numMipMaps = ddsd.dwMipMapCount; - {//sprawdzenie prawidłowości rozmiarów - int i,j; - for (i=data.width,j=0;i;i>>=1) if (i&1) ++j; - if (j==1) - for (i=data.height,j=0;i;i>>=1) if (i&1) ++j; - if (j!=1) WriteLog("Bad texture: "+AnsiString(fileName.c_str())+" is "+AnsiString(data.width)+"×"+AnsiString(data.height)); - } + { // sprawdzenie prawidłowości rozmiarów + int i, j; + for (i = data.width, j = 0; i; i >>= 1) + if (i & 1) + ++j; + if (j == 1) + for (i = data.height, j = 0; i; i >>= 1) + if (i & 1) + ++j; + if (j != 1) + WriteLog("Bad texture: " + AnsiString(fileName.c_str()) + " is " + + AnsiString(data.width) + "×" + AnsiString(data.height)); + } if (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1) data.components = 3; @@ -694,142 +724,154 @@ TTexturesManager::AlphaValue TTexturesManager::LoadDDS(std::string fileName,int GLuint id; glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); - if (filter>=0) - SetFiltering(filter); //cyfra po % w nazwie + if (filter >= 0) + SetFiltering(filter); // cyfra po % w nazwie else - //SetFiltering(bHasAlpha&&bDollar,bHash); //znaki #, $ i kanał alfa w nazwie - SetFiltering(data.components==4,fileName.find('#')!=std::string::npos); + // SetFiltering(bHasAlpha&&bDollar,bHash); //znaki #, $ i kanał alfa w nazwie + SetFiltering(data.components == 4, fileName.find('#') != std::string::npos); GLuint offset = 0; int firstMipMap = 0; - - while ((data.width>Global::iMaxTextureSize)||(data.height>Global::iMaxTextureSize)) - {//pomijanie zbyt dużych mipmap, jeśli wymagane jest ograniczenie rozmiaru - offset+=((data.width+3)/4)*((data.height+3)/4)*data.blockSize; - data.width/=2; - data.height/=2; - firstMipMap++; - }; - for (int i=0;i Global::iMaxTextureSize) || (data.height > Global::iMaxTextureSize)) + { // pomijanie zbyt dużych mipmap, jeśli wymagane jest ograniczenie rozmiaru + offset += ((data.width + 3) / 4) * ((data.height + 3) / 4) * data.blockSize; + data.width /= 2; + data.height /= 2; + firstMipMap++; + }; + + for (int i = 0; i < data.numMipMaps - firstMipMap; i++) + { // wczytanie kolejnych poziomów mipmap + if (!data.width) + data.width = 1; + if (!data.height) + data.height = 1; + GLuint size = ((data.width + 3) / 4) * ((data.height + 3) / 4) * data.blockSize; + if (Global::bDecompressDDS) + { // programowa dekompresja DDS + // if (i==1) //should be i==0 but then problem with "glBindTexture()" + { + GLuint decomp_size = data.width * data.height * 4; + GLubyte *output = new GLubyte[decomp_size]; + DecompressDXT(data, data.pixels + offset, output); + glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, data.width, data.height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, output); + delete[] output; + } + } + else // przetwarzanie DDS przez OpenGL (istnieje odpowiednie rozszerzenie) + glCompressedTexImage2D(GL_TEXTURE_2D, i, data.format, data.width, data.height, 0, size, + data.pixels + offset); + offset += size; + // Half the image size for the next mip-map level... + data.width /= 2; + data.height /= 2; + }; + delete[] data.pixels; + return std::make_pair(id, data.components == 4); }; void TTexturesManager::SetFiltering(int filter) { - if (filter<4) //rozmycie przy powiększeniu - {//brak rozmycia z bliska - tych jest 4: 0..3, aby nie było przeskoku - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); - filter+=4; - } - else - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - switch (filter) //rozmycie przy oddaleniu - {case 4: //najbliższy z tekstury - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); break; - case 5: //średnia z tekstury - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); break; - case 6: //najbliższy z mipmapy - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST); break; - case 7: //średnia z mipmapy - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); break; - case 8: //najbliższy z dwóch mipmap - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR); break; - case 9: //średnia z dwóch mipmap - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); break; - } + if (filter < 4) // rozmycie przy powiększeniu + { // brak rozmycia z bliska - tych jest 4: 0..3, aby nie było przeskoku + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + filter += 4; + } + else + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + switch (filter) // rozmycie przy oddaleniu + { + case 4: // najbliższy z tekstury + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + break; + case 5: //średnia z tekstury + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + break; + case 6: // najbliższy z mipmapy + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + break; + case 7: //średnia z mipmapy + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + break; + case 8: // najbliższy z dwóch mipmap + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); + break; + case 9: //średnia z dwóch mipmap + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + break; + } }; void TTexturesManager::SetFiltering(bool alpha, bool hash) { - if ( alpha || hash ) + if (alpha || hash) { - if (alpha) // przezroczystosc: nie wlaczac mipmapingu - { - if (hash) // #: calkowity brak filtracji - pikseloza - { - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - else - { - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - } - else // filtruj ale bez dalekich mipmap - robi artefakty - { - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - } + if (alpha) // przezroczystosc: nie wlaczac mipmapingu + { + if (hash) // #: calkowity brak filtracji - pikseloza + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + else + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + } + else // filtruj ale bez dalekich mipmap - robi artefakty + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + } else // $: filtruj wszystko - brzydko się zlewa - { - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } }; /////////////////////////////////////////////////////////////////////////////// -GLuint TTexturesManager::CreateTexture(char* buff,GLint bpp,int width,int height,bool bHasAlpha,bool bHash,bool bDollar,int filter) -{//Ra: używane tylko dla TGA i TEX - //Ra: dodana obsługa GL_BGR oraz GL_BGRA dla TGA - szybciej się wczytuje - GLuint ID; - glGenTextures(1,&ID); - glBindTexture(GL_TEXTURE_2D,ID); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - if (filter>=0) - SetFiltering(filter); //cyfra po % w nazwie - else - SetFiltering(bHasAlpha&&bDollar,bHash); //znaki #, $ i kanał alfa w nazwie - glPixelStorei(GL_UNPACK_ALIGNMENT,1); - glPixelStorei(GL_UNPACK_ROW_LENGTH,0); - glPixelStorei(GL_UNPACK_SKIP_ROWS,0); - glPixelStorei(GL_UNPACK_SKIP_PIXELS,0); - if (bHasAlpha || bHash || (filter==0)) - glTexImage2D(GL_TEXTURE_2D,0,(bHasAlpha?GL_RGBA:GL_RGB),width,height,0,bpp,GL_UNSIGNED_BYTE,buff); - else - gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGB,width,height,bpp,GL_UNSIGNED_BYTE,buff); - return ID; +GLuint TTexturesManager::CreateTexture(char *buff, GLint bpp, int width, int height, bool bHasAlpha, + bool bHash, bool bDollar, int filter) +{ // Ra: używane tylko dla TGA i TEX + // Ra: dodana obsługa GL_BGR oraz GL_BGRA dla TGA - szybciej się wczytuje + GLuint ID; + glGenTextures(1, &ID); + glBindTexture(GL_TEXTURE_2D, ID); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + if (filter >= 0) + SetFiltering(filter); // cyfra po % w nazwie + else + SetFiltering(bHasAlpha && bDollar, bHash); // znaki #, $ i kanał alfa w nazwie + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + if (bHasAlpha || bHash || (filter == 0)) + glTexImage2D(GL_TEXTURE_2D, 0, (bHasAlpha ? GL_RGBA : GL_RGB), width, height, 0, bpp, + GL_UNSIGNED_BYTE, buff); + else + gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, width, height, bpp, GL_UNSIGNED_BYTE, buff); + return ID; } void TTexturesManager::Free() -{//usunięcie wszyskich tekstur (bez usuwania struktury) - for (Names::iterator iter=_names.begin();iter!=_names.end();iter++) - glDeleteTextures(1,&(iter->second)); +{ // usunięcie wszyskich tekstur (bez usuwania struktury) + for (Names::iterator iter = _names.begin(); iter != _names.end(); iter++) + glDeleteTextures(1, &(iter->second)); } std::string TTexturesManager::GetName(GLuint id) -{//pobranie nazwy tekstury - for (Names::iterator iter=_names.begin();iter!=_names.end();iter++) - if (iter->second==id) - return iter->first; - return ""; +{ // pobranie nazwy tekstury + for (Names::iterator iter = _names.begin(); iter != _names.end(); iter++) + if (iter->second == id) + return iter->first; + return ""; }; #pragma package(smart_init) - diff --git a/Texture.h b/Texture.h index 88230ceb..703a60d8 100644 --- a/Texture.h +++ b/Texture.h @@ -24,35 +24,35 @@ void __fastcall glDebug() class TTexturesManager { -public: + public: static void Init(); static void Free(); - static GLuint GetTextureID(char* dir,char* where,std::string name,int filter=-1); - static bool GetAlpha(GLuint ID); //McZapkie-141203: czy tekstura ma polprzeroczystosc + static GLuint GetTextureID(char *dir, char *where, std::string name, int filter = -1); + static bool GetAlpha(GLuint ID); // McZapkie-141203: czy tekstura ma polprzeroczystosc static std::string GetName(GLuint id); -private: + private: typedef std::pair AlphaValue; typedef std::map Names; typedef std::map Alphas; - static Names::iterator LoadFromFile(std::string name,int filter=-1); + static Names::iterator LoadFromFile(std::string name, int filter = -1); static AlphaValue LoadBMP(std::string fileName); static AlphaValue LoadTEX(std::string fileName); - static AlphaValue LoadTGA(std::string fileName,int filter=-1); - static AlphaValue LoadDDS(std::string fileName,int filter=-1); + static AlphaValue LoadTGA(std::string fileName, int filter = -1); + static AlphaValue LoadDDS(std::string fileName, int filter = -1); static void SetFiltering(int filter); static void SetFiltering(bool alpha, bool hash); - static GLuint CreateTexture(char *buff,GLint bpp,int width,int height,bool bHasAlpha,bool bHash,bool bDollar=true,int filter=-1); + static GLuint CreateTexture(char *buff, GLint bpp, int width, int height, bool bHasAlpha, + bool bHash, bool bDollar = true, int filter = -1); static Names _names; static Alphas _alphas; -// std::list Textures; - + // std::list Textures; }; //--------------------------------------------------------------------------- #endif diff --git a/TextureDDS.cpp b/TextureDDS.cpp index 10eebebb..d92cb433 100644 --- a/TextureDDS.cpp +++ b/TextureDDS.cpp @@ -1,299 +1,330 @@ #include "TextureDDS.h" -void DxtcReadColors(const GLubyte* Data, Color8888* result) +void DxtcReadColors(const GLubyte *Data, Color8888 *result) { - GLubyte r0, g0, b0, r1, g1, b1; + GLubyte r0, g0, b0, r1, g1, b1; - b0 = Data[0] & 0x1F; - g0 = ((Data[0] & 0xE0) >> 5) | ((Data[1] & 0x7) << 3); - r0 = (Data[1] & 0xF8) >> 3; + b0 = Data[0] & 0x1F; + g0 = ((Data[0] & 0xE0) >> 5) | ((Data[1] & 0x7) << 3); + r0 = (Data[1] & 0xF8) >> 3; - b1 = Data[2] & 0x1F; - g1 = ((Data[2] & 0xE0) >> 5) | ((Data[3] & 0x7) << 3); - r1 = (Data[3] & 0xF8) >> 3; + b1 = Data[2] & 0x1F; + g1 = ((Data[2] & 0xE0) >> 5) | ((Data[3] & 0x7) << 3); + r1 = (Data[3] & 0xF8) >> 3; - result[0].r = r0 << 3 | r0 >> 2; - result[0].g = g0 << 2 | g0 >> 3; - result[0].b = b0 << 3 | b0 >> 2; + result[0].r = r0 << 3 | r0 >> 2; + result[0].g = g0 << 2 | g0 >> 3; + result[0].b = b0 << 3 | b0 >> 2; - result[1].r = r1 << 3 | r1 >> 2; - result[1].g = g1 << 2 | g1 >> 3; - result[1].b = b1 << 3 | b1 >> 2; + result[1].r = r1 << 3 | r1 >> 2; + result[1].g = g1 << 2 | g1 >> 3; + result[1].b = b1 << 3 | b1 >> 2; }; -void DxtcReadColor(GLushort Data, Color8888* Out) +void DxtcReadColor(GLushort Data, Color8888 *Out) { - GLubyte r, g, b; + GLubyte r, g, b; - b = Data & 0x1f; - g = (Data & 0x7E0) >> 5; - r = (Data & 0xF800) >> 11; + b = Data & 0x1f; + g = (Data & 0x7E0) >> 5; + r = (Data & 0xF800) >> 11; - Out->r = r << 3 | r >> 2; - Out->g = g << 2 | g >> 3; - Out->b = b << 3 | r >> 2; + Out->r = r << 3 | r >> 2; + Out->g = g << 2 | g >> 3; + Out->b = b << 3 | r >> 2; }; void DecompressDXT1(DDS_IMAGE_DATA lImage, const GLubyte *lCompData, GLubyte *Data) { - GLint x, y, i, j, k; - GLuint Select; - const GLubyte *Temp; - Color8888 colours[4], *col; - GLushort color_0, color_1; - GLuint bitmask, Offset; + GLint x, y, i, j, k; + GLuint Select; + const GLubyte *Temp; + Color8888 colours[4], *col; + GLushort color_0, color_1; + GLuint bitmask, Offset; - Temp = lCompData; - colours[0].a = 0xFF; - colours[1].a = 0xFF; - colours[2].a = 0xFF; + Temp = lCompData; + colours[0].a = 0xFF; + colours[1].a = 0xFF; + colours[2].a = 0xFF; - for (y = 0; y < lImage.height; y += 4) { - for (x = 0; x < lImage.width; x += 4) { - color_0 = *((const GLushort*)Temp); - color_1 = *((const GLushort*)(Temp + 2)); + for (y = 0; y < lImage.height; y += 4) + { + for (x = 0; x < lImage.width; x += 4) + { + color_0 = *((const GLushort *)Temp); + color_1 = *((const GLushort *)(Temp + 2)); - DxtcReadColor(color_0, colours); - DxtcReadColor(color_1, colours + 1); - bitmask = ((const GLuint*)Temp)[1]; + DxtcReadColor(color_0, colours); + DxtcReadColor(color_1, colours + 1); + bitmask = ((const GLuint *)Temp)[1]; - Temp += 8; + Temp += 8; - if (color_0 > color_1) { - // Four-color block: derive the other two colors. - // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 - // These 2-bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3; - colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3; - colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3; - - colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3; - colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3; - colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3; - colours[3].a = 0xFF; - } - else + if (color_0 > color_1) { - // Three-color block: derive the other color. - // 00 = color_0, 01 = color_1, 10 = color_2, - // 11 = transparent. - // These 2-bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - colours[2].b = (colours[0].b + colours[1].b) / 2; - colours[2].g = (colours[0].g + colours[1].g) / 2; - colours[2].r = (colours[0].r + colours[1].r) / 2; + // Four-color block: derive the other two colors. + // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 + // These 2-bit codes correspond to the 2-bit fields + // stored in the 64-bit block. + colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3; + colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3; + colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3; - colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3; - colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3; - colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3; - colours[3].a = 0x00; - } + colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3; + colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3; + colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3; + colours[3].a = 0xFF; + } + else + { + // Three-color block: derive the other color. + // 00 = color_0, 01 = color_1, 10 = color_2, + // 11 = transparent. + // These 2-bit codes correspond to the 2-bit fields + // stored in the 64-bit block. + colours[2].b = (colours[0].b + colours[1].b) / 2; + colours[2].g = (colours[0].g + colours[1].g) / 2; + colours[2].r = (colours[0].r + colours[1].r) / 2; - for (j = 0, k = 0; j < 4; j++) { - for (i = 0; i < 4; i++, k++) { - Select = (bitmask & (0x03 << k*2)) >> k*2; - col = &colours[Select]; + colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3; + colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3; + colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3; + colours[3].a = 0x00; + } - if (((x + i) < lImage.width) && ((y + j) < lImage.height)) { - Offset = (y + j) * lImage.width * lImage.components + (x + i) * lImage.components; - Data[Offset + 0] = col->r; - Data[Offset + 1] = col->g; - Data[Offset + 2] = col->b; - Data[Offset + 3] = col->a; - } - } - } - } - } + for (j = 0, k = 0; j < 4; j++) + { + for (i = 0; i < 4; i++, k++) + { + Select = (bitmask & (0x03 << k * 2)) >> k * 2; + col = &colours[Select]; + + if (((x + i) < lImage.width) && ((y + j) < lImage.height)) + { + Offset = (y + j) * lImage.width * lImage.components + + (x + i) * lImage.components; + Data[Offset + 0] = col->r; + Data[Offset + 1] = col->g; + Data[Offset + 2] = col->b; + Data[Offset + 3] = col->a; + } + } + } + } + } } void DecompressDXT3(DDS_IMAGE_DATA lImage, const GLubyte *lCompData, GLubyte *Data) { - const GLubyte* Temp = lCompData; + const GLubyte *Temp = lCompData; - Color8888 colours[4], *col; - GLuint bitmask, Offset; - const GLubyte* alpha; + Color8888 colours[4], *col; + GLuint bitmask, Offset; + const GLubyte *alpha; - for (GLint y = 0; y < lImage.height; y += 4) { - for (GLint x = 0; x < lImage.width; x += 4) { - alpha = Temp; - Temp += 8; - DxtcReadColors(Temp, colours); - bitmask = ((GLuint*)Temp)[1]; + for (GLint y = 0; y < lImage.height; y += 4) + { + for (GLint x = 0; x < lImage.width; x += 4) + { + alpha = Temp; + Temp += 8; + DxtcReadColors(Temp, colours); + bitmask = ((GLuint *)Temp)[1]; - Temp += 8; + Temp += 8; - // Four-color block: derive the other two colors. - // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 - // These 2-bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3; - colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3; - colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3; + // Four-color block: derive the other two colors. + // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 + // These 2-bit codes correspond to the 2-bit fields + // stored in the 64-bit block. + colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3; + colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3; + colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3; - colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3; - colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3; - colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3; + colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3; + colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3; + colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3; - GLuint k = 0; - for (GLint j = 0; j < 4; j++) { - for (GLint i = 0; i < 4; i++, k++) { - GLuint Select = (bitmask & (0x03 << k*2)) >> k*2; - col = &colours[Select]; + GLuint k = 0; + for (GLint j = 0; j < 4; j++) + { + for (GLint i = 0; i < 4; i++, k++) + { + GLuint Select = (bitmask & (0x03 << k * 2)) >> k * 2; + col = &colours[Select]; - if (((x + i) < lImage.width) && ((y + j) < lImage.height)) { - Offset = (y + j) * lImage.width * lImage.components + (x + i) * lImage.components; - Data[Offset + 0] = col->r; - Data[Offset + 1] = col->g; - Data[Offset + 2] = col->b; - } - } - } + if (((x + i) < lImage.width) && ((y + j) < lImage.height)) + { + Offset = (y + j) * lImage.width * lImage.components + + (x + i) * lImage.components; + Data[Offset + 0] = col->r; + Data[Offset + 1] = col->g; + Data[Offset + 2] = col->b; + } + } + } - for (GLint j = 0; j < 4; j++) { - GLushort word = alpha[2*j] + 256*alpha[2*j+1]; - for (GLint i = 0; i < 4; i++) { - if (((x + i) < lImage.width) && ((y + j) < lImage.height)) { - Offset = (y + j) * lImage.width * lImage.components + (x + i) * lImage.components + 3; - Data[Offset] = word & 0x0F; - Data[Offset] = Data[Offset] | (Data[Offset] << 4); - } - word >>= 4; - } - } - } - } + for (GLint j = 0; j < 4; j++) + { + GLushort word = alpha[2 * j] + 256 * alpha[2 * j + 1]; + for (GLint i = 0; i < 4; i++) + { + if (((x + i) < lImage.width) && ((y + j) < lImage.height)) + { + Offset = (y + j) * lImage.width * lImage.components + + (x + i) * lImage.components + 3; + Data[Offset] = word & 0x0F; + Data[Offset] = Data[Offset] | (Data[Offset] << 4); + } + word >>= 4; + } + } + } + } } void DecompressDXT5(DDS_IMAGE_DATA lImage, const GLubyte *lCompData, GLubyte *Data) { - GLint x, y, z, i, j, k; - GLuint Select; - const GLubyte *Temp; //, r0, g0, b0, r1, g1, b1; - Color8888 colours[4], *col; - GLuint bitmask, Offset; - GLubyte alphas[8]; - GLuint bits; + GLint x, y, z, i, j, k; + GLuint Select; + const GLubyte *Temp; //, r0, g0, b0, r1, g1, b1; + Color8888 colours[4], *col; + GLuint bitmask, Offset; + GLubyte alphas[8]; + GLuint bits; - Temp = lCompData; + Temp = lCompData; - for (y = 0; y < lImage.height; y += 4) { - for (x = 0; x < lImage.width; x += 4) { - if (y >= lImage.height || x >= lImage.width) - break; - alphas[0] = Temp[0]; - alphas[1] = Temp[1]; - const GLubyte* alphamask = Temp + 2; - Temp += 8; + for (y = 0; y < lImage.height; y += 4) + { + for (x = 0; x < lImage.width; x += 4) + { + if (y >= lImage.height || x >= lImage.width) + break; + alphas[0] = Temp[0]; + alphas[1] = Temp[1]; + const GLubyte *alphamask = Temp + 2; + Temp += 8; - DxtcReadColors(Temp, colours); - bitmask = ((const GLuint*)Temp)[1]; + DxtcReadColors(Temp, colours); + bitmask = ((const GLuint *)Temp)[1]; - Temp += 8; + Temp += 8; - // Four-color block: derive the other two colors. - // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 - // These 2-bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3; - colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3; - colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3; + // Four-color block: derive the other two colors. + // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 + // These 2-bit codes correspond to the 2-bit fields + // stored in the 64-bit block. + colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3; + colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3; + colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3; - colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3; - colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3; - colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3; + colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3; + colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3; + colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3; - k = 0; - for (j = 0; j < 4; j++) { - for (i = 0; i < 4; i++, k++) { + k = 0; + for (j = 0; j < 4; j++) + { + for (i = 0; i < 4; i++, k++) + { - Select = (bitmask & (0x03 << k*2)) >> k*2; - col = &colours[Select]; + Select = (bitmask & (0x03 << k * 2)) >> k * 2; + col = &colours[Select]; - // only put pixels out < width or height - if (((x + i) < lImage.width) && ((y + j) < lImage.height)) { - Offset = (y + j) * lImage.width * lImage.components + (x + i) * lImage.components; - Data[Offset + 0] = col->r; - Data[Offset + 1] = col->g; - Data[Offset + 2] = col->b; - } - } - } + // only put pixels out < width or height + if (((x + i) < lImage.width) && ((y + j) < lImage.height)) + { + Offset = (y + j) * lImage.width * lImage.components + + (x + i) * lImage.components; + Data[Offset + 0] = col->r; + Data[Offset + 1] = col->g; + Data[Offset + 2] = col->b; + } + } + } - // 8-alpha or 6-alpha block? - if (alphas[0] > alphas[1]) { - // 8-alpha block: derive the other six alphas. - // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated. - alphas[2] = (6 * alphas[0] + 1 * alphas[1] + 3) / 7; // bit code 010 - alphas[3] = (5 * alphas[0] + 2 * alphas[1] + 3) / 7; // bit code 011 - alphas[4] = (4 * alphas[0] + 3 * alphas[1] + 3) / 7; // bit code 100 - alphas[5] = (3 * alphas[0] + 4 * alphas[1] + 3) / 7; // bit code 101 - alphas[6] = (2 * alphas[0] + 5 * alphas[1] + 3) / 7; // bit code 110 - alphas[7] = (1 * alphas[0] + 6 * alphas[1] + 3) / 7; // bit code 111 - } - else { - // 6-alpha block. - // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated. - alphas[2] = (4 * alphas[0] + 1 * alphas[1] + 2) / 5; // Bit code 010 - alphas[3] = (3 * alphas[0] + 2 * alphas[1] + 2) / 5; // Bit code 011 - alphas[4] = (2 * alphas[0] + 3 * alphas[1] + 2) / 5; // Bit code 100 - alphas[5] = (1 * alphas[0] + 4 * alphas[1] + 2) / 5; // Bit code 101 - alphas[6] = 0x00; // Bit code 110 - alphas[7] = 0xFF; // Bit code 111 - } + // 8-alpha or 6-alpha block? + if (alphas[0] > alphas[1]) + { + // 8-alpha block: derive the other six alphas. + // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated. + alphas[2] = (6 * alphas[0] + 1 * alphas[1] + 3) / 7; // bit code 010 + alphas[3] = (5 * alphas[0] + 2 * alphas[1] + 3) / 7; // bit code 011 + alphas[4] = (4 * alphas[0] + 3 * alphas[1] + 3) / 7; // bit code 100 + alphas[5] = (3 * alphas[0] + 4 * alphas[1] + 3) / 7; // bit code 101 + alphas[6] = (2 * alphas[0] + 5 * alphas[1] + 3) / 7; // bit code 110 + alphas[7] = (1 * alphas[0] + 6 * alphas[1] + 3) / 7; // bit code 111 + } + else + { + // 6-alpha block. + // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated. + alphas[2] = (4 * alphas[0] + 1 * alphas[1] + 2) / 5; // Bit code 010 + alphas[3] = (3 * alphas[0] + 2 * alphas[1] + 2) / 5; // Bit code 011 + alphas[4] = (2 * alphas[0] + 3 * alphas[1] + 2) / 5; // Bit code 100 + alphas[5] = (1 * alphas[0] + 4 * alphas[1] + 2) / 5; // Bit code 101 + alphas[6] = 0x00; // Bit code 110 + alphas[7] = 0xFF; // Bit code 111 + } - // Note: Have to separate the next two loops, - // it operates on a 6-byte system. + // Note: Have to separate the next two loops, + // it operates on a 6-byte system. - // First three bytes - //bits = *((ILint*)alphamask); - bits = (alphamask[0]) | (alphamask[1] << 8) | (alphamask[2] << 16); - for (j = 0; j < 2; j++) { - for (i = 0; i < 4; i++) { - // only put pixels out < width or height - if (((x + i) < lImage.width) && ((y + j) < lImage.height)) { - Offset = (y + j) * lImage.width * lImage.components + (x + i) * lImage.components + 3; - Data[Offset] = alphas[bits & 0x07]; - } - bits >>= 3; - } - } + // First three bytes + // bits = *((ILint*)alphamask); + bits = (alphamask[0]) | (alphamask[1] << 8) | (alphamask[2] << 16); + for (j = 0; j < 2; j++) + { + for (i = 0; i < 4; i++) + { + // only put pixels out < width or height + if (((x + i) < lImage.width) && ((y + j) < lImage.height)) + { + Offset = (y + j) * lImage.width * lImage.components + + (x + i) * lImage.components + 3; + Data[Offset] = alphas[bits & 0x07]; + } + bits >>= 3; + } + } - // Last three bytes - //bits = *((ILint*)&alphamask[3]); - bits = (alphamask[3]) | (alphamask[4] << 8) | (alphamask[5] << 16); - for (j = 2; j < 4; j++) { - for (i = 0; i < 4; i++) { - // only put pixels out < width or height - if (((x + i) < lImage.width) && ((y + j) < lImage.height)) { - Offset = (y + j) * lImage.width * lImage.components + (x + i) * lImage.components + 3; - Data[Offset] = alphas[bits & 0x07]; - } - bits >>= 3; - } - } - } - } + // Last three bytes + // bits = *((ILint*)&alphamask[3]); + bits = (alphamask[3]) | (alphamask[4] << 8) | (alphamask[5] << 16); + for (j = 2; j < 4; j++) + { + for (i = 0; i < 4; i++) + { + // only put pixels out < width or height + if (((x + i) < lImage.width) && ((y + j) < lImage.height)) + { + Offset = (y + j) * lImage.width * lImage.components + + (x + i) * lImage.components + 3; + Data[Offset] = alphas[bits & 0x07]; + } + bits >>= 3; + } + } + } + } } void DecompressDXT(DDS_IMAGE_DATA lImage, const GLubyte *lCompData, GLubyte *Data) { - switch(lImage.format) + switch (lImage.format) { - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - DecompressDXT1(lImage, lCompData, Data); - break; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + DecompressDXT1(lImage, lCompData, Data); + break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - DecompressDXT3(lImage, lCompData, Data); - break; - - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - DecompressDXT5(lImage, lCompData, Data); - break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + DecompressDXT3(lImage, lCompData, Data); + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + DecompressDXT5(lImage, lCompData, Data); + break; }; } - diff --git a/TextureDDS.h b/TextureDDS.h index 8fdfc859..94571f3b 100644 --- a/TextureDDS.h +++ b/TextureDDS.h @@ -7,24 +7,23 @@ struct Color8888 { - GLubyte r; // change the order of names to change the - GLubyte g; // order of the output ARGB or BGRA, etc... - GLubyte b; // Last one is MSB, 1st is LSB. - GLubyte a; + GLubyte r; // change the order of names to change the + GLubyte g; // order of the output ARGB or BGRA, etc... + GLubyte b; // Last one is MSB, 1st is LSB. + GLubyte a; }; struct DDS_IMAGE_DATA { - GLsizei width; - GLsizei height; - GLint components; - GLenum format; - GLuint blockSize; - int numMipMaps; + GLsizei width; + GLsizei height; + GLint components; + GLenum format; + GLuint blockSize; + int numMipMaps; GLubyte *pixels; }; void DecompressDXT(DDS_IMAGE_DATA lImage, const GLubyte *lCompData, GLubyte *Data); #endif - \ No newline at end of file diff --git a/Timer.cpp b/Timer.cpp index d5ebc7b2..9a7ea03e 100644 --- a/Timer.cpp +++ b/Timer.cpp @@ -7,113 +7,85 @@ #include "Timer.h" #include "Globals.h" -namespace Timer { - -double DeltaTime,DeltaRenderTime; -double fFPS =0.0f; -double fLastTime =0.0f; -DWORD dwFrames =0L; -double fSimulationTime=0; -double fSoundTimer=0; -double fSinceStart=0; - - - -double __fastcall GetTime() +namespace Timer { - return fSimulationTime; -} -double __fastcall GetDeltaTime() -{//czas symulacji (stoi gdy pauza) - return DeltaTime; -} +double DeltaTime, DeltaRenderTime; +double fFPS = 0.0f; +double fLastTime = 0.0f; +DWORD dwFrames = 0L; +double fSimulationTime = 0; +double fSoundTimer = 0; +double fSinceStart = 0; -double __fastcall GetDeltaRenderTime() -{//czas renderowania (do poruszania się) - return DeltaRenderTime; -} +double __fastcall GetTime() { return fSimulationTime; } -double __fastcall GetfSinceStart() -{ - return fSinceStart; -} +double __fastcall GetDeltaTime() { // czas symulacji (stoi gdy pauza) return DeltaTime; } -void __fastcall SetDeltaTime(double t) -{ - DeltaTime= t; -} +double __fastcall GetDeltaRenderTime() { // czas renderowania (do poruszania się) return DeltaRenderTime; } -double __fastcall GetSimulationTime() -{ - return fSimulationTime; -} +double __fastcall GetfSinceStart() { return fSinceStart; } -void __fastcall SetSimulationTime(double t) -{ - fSimulationTime=t; -} +void __fastcall SetDeltaTime(double t) { DeltaTime = t; } + +double __fastcall GetSimulationTime() { return fSimulationTime; } + +void __fastcall SetSimulationTime(double t) { fSimulationTime = t; } bool __fastcall GetSoundTimer() -{//Ra: być może, by dźwięki nie modyfikowały się zbyt często, po 0.1s zeruje się ten licznik - return (fSoundTimer==0.0f); -} +{ // Ra: być może, by dźwięki nie modyfikowały się zbyt często, po 0.1s zeruje się ten licznik + return (fSoundTimer == 0.0f); } - -double __fastcall GetFPS() -{ - return fFPS; -} +double __fastcall GetFPS() { return fFPS; } void __fastcall ResetTimers() { - //double CurrentTime= - GetTickCount(); - DeltaTime=0.1; - DeltaRenderTime=0; - fSoundTimer=0; + // double CurrentTime= + GetTickCount(); + DeltaTime = 0.1; + DeltaRenderTime = 0; + fSoundTimer = 0; }; -LONGLONG fr,count,oldCount; -//LARGE_INTEGER fr,count; +LONGLONG fr, count, oldCount; +// LARGE_INTEGER fr,count; void __fastcall UpdateTimers(bool pause) { - QueryPerformanceFrequency((LARGE_INTEGER*)&fr); - QueryPerformanceCounter((LARGE_INTEGER*)&count); - DeltaRenderTime=double(count-oldCount)/double(fr); - if (!pause) - {DeltaTime=Global::fTimeSpeed*DeltaRenderTime; - fSoundTimer+=DeltaTime; - if (fSoundTimer>0.1) fSoundTimer=0; -/* - double CurrentTime= double(count)/double(fr);//GetTickCount(); - DeltaTime= (CurrentTime-OldTime); - OldTime= CurrentTime; -*/ - if (DeltaTime>1) DeltaTime=1; - } - else - DeltaTime=0; //wszystko stoi, bo czas nie płynie - oldCount=count; + QueryPerformanceFrequency((LARGE_INTEGER *)&fr); + QueryPerformanceCounter((LARGE_INTEGER *)&count); + DeltaRenderTime = double(count - oldCount) / double(fr); + if (!pause) + { + DeltaTime = Global::fTimeSpeed * DeltaRenderTime; + fSoundTimer += DeltaTime; + if (fSoundTimer > 0.1) + fSoundTimer = 0; + /* + double CurrentTime= double(count)/double(fr);//GetTickCount(); + DeltaTime= (CurrentTime-OldTime); + OldTime= CurrentTime; + */ + if (DeltaTime > 1) + DeltaTime = 1; + } + else + DeltaTime = 0; // wszystko stoi, bo czas nie płynie + oldCount = count; - // Keep track of the time lapse and frame count - double fTime=GetTickCount()*0.001f; // Get current time in seconds - ++dwFrames; //licznik ramek - //update the frame rate once per second - if (fTime-fLastTime>1.0f) - { - fFPS =dwFrames/(fTime-fLastTime); - fLastTime=fTime; - dwFrames =0L; - } - fSimulationTime+=DeltaTime; + // Keep track of the time lapse and frame count + double fTime = GetTickCount() * 0.001f; // Get current time in seconds + ++dwFrames; // licznik ramek + // update the frame rate once per second + if (fTime - fLastTime > 1.0f) + { + fFPS = dwFrames / (fTime - fLastTime); + fLastTime = fTime; + dwFrames = 0L; + } + fSimulationTime += DeltaTime; }; - - - }; //--------------------------------------------------------------------------- #pragma package(smart_init) - \ No newline at end of file diff --git a/Timer.h b/Timer.h index 0f2f042b..1904db8c 100644 --- a/Timer.h +++ b/Timer.h @@ -3,8 +3,8 @@ #ifndef TimerH #define TimerH -namespace Timer { - +namespace Timer +{ double __fastcall GetTime(); @@ -26,7 +26,6 @@ double __fastcall GetFPS(); void __fastcall ResetTimers(); void __fastcall UpdateTimers(bool pause); - }; //--------------------------------------------------------------------------- diff --git a/Track.cpp b/Track.cpp index 5ab2db36..95829a2e 100644 --- a/Track.cpp +++ b/Track.cpp @@ -5,7 +5,7 @@ */ -//nagłówki identyczne w każdym pliku... +// nagłówki identyczne w każdym pliku... #pragma hdrstop #include "Track.h" @@ -23,989 +23,1062 @@ #pragma package(smart_init) -//101206 Ra: trapezoidalne drogi i tory -//110720 Ra: rozprucie zwrotnicy i odcinki izolowane +// 101206 Ra: trapezoidalne drogi i tory +// 110720 Ra: rozprucie zwrotnicy i odcinki izolowane -static const double fMaxOffset=0.1; //double(0.1f)==0.100000001490116 -//const int NextMask[4]={0,1,0,1}; //tor następny dla stanów 0, 1, 2, 3 -//const int PrevMask[4]={0,0,1,1}; //tor poprzedni dla stanów 0, 1, 2, 3 -const int iLewo4[4]={5,3,4,6}; //segmenty (1..6) do skręcania w lewo -const int iPrawo4[4]={-4,-6,-3,-5}; //segmenty (1..6) do skręcania w prawo -const int iProsto4[4]={1,-1,2,-2}; //segmenty (1..6) do jazdy prosto -const int iEnds4[13]={3,0,2,1,2,0,-1,1,3,2,0,3,1}; //numer sąsiedniego toru na końcu segmentu "-1" -const int iLewo3[4]={1,3,2,1}; //segmenty do skręcania w lewo -const int iPrawo3[4]={-2,-1,-3,-2}; //segmenty do skręcania w prawo -const int iProsto3[4]={1,-1,2,1}; //segmenty do jazdy prosto -const int iEnds3[13]={3,0,2,1,2,0,-1,1,0,2,0,3,1}; //numer sąsiedniego toru na końcu segmentu "-1" -TIsolated *TIsolated::pRoot=NULL; +static const double fMaxOffset = 0.1; // double(0.1f)==0.100000001490116 +// const int NextMask[4]={0,1,0,1}; //tor następny dla stanów 0, 1, 2, 3 +// const int PrevMask[4]={0,0,1,1}; //tor poprzedni dla stanów 0, 1, 2, 3 +const int iLewo4[4] = {5, 3, 4, 6}; // segmenty (1..6) do skręcania w lewo +const int iPrawo4[4] = {-4, -6, -3, -5}; // segmenty (1..6) do skręcania w prawo +const int iProsto4[4] = {1, -1, 2, -2}; // segmenty (1..6) do jazdy prosto +const int iEnds4[13] = {3, 0, 2, 1, 2, 0, -1, + 1, 3, 2, 0, 3, 1}; // numer sąsiedniego toru na końcu segmentu "-1" +const int iLewo3[4] = {1, 3, 2, 1}; // segmenty do skręcania w lewo +const int iPrawo3[4] = {-2, -1, -3, -2}; // segmenty do skręcania w prawo +const int iProsto3[4] = {1, -1, 2, 1}; // segmenty do jazdy prosto +const int iEnds3[13] = {3, 0, 2, 1, 2, 0, -1, + 1, 0, 2, 0, 3, 1}; // numer sąsiedniego toru na końcu segmentu "-1" +TIsolated *TIsolated::pRoot = NULL; -__fastcall TSwitchExtension::TSwitchExtension(TTrack *owner,int what) -{//na początku wszystko puste - CurrentIndex=0; - pNexts[0]=NULL; //wskaźniki do kolejnych odcinków ruchu - pNexts[1]=NULL; - pPrevs[0]=NULL; - pPrevs[1]=NULL; - fOffsetSpeed=0.1; //prędkość liniowa iglic - fOffsetDelay=0.05; //dodatkowy ruch drugiej iglicy po zablokowaniu pierwszej na opornicy - fOffset1=fOffset=fDesiredOffset=-fOffsetDelay; //położenie zasadnicze - fOffset2=0.0; //w zasadniczym wewnętrzna iglica dolega - pOwner=NULL; - pNextAnim=NULL; - bMovement=false; //nie potrzeba przeliczać fOffset1 - Segments[0]=new TSegment(owner); //z punktu 1 do 2 - Segments[1]=new TSegment(owner); //z punktu 3 do 4 (1=3 dla zwrotnic; odwrócony dla skrzyżowań, ewentualnie 1=4) - Segments[2]=(what>=3)?new TSegment(owner):NULL; //z punktu 2 do 4 skrzyżowanie od góry: wersja "-1": - Segments[3]=(what>=4)?new TSegment(owner):NULL; //z punktu 4 do 1 1 1=4 0 0=3 - Segments[4]=(what>=5)?new TSegment(owner):NULL; //z punktu 1 do 3 4 x 3 3 3 x 2 2 - Segments[5]=(what>=6)?new TSegment(owner):NULL; //z punktu 3 do 2 2 2 1 1 - evPlus=evMinus=NULL; - fVelocity=-1.0; //maksymalne ograniczenie prędkości (ustawianej eventem) - vTrans=vector3(0,0,0); //docelowa translacja przesuwnicy +__fastcall TSwitchExtension::TSwitchExtension(TTrack *owner, int what) +{ // na początku wszystko puste + CurrentIndex = 0; + pNexts[0] = NULL; // wskaźniki do kolejnych odcinków ruchu + pNexts[1] = NULL; + pPrevs[0] = NULL; + pPrevs[1] = NULL; + fOffsetSpeed = 0.1; // prędkość liniowa iglic + fOffsetDelay = 0.05; // dodatkowy ruch drugiej iglicy po zablokowaniu pierwszej na opornicy + fOffset1 = fOffset = fDesiredOffset = -fOffsetDelay; // położenie zasadnicze + fOffset2 = 0.0; // w zasadniczym wewnętrzna iglica dolega + pOwner = NULL; + pNextAnim = NULL; + bMovement = false; // nie potrzeba przeliczać fOffset1 + Segments[0] = new TSegment(owner); // z punktu 1 do 2 + Segments[1] = new TSegment( + owner); // z punktu 3 do 4 (1=3 dla zwrotnic; odwrócony dla skrzyżowań, ewentualnie 1=4) + Segments[2] = (what >= 3) ? + new TSegment(owner) : + NULL; // z punktu 2 do 4 skrzyżowanie od góry: wersja "-1": + Segments[3] = (what >= 4) ? new TSegment(owner) : + NULL; // z punktu 4 do 1 1 1=4 0 0=3 + Segments[4] = + (what >= 5) ? new TSegment(owner) : NULL; // z punktu 1 do 3 4 x 3 3 3 x 2 2 + Segments[5] = (what >= 6) ? new TSegment(owner) : + NULL; // z punktu 3 do 2 2 2 1 1 + evPlus = evMinus = NULL; + fVelocity = -1.0; // maksymalne ograniczenie prędkości (ustawianej eventem) + vTrans = vector3(0, 0, 0); // docelowa translacja przesuwnicy } __fastcall TSwitchExtension::~TSwitchExtension() -{//nie ma nic do usuwania - //delete Segments[0]; - //delete Segments[1]; - delete Segments[2]; - delete Segments[3]; - delete Segments[4]; - delete Segments[5]; +{ // nie ma nic do usuwania + // delete Segments[0]; + // delete Segments[1]; + delete Segments[2]; + delete Segments[3]; + delete Segments[4]; + delete Segments[5]; } -__fastcall TIsolated::TIsolated() -{//utworznie pustego - TIsolated("none",NULL); -}; -__fastcall TIsolated::TIsolated(const AnsiString &n,TIsolated *i) -{//utworznie obwodu izolowanego - asName=n; - pNext=i; - iAxles=0; - evBusy=evFree=NULL; - pMemCell=NULL; //podpiąć istniejącą albo utworzyć pustą +__fastcall TIsolated::TIsolated() { // utworznie pustego TIsolated("none", NULL); }; +__fastcall TIsolated::TIsolated(const AnsiString &n, TIsolated *i) +{ // utworznie obwodu izolowanego + asName = n; + pNext = i; + iAxles = 0; + evBusy = evFree = NULL; + pMemCell = NULL; // podpiąć istniejącą albo utworzyć pustą }; -__fastcall TIsolated::~TIsolated() -{//usuwanie -/* - TIsolated *p=pRoot; - while (pRoot) - { - p=pRoot; - p->pNext=NULL; - delete p; - } -*/ +__fastcall TIsolated::~TIsolated(){// usuwanie + /* + TIsolated *p=pRoot; + while (pRoot) + { + p=pRoot; + p->pNext=NULL; + delete p; + } + */ }; -TIsolated* __fastcall TIsolated::Find(const AnsiString &n) -{//znalezienie obiektu albo utworzenie nowego - TIsolated *p=pRoot; - while (p) - {//jeśli się znajdzie, to podać wskaźnik - if (p->asName==n) return p; - p=p->pNext; - } - pRoot=new TIsolated(n,pRoot); - return pRoot; +TIsolated *__fastcall TIsolated::Find(const AnsiString &n) +{ // znalezienie obiektu albo utworzenie nowego + TIsolated *p = pRoot; + while (p) + { // jeśli się znajdzie, to podać wskaźnik + if (p->asName == n) + return p; + p = p->pNext; + } + pRoot = new TIsolated(n, pRoot); + return pRoot; }; -void __fastcall TIsolated::Modify(int i,TDynamicObject *o) -{//dodanie lub odjęcie osi - if (iAxles) - {//grupa zajęta - iAxles+=i; - if (!iAxles) - {//jeśli po zmianie nie ma żadnej osi na odcinku izolowanym - if (evFree) - Global::AddToQuery(evFree,o); //dodanie zwolnienia do kolejki - if (Global::iMultiplayer) //jeśli multiplayer - Global::pGround->WyslijString(asName,10); //wysłanie pakietu o zwolnieniu - if (pMemCell) //w powiązanej komórce - pMemCell->UpdateValues(NULL,0,int(pMemCell->Value2())&~0xFF,update_memval2); //"zerujemy" ostatnią wartość - } - } - else - {//grupa była wolna - iAxles+=i; - if (iAxles) - { - if (evBusy) - Global::AddToQuery(evBusy,o); //dodanie zajętości do kolejki - if (Global::iMultiplayer) //jeśli multiplayer - Global::pGround->WyslijString(asName,11); //wysłanie pakietu o zajęciu - if (pMemCell) //w powiązanej komórce - pMemCell->UpdateValues(NULL,0,int(pMemCell->Value2())|1,update_memval2); //zmieniamy ostatnią wartość na nieparzystą - } - } +void __fastcall TIsolated::Modify(int i, TDynamicObject *o) +{ // dodanie lub odjęcie osi + if (iAxles) + { // grupa zajęta + iAxles += i; + if (!iAxles) + { // jeśli po zmianie nie ma żadnej osi na odcinku izolowanym + if (evFree) + Global::AddToQuery(evFree, o); // dodanie zwolnienia do kolejki + if (Global::iMultiplayer) // jeśli multiplayer + Global::pGround->WyslijString(asName, 10); // wysłanie pakietu o zwolnieniu + if (pMemCell) // w powiązanej komórce + pMemCell->UpdateValues(NULL, 0, int(pMemCell->Value2()) & ~0xFF, + update_memval2); //"zerujemy" ostatnią wartość + } + } + else + { // grupa była wolna + iAxles += i; + if (iAxles) + { + if (evBusy) + Global::AddToQuery(evBusy, o); // dodanie zajętości do kolejki + if (Global::iMultiplayer) // jeśli multiplayer + Global::pGround->WyslijString(asName, 11); // wysłanie pakietu o zajęciu + if (pMemCell) // w powiązanej komórce + pMemCell->UpdateValues(NULL, 0, int(pMemCell->Value2()) | 1, + update_memval2); // zmieniamy ostatnią wartość na nieparzystą + } + } }; - __fastcall TTrack::TTrack(TGroundNode *g) -{//tworzenie nowego odcinka ruchu - trNext=trPrev=NULL; //sąsiednie - Segment=NULL; //dane odcinka - SwitchExtension=NULL; //dodatkowe parametry zwrotnicy i obrotnicy - TextureID1=0; //tekstura szyny - fTexLength=4.0; //powtarzanie tekstury - TextureID2=0; //tekstura podsypki albo drugiego toru zwrotnicy - fTexHeight1=0.6; //nowy profil podsypki ;) - fTexWidth=0.9; - fTexSlope=0.9; - eType=tt_Normal; //domyślnie zwykły - iCategoryFlag=1; //1-tor, 2-droga, 4-rzeka, 8-samolot? - fTrackWidth=1.435; //rozstaw toru, szerokość nawierzchni - fFriction=0.15; //współczynnik tarcia - fSoundDistance=-1; - iQualityFlag=20; - iDamageFlag=0; - eEnvironment=e_flat; - bVisible=true; - iEvents=0; //Ra: flaga informująca o obecności eventów - evEvent0=NULL; - evEvent1=NULL; - evEvent2=NULL; - evEventall0=NULL; - evEventall1=NULL; - evEventall2=NULL; - fVelocity=-1; //ograniczenie prędkości - fTrackLength=100.0; - fRadius=0; //promień wybranego toru zwrotnicy - fRadiusTable[0]=0; //dwa promienie nawet dla prostego - fRadiusTable[1]=0; - iNumDynamics=0; - ScannedFlag=false; - DisplayListID=0; - iTrapezoid=0; //parametry kształtu: 0-standard, 1-przechyłka, 2-trapez, 3-oba - hvOverhead=NULL; //drut zasilający, najbliższy Point1 toru - fTexRatio1=1.0; //proporcja boków tekstury nawierzchni (żeby zaoszczędzić na rozmiarach tekstur...) - fTexRatio2=1.0; //proporcja boków tekstury chodnika (żeby zaoszczędzić na rozmiarach tekstur...) - iPrevDirection=0; //domyślnie wirtualne odcinki dołączamy stroną od Point1 - iNextDirection=0; - pIsolated=NULL; - pMyNode=g; //Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode - iAction=0; //normalnie może być pomijany podczas skanowania - fOverhead=-1.0; //można normalnie pobierać prąd (0 dla jazdy bezprądowej po danym odcinku - nFouling[0]=NULL; //ukres albo kozioł od strony Point1 - nFouling[1]=NULL; //ukres albo kozioł od strony Point2 - trColides=NULL; //tor kolizyjny, na którym trzeba sprawdzać pojazdy pod kątem zderzenia +{ // tworzenie nowego odcinka ruchu + trNext = trPrev = NULL; // sąsiednie + Segment = NULL; // dane odcinka + SwitchExtension = NULL; // dodatkowe parametry zwrotnicy i obrotnicy + TextureID1 = 0; // tekstura szyny + fTexLength = 4.0; // powtarzanie tekstury + TextureID2 = 0; // tekstura podsypki albo drugiego toru zwrotnicy + fTexHeight1 = 0.6; // nowy profil podsypki ;) + fTexWidth = 0.9; + fTexSlope = 0.9; + eType = tt_Normal; // domyślnie zwykły + iCategoryFlag = 1; // 1-tor, 2-droga, 4-rzeka, 8-samolot? + fTrackWidth = 1.435; // rozstaw toru, szerokość nawierzchni + fFriction = 0.15; // współczynnik tarcia + fSoundDistance = -1; + iQualityFlag = 20; + iDamageFlag = 0; + eEnvironment = e_flat; + bVisible = true; + iEvents = 0; // Ra: flaga informująca o obecności eventów + evEvent0 = NULL; + evEvent1 = NULL; + evEvent2 = NULL; + evEventall0 = NULL; + evEventall1 = NULL; + evEventall2 = NULL; + fVelocity = -1; // ograniczenie prędkości + fTrackLength = 100.0; + fRadius = 0; // promień wybranego toru zwrotnicy + fRadiusTable[0] = 0; // dwa promienie nawet dla prostego + fRadiusTable[1] = 0; + iNumDynamics = 0; + ScannedFlag = false; + DisplayListID = 0; + iTrapezoid = 0; // parametry kształtu: 0-standard, 1-przechyłka, 2-trapez, 3-oba + hvOverhead = NULL; // drut zasilający, najbliższy Point1 toru + fTexRatio1 = + 1.0; // proporcja boków tekstury nawierzchni (żeby zaoszczędzić na rozmiarach tekstur...) + fTexRatio2 = + 1.0; // proporcja boków tekstury chodnika (żeby zaoszczędzić na rozmiarach tekstur...) + iPrevDirection = 0; // domyślnie wirtualne odcinki dołączamy stroną od Point1 + iNextDirection = 0; + pIsolated = NULL; + pMyNode = g; // Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode + iAction = 0; // normalnie może być pomijany podczas skanowania + fOverhead = -1.0; // można normalnie pobierać prąd (0 dla jazdy bezprądowej po danym odcinku + nFouling[0] = NULL; // ukres albo kozioł od strony Point1 + nFouling[1] = NULL; // ukres albo kozioł od strony Point2 + trColides = NULL; // tor kolizyjny, na którym trzeba sprawdzać pojazdy pod kątem zderzenia } __fastcall TTrack::~TTrack() -{//likwidacja odcinka - if (eType==tt_Normal) - delete Segment; //dla zwrotnic nie usuwać tego (kopiowany) - else - {//usuwanie dodatkowych danych dla niezwykłych odcinków - if (eType==tt_Cross) - delete SwitchExtension->vPoints; //skrzyżowanie może mieć punkty - SafeDelete(SwitchExtension); - } +{ // likwidacja odcinka + if (eType == tt_Normal) + delete Segment; // dla zwrotnic nie usuwać tego (kopiowany) + else + { // usuwanie dodatkowych danych dla niezwykłych odcinków + if (eType == tt_Cross) + delete SwitchExtension->vPoints; // skrzyżowanie może mieć punkty + SafeDelete(SwitchExtension); + } } void __fastcall TTrack::Init() -{//tworzenie pomocniczych danych - switch (eType) - { - case tt_Switch: - SwitchExtension=new TSwitchExtension(this,2); //na wprost i na bok - break; - case tt_Cross: //tylko dla skrzyżowania dróg - SwitchExtension=new TSwitchExtension(this,6); //6 połączeń - SwitchExtension->vPoints=NULL; //brak tablicy punktów - SwitchExtension->iPoints=0; - SwitchExtension->bPoints=false; //tablica punktów nie wypełniona - SwitchExtension->iRoads=4; //domyślnie 4 - break; - case tt_Normal: - Segment=new TSegment(this); - break; - case tt_Table: //oba potrzebne - SwitchExtension=new TSwitchExtension(this,1); //kopia oryginalnego toru - Segment=new TSegment(this); - break; - } +{ // tworzenie pomocniczych danych + switch (eType) + { + case tt_Switch: + SwitchExtension = new TSwitchExtension(this, 2); // na wprost i na bok + break; + case tt_Cross: // tylko dla skrzyżowania dróg + SwitchExtension = new TSwitchExtension(this, 6); // 6 połączeń + SwitchExtension->vPoints = NULL; // brak tablicy punktów + SwitchExtension->iPoints = 0; + SwitchExtension->bPoints = false; // tablica punktów nie wypełniona + SwitchExtension->iRoads = 4; // domyślnie 4 + break; + case tt_Normal: + Segment = new TSegment(this); + break; + case tt_Table: // oba potrzebne + SwitchExtension = new TSwitchExtension(this, 1); // kopia oryginalnego toru + Segment = new TSegment(this); + break; + } } -TTrack* __fastcall TTrack::Create400m(int what,double dx) -{//tworzenie toru do wstawiania taboru podczas konwersji na E3D - TGroundNode *tmp=new TGroundNode(TP_TRACK); //node - TTrack* trk=tmp->pTrack; - trk->bVisible=false; //nie potrzeba pokazywać, zresztą i tak nie ma tekstur - trk->iCategoryFlag=what; //taki sam typ plus informacja, że dodatkowy - trk->Init(); //utworzenie segmentu - trk->Segment->Init(vector3(-dx,0,0),vector3(-dx,0,400),0,0,0); //prosty - tmp->pCenter=vector3(-dx,0,200); //środek, aby się mogło wyświetlić - TSubRect *r=Global::pGround->GetSubRect(tmp->pCenter.x,tmp->pCenter.z); - r->NodeAdd(tmp); //dodanie toru do segmentu - r->Sort(); //żeby wyświetlał tabor z dodanego toru - r->Release(); //usunięcie skompilowanych zasobów - return trk; +TTrack *__fastcall TTrack::Create400m(int what, double dx) +{ // tworzenie toru do wstawiania taboru podczas konwersji na E3D + TGroundNode *tmp = new TGroundNode(TP_TRACK); // node + TTrack *trk = tmp->pTrack; + trk->bVisible = false; // nie potrzeba pokazywać, zresztą i tak nie ma tekstur + trk->iCategoryFlag = what; // taki sam typ plus informacja, że dodatkowy + trk->Init(); // utworzenie segmentu + trk->Segment->Init(vector3(-dx, 0, 0), vector3(-dx, 0, 400), 0, 0, 0); // prosty + tmp->pCenter = vector3(-dx, 0, 200); //środek, aby się mogło wyświetlić + TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z); + r->NodeAdd(tmp); // dodanie toru do segmentu + r->Sort(); //żeby wyświetlał tabor z dodanego toru + r->Release(); // usunięcie skompilowanych zasobów + return trk; }; -TTrack* __fastcall TTrack::NullCreate(int dir) -{//tworzenie toru wykolejającego od strony (dir), albo pętli dla samochodów - TGroundNode *tmp=new TGroundNode(TP_TRACK),*tmp2=NULL; //node - TTrack* trk=tmp->pTrack; //tor; UWAGA! obrotnica może generować duże ilości tego - //tmp->iType=TP_TRACK; - //TTrack* trk=new TTrack(tmp); //tor; UWAGA! obrotnica może generować duże ilości tego - //tmp->pTrack=trk; - trk->bVisible=false; //nie potrzeba pokazywać, zresztą i tak nie ma tekstur - //trk->iTrapezoid=1; //są przechyłki do uwzględniania w rysowaniu - trk->iCategoryFlag=(iCategoryFlag&15)|0x80; //taki sam typ plus informacja, że dodatkowy - double r1,r2; - Segment->GetRolls(r1,r2); //pobranie przechyłek na początku toru - vector3 p1,cv1,cv2,p2; //będziem tworzyć trajektorię lotu - if (iCategoryFlag&1) - {//tylko dla kolei - trk->iDamageFlag=128; //wykolejenie - trk->fVelocity=0.0; //koniec jazdy - trk->Init(); //utworzenie segmentu - switch (dir) - {//łączenie z nowym torem - case 0: - p1=Segment->FastGetPoint_0(); - p2=p1-450.0*Normalize(Segment->GetDirection1()); - trk->Segment->Init(p1,p2,5,-RadToDeg(r1),70.0); //bo prosty, kontrolne wyliczane przy zmiennej przechyłce - ConnectPrevPrev(trk,0); - break; - case 1: - p1=Segment->FastGetPoint_1(); - p2=p1-450.0*Normalize(Segment->GetDirection2()); - trk->Segment->Init(p1,p2,5,RadToDeg(r2),70.0); //bo prosty, kontrolne wyliczane przy zmiennej przechyłce - ConnectNextPrev(trk,0); - break; - case 3: //na razie nie możliwe - p1=SwitchExtension->Segments[1]->FastGetPoint_1(); //koniec toru drugiego zwrotnicy - p2=p1-450.0*Normalize(SwitchExtension->Segments[1]->GetDirection2()); //przedłużenie na wprost - trk->Segment->Init(p1,p2,5,RadToDeg(r2),70.0); //bo prosty, kontrolne wyliczane przy zmiennej przechyłce - ConnectNextPrev(trk,0); - //trk->ConnectPrevNext(trk,dir); - SetConnections(1); //skopiowanie połączeń - Switch(1); //bo się przełączy na 0, a to coś chce się przecież wykoleić na bok - break; //do drugiego zwrotnicy... nie zadziała? - } - } - else - {//tworznie pętelki dla samochodów - trk->fVelocity=20.0; //zawracanie powoli - trk->fRadius=20.0; //promień, aby się dodawało do tabelki prędkości i liczyło narastająco - trk->Init(); //utworzenie segmentu - tmp2=new TGroundNode(TP_TRACK); //drugi odcinek do zapętlenia - TTrack* trk2=tmp2->pTrack; - trk2->iCategoryFlag=(iCategoryFlag&15)|0x80; //taki sam typ plus informacja, że dodatkowy - trk2->bVisible=false; - trk2->fVelocity=20.0; //zawracanie powoli - trk2->fRadius=20.0; //promień, aby się dodawało do tabelki prędkości i liczyło narastająco - trk2->Init(); //utworzenie segmentu - switch (dir) - {//łączenie z nowym torem - case 0: - p1=Segment->FastGetPoint_0(); - cv1=-20.0*Normalize(Segment->GetDirection1()); //pierwszy wektor kontrolny - p2=p1+cv1+cv1; //40m - trk->Segment->Init(p1,p1+cv1,p2+vector3(-cv1.z,cv1.y,cv1.x),p2,2,-RadToDeg(r1),0.0); //bo prosty, kontrolne wyliczane przy zmiennej przechyłce - ConnectPrevPrev(trk,0); - trk2->Segment->Init(p1,p1+cv1,p2+vector3(cv1.z,cv1.y,-cv1.x),p2,2,-RadToDeg(r1),0.0); //bo prosty, kontrolne wyliczane przy zmiennej przechyłce - trk2->iPrevDirection=0; //zwrotnie do tego samego odcinka - break; - case 1: - p1=Segment->FastGetPoint_1(); - cv1=-20.0*Normalize(Segment->GetDirection2()); //pierwszy wektor kontrolny - p2=p1+cv1+cv1; - trk->Segment->Init(p1,p1+cv1,p2+vector3(-cv1.z,cv1.y,cv1.x),p2,2,RadToDeg(r2),0.0); //bo prosty, kontrolne wyliczane przy zmiennej przechyłce - ConnectNextPrev(trk,0); - trk2->Segment->Init(p1,p1+cv1,p2+vector3(cv1.z,cv1.y,-cv1.x),p2,2,RadToDeg(r2),0.0); //bo prosty, kontrolne wyliczane przy zmiennej przechyłce - trk2->iPrevDirection=1; //zwrotnie do tego samego odcinka - break; - } - trk2->trPrev=this; - trk->ConnectNextNext(trk2,1); //połączenie dwóch dodatkowych odcinków punktami 2 - tmp2->pCenter=(0.5*(p1+p2)); //środek, aby się mogło wyświetlić - } - //trzeba jeszcze dodać do odpowiedniego segmentu, aby się renderowały z niego pojazdy - tmp->pCenter=(0.5*(p1+p2)); //środek, aby się mogło wyświetlić - if (tmp2) tmp2->pCenter=tmp->pCenter; //ten sam środek jest - //Ra: to poniżej to porażka, ale na razie się nie da inaczej - TSubRect *r=Global::pGround->GetSubRect(tmp->pCenter.x,tmp->pCenter.z); - r->NodeAdd(tmp); //dodanie toru do segmentu - if (tmp2) r->NodeAdd(tmp2); //drugiego też - r->Sort(); //żeby wyświetlał tabor z dodanego toru - r->Release(); //usunięcie skompilowanych zasobów - return trk; +TTrack *__fastcall TTrack::NullCreate(int dir) +{ // tworzenie toru wykolejającego od strony (dir), albo pętli dla samochodów + TGroundNode *tmp = new TGroundNode(TP_TRACK), *tmp2 = NULL; // node + TTrack *trk = tmp->pTrack; // tor; UWAGA! obrotnica może generować duże ilości tego + // tmp->iType=TP_TRACK; + // TTrack* trk=new TTrack(tmp); //tor; UWAGA! obrotnica może generować duże ilości tego + // tmp->pTrack=trk; + trk->bVisible = false; // nie potrzeba pokazywać, zresztą i tak nie ma tekstur + // trk->iTrapezoid=1; //są przechyłki do uwzględniania w rysowaniu + trk->iCategoryFlag = (iCategoryFlag & 15) | 0x80; // taki sam typ plus informacja, że dodatkowy + double r1, r2; + Segment->GetRolls(r1, r2); // pobranie przechyłek na początku toru + vector3 p1, cv1, cv2, p2; // będziem tworzyć trajektorię lotu + if (iCategoryFlag & 1) + { // tylko dla kolei + trk->iDamageFlag = 128; // wykolejenie + trk->fVelocity = 0.0; // koniec jazdy + trk->Init(); // utworzenie segmentu + switch (dir) + { //łączenie z nowym torem + case 0: + p1 = Segment->FastGetPoint_0(); + p2 = p1 - 450.0 * Normalize(Segment->GetDirection1()); + trk->Segment->Init(p1, p2, 5, -RadToDeg(r1), + 70.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce + ConnectPrevPrev(trk, 0); + break; + case 1: + p1 = Segment->FastGetPoint_1(); + p2 = p1 - 450.0 * Normalize(Segment->GetDirection2()); + trk->Segment->Init(p1, p2, 5, RadToDeg(r2), + 70.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce + ConnectNextPrev(trk, 0); + break; + case 3: // na razie nie możliwe + p1 = SwitchExtension->Segments[1]->FastGetPoint_1(); // koniec toru drugiego zwrotnicy + p2 = p1 - + 450.0 * + Normalize( + SwitchExtension->Segments[1]->GetDirection2()); // przedłużenie na wprost + trk->Segment->Init(p1, p2, 5, RadToDeg(r2), + 70.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce + ConnectNextPrev(trk, 0); + // trk->ConnectPrevNext(trk,dir); + SetConnections(1); // skopiowanie połączeń + Switch(1); // bo się przełączy na 0, a to coś chce się przecież wykoleić na bok + break; // do drugiego zwrotnicy... nie zadziała? + } + } + else + { // tworznie pętelki dla samochodów + trk->fVelocity = 20.0; // zawracanie powoli + trk->fRadius = 20.0; // promień, aby się dodawało do tabelki prędkości i liczyło narastająco + trk->Init(); // utworzenie segmentu + tmp2 = new TGroundNode(TP_TRACK); // drugi odcinek do zapętlenia + TTrack *trk2 = tmp2->pTrack; + trk2->iCategoryFlag = + (iCategoryFlag & 15) | 0x80; // taki sam typ plus informacja, że dodatkowy + trk2->bVisible = false; + trk2->fVelocity = 20.0; // zawracanie powoli + trk2->fRadius = 20.0; // promień, aby się dodawało do tabelki prędkości i liczyło + // narastająco + trk2->Init(); // utworzenie segmentu + switch (dir) + { //łączenie z nowym torem + case 0: + p1 = Segment->FastGetPoint_0(); + cv1 = -20.0 * Normalize(Segment->GetDirection1()); // pierwszy wektor kontrolny + p2 = p1 + cv1 + cv1; // 40m + trk->Segment->Init(p1, p1 + cv1, p2 + vector3(-cv1.z, cv1.y, cv1.x), p2, 2, + -RadToDeg(r1), + 0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce + ConnectPrevPrev(trk, 0); + trk2->Segment->Init(p1, p1 + cv1, p2 + vector3(cv1.z, cv1.y, -cv1.x), p2, 2, + -RadToDeg(r1), + 0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce + trk2->iPrevDirection = 0; // zwrotnie do tego samego odcinka + break; + case 1: + p1 = Segment->FastGetPoint_1(); + cv1 = -20.0 * Normalize(Segment->GetDirection2()); // pierwszy wektor kontrolny + p2 = p1 + cv1 + cv1; + trk->Segment->Init(p1, p1 + cv1, p2 + vector3(-cv1.z, cv1.y, cv1.x), p2, 2, + RadToDeg(r2), + 0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce + ConnectNextPrev(trk, 0); + trk2->Segment->Init(p1, p1 + cv1, p2 + vector3(cv1.z, cv1.y, -cv1.x), p2, 2, + RadToDeg(r2), + 0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce + trk2->iPrevDirection = 1; // zwrotnie do tego samego odcinka + break; + } + trk2->trPrev = this; + trk->ConnectNextNext(trk2, 1); // połączenie dwóch dodatkowych odcinków punktami 2 + tmp2->pCenter = (0.5 * (p1 + p2)); //środek, aby się mogło wyświetlić + } + // trzeba jeszcze dodać do odpowiedniego segmentu, aby się renderowały z niego pojazdy + tmp->pCenter = (0.5 * (p1 + p2)); //środek, aby się mogło wyświetlić + if (tmp2) + tmp2->pCenter = tmp->pCenter; // ten sam środek jest + // Ra: to poniżej to porażka, ale na razie się nie da inaczej + TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z); + r->NodeAdd(tmp); // dodanie toru do segmentu + if (tmp2) + r->NodeAdd(tmp2); // drugiego też + r->Sort(); //żeby wyświetlał tabor z dodanego toru + r->Release(); // usunięcie skompilowanych zasobów + return trk; }; -void __fastcall TTrack::ConnectPrevPrev(TTrack *pTrack,int typ) -{//łączenie torów - Point1 własny do Point1 cudzego - if (pTrack) - {//(pTrack) może być zwrotnicą, a (this) tylko zwykłym odcinkiem - trPrev=pTrack; - iPrevDirection=((pTrack->eType==tt_Switch)?0:(typ&2)); - pTrack->trPrev=this; - pTrack->iPrevDirection=0; - } +void __fastcall TTrack::ConnectPrevPrev(TTrack *pTrack, int typ) +{ //łączenie torów - Point1 własny do Point1 cudzego + if (pTrack) + { //(pTrack) może być zwrotnicą, a (this) tylko zwykłym odcinkiem + trPrev = pTrack; + iPrevDirection = ((pTrack->eType == tt_Switch) ? 0 : (typ & 2)); + pTrack->trPrev = this; + pTrack->iPrevDirection = 0; + } } -void __fastcall TTrack::ConnectPrevNext(TTrack *pTrack,int typ) -{//łaczenie torów - Point1 własny do Point2 cudzego - if (pTrack) - { - trPrev=pTrack; - iPrevDirection=typ|1; //1:zwykły lub pierwszy zwrotnicy, 3:drugi zwrotnicy - pTrack->trNext=this; - pTrack->iNextDirection=0; - if (bVisible) - if (pTrack->bVisible) - if (eType==tt_Normal) //jeśli łączone są dwa normalne - if (pTrack->eType==tt_Normal) - if ((fTrackWidth!=pTrack->fTrackWidth) //Ra: jeśli kolejny ma inne wymiary - || (fTexHeight1!=pTrack->fTexHeight1) - || (fTexWidth!=pTrack->fTexWidth) - || (fTexSlope!=pTrack->fTexSlope)) - pTrack->iTrapezoid|=2; //to rysujemy potworka - } +void __fastcall TTrack::ConnectPrevNext(TTrack *pTrack, int typ) +{ //łaczenie torów - Point1 własny do Point2 cudzego + if (pTrack) + { + trPrev = pTrack; + iPrevDirection = typ | 1; // 1:zwykły lub pierwszy zwrotnicy, 3:drugi zwrotnicy + pTrack->trNext = this; + pTrack->iNextDirection = 0; + if (bVisible) + if (pTrack->bVisible) + if (eType == tt_Normal) // jeśli łączone są dwa normalne + if (pTrack->eType == tt_Normal) + if ((fTrackWidth != + pTrack->fTrackWidth) // Ra: jeśli kolejny ma inne wymiary + || + (fTexHeight1 != pTrack->fTexHeight1) || + (fTexWidth != pTrack->fTexWidth) || (fTexSlope != pTrack->fTexSlope)) + pTrack->iTrapezoid |= 2; // to rysujemy potworka + } } -void __fastcall TTrack::ConnectNextPrev(TTrack *pTrack,int typ) -{//łaczenie torów - Point2 własny do Point1 cudzego - if (pTrack) - { - trNext=pTrack; - iNextDirection=((pTrack->eType==tt_Switch)?0:(typ&2)); - pTrack->trPrev=this; - pTrack->iPrevDirection=1; - if (bVisible) - if (pTrack->bVisible) - if (eType==tt_Normal) //jeśli łączone są dwa normalne - if (pTrack->eType==tt_Normal) - if ((fTrackWidth!=pTrack->fTrackWidth) //Ra: jeśli kolejny ma inne wymiary - || (fTexHeight1!=pTrack->fTexHeight1) - || (fTexWidth!=pTrack->fTexWidth) - || (fTexSlope!=pTrack->fTexSlope)) - iTrapezoid|=2; //to rysujemy potworka - } +void __fastcall TTrack::ConnectNextPrev(TTrack *pTrack, int typ) +{ //łaczenie torów - Point2 własny do Point1 cudzego + if (pTrack) + { + trNext = pTrack; + iNextDirection = ((pTrack->eType == tt_Switch) ? 0 : (typ & 2)); + pTrack->trPrev = this; + pTrack->iPrevDirection = 1; + if (bVisible) + if (pTrack->bVisible) + if (eType == tt_Normal) // jeśli łączone są dwa normalne + if (pTrack->eType == tt_Normal) + if ((fTrackWidth != + pTrack->fTrackWidth) // Ra: jeśli kolejny ma inne wymiary + || + (fTexHeight1 != pTrack->fTexHeight1) || + (fTexWidth != pTrack->fTexWidth) || (fTexSlope != pTrack->fTexSlope)) + iTrapezoid |= 2; // to rysujemy potworka + } } -void __fastcall TTrack::ConnectNextNext(TTrack *pTrack,int typ) -{//łaczenie torów - Point2 własny do Point2 cudzego - if (pTrack) - { - trNext=pTrack; - iNextDirection=typ|1; //1:zwykły lub pierwszy zwrotnicy, 3:drugi zwrotnicy - pTrack->trNext=this; - pTrack->iNextDirection=1; - } +void __fastcall TTrack::ConnectNextNext(TTrack *pTrack, int typ) +{ //łaczenie torów - Point2 własny do Point2 cudzego + if (pTrack) + { + trNext = pTrack; + iNextDirection = typ | 1; // 1:zwykły lub pierwszy zwrotnicy, 3:drugi zwrotnicy + pTrack->trNext = this; + pTrack->iNextDirection = 1; + } } -vector3 __fastcall MakeCPoint(vector3 p,double d,double a1,double a2) +vector3 __fastcall MakeCPoint(vector3 p, double d, double a1, double a2) { - vector3 cp=vector3(0,0,1); - cp.RotateX(DegToRad(a2)); - cp.RotateY(DegToRad(a1)); - cp=cp*d+p; - return cp; + vector3 cp = vector3(0, 0, 1); + cp.RotateX(DegToRad(a2)); + cp.RotateY(DegToRad(a1)); + cp = cp * d + p; + return cp; } vector3 __fastcall LoadPoint(cParser *parser) -{//pobranie współrzędnych punktu - vector3 p; - std::string token; - parser->getTokens(3); - *parser >> p.x >> p.y >> p.z; - return p; +{ // pobranie współrzędnych punktu + vector3 p; + std::string token; + parser->getTokens(3); + *parser >> p.x >> p.y >> p.z; + return p; } -void __fastcall TTrack::Load(cParser *parser,vector3 pOrigin,AnsiString name) -{//pobranie obiektu trajektorii ruchu - vector3 pt,vec,p1,p2,cp1,cp2,p3,p4,cp3,cp4; //dodatkowe punkty potrzebne do skrzyżowań - double a1,a2,r1,r2,r3,r4,d1,d2,a; - AnsiString str; - bool bCurve; - int i;//,state; //Ra: teraz już nie ma początkowego stanu zwrotnicy we wpisie - std::string token; +void __fastcall TTrack::Load(cParser *parser, vector3 pOrigin, AnsiString name) +{ // pobranie obiektu trajektorii ruchu + vector3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań + double a1, a2, r1, r2, r3, r4, d1, d2, a; + AnsiString str; + bool bCurve; + int i; //,state; //Ra: teraz już nie ma początkowego stanu zwrotnicy we wpisie + std::string token; - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); //typ toru + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); // typ toru - if (str=="normal") - { - eType=tt_Normal; - iCategoryFlag=1; - } - else if (str=="switch") - { - eType=tt_Switch; - iCategoryFlag=1; - } - else if (str=="turn") - {//Ra: to jest obrotnica - eType=tt_Table; - iCategoryFlag=1; - } - else if (str=="table") - {//Ra: obrotnica, przesuwnica albo wywrotnica - eType=tt_Table; - iCategoryFlag=1; - } - else if (str=="road") - { - eType=tt_Normal; - iCategoryFlag=2; - } - else if (str=="cross") - {//Ra: to będzie skrzyżowanie dróg - eType=tt_Cross; - iCategoryFlag=2; - } - else if (str=="river") - {eType=tt_Normal; - iCategoryFlag=4; - } - else if (str=="tributary") - {eType=tt_Tributary; - iCategoryFlag=4; - } - else - eType=tt_Unknown; - if (Global::iWriteLogEnabled&4) - WriteLog(str.c_str()); - parser->getTokens(4); - *parser >> fTrackLength >> fTrackWidth >> fFriction >> fSoundDistance; -// fTrackLength=Parser->GetNextSymbol().ToDouble(); //track length 100502 -// fTrackWidth=Parser->GetNextSymbol().ToDouble(); //track width -// fFriction=Parser->GetNextSymbol().ToDouble(); //friction coeff. -// fSoundDistance=Parser->GetNextSymbol().ToDouble(); //snd - fTrackWidth2=fTrackWidth; //rozstaw/szerokość w punkcie 2, na razie taka sama - parser->getTokens(2); - *parser >> iQualityFlag >> iDamageFlag; -// iQualityFlag=Parser->GetNextSymbol().ToInt(); //McZapkie: qualityflag -// iDamageFlag=Parser->GetNextSymbol().ToInt(); //damage - if (iDamageFlag&128) - iAction|=0x80; //flaga wykolejania z powodu uszkodzenia - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); //environment - if (str=="flat") - eEnvironment=e_flat; - else if (str=="mountains" || str=="mountain") - eEnvironment=e_mountains; - else if (str=="canyon") - eEnvironment=e_canyon; - else if (str=="tunnel") - eEnvironment=e_tunnel; - else if (str=="bridge") - eEnvironment=e_bridge; - else if (str=="bank") - eEnvironment=e_bank; - else - { - eEnvironment=e_unknown; - Error("Unknown track environment: \""+str+"\""); - } - parser->getTokens(); - *parser >> token; - bVisible=(token.compare( "vis" )==0); //visible - if (bVisible) - { - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); //railtex - TextureID1=(str=="none"?0:TTexturesManager::GetTextureID(szTexturePath,szSceneryPath,str.c_str(),(iCategoryFlag&1)?Global::iRailProFiltering:Global::iBallastFiltering)); - parser->getTokens(); - *parser >> fTexLength; //tex tile length - if (fTexLength<0.01) fTexLength=4; //Ra: zabezpiecznie przed zawieszeniem - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); //sub || railtex - TextureID2=(str=="none"?0:TTexturesManager::GetTextureID(szTexturePath,szSceneryPath,str.c_str(),(eType==tt_Normal)?Global::iBallastFiltering:Global::iRailProFiltering)); - parser->getTokens(3); - *parser >> fTexHeight1 >> fTexWidth >> fTexSlope; -// fTexHeight=Parser->GetNextSymbol().ToDouble(); //tex sub height -// fTexWidth=Parser->GetNextSymbol().ToDouble(); //tex sub width -// fTexSlope=Parser->GetNextSymbol().ToDouble(); //tex sub slope width - if (iCategoryFlag&4) - fTexHeight1=-fTexHeight1; //rzeki mają wysokość odwrotnie niż drogi - } - else - if (Global::iWriteLogEnabled&4) WriteLog("unvis"); - Init(); //ustawia SwitchExtension - double segsize=5.0; //długość odcinka segmentowania - switch (eType) - {//Ra: łuki segmentowane co 5m albo 314-kątem foremnym - case tt_Table: //obrotnica jest prawie jak zwykły tor - iAction|=2; //flaga zmiany położenia typu obrotnica - case tt_Normal: - p1=LoadPoint(parser)+pOrigin; //pobranie współrzędnych P1 - parser->getTokens(); - *parser >> r1; //pobranie przechyłki w P1 - cp1=LoadPoint(parser); //pobranie współrzędnych punktów kontrolnych - cp2=LoadPoint(parser); - p2=LoadPoint(parser)+pOrigin; //pobranie współrzędnych P2 - parser->getTokens(2); - *parser >> r2 >> fRadius; //pobranie przechyłki w P1 i promienia - fRadius=fabs(fRadius); //we wpisie może być ujemny - if (iCategoryFlag&1) - {//zero na główce szyny - p1.y+=0.18; - p2.y+=0.18; - //na przechyłce doliczyć jeszcze pół przechyłki - } - if (fRadius!=0) //gdy podany promień - segsize=Min0R(5.0,0.2+fabs(fRadius)*0.02); //do 250m - 5, potem 1 co 50m - - if ((((p1+p1+p2)/3.0-p1-cp1).Length()<0.02)||(((p1+p2+p2)/3.0-p2+cp1).Length()<0.02)) - cp1=cp2=vector3(0,0,0); //"prostowanie" prostych z kontrolnymi, dokładność 2cm - - if ((cp1==vector3(0,0,0)) && (cp2==vector3(0,0,0))) //Ra: hm, czasem dla prostego są podane... - Segment->Init(p1,p2,segsize,r1,r2); //gdy prosty, kontrolne wyliczane przy zmiennej przechyłce - else - Segment->Init(p1,cp1+p1,cp2+p2,p2,segsize,r1,r2); //gdy łuk (ustawia bCurve=true) - if ((r1!=0)||(r2!=0)) iTrapezoid=1; //są przechyłki do uwzględniania w rysowaniu - if (eType==tt_Table) //obrotnica ma doklejkę - {//SwitchExtension=new TSwitchExtension(this,1); //dodatkowe zmienne dla obrotnicy - SwitchExtension->Segments[0]->Init(p1,p2,segsize); //kopia oryginalnego toru - } - else if (iCategoryFlag&2) - if (TextureID1&&fTexLength) - {//dla drogi trzeba ustalić proporcje boków nawierzchni - float w,h; - glBindTexture(GL_TEXTURE_2D,TextureID1); - glGetTexLevelParameterfv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&w); - glGetTexLevelParameterfv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&h); - if (h!=0.0) fTexRatio1=w/h; //proporcja boków - glBindTexture(GL_TEXTURE_2D,TextureID2); - glGetTexLevelParameterfv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&w); - glGetTexLevelParameterfv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&h); - if (h!=0.0) fTexRatio2=w/h; //proporcja boków + if (str == "normal") + { + eType = tt_Normal; + iCategoryFlag = 1; + } + else if (str == "switch") + { + eType = tt_Switch; + iCategoryFlag = 1; + } + else if (str == "turn") + { // Ra: to jest obrotnica + eType = tt_Table; + iCategoryFlag = 1; + } + else if (str == "table") + { // Ra: obrotnica, przesuwnica albo wywrotnica + eType = tt_Table; + iCategoryFlag = 1; + } + else if (str == "road") + { + eType = tt_Normal; + iCategoryFlag = 2; + } + else if (str == "cross") + { // Ra: to będzie skrzyżowanie dróg + eType = tt_Cross; + iCategoryFlag = 2; + } + else if (str == "river") + { + eType = tt_Normal; + iCategoryFlag = 4; + } + else if (str == "tributary") + { + eType = tt_Tributary; + iCategoryFlag = 4; } - break; - - case tt_Cross: //skrzyżowanie dróg - 4 punkty z wektorami kontrolnymi - segsize=1.0; //specjalne segmentowanie ze względu na małe promienie - case tt_Tributary: //dopływ - case tt_Switch: //zwrotnica - iAction|=1; //flaga zmiany położenia typu zwrotnica lub skrzyżowanie dróg - //problemy z animacją iglic powstaje, gdzy odcinek prosty ma zmienną przechyłkę - //wtedy dzieli się na dodatkowe odcinki (po 0.2m, bo R=0) i animację diabli biorą - //Ra: na razie nie podejmuję się przerabiania iglic - - //SwitchExtension=new TSwitchExtension(this,eType==tt_Cross?6:2); //zwrotnica ma doklejkę - - p1=LoadPoint(parser)+pOrigin; //pobranie współrzędnych P1 - parser->getTokens(); - *parser >> r1; - cp1=LoadPoint(parser); - cp2=LoadPoint(parser); - p2=LoadPoint(parser)+pOrigin; //pobranie współrzędnych P2 - parser->getTokens(2); - *parser >> r2 >> fRadiusTable[0]; - fRadiusTable[0]=fabs(fRadiusTable[0]); //we wpisie może być ujemny - if (iCategoryFlag&1) - {//zero na główce szyny - p1.y+=0.18; - p2.y+=0.18; - //na przechyłce doliczyć jeszcze pół przechyłki? - } - if (fRadiusTable[0]>0) - segsize=Min0R(5.0,0.2+fRadiusTable[0]*0.02); - else - if (eType!=tt_Cross) //dla skrzyżowań muszą być podane kontrolne - {//jak promień zerowy, to przeliczamy punkty kontrolne - cp1=(p1+p1+p2)/3.0-p1; //jak jest prosty, to się zoptymalizuje - cp2=(p1+p2+p2)/3.0-p2; - segsize=5.0; - } //ułomny prosty - if (!(cp1==vector3(0,0,0)) && !(cp2==vector3(0,0,0))) - SwitchExtension->Segments[0]->Init(p1,p1+cp1,p2+cp2,p2,segsize,r1,r2); - else - SwitchExtension->Segments[0]->Init(p1,p2,segsize,r1,r2); - - p3=LoadPoint(parser)+pOrigin; //pobranie współrzędnych P3 - parser->getTokens(); - *parser >> r3; - cp3=LoadPoint(parser); - cp4=LoadPoint(parser); - p4=LoadPoint(parser)+pOrigin; //pobranie współrzędnych P4 - parser->getTokens(2); - *parser >> r4 >> fRadiusTable[1]; - fRadiusTable[1]=fabs(fRadiusTable[1]); //we wpisie może być ujemny - if (iCategoryFlag&1) - {//zero na główce szyny - p3.y+=0.18; - p4.y+=0.18; - //na przechyłce doliczyć jeszcze pół przechyłki? - } - - if (fRadiusTable[1]>0) - segsize=Min0R(5.0,0.2+fRadiusTable[1]*0.02); - else - if (eType!=tt_Cross) //dla skrzyżowań muszą być podane kontrolne - {//jak promień zerowy, to przeliczamy punkty kontrolne - cp3=(p3+p3+p4)/3.0-p3; //jak jest prosty, to się zoptymalizuje - cp4=(p3+p4+p4)/3.0-p4; - segsize=5.0; - } //ułomny prosty - - if (!(cp3==vector3(0,0,0)) && !(cp4==vector3(0,0,0))) - {//dla skrzyżowania dróg dać odwrotnie końce, żeby brzegi generować lewym - if (eType!=tt_Cross) - SwitchExtension->Segments[1]->Init(p3,p3+cp3,p4+cp4,p4,segsize,r3,r4); else - SwitchExtension->Segments[1]->Init(p4,p4+cp4,p3+cp3,p3,segsize,r4,r3); //odwrócony - } - else - SwitchExtension->Segments[1]->Init(p3,p4,segsize,r3,r4); - if (eType==tt_Cross) - {//Ra 2014-07: dla skrzyżowań będą dodatkowe segmenty - SwitchExtension->Segments[2]->Init(p2,cp2+p2,cp4+p4,p4,segsize,r2,r4); //z punktu 2 do 4 - if (LengthSquared3(p3-p1)<0.01) //gdy mniej niż 10cm, to mamy skrzyżowanie trzech dróg - SwitchExtension->iRoads=3; - else //dla 4 dróg będą dodatkowe 3 segmenty - {SwitchExtension->Segments[3]->Init(p4,p4+cp4,p1+cp1,p1,segsize,r4,r1); //z punktu 4 do 1 - SwitchExtension->Segments[4]->Init(p1,p1+cp1,p3+cp3,p3,segsize,r1,r3); //z punktu 1 do 3 - SwitchExtension->Segments[5]->Init(p3,p3+cp3,p2+cp2,p2,segsize,r3,r2); //z punktu 3 do 2 + eType = tt_Unknown; + if (Global::iWriteLogEnabled & 4) + WriteLog(str.c_str()); + parser->getTokens(4); + *parser >> fTrackLength >> fTrackWidth >> fFriction >> fSoundDistance; + // fTrackLength=Parser->GetNextSymbol().ToDouble(); //track length + // 100502 + // fTrackWidth=Parser->GetNextSymbol().ToDouble(); //track width + // fFriction=Parser->GetNextSymbol().ToDouble(); //friction coeff. + // fSoundDistance=Parser->GetNextSymbol().ToDouble(); //snd + fTrackWidth2 = fTrackWidth; // rozstaw/szerokość w punkcie 2, na razie taka sama + parser->getTokens(2); + *parser >> iQualityFlag >> iDamageFlag; + // iQualityFlag=Parser->GetNextSymbol().ToInt(); //McZapkie: qualityflag + // iDamageFlag=Parser->GetNextSymbol().ToInt(); //damage + if (iDamageFlag & 128) + iAction |= 0x80; // flaga wykolejania z powodu uszkodzenia + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); // environment + if (str == "flat") + eEnvironment = e_flat; + else if (str == "mountains" || str == "mountain") + eEnvironment = e_mountains; + else if (str == "canyon") + eEnvironment = e_canyon; + else if (str == "tunnel") + eEnvironment = e_tunnel; + else if (str == "bridge") + eEnvironment = e_bridge; + else if (str == "bank") + eEnvironment = e_bank; + else + { + eEnvironment = e_unknown; + Error("Unknown track environment: \"" + str + "\""); } - } + parser->getTokens(); + *parser >> token; + bVisible = (token.compare("vis") == 0); // visible + if (bVisible) + { + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); // railtex + TextureID1 = (str == "none" ? 0 : TTexturesManager::GetTextureID( + szTexturePath, szSceneryPath, str.c_str(), + (iCategoryFlag & 1) ? Global::iRailProFiltering : + Global::iBallastFiltering)); + parser->getTokens(); + *parser >> fTexLength; // tex tile length + if (fTexLength < 0.01) + fTexLength = 4; // Ra: zabezpiecznie przed zawieszeniem + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); // sub || railtex + TextureID2 = (str == "none" ? 0 : TTexturesManager::GetTextureID( + szTexturePath, szSceneryPath, str.c_str(), + (eType == tt_Normal) ? Global::iBallastFiltering : + Global::iRailProFiltering)); + parser->getTokens(3); + *parser >> fTexHeight1 >> fTexWidth >> fTexSlope; + // fTexHeight=Parser->GetNextSymbol().ToDouble(); //tex sub height + // fTexWidth=Parser->GetNextSymbol().ToDouble(); //tex sub width + // fTexSlope=Parser->GetNextSymbol().ToDouble(); //tex sub slope width + if (iCategoryFlag & 4) + fTexHeight1 = -fTexHeight1; // rzeki mają wysokość odwrotnie niż drogi + } + else if (Global::iWriteLogEnabled & 4) + WriteLog("unvis"); + Init(); // ustawia SwitchExtension + double segsize = 5.0; // długość odcinka segmentowania + switch (eType) + { // Ra: łuki segmentowane co 5m albo 314-kątem foremnym + case tt_Table: // obrotnica jest prawie jak zwykły tor + iAction |= 2; // flaga zmiany położenia typu obrotnica + case tt_Normal: + p1 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P1 + parser->getTokens(); + *parser >> r1; // pobranie przechyłki w P1 + cp1 = LoadPoint(parser); // pobranie współrzędnych punktów kontrolnych + cp2 = LoadPoint(parser); + p2 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P2 + parser->getTokens(2); + *parser >> r2 >> fRadius; // pobranie przechyłki w P1 i promienia + fRadius = fabs(fRadius); // we wpisie może być ujemny + if (iCategoryFlag & 1) + { // zero na główce szyny + p1.y += 0.18; + p2.y += 0.18; + // na przechyłce doliczyć jeszcze pół przechyłki + } + if (fRadius != 0) // gdy podany promień + segsize = Min0R(5.0, 0.2 + fabs(fRadius) * 0.02); // do 250m - 5, potem 1 co 50m - Switch(0); //na stałe w położeniu 0 - nie ma początkowego stanu zwrotnicy we wpisie + if ((((p1 + p1 + p2) / 3.0 - p1 - cp1).Length() < 0.02) || + (((p1 + p2 + p2) / 3.0 - p2 + cp1).Length() < 0.02)) + cp1 = cp2 = vector3(0, 0, 0); //"prostowanie" prostych z kontrolnymi, dokładność 2cm - //Ra: zamienić później na iloczyn wektorowy - {vector3 v1,v2; - double a1,a2; - v1=SwitchExtension->Segments[0]->FastGetPoint_1()-SwitchExtension->Segments[0]->FastGetPoint_0(); - v2=SwitchExtension->Segments[1]->FastGetPoint_1()-SwitchExtension->Segments[1]->FastGetPoint_0(); - a1=atan2(v1.x,v1.z); - a2=atan2(v2.x,v2.z); - a2=a2-a1; - while (a2>M_PI) a2=a2-2*M_PI; - while (a2<-M_PI) a2=a2+2*M_PI; - SwitchExtension->RightSwitch=a2<0; //lustrzany układ OXY... - } - break; - } - parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - while (str!="endtrack") - { - if (str=="event0") - { - parser->getTokens(); - *parser >> token; - asEvent0Name=AnsiString(token.c_str()); - } - else if (str=="event1") - { - parser->getTokens(); - *parser >> token; - asEvent1Name=AnsiString(token.c_str()); - } - else if (str=="event2") - { - parser->getTokens(); - *parser >> token; - asEvent2Name=AnsiString(token.c_str()); - } - else if (str=="eventall0") - { - parser->getTokens(); - *parser >> token; - asEventall0Name=AnsiString(token.c_str()); - } - else if (str=="eventall1") - { - parser->getTokens(); - *parser >> token; - asEventall1Name=AnsiString(token.c_str()); - } - else if (str=="eventall2") - { - parser->getTokens(); - *parser >> token; - asEventall2Name=AnsiString(token.c_str()); - } - else if (str=="velocity") - { - parser->getTokens(); - *parser >> fVelocity; //*0.28; McZapkie-010602 - if (SwitchExtension) //jeśli tor ruchomy - if (fabs(fVelocity)>=1.0) //żeby zero nie ograniczało dożywotnio - SwitchExtension->fVelocity=fVelocity; //zapamiętanie głównego ograniczenia; a np. -40 ogranicza tylko na bok - } - else if (str=="isolated") - {//obwód izolowany, do którego tor należy - parser->getTokens(); - *parser >> token; - pIsolated=TIsolated::Find(AnsiString(token.c_str())); - } - else if (str=="angle1") - {//kąt ścięcia końca od strony 1 - parser->getTokens(); - *parser >> a1; - Segment->AngleSet(0,a1); - } - else if (str=="angle2") - {//kąt ścięcia końca od strony 2 - parser->getTokens(); - *parser >> a2; - Segment->AngleSet(1,a2); - } - else if (str=="fouling1") - {//wskazanie modelu ukresu w kierunku 1 - parser->getTokens(); - *parser >> token; - //nFouling[0]= - } - else if (str=="fouling2") - {//wskazanie modelu ukresu w kierunku 2 - parser->getTokens(); - *parser >> token; - //nFouling[1]= - } - else if (str=="overhead") - {//informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem prędkości - parser->getTokens(); - *parser >> fOverhead; - if (fOverhead>0.0) - iAction|=0x40; //flaga opuszczenia pantografu (tor uwzględniany w skanowaniu jako ograniczenie dla pantografujących) - } - else if (str=="colides") - {//informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem prędkości - parser->getTokens(); - *parser >> token; - //trColides=; //tor kolizyjny, na którym trzeba sprawdzać pojazdy pod kątem zderzenia - } - else - ErrorLog("Unknown property: \""+str+"\" in track \""+name+"\""); - parser->getTokens(); *parser >> token; - str=AnsiString(token.c_str()); - } - //alternatywny zapis nazwy odcinka izolowanego - po znaku "@" w nazwie toru - if (!pIsolated) - if ((i=name.Pos("@"))>0) - if (iInit(p1, p2, segsize, r1, + r2); // gdy prosty, kontrolne wyliczane przy zmiennej przechyłce + else + Segment->Init(p1, cp1 + p1, cp2 + p2, p2, segsize, r1, + r2); // gdy łuk (ustawia bCurve=true) + if ((r1 != 0) || (r2 != 0)) + iTrapezoid = 1; // są przechyłki do uwzględniania w rysowaniu + if (eType == tt_Table) // obrotnica ma doklejkę + { // SwitchExtension=new TSwitchExtension(this,1); //dodatkowe zmienne dla obrotnicy + SwitchExtension->Segments[0]->Init(p1, p2, segsize); // kopia oryginalnego toru + } + else if (iCategoryFlag & 2) + if (TextureID1 && fTexLength) + { // dla drogi trzeba ustalić proporcje boków nawierzchni + float w, h; + glBindTexture(GL_TEXTURE_2D, TextureID1); + glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); + glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); + if (h != 0.0) + fTexRatio1 = w / h; // proporcja boków + glBindTexture(GL_TEXTURE_2D, TextureID2); + glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); + glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); + if (h != 0.0) + fTexRatio2 = w / h; // proporcja boków + } + break; + + case tt_Cross: // skrzyżowanie dróg - 4 punkty z wektorami kontrolnymi + segsize = 1.0; // specjalne segmentowanie ze względu na małe promienie + case tt_Tributary: // dopływ + case tt_Switch: // zwrotnica + iAction |= 1; // flaga zmiany położenia typu zwrotnica lub skrzyżowanie dróg + // problemy z animacją iglic powstaje, gdzy odcinek prosty ma zmienną przechyłkę + // wtedy dzieli się na dodatkowe odcinki (po 0.2m, bo R=0) i animację diabli biorą + // Ra: na razie nie podejmuję się przerabiania iglic + + // SwitchExtension=new TSwitchExtension(this,eType==tt_Cross?6:2); //zwrotnica ma doklejkę + + p1 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P1 + parser->getTokens(); + *parser >> r1; + cp1 = LoadPoint(parser); + cp2 = LoadPoint(parser); + p2 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P2 + parser->getTokens(2); + *parser >> r2 >> fRadiusTable[0]; + fRadiusTable[0] = fabs(fRadiusTable[0]); // we wpisie może być ujemny + if (iCategoryFlag & 1) + { // zero na główce szyny + p1.y += 0.18; + p2.y += 0.18; + // na przechyłce doliczyć jeszcze pół przechyłki? + } + if (fRadiusTable[0] > 0) + segsize = Min0R(5.0, 0.2 + fRadiusTable[0] * 0.02); + else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne + { // jak promień zerowy, to przeliczamy punkty kontrolne + cp1 = (p1 + p1 + p2) / 3.0 - p1; // jak jest prosty, to się zoptymalizuje + cp2 = (p1 + p2 + p2) / 3.0 - p2; + segsize = 5.0; + } // ułomny prosty + if (!(cp1 == vector3(0, 0, 0)) && !(cp2 == vector3(0, 0, 0))) + SwitchExtension->Segments[0]->Init(p1, p1 + cp1, p2 + cp2, p2, segsize, r1, r2); + else + SwitchExtension->Segments[0]->Init(p1, p2, segsize, r1, r2); + + p3 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P3 + parser->getTokens(); + *parser >> r3; + cp3 = LoadPoint(parser); + cp4 = LoadPoint(parser); + p4 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P4 + parser->getTokens(2); + *parser >> r4 >> fRadiusTable[1]; + fRadiusTable[1] = fabs(fRadiusTable[1]); // we wpisie może być ujemny + if (iCategoryFlag & 1) + { // zero na główce szyny + p3.y += 0.18; + p4.y += 0.18; + // na przechyłce doliczyć jeszcze pół przechyłki? + } + + if (fRadiusTable[1] > 0) + segsize = Min0R(5.0, 0.2 + fRadiusTable[1] * 0.02); + else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne + { // jak promień zerowy, to przeliczamy punkty kontrolne + cp3 = (p3 + p3 + p4) / 3.0 - p3; // jak jest prosty, to się zoptymalizuje + cp4 = (p3 + p4 + p4) / 3.0 - p4; + segsize = 5.0; + } // ułomny prosty + + if (!(cp3 == vector3(0, 0, 0)) && !(cp4 == vector3(0, 0, 0))) + { // dla skrzyżowania dróg dać odwrotnie końce, żeby brzegi generować lewym + if (eType != tt_Cross) + SwitchExtension->Segments[1]->Init(p3, p3 + cp3, p4 + cp4, p4, segsize, r3, r4); + else + SwitchExtension->Segments[1]->Init(p4, p4 + cp4, p3 + cp3, p3, segsize, r4, + r3); // odwrócony + } + else + SwitchExtension->Segments[1]->Init(p3, p4, segsize, r3, r4); + if (eType == tt_Cross) + { // Ra 2014-07: dla skrzyżowań będą dodatkowe segmenty + SwitchExtension->Segments[2]->Init(p2, cp2 + p2, cp4 + p4, p4, segsize, r2, + r4); // z punktu 2 do 4 + if (LengthSquared3(p3 - p1) < + 0.01) // gdy mniej niż 10cm, to mamy skrzyżowanie trzech dróg + SwitchExtension->iRoads = 3; + else // dla 4 dróg będą dodatkowe 3 segmenty + { + SwitchExtension->Segments[3]->Init(p4, p4 + cp4, p1 + cp1, p1, segsize, r4, + r1); // z punktu 4 do 1 + SwitchExtension->Segments[4]->Init(p1, p1 + cp1, p3 + cp3, p3, segsize, r1, + r3); // z punktu 1 do 3 + SwitchExtension->Segments[5]->Init(p3, p3 + cp3, p2 + cp2, p2, segsize, r3, + r2); // z punktu 3 do 2 + } + } + + Switch(0); // na stałe w położeniu 0 - nie ma początkowego stanu zwrotnicy we wpisie + + // Ra: zamienić później na iloczyn wektorowy + { + vector3 v1, v2; + double a1, a2; + v1 = SwitchExtension->Segments[0]->FastGetPoint_1() - + SwitchExtension->Segments[0]->FastGetPoint_0(); + v2 = SwitchExtension->Segments[1]->FastGetPoint_1() - + SwitchExtension->Segments[1]->FastGetPoint_0(); + a1 = atan2(v1.x, v1.z); + a2 = atan2(v2.x, v2.z); + a2 = a2 - a1; + while (a2 > M_PI) + a2 = a2 - 2 * M_PI; + while (a2 < -M_PI) + a2 = a2 + 2 * M_PI; + SwitchExtension->RightSwitch = a2 < 0; // lustrzany układ OXY... + } + break; + } + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + while (str != "endtrack") + { + if (str == "event0") + { + parser->getTokens(); + *parser >> token; + asEvent0Name = AnsiString(token.c_str()); + } + else if (str == "event1") + { + parser->getTokens(); + *parser >> token; + asEvent1Name = AnsiString(token.c_str()); + } + else if (str == "event2") + { + parser->getTokens(); + *parser >> token; + asEvent2Name = AnsiString(token.c_str()); + } + else if (str == "eventall0") + { + parser->getTokens(); + *parser >> token; + asEventall0Name = AnsiString(token.c_str()); + } + else if (str == "eventall1") + { + parser->getTokens(); + *parser >> token; + asEventall1Name = AnsiString(token.c_str()); + } + else if (str == "eventall2") + { + parser->getTokens(); + *parser >> token; + asEventall2Name = AnsiString(token.c_str()); + } + else if (str == "velocity") + { + parser->getTokens(); + *parser >> fVelocity; //*0.28; McZapkie-010602 + if (SwitchExtension) // jeśli tor ruchomy + if (fabs(fVelocity) >= 1.0) //żeby zero nie ograniczało dożywotnio + SwitchExtension->fVelocity = fVelocity; // zapamiętanie głównego ograniczenia; a + // np. -40 ogranicza tylko na bok + } + else if (str == "isolated") + { // obwód izolowany, do którego tor należy + parser->getTokens(); + *parser >> token; + pIsolated = TIsolated::Find(AnsiString(token.c_str())); + } + else if (str == "angle1") + { // kąt ścięcia końca od strony 1 + parser->getTokens(); + *parser >> a1; + Segment->AngleSet(0, a1); + } + else if (str == "angle2") + { // kąt ścięcia końca od strony 2 + parser->getTokens(); + *parser >> a2; + Segment->AngleSet(1, a2); + } + else if (str == "fouling1") + { // wskazanie modelu ukresu w kierunku 1 + parser->getTokens(); + *parser >> token; + // nFouling[0]= + } + else if (str == "fouling2") + { // wskazanie modelu ukresu w kierunku 2 + parser->getTokens(); + *parser >> token; + // nFouling[1]= + } + else if (str == "overhead") + { // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem + // prędkości + parser->getTokens(); + *parser >> fOverhead; + if (fOverhead > 0.0) + iAction |= 0x40; // flaga opuszczenia pantografu (tor uwzględniany w skanowaniu jako + // ograniczenie dla pantografujących) + } + else if (str == "colides") + { // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem + // prędkości + parser->getTokens(); + *parser >> token; + // trColides=; //tor kolizyjny, na którym trzeba sprawdzać pojazdy pod kątem zderzenia + } + else + ErrorLog("Unknown property: \"" + str + "\" in track \"" + name + "\""); + parser->getTokens(); + *parser >> token; + str = AnsiString(token.c_str()); + } + // alternatywny zapis nazwy odcinka izolowanego - po znaku "@" w nazwie toru + if (!pIsolated) + if ((i = name.Pos("@")) > 0) + if (i < name.Length()) // nie może być puste + { + pIsolated = TIsolated::Find(name.SubString(i + 1, name.Length())); + name = name.SubString(1, i - 1); // usunięcie z nazwy + } } -bool __fastcall TTrack::AssignEvents(TEvent *NewEvent0,TEvent *NewEvent1,TEvent *NewEvent2) +bool __fastcall TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2) { - bool bError=false; - if (!evEvent0) - { - if (NewEvent0) - { - evEvent0=NewEvent0; - asEvent0Name=""; - iEvents|=1; //sumaryczna informacja o eventach - } - else - { - if (!asEvent0Name.IsEmpty()) - { - ErrorLog(AnsiString("Bad track: Event0 \"")+asEvent0Name+AnsiString("\" does not exist")); - bError=true; - } - } - } - else - { - ErrorLog(AnsiString("Bad track: Event0 cannot be assigned to track, track already has one")); - bError=true; - } - if (!evEvent1) - { - if (NewEvent1) - { - evEvent1=NewEvent1; - asEvent1Name=""; - iEvents|=2; //sumaryczna informacja o eventach - } - else if (!asEvent1Name.IsEmpty()) - {//Ra: tylko w logu informacja - ErrorLog(AnsiString("Bad track: Event1 \"")+asEvent1Name+AnsiString("\" does not exist").c_str()); - bError=true; - } - } - else - { - ErrorLog(AnsiString("Bad track: Event1 cannot be assigned to track, track already has one")); - bError=true; - } - if (!evEvent2) - { - if (NewEvent2) - { - evEvent2=NewEvent2; - asEvent2Name=""; - iEvents|=4; //sumaryczna informacja o eventach - } - else if (!asEvent2Name.IsEmpty()) - {//Ra: tylko w logu informacja - ErrorLog(AnsiString("Bad track: Event2 \"")+asEvent2Name+AnsiString("\" does not exist")); - bError=true; - } - } - else - { - ErrorLog(AnsiString("Bad track: Event2 cannot be assigned to track, track already has one")); - bError=true; - } - return !bError; + bool bError = false; + if (!evEvent0) + { + if (NewEvent0) + { + evEvent0 = NewEvent0; + asEvent0Name = ""; + iEvents |= 1; // sumaryczna informacja o eventach + } + else + { + if (!asEvent0Name.IsEmpty()) + { + ErrorLog(AnsiString("Bad track: Event0 \"") + asEvent0Name + + AnsiString("\" does not exist")); + bError = true; + } + } + } + else + { + ErrorLog( + AnsiString("Bad track: Event0 cannot be assigned to track, track already has one")); + bError = true; + } + if (!evEvent1) + { + if (NewEvent1) + { + evEvent1 = NewEvent1; + asEvent1Name = ""; + iEvents |= 2; // sumaryczna informacja o eventach + } + else if (!asEvent1Name.IsEmpty()) + { // Ra: tylko w logu informacja + ErrorLog(AnsiString("Bad track: Event1 \"") + asEvent1Name + + AnsiString("\" does not exist").c_str()); + bError = true; + } + } + else + { + ErrorLog( + AnsiString("Bad track: Event1 cannot be assigned to track, track already has one")); + bError = true; + } + if (!evEvent2) + { + if (NewEvent2) + { + evEvent2 = NewEvent2; + asEvent2Name = ""; + iEvents |= 4; // sumaryczna informacja o eventach + } + else if (!asEvent2Name.IsEmpty()) + { // Ra: tylko w logu informacja + ErrorLog(AnsiString("Bad track: Event2 \"") + asEvent2Name + + AnsiString("\" does not exist")); + bError = true; + } + } + else + { + ErrorLog( + AnsiString("Bad track: Event2 cannot be assigned to track, track already has one")); + bError = true; + } + return !bError; } -bool __fastcall TTrack::AssignallEvents(TEvent *NewEvent0,TEvent *NewEvent1,TEvent *NewEvent2) +bool __fastcall TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2) { - bool bError=false; - if (!evEventall0) - { - if (NewEvent0) - { - evEventall0=NewEvent0; - asEventall0Name=""; - iEvents|=8; //sumaryczna informacja o eventach - } - else - { - if (!asEvent0Name.IsEmpty()) - { - Error(AnsiString("Eventall0 \"")+asEventall0Name+AnsiString("\" does not exist")); - bError=true; - } - } - } - else - { - Error(AnsiString("Eventall0 cannot be assigned to track, track already has one")); - bError=true; - } - if (!evEventall1) - { - if (NewEvent1) - { - evEventall1=NewEvent1; - asEventall1Name=""; - iEvents|=16; //sumaryczna informacja o eventach - } - else - { - if (!asEvent0Name.IsEmpty()) - {//Ra: tylko w logu informacja - WriteLog(AnsiString("Eventall1 \"")+asEventall1Name+AnsiString("\" does not exist")); - bError=true; - } - } - } - else - { - Error(AnsiString("Eventall1 cannot be assigned to track, track already has one")); - bError=true; - } - if (!evEventall2) - { - if (NewEvent2) - { - evEventall2=NewEvent2; - asEventall2Name=""; - iEvents|=32; //sumaryczna informacja o eventach - } - else - { - if (!asEvent0Name.IsEmpty()) - {//Ra: tylko w logu informacja - WriteLog(AnsiString("Eventall2 \"")+asEventall2Name+AnsiString("\" does not exist")); - bError=true; - } - } - } - else - { - Error(AnsiString("Eventall2 cannot be assigned to track, track already has one")); - bError=true; - } - return !bError; + bool bError = false; + if (!evEventall0) + { + if (NewEvent0) + { + evEventall0 = NewEvent0; + asEventall0Name = ""; + iEvents |= 8; // sumaryczna informacja o eventach + } + else + { + if (!asEvent0Name.IsEmpty()) + { + Error(AnsiString("Eventall0 \"") + asEventall0Name + + AnsiString("\" does not exist")); + bError = true; + } + } + } + else + { + Error(AnsiString("Eventall0 cannot be assigned to track, track already has one")); + bError = true; + } + if (!evEventall1) + { + if (NewEvent1) + { + evEventall1 = NewEvent1; + asEventall1Name = ""; + iEvents |= 16; // sumaryczna informacja o eventach + } + else + { + if (!asEvent0Name.IsEmpty()) + { // Ra: tylko w logu informacja + WriteLog(AnsiString("Eventall1 \"") + asEventall1Name + + AnsiString("\" does not exist")); + bError = true; + } + } + } + else + { + Error(AnsiString("Eventall1 cannot be assigned to track, track already has one")); + bError = true; + } + if (!evEventall2) + { + if (NewEvent2) + { + evEventall2 = NewEvent2; + asEventall2Name = ""; + iEvents |= 32; // sumaryczna informacja o eventach + } + else + { + if (!asEvent0Name.IsEmpty()) + { // Ra: tylko w logu informacja + WriteLog(AnsiString("Eventall2 \"") + asEventall2Name + + AnsiString("\" does not exist")); + bError = true; + } + } + } + else + { + Error(AnsiString("Eventall2 cannot be assigned to track, track already has one")); + bError = true; + } + return !bError; } bool __fastcall TTrack::AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus) -{//ustawienie eventów sygnalizacji rozprucia - if (SwitchExtension) - {if (NewEventPlus) - SwitchExtension->evPlus=NewEventPlus; - if (NewEventMinus) - SwitchExtension->evMinus=NewEventMinus; - return true; - } - return false; +{ // ustawienie eventów sygnalizacji rozprucia + if (SwitchExtension) + { + if (NewEventPlus) + SwitchExtension->evPlus = NewEventPlus; + if (NewEventMinus) + SwitchExtension->evMinus = NewEventMinus; + return true; + } + return false; }; AnsiString __fastcall TTrack::IsolatedName() -{//podaje nazwę odcinka izolowanego, jesli nie ma on jeszcze przypisanych zdarzeń - if (pIsolated) - if (!pIsolated->evBusy&&!pIsolated->evFree) - return pIsolated->asName; - return ""; +{ // podaje nazwę odcinka izolowanego, jesli nie ma on jeszcze przypisanych zdarzeń + if (pIsolated) + if (!pIsolated->evBusy && !pIsolated->evFree) + return pIsolated->asName; + return ""; }; bool __fastcall TTrack::IsolatedEventsAssign(TEvent *busy, TEvent *free) -{//ustawia zdarzenia dla odcinka izolowanego - if (pIsolated) - {if (busy) - pIsolated->evBusy=busy; - if (free) - pIsolated->evFree=free; - return true; - } - return false; -}; - - -//ABu: przeniesione z Track.h i poprawione!!! -bool __fastcall TTrack::AddDynamicObject(TDynamicObject *Dynamic) -{//dodanie pojazdu do trajektorii - //Ra: tymczasowo wysyłanie informacji o zajętości konkretnego toru - //Ra: usunąć po upowszechnieniu się odcinków izolowanych - if (iCategoryFlag&0x100) //jeśli usuwaczek - {Dynamic->MyTrack=NULL; //trzeba by to uzależnić od kierunku ruchu... - return true; - } - if (Global::iMultiplayer) //jeśli multiplayer - if (!iNumDynamics) //pierwszy zajmujący - if (pMyNode->asName!="none") - Global::pGround->WyslijString(pMyNode->asName,8); //przekazanie informacji o zajętości toru - if (iNumDynamicsMyTrack=this; //ABu: na ktorym torze jesteśmy - if (Dynamic->iOverheadMask) //jeśli ma pantografy - Dynamic->OverheadTrack(fOverhead); //przekazanie informacji o jeździe bezprądowej na tym odcinku toru - return true; - } - else - { - Error("Too many dynamics on track "+pMyNode->asName); - return false; - } -}; - -void __fastcall TTrack::MoveMe(vector3 pPosition) -{//to nie jest używane - if (SwitchExtension) +{ // ustawia zdarzenia dla odcinka izolowanego + if (pIsolated) { - SwitchExtension->Segments[0]->MoveMe(1*pPosition); - SwitchExtension->Segments[1]->MoveMe(1*pPosition); - SwitchExtension->Segments[2]->MoveMe(3*pPosition); //Ra: 3 razy? - SwitchExtension->Segments[3]->MoveMe(4*pPosition); + if (busy) + pIsolated->evBusy = busy; + if (free) + pIsolated->evFree = free; + return true; + } + return false; +}; + +// ABu: przeniesione z Track.h i poprawione!!! +bool __fastcall TTrack::AddDynamicObject(TDynamicObject *Dynamic) +{ // dodanie pojazdu do trajektorii + // Ra: tymczasowo wysyłanie informacji o zajętości konkretnego toru + // Ra: usunąć po upowszechnieniu się odcinków izolowanych + if (iCategoryFlag & 0x100) // jeśli usuwaczek + { + Dynamic->MyTrack = NULL; // trzeba by to uzależnić od kierunku ruchu... + return true; + } + if (Global::iMultiplayer) // jeśli multiplayer + if (!iNumDynamics) // pierwszy zajmujący + if (pMyNode->asName != "none") + Global::pGround->WyslijString(pMyNode->asName, + 8); // przekazanie informacji o zajętości toru + if (iNumDynamics < iMaxNumDynamics) + { // jeśli jest miejsce, dajemy na koniec + Dynamics[iNumDynamics++] = Dynamic; + Dynamic->MyTrack = this; // ABu: na ktorym torze jesteśmy + if (Dynamic->iOverheadMask) // jeśli ma pantografy + Dynamic->OverheadTrack( + fOverhead); // przekazanie informacji o jeździe bezprądowej na tym odcinku toru + return true; } else { - Segment->MoveMe(pPosition); + Error("Too many dynamics on track " + pMyNode->asName); + return false; + } +}; + +void __fastcall TTrack::MoveMe(vector3 pPosition) +{ // to nie jest używane + if (SwitchExtension) + { + SwitchExtension->Segments[0]->MoveMe(1 * pPosition); + SwitchExtension->Segments[1]->MoveMe(1 * pPosition); + SwitchExtension->Segments[2]->MoveMe(3 * pPosition); // Ra: 3 razy? + SwitchExtension->Segments[3]->MoveMe(4 * pPosition); + } + else + { + Segment->MoveMe(pPosition); }; ResourceManager::Unregister(this); }; - -const int numPts=4; -const int nnumPts=12; +const int numPts = 4; +const int nnumPts = 12; /* const vector6 szyna[nnumPts]= //szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn) {pierwotna szyna, opracował youBy, zmiany w celu uzyskania symetrii @@ -1023,535 +1096,756 @@ const vector6 szyna[nnumPts]= //szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn) vector6(-0.039,-0.180,1.00,-1.000, 0.000,0.000) }; */ -const vector6 szyna[nnumPts]= //szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn) -{//tę wersję opracował Tolein (bez pochylenia) - vector6( 0.111,-0.180,0.00, 1.000, 0.000,0.000), - vector6( 0.046,-0.150,0.15, 0.707, 0.707,0.000), - vector6( 0.044,-0.050,0.25, 0.707,-0.707,0.000), - vector6( 0.073,-0.038,0.35, 0.707,-0.707,0.000), - vector6( 0.072,-0.010,0.40, 0.707, 0.707,0.000), - vector6( 0.052,-0.000,0.45, 0.000, 1.000,0.000), - vector6( 0.020,-0.000,0.55, 0.000, 1.000,0.000), - vector6( 0.000,-0.010,0.60,-0.707, 0.707,0.000), - vector6( -0.001,-0.038,0.65,-0.707,-0.707,0.000), - vector6( 0.028,-0.050,0.75,-0.707,-0.707,0.000), - vector6( 0.026,-0.150,0.85,-0.707, 0.707,0.000), - vector6(-0.039,-0.180,1.00,-1.000, 0.000,0.000) +const vector6 szyna[nnumPts] = // szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn) + { // tę wersję opracował Tolein (bez pochylenia) + vector6(0.111, -0.180, 0.00, 1.000, 0.000, 0.000), + vector6(0.046, -0.150, 0.15, 0.707, 0.707, 0.000), + vector6(0.044, -0.050, 0.25, 0.707, -0.707, 0.000), + vector6(0.073, -0.038, 0.35, 0.707, -0.707, 0.000), + vector6(0.072, -0.010, 0.40, 0.707, 0.707, 0.000), + vector6(0.052, -0.000, 0.45, 0.000, 1.000, 0.000), + vector6(0.020, -0.000, 0.55, 0.000, 1.000, 0.000), + vector6(0.000, -0.010, 0.60, -0.707, 0.707, 0.000), + vector6(-0.001, -0.038, 0.65, -0.707, -0.707, 0.000), + vector6(0.028, -0.050, 0.75, -0.707, -0.707, 0.000), + vector6(0.026, -0.150, 0.85, -0.707, 0.707, 0.000), + vector6(-0.039, -0.180, 1.00, -1.000, 0.000, 0.000)}; + +const vector6 iglica[nnumPts] = // iglica - vextor3(x,y,mapowanie tekstury) + { + vector6(0.010, -0.180, 0.00, 1.000, 0.000, 0.000), + vector6(0.010, -0.155, 0.15, 1.000, 0.000, 0.000), + vector6(0.010, -0.070, 0.25, 1.000, 0.000, 0.000), + vector6(0.010, -0.040, 0.35, 1.000, 0.000, 0.000), + vector6(0.010, -0.010, 0.40, 1.000, 0.000, 0.000), + vector6(0.010, -0.000, 0.45, 0.707, 0.707, 0.000), + vector6(0.000, -0.000, 0.55, 0.707, 0.707, 0.000), + vector6(0.000, -0.010, 0.60, -1.000, 0.000, 0.000), + vector6(0.000, -0.040, 0.65, -1.000, 0.000, 0.000), + vector6(0.000, -0.070, 0.75, -1.000, 0.000, 0.000), + vector6(0.000, -0.155, 0.85, -0.707, 0.707, 0.000), + vector6(-0.040, -0.180, 1.00, -1.000, 0.000, + 0.000) // 1mm więcej, żeby nie nachodziły tekstury? }; - -const vector6 iglica[nnumPts]= //iglica - vextor3(x,y,mapowanie tekstury) -{vector6( 0.010,-0.180,0.00, 1.000, 0.000,0.000), - vector6( 0.010,-0.155,0.15, 1.000, 0.000,0.000), - vector6( 0.010,-0.070,0.25, 1.000, 0.000,0.000), - vector6( 0.010,-0.040,0.35, 1.000, 0.000,0.000), - vector6( 0.010,-0.010,0.40, 1.000, 0.000,0.000), - vector6( 0.010,-0.000,0.45, 0.707, 0.707,0.000), - vector6( 0.000,-0.000,0.55, 0.707, 0.707,0.000), - vector6( 0.000,-0.010,0.60,-1.000, 0.000,0.000), - vector6( 0.000,-0.040,0.65,-1.000, 0.000,0.000), - vector6( 0.000,-0.070,0.75,-1.000, 0.000,0.000), - vector6( 0.000,-0.155,0.85,-0.707, 0.707,0.000), - vector6(-0.040,-0.180,1.00,-1.000, 0.000,0.000) //1mm więcej, żeby nie nachodziły tekstury? -}; - - - void __fastcall TTrack::Compile(GLuint tex) -{//generowanie treści dla Display Lists - model proceduralny - if (!tex) - {//jeśli nie podana tekstura, to każdy tor ma wlasne DL - if (DisplayListID) - Release(); //zwolnienie zasobów w celu ponownego utworzenia - if (Global::bManageNodes) - { - DisplayListID=glGenLists(1); //otwarcie nowej listy - glNewList(DisplayListID,GL_COMPILE); - }; - } - glColor3f(1.0f,1.0f,1.0f); //to tutaj potrzebne? - //Ra: nie zmieniamy oświetlenia przy kompilowaniu, ponieważ ono się zmienia w czasie! - //trochę podliczonych zmiennych, co się potem przydadzą - double fHTW=0.5*fabs(fTrackWidth); //połowa szerokości - double side=fabs(fTexWidth); //szerokść podsypki na zewnątrz szyny albo pobocza - double slop=fabs(fTexSlope); //szerokość pochylenia - double rozp=fHTW+side+slop; //brzeg zewnętrzny - double hypot1=hypot(slop,fTexHeight1); //rozmiar pochylenia do liczenia normalnych - if (hypot1==0.0) hypot1=1.0; - vector3 normal1=vector3(fTexSlope/hypot1,fTexHeight1/hypot1,0.0); //wektor normalny - double fHTW2,side2,slop2,rozp2,fTexHeight2,hypot2; - vector3 normal2; - if (iTrapezoid&2) //ten bit oznacza, że istnieje odpowiednie pNext - {//Ra: jest OK - fHTW2=0.5*fabs(trNext->fTrackWidth); //połowa rozstawu/nawierzchni - side2=fabs(trNext->fTexWidth); - slop2=fabs(trNext->fTexSlope); - rozp2=fHTW2+side2+slop2; //szerokość podstawy - fTexHeight2=trNext->fTexHeight1; - hypot2=hypot(slop2,fTexHeight2); - if (hypot2==0.0) hypot2=1.0; - normal2=vector3(trNext->fTexSlope/hypot2,fTexHeight2/hypot2,0.0); - } - else //gdy nie ma następnego albo jest nieodpowiednim końcem podpięty - {fHTW2=fHTW; side2=side; slop2=slop; rozp2=rozp; fTexHeight2=fTexHeight1; hypot2=hypot1; normal2=normal1;} - double roll1,roll2; - switch (iCategoryFlag&15) - { - case 1: //tor - { - Segment->GetRolls(roll1,roll2); - double sin1=sin(roll1),cos1=cos(roll1),sin2=sin(roll2),cos2=cos(roll2); - // zwykla szyna: //Ra: czemu główki są asymetryczne na wysokości 0.140? - vector6 rpts1[24],rpts2[24],rpts3[24],rpts4[24]; - int i; - for (i=0;i<12;++i) - {rpts1[i] =vector6(( fHTW+szyna[i].x)*cos1+szyna[i].y*sin1,-( fHTW+szyna[i].x)*sin1+szyna[i].y*cos1,szyna[i].z ,+szyna[i].n.x*cos1+szyna[i].n.y*sin1,-szyna[i].n.x*sin1+szyna[i].n.y*cos1,0.0); - rpts2[11-i]=vector6((-fHTW-szyna[i].x)*cos1+szyna[i].y*sin1,-(-fHTW-szyna[i].x)*sin1+szyna[i].y*cos1,szyna[i].z ,-szyna[i].n.x*cos1+szyna[i].n.y*sin1,+szyna[i].n.x*sin1+szyna[i].n.y*cos1,0.0); - } - if (iTrapezoid) //jak trapez albo przechyłki, to oddzielne punkty na końcu - for (i=0;i<12;++i) - {rpts1[12+i]=vector6(( fHTW2+szyna[i].x)*cos2+szyna[i].y*sin2,-( fHTW2+szyna[i].x)*sin2+szyna[i].y*cos2,szyna[i].z ,+szyna[i].n.x*cos2+szyna[i].n.y*sin2,-szyna[i].n.x*sin2+szyna[i].n.y*cos2,0.0); - rpts2[23-i]=vector6((-fHTW2-szyna[i].x)*cos2+szyna[i].y*sin2,-(-fHTW2-szyna[i].x)*sin2+szyna[i].y*cos2,szyna[i].z ,-szyna[i].n.x*cos2+szyna[i].n.y*sin2,+szyna[i].n.x*sin2+szyna[i].n.y*cos2,0.0); +{ // generowanie treści dla Display Lists - model proceduralny + if (!tex) + { // jeśli nie podana tekstura, to każdy tor ma wlasne DL + if (DisplayListID) + Release(); // zwolnienie zasobów w celu ponownego utworzenia + if (Global::bManageNodes) + { + DisplayListID = glGenLists(1); // otwarcie nowej listy + glNewList(DisplayListID, GL_COMPILE); + }; } - switch (eType) //dalej zależnie od typu - { - case tt_Table: //obrotnica jak zwykły tor, animacja wykonywana w RaAnimate(), tutaj tylko regeneracja siatek - case tt_Normal: - if (TextureID2) - if (tex?TextureID2==tex:true) //jeśli pasuje do grupy (tex) - {//podsypka z podkładami jest tylko dla zwykłego toru - vector6 bpts1[8]; //punkty głównej płaszczyzny nie przydają się do robienia boków - if (fTexLength==4.0) //jeśli stare mapowanie na profil 0.2 0.5 1.1 (również 6-9-9/noil) - {//stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil - if (iTrapezoid) //trapez albo przechyłki - {//podsypka z podkladami trapezowata - //ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 ((0.3464,0.6536) - //bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu - bpts1[0]=vector6(rozp, -fTexHeight1-0.18, 0.00,normal1.x,-normal1.y,0.0); //lewy brzeg - bpts1[1]=vector6((fHTW+side)*cos1, -(fHTW+side)*sin1-0.18, 0.33,0.0,1.0,0.0); //krawędź załamania - bpts1[2]=vector6(-bpts1[1].x, +(fHTW+side)*sin1-0.18, 0.67,-normal1.x,-normal1.y,0.0); //prawy brzeg początku symetrycznie - bpts1[3]=vector6(-rozp, -fTexHeight1-0.18, 1.00,-normal1.x,-normal1.y,0.0); //prawy skos - //przekrój końcowy - bpts1[4]=vector6(rozp2, -fTexHeight2-0.18, 0.00,normal2.x,-normal2.y,0.0); //lewy brzeg - bpts1[5]=vector6((fHTW2+side2)*cos2,-(fHTW2+side2)*sin2-0.18,0.33,0.0,1.0,0.0); //krawędź załamania - bpts1[6]=vector6(-bpts1[5].x, +(fHTW2+side2)*sin2-0.18,0.67,0.0,1.0,0.0); //prawy brzeg początku symetrycznie - bpts1[7]=vector6(-rozp2, -fTexHeight2-0.18, 1.00,-normal2.x,-normal2.y,0.0); //prawy skos - } - else - {bpts1[0]=vector6(rozp, -fTexHeight1-0.18,0.0,+normal1.x,-normal1.y,0.0); //lewy brzeg - bpts1[1]=vector6(fHTW+side, -0.18,0.33, +normal1.x,-normal1.y,0.0); //krawędź załamania - bpts1[2]=vector6(-fHTW-side,-0.18,0.67, -normal1.x,-normal1.y,0.0); //druga - bpts1[3]=vector6(-rozp, -fTexHeight1-0.18,1.0,-normal1.x,-normal1.y,0.0); //prawy skos - } - } - else - {//mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa fTexLength - double max=fTexRatio2*fTexLength; //szerokość proporcjonalna do długości - double map11=max>0.0?(fHTW+side)/max:0.25; //załamanie od strony 1 - double map12=max>0.0?(fHTW+side+hypot1)/max:0.5; //brzeg od strony 1 - if (iTrapezoid) //trapez albo przechyłki - {//podsypka z podkladami trapezowata - double map21=max>0.0?(fHTW2+side2)/max:0.25; //załamanie od strony 2 - double map22=max>0.0?(fHTW2+side2+hypot2)/max:0.5; //brzeg od strony 2 - //ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 ((0.3464,0.6536) - //bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu - bpts1[0]=vector6(rozp, -fTexHeight1-0.18 ,0.5-map12,normal1.x,-normal1.y,0.0); //lewy brzeg - bpts1[1]=vector6((fHTW+side)*cos1, -(fHTW+side)*sin1-0.18 ,0.5-map11,0.0,1.0,0.0); //krawędź załamania - bpts1[2]=vector6(-bpts1[1].x, +(fHTW+side)*sin1-0.18 ,0.5+map11,0.0,1.0,0.0); //prawy brzeg początku symetrycznie - bpts1[3]=vector6(-rozp, -fTexHeight1-0.18 ,0.5+map12,-normal1.x,-normal1.y,0.0); //prawy skos - //przekrój końcowy - bpts1[4]=vector6(rozp2, -fTexHeight2-0.18 ,0.5-map22,normal2.x,-normal2.y,0.0); //lewy brzeg - bpts1[5]=vector6((fHTW2+side2)*cos2,-(fHTW2+side2)*sin2-0.18,0.5-map21,0.0,1.0,0.0); //krawędź załamania - bpts1[6]=vector6(-bpts1[5].x, +(fHTW2+side2)*sin2-0.18,0.5+map21,0.0,1.0,0.0); //prawy brzeg początku symetrycznie - bpts1[7]=vector6(-rozp2, -fTexHeight2-0.18 ,0.5+map22,-normal2.x,-normal2.y,0.0); //prawy skos - } - else - {bpts1[0]=vector6(rozp, -fTexHeight1-0.18,0.5-map12,+normal1.x,-normal1.y,0.0); //lewy brzeg - bpts1[1]=vector6(fHTW+side, -0.18 ,0.5-map11,+normal1.x,-normal1.y,0.0); //krawędź załamania - bpts1[2]=vector6(-fHTW-side,-0.18 ,0.5+map11,-normal1.x,-normal1.y,0.0); //druga - bpts1[3]=vector6(-rozp, -fTexHeight1-0.18,0.5+map12,-normal1.x,-normal1.y,0.0); //prawy skos - } - } - if (!tex) glBindTexture(GL_TEXTURE_2D,TextureID2); - Segment->RenderLoft(bpts1,iTrapezoid?-4:4,fTexLength); - } - if (TextureID1) - if (tex?TextureID1==tex:true) //jeśli pasuje do grupy (tex) - {// szyny - if (!tex) glBindTexture(GL_TEXTURE_2D,TextureID1); - Segment->RenderLoft(rpts1,iTrapezoid?-nnumPts:nnumPts,fTexLength); - Segment->RenderLoft(rpts2,iTrapezoid?-nnumPts:nnumPts,fTexLength); - } - break; - case tt_Switch: //dla zwrotnicy dwa razy szyny - if (TextureID1) //zwrotnice nie są grupowane, aby prościej było je animować - {//iglice liczone tylko dla zwrotnic - //Ra: TODO: oddzielna animacja każdej iglicy, opór na docisku - vector6 rpts3[24],rpts4[24]; - for (i=0;i<12;++i) - {rpts3[i] =vector6(( fHTW+iglica[i].x)*cos1+iglica[i].y*sin1,-( fHTW+iglica[i].x)*sin1+iglica[i].y*cos1,iglica[i].z,+iglica[i].n.x*cos1+iglica[i].n.y*sin1,-iglica[i].n.x*sin1+iglica[i].n.y*cos1,0.0); - rpts4[11-i]=vector6((-fHTW-iglica[i].x)*cos1+iglica[i].y*sin1,-(-fHTW-iglica[i].x)*sin1+iglica[i].y*cos1,iglica[i].z,-iglica[i].n.x*cos1+iglica[i].n.y*sin1,+iglica[i].n.x*sin1+iglica[i].n.y*cos1,0.0); - } - if (iTrapezoid) //trapez albo przechyłki, to oddzielne punkty na końcu - for (i=0;i<12;++i) - {rpts3[12+i]=vector6(( fHTW2+iglica[i].x)*cos2+iglica[i].y*sin2,-( fHTW2+iglica[i].x)*sin2+iglica[i].y*cos2,iglica[i].z,+iglica[i].n.x*cos2+iglica[i].n.y*sin2,-iglica[i].n.x*sin2+iglica[i].n.y*cos2,0.0); - rpts4[23-i]=vector6((-fHTW2-iglica[i].x)*cos2+iglica[i].y*sin2,-(-fHTW2-iglica[i].x)*sin2+iglica[i].y*cos2,iglica[i].z,-iglica[i].n.x*cos2+iglica[i].n.y*sin2,+iglica[i].n.x*sin2+iglica[i].n.y*cos2,0.0); - } - //McZapkie-130302 - poprawione rysowanie szyn - if (SwitchExtension->RightSwitch) - {//zwrotnica prawa - glBindTexture(GL_TEXTURE_2D,TextureID1); - SwitchExtension->Segments[0]->RenderLoft(rpts1,nnumPts,fTexLength,2); //prawa szyna za iglicą - SwitchExtension->Segments[0]->RenderSwitchRail(rpts1,rpts3,nnumPts,fTexLength,2,SwitchExtension->fOffset2); //prawa iglica - SwitchExtension->Segments[0]->RenderLoft(rpts2,nnumPts,fTexLength); //lewa szyna normalnie cała - if (TextureID2!=TextureID1) //nie wiadomo, czy OpenGL to optymalizuje - glBindTexture(GL_TEXTURE_2D,TextureID2); - SwitchExtension->Segments[1]->RenderLoft(rpts1,nnumPts,fTexLength); //prawa szyna normalna cała - SwitchExtension->Segments[1]->RenderLoft(rpts2,nnumPts,fTexLength,2); //lewa szyna za iglicą - SwitchExtension->Segments[1]->RenderSwitchRail(rpts2,rpts4,nnumPts,fTexLength,2,-fMaxOffset+SwitchExtension->fOffset1); //lewa iglica - } - else - {//lewa kiedyś działała lepiej niż prawa - glBindTexture(GL_TEXTURE_2D,TextureID1); - SwitchExtension->Segments[0]->RenderLoft(rpts1,nnumPts,fTexLength); //prawa szyna normalna cała - SwitchExtension->Segments[0]->RenderLoft(rpts2,nnumPts,fTexLength,2); //lewa szyna za iglicą - SwitchExtension->Segments[0]->RenderSwitchRail(rpts2,rpts4,nnumPts,fTexLength,2,-SwitchExtension->fOffset2); //lewa iglica - if (TextureID2!=TextureID1) //nie wiadomo, czy OpenGL to optymalizuje - glBindTexture(GL_TEXTURE_2D,TextureID2); - SwitchExtension->Segments[1]->RenderLoft(rpts1,nnumPts,fTexLength,2); //prawa szyna za iglicą - SwitchExtension->Segments[1]->RenderSwitchRail(rpts1,rpts3,nnumPts,fTexLength,2,fMaxOffset-SwitchExtension->fOffset1); //prawa iglica - SwitchExtension->Segments[1]->RenderLoft(rpts2,nnumPts,fTexLength); //lewa szyna normalnie cała - } - } - break; - } - } //koniec obsługi torów - break; - case 2: //McZapkie-260302 - droga - rendering - //McZapkie:240702-zmieniony zakres widzialnosci - switch (eType) //dalej zależnie od typu - { - case tt_Normal: //drogi proste, bo skrzyżowania osobno - {vector6 bpts1[4]; //punkty głównej płaszczyzny przydają się do robienia boków - if (TextureID1||TextureID2) //punkty się przydadzą, nawet jeśli nawierzchni nie ma - {//double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% - double max=fTexRatio1*fTexLength; //test: szerokość proporcjonalna do długości - double map1=max>0.0?fHTW/max:0.5; //obcięcie tekstury od strony 1 - double map2=max>0.0?fHTW2/max:0.5; //obcięcie tekstury od strony 2 - if (iTrapezoid) //trapez albo przechyłki - {//nawierzchnia trapezowata - Segment->GetRolls(roll1,roll2); - bpts1[0]=vector6(fHTW*cos(roll1),-fHTW*sin(roll1),0.5-map1,sin(roll1),cos(roll1),0.0); //lewy brzeg początku - bpts1[1]=vector6(-bpts1[0].x,-bpts1[0].y,0.5+map1,-sin(roll1),cos(roll1),0.0); //prawy brzeg początku symetrycznie - bpts1[2]=vector6(fHTW2*cos(roll2),-fHTW2*sin(roll2),0.5-map2,sin(roll2),cos(roll2),0.0); //lewy brzeg końca - bpts1[3]=vector6(-bpts1[2].x,-bpts1[2].y,0.5+map2,-sin(roll2),cos(roll2),0.0); //prawy brzeg początku symetrycznie - } - else - {bpts1[0]=vector6( fHTW,0.0,0.5-map1,0.0,1.0,0.0); - bpts1[1]=vector6(-fHTW,0.0,0.5+map1,0.0,1.0,0.0); - } - } - if (TextureID1) //jeśli podana była tekstura, generujemy trójkąty - if (tex?TextureID1==tex:true) //jeśli pasuje do grupy (tex) - {//tworzenie trójkątów nawierzchni szosy - if (!tex) glBindTexture(GL_TEXTURE_2D,TextureID1); - Segment->RenderLoft(bpts1,iTrapezoid?-2:2,fTexLength); - } - if (TextureID2) - if (tex?TextureID2==tex:true) //jeśli pasuje do grupy (tex) - {//pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) - if (!tex) glBindTexture(GL_TEXTURE_2D,TextureID2); - vector6 rpts1[6],rpts2[6]; //współrzędne przekroju i mapowania dla prawej i lewej strony - if (fTexHeight1>=0.0) - {//standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo - rpts1[0]=vector6(rozp,-fTexHeight1,0.0); //lewy brzeg podstawy - rpts1[1]=vector6(bpts1[0].x+side,bpts1[0].y,0.5); //lewa krawędź załamania - rpts1[2]=vector6(bpts1[0].x,bpts1[0].y,1.0); //lewy brzeg pobocza (mapowanie może być inne - rpts2[0]=vector6(bpts1[1].x,bpts1[1].y,1.0); //prawy brzeg pobocza - rpts2[1]=vector6(bpts1[1].x-side,bpts1[1].y,0.5); //prawa krawędź załamania - rpts2[2]=vector6(-rozp,-fTexHeight1,0.0); //prawy brzeg podstawy - if (iTrapezoid) //trapez albo przechyłki - {//pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - rpts1[3]=vector6(rozp2,-fTexHeight2,0.0); //lewy brzeg lewego pobocza - rpts1[4]=vector6(bpts1[2].x+side2,bpts1[2].y,0.5); //krawędź załamania - rpts1[5]=vector6(bpts1[2].x,bpts1[2].y,1.0); //brzeg pobocza - rpts2[3]=vector6(bpts1[3].x,bpts1[3].y,1.0); - rpts2[4]=vector6(bpts1[3].x-side2,bpts1[3].y,0.5); - rpts2[5]=vector6(-rozp2,-fTexHeight2,0.0); //prawy brzeg prawego pobocza - } - } - else - {//wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości - //mapowanie propocjonalne do szerokości chodnika - //krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy - double d=-fTexHeight1/3.75; //krawężnik o wysokości 150mm jest pochylony 40mm - double max=fTexRatio2*fTexLength; //test: szerokość proporcjonalna do długości - double map1l=max>0.0?side/max:0.484375; //obcięcie tekstury od lewej strony punktu 1 - double map1r=max>0.0?slop/max:0.484375; //obcięcie tekstury od prawej strony punktu 1 - rpts1[0]=vector6(bpts1[0].x+slop,bpts1[0].y-fTexHeight1,0.515625+map1r ); //prawy brzeg prawego chodnika - rpts1[1]=vector6(bpts1[0].x+d, bpts1[0].y-fTexHeight1,0.515625 ); //prawy krawężnik u góry - rpts1[2]=vector6(bpts1[0].x, bpts1[0].y, 0.515625-d/2.56); //prawy krawężnik u dołu - rpts2[0]=vector6(bpts1[1].x, bpts1[1].y, 0.484375+d/2.56); //lewy krawężnik u dołu - rpts2[1]=vector6(bpts1[1].x-d, bpts1[1].y-fTexHeight1,0.484375 ); //lewy krawężnik u góry - rpts2[2]=vector6(bpts1[1].x-side,bpts1[1].y-fTexHeight1,0.484375-map1l ); //lewy brzeg lewego chodnika - if (iTrapezoid) //trapez albo przechyłki - {//pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - slop2=fabs((iTrapezoid&2)?slop2:slop); //szerokość chodnika po prawej - double map2l=max>0.0?side2/max:0.484375; //obcięcie tekstury od lewej strony punktu 2 - double map2r=max>0.0?slop2/max:0.484375; //obcięcie tekstury od prawej strony punktu 2 - rpts1[3]=vector6(bpts1[2].x+slop2,bpts1[2].y-fTexHeight2,0.515625+map2r ); //prawy brzeg prawego chodnika - rpts1[4]=vector6(bpts1[2].x+d, bpts1[2].y-fTexHeight2,0.515625 ); //prawy krawężnik u góry - rpts1[5]=vector6(bpts1[2].x, bpts1[2].y, 0.515625-d/2.56); //prawy krawężnik u dołu - rpts2[3]=vector6(bpts1[3].x, bpts1[3].y, 0.484375+d/2.56); //lewy krawężnik u dołu - rpts2[4]=vector6(bpts1[3].x-d, bpts1[3].y-fTexHeight2,0.484375 ); //lewy krawężnik u góry - rpts2[5]=vector6(bpts1[3].x-side2,bpts1[3].y-fTexHeight2,0.484375-map2l ); //lewy brzeg lewego chodnika - } - } - if (iTrapezoid) //trapez albo przechyłki - {//pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - if ((fTexHeight1>=0.0)?true:(slop!=0.0)) - Segment->RenderLoft(rpts1,-3,fTexLength); //tylko jeśli jest z prawej - if ((fTexHeight1>=0.0)?true:(side!=0.0)) - Segment->RenderLoft(rpts2,-3,fTexLength); //tylko jeśli jest z lewej - } - else - {//pobocza zwykłe, brak przechyłki - if ((fTexHeight1>=0.0)?true:(slop!=0.0)) - Segment->RenderLoft(rpts1,3,fTexLength); - if ((fTexHeight1>=0.0)?true:(side!=0.0)) - Segment->RenderLoft(rpts2,3,fTexLength); - } - } - break; + glColor3f(1.0f, 1.0f, 1.0f); // to tutaj potrzebne? + // Ra: nie zmieniamy oświetlenia przy kompilowaniu, ponieważ ono się zmienia w czasie! + // trochę podliczonych zmiennych, co się potem przydadzą + double fHTW = 0.5 * fabs(fTrackWidth); // połowa szerokości + double side = fabs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza + double slop = fabs(fTexSlope); // szerokość pochylenia + double rozp = fHTW + side + slop; // brzeg zewnętrzny + double hypot1 = hypot(slop, fTexHeight1); // rozmiar pochylenia do liczenia normalnych + if (hypot1 == 0.0) + hypot1 = 1.0; + vector3 normal1 = vector3(fTexSlope / hypot1, fTexHeight1 / hypot1, 0.0); // wektor normalny + double fHTW2, side2, slop2, rozp2, fTexHeight2, hypot2; + vector3 normal2; + if (iTrapezoid & 2) // ten bit oznacza, że istnieje odpowiednie pNext + { // Ra: jest OK + fHTW2 = 0.5 * fabs(trNext->fTrackWidth); // połowa rozstawu/nawierzchni + side2 = fabs(trNext->fTexWidth); + slop2 = fabs(trNext->fTexSlope); + rozp2 = fHTW2 + side2 + slop2; // szerokość podstawy + fTexHeight2 = trNext->fTexHeight1; + hypot2 = hypot(slop2, fTexHeight2); + if (hypot2 == 0.0) + hypot2 = 1.0; + normal2 = vector3(trNext->fTexSlope / hypot2, fTexHeight2 / hypot2, 0.0); } - case tt_Cross: //skrzyżowanie dróg rysujemy inaczej - {//ustalenie współrzędnych środka - przecięcie Point1-Point2 z CV4-Point4 - double a[4]; //kąty osi ulic wchodzących - vector3 p[4]; //punkty się przydadzą do obliczeń - //na razie połowa odległości pomiędzy Point1 i Point2, potem się dopracuje - a[0]=a[1]=0.5; //parametr do poszukiwania przecięcia łuków - //modyfikować a[0] i a[1] tak, aby trafić na przecięcie odcinka 34 - p[0]=SwitchExtension->Segments[0]->FastGetPoint(a[0]); //współrzędne środka pierwszego odcinka - p[1]=SwitchExtension->Segments[1]->FastGetPoint(a[1]); //-//- drugiego - //p[2]=p[1]-p[0]; //jeśli różne od zera, przeliczyć a[0] i a[1] i wyznaczyć nowe punkty - vector3 oxz=p[0]; //punkt mapowania środka tekstury skrzyżowania - p[0]=SwitchExtension->Segments[0]->GetDirection1(); //Point1 - pobranie wektorów kontrolnych - p[1]=SwitchExtension->Segments[1]->GetDirection2(); //Point3 (bo zamienione) - p[2]=SwitchExtension->Segments[0]->GetDirection2(); //Point2 - p[3]=SwitchExtension->Segments[1]->GetDirection1(); //Point4 (bo zamienione) - a[0]=atan2(-p[0].x,p[0].z); // kąty stycznych osi dróg - a[1]=atan2(-p[1].x,p[1].z); - a[2]=atan2(-p[2].x,p[2].z); - a[3]=atan2(-p[3].x,p[3].z); - p[0]=SwitchExtension->Segments[0]->FastGetPoint_0(); //Point1 - pobranie współrzędnych końców - p[1]=SwitchExtension->Segments[1]->FastGetPoint_1(); //Point3 - p[2]=SwitchExtension->Segments[0]->FastGetPoint_1(); //Point2 - p[3]=SwitchExtension->Segments[1]->FastGetPoint_0(); //Point4 - przy trzech drogach pokrywa się z Point1 - //2014-07: na początek rysować brzegi jak dla łuków - //punkty brzegu nawierzchni uzyskujemy podczas renderowania boków (bez sensu, ale najszybciej było zrobić) - int i,j; //ile punktów (może byc różna ilość punktów między drogami) - if (!SwitchExtension->vPoints) - {//jeśli tablica punktów nie jest jeszcze utworzona, zliczamy punkty i tworzymy ją - if (SwitchExtension->iRoads==3) //mogą być tylko 3 drogi zamiast 4 - SwitchExtension->iPoints=5+SwitchExtension->Segments[0]->RaSegCount()+SwitchExtension->Segments[1]->RaSegCount()+SwitchExtension->Segments[2]->RaSegCount(); - else - SwitchExtension->iPoints=5+SwitchExtension->Segments[2]->RaSegCount()+SwitchExtension->Segments[3]->RaSegCount()+SwitchExtension->Segments[4]->RaSegCount()+SwitchExtension->Segments[5]->RaSegCount(); //mogą być tylko 3 drogi - SwitchExtension->vPoints=new vector3[SwitchExtension->iPoints]; //tablica utworzona z zapasem, ale nie wypełniona współrzędnymi - } - vector3 *b=SwitchExtension->bPoints?NULL:SwitchExtension->vPoints; //zmienna robocza, NULL gdy tablica punktów już jest wypełniona - vector6 bpts1[4]; //punkty głównej płaszczyzny przydają się do robienia boków - if (TextureID1||TextureID2) //punkty się przydadzą, nawet jeśli nawierzchni nie ma - {//double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% - double max=fTexRatio1*fTexLength; //test: szerokość proporcjonalna do długości - double map1=max>0.0?fHTW/max:0.5; //obcięcie tekstury od strony 1 - double map2=max>0.0?fHTW2/max:0.5; //obcięcie tekstury od strony 2 - //if (iTrapezoid) //trapez albo przechyłki - {//nawierzchnia trapezowata - Segment->GetRolls(roll1,roll2); - bpts1[0]=vector6(fHTW*cos(roll1),-fHTW*sin(roll1),0.5-map1,sin(roll1),cos(roll1),0.0); //lewy brzeg początku - bpts1[1]=vector6(-bpts1[0].x,-bpts1[0].y,0.5+map1,-sin(roll1),cos(roll1),0.0); //prawy brzeg początku symetrycznie - bpts1[2]=vector6(fHTW2*cos(roll2),-fHTW2*sin(roll2),0.5-map2,sin(roll2),cos(roll2),0.0); //lewy brzeg końca - bpts1[3]=vector6(-bpts1[2].x,-bpts1[2].y,0.5+map2,-sin(roll2),cos(roll2),0.0); //prawy brzeg początku symetrycznie - } - } - //najpierw renderowanie poboczy i zapamiętywanie punktów - //problem ze skrzyżowaniami jest taki, że teren chce się pogrupować wg tekstur, ale zaczyna od nawierzchni - //sama nawierzchnia nie wypełni tablicy punktów, bo potrzebne są pobocza - //ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie w swoim czasie - //if (TextureID2) - //if (tex?TextureID2==tex:true) //jeśli pasuje do grupy (tex) - {//pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) - if (TextureID2) if (!tex) glBindTexture(GL_TEXTURE_2D,TextureID2); - vector6 rpts1[6],rpts2[6]; //współrzędne przekroju i mapowania dla prawej i lewej strony - //Ra 2014-07: trzeba to przerobić na pętlę i pobierać profile (przynajmniej 2..4) z sąsiednich dróg - if (fTexHeight1>=0.0) - {//standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo - rpts1[0]=vector6(rozp,-fTexHeight1,0.0); //lewy brzeg podstawy - rpts1[1]=vector6(bpts1[0].x+side,bpts1[0].y,0.5); //lewa krawędź załamania - rpts1[2]=vector6(bpts1[0].x,bpts1[0].y,1.0); //lewy brzeg pobocza (mapowanie może być inne - rpts2[0]=vector6(bpts1[1].x,bpts1[1].y,1.0); //prawy brzeg pobocza - rpts2[1]=vector6(bpts1[1].x-side,bpts1[1].y,0.5); //prawa krawędź załamania - rpts2[2]=vector6(-rozp,-fTexHeight1,0.0); //prawy brzeg podstawy - //if (iTrapezoid) //trapez albo przechyłki - {//pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - rpts1[3]=vector6(rozp2,-fTexHeight2,0.0); //lewy brzeg lewego pobocza - rpts1[4]=vector6(bpts1[2].x+side2,bpts1[2].y,0.5); //krawędź załamania - rpts1[5]=vector6(bpts1[2].x,bpts1[2].y,1.0); //brzeg pobocza - rpts2[3]=vector6(bpts1[3].x,bpts1[3].y,1.0); - rpts2[4]=vector6(bpts1[3].x-side2,bpts1[3].y,0.5); - rpts2[5]=vector6(-rozp2,-fTexHeight2,0.0); //prawy brzeg prawego pobocza - } - } - else - {//wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości - //mapowanie propocjonalne do szerokości chodnika - //krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy - double d=-fTexHeight1/3.75; //krawężnik o wysokości 150mm jest pochylony 40mm - double max=fTexRatio2*fTexLength; //test: szerokość proporcjonalna do długości - double map1l=max>0.0?side/max:0.484375; //obcięcie tekstury od lewej strony punktu 1 - double map1r=max>0.0?slop/max:0.484375; //obcięcie tekstury od prawej strony punktu 1 - rpts1[0]=vector6(bpts1[0].x+slop,bpts1[0].y-fTexHeight1,0.515625+map1r ); //prawy brzeg prawego chodnika - rpts1[1]=vector6(bpts1[0].x+d, bpts1[0].y-fTexHeight1,0.515625 ); //prawy krawężnik u góry - rpts1[2]=vector6(bpts1[0].x, bpts1[0].y, 0.515625-d/2.56); //prawy krawężnik u dołu - rpts2[0]=vector6(bpts1[1].x, bpts1[1].y, 0.484375+d/2.56); //lewy krawężnik u dołu - rpts2[1]=vector6(bpts1[1].x-d, bpts1[1].y-fTexHeight1,0.484375 ); //lewy krawężnik u góry - rpts2[2]=vector6(bpts1[1].x-side,bpts1[1].y-fTexHeight1,0.484375-map1l ); //lewy brzeg lewego chodnika - //if (iTrapezoid) //trapez albo przechyłki - {//pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - slop2=fabs((iTrapezoid&2)?slop2:slop); //szerokość chodnika po prawej - double map2l=max>0.0?side2/max:0.484375; //obcięcie tekstury od lewej strony punktu 2 - double map2r=max>0.0?slop2/max:0.484375; //obcięcie tekstury od prawej strony punktu 2 - rpts1[3]=vector6(bpts1[2].x+slop2,bpts1[2].y-fTexHeight2,0.515625+map2r ); //prawy brzeg prawego chodnika - rpts1[4]=vector6(bpts1[2].x+d, bpts1[2].y-fTexHeight2,0.515625 ); //prawy krawężnik u góry - rpts1[5]=vector6(bpts1[2].x, bpts1[2].y, 0.515625-d/2.56); //prawy krawężnik u dołu - rpts2[3]=vector6(bpts1[3].x, bpts1[3].y, 0.484375+d/2.56); //lewy krawężnik u dołu - rpts2[4]=vector6(bpts1[3].x-d, bpts1[3].y-fTexHeight2,0.484375 ); //lewy krawężnik u góry - rpts2[5]=vector6(bpts1[3].x-side2,bpts1[3].y-fTexHeight2,0.484375-map2l ); //lewy brzeg lewego chodnika - } - } - bool render=TextureID2?(tex?TextureID2==tex:true):false; //renderować nie trzeba, ale trzeba wyznaczyć punkty brzegowe nawierzchni - //if (iTrapezoid) //trapez albo przechyłki - if (SwitchExtension->iRoads==4) - {//pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - if ((fTexHeight1>=0.0)?true:(side!=0.0)) - SwitchExtension->Segments[2]->RenderLoft(rpts2,-3,fTexLength,0,1,&b,render); //tylko jeśli jest z lewej - if ((fTexHeight1>=0.0)?true:(side!=0.0)) - SwitchExtension->Segments[3]->RenderLoft(rpts2,-3,fTexLength,0,1,&b,render); //tylko jeśli jest z lewej - if ((fTexHeight1>=0.0)?true:(side!=0.0)) - SwitchExtension->Segments[4]->RenderLoft(rpts2,-3,fTexLength,0,1,&b,render); //tylko jeśli jest z lewej - if ((fTexHeight1>=0.0)?true:(side!=0.0)) - SwitchExtension->Segments[5]->RenderLoft(rpts2,-3,fTexLength,0,1,&b,render); //tylko jeśli jest z lewej - } - else //to będzie ewentualnie dla prostego na skrzyżowaniu trzech dróg - {//punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe - if ((fTexHeight1>=0.0)?true:(side!=0.0)) //OK - SwitchExtension->Segments[2]->RenderLoft(rpts2,-3,fTexLength,0,1,&b,render); //z P2 do P4 - if ((fTexHeight1>=0.0)?true:(side!=0.0)) //OK - SwitchExtension->Segments[1]->RenderLoft(rpts2,-3,fTexLength,0,1,&b,render); //z P4 do P3=P1 (odwrócony) - if ((fTexHeight1>=0.0)?true:(side!=0.0)) //OK - SwitchExtension->Segments[0]->RenderLoft(rpts2,-3,fTexLength,0,1,&b,render); //z P1 do P2 - /* - if ((fTexHeight1>=0.0)?true:(slop!=0.0)) - Segment->RenderLoft(rpts1,3,fTexLength); - if ((fTexHeight1>=0.0)?true:(side!=0.0)) - Segment->RenderLoft(rpts2,3,fTexLength); - */ - } - } - //renderowanie nawierzchni na końcu - double sina0=sin(a[0]),cosa0=cos(a[0]); - double u,v; - if (!SwitchExtension->bPoints) //jeśli tablica nie wypełniona - if (b) //ale jest wskaźnik do tablicy - może nie być? - {//coś się gubi w obliczeniach na wskaźnikach - i=(int((void*)(b))-int((void*)(SwitchExtension->vPoints)))/sizeof(vector3); //ustalenie liczby punktów, bo mogło wyjść inaczej niż policzone z góry - if (i>0) - {//jeśli zostało to właśnie utworzone - if (SwitchExtension->iPoints>i) //jeśli wyszło mniej niż było miejsca - SwitchExtension->iPoints=i; //domknięcie wachlarza - else - --SwitchExtension->iPoints; //jak tutaj wejdzie, to błąd jest - zrobić miejsce na powtórzenie pierwszego punktu na końcu - SwitchExtension->vPoints[SwitchExtension->iPoints++]=SwitchExtension->vPoints[0]; - SwitchExtension->bPoints=true; //tablica punktów została wypełniona - } - } - if (TextureID1) //jeśli podana tekstura nawierzchni - if (tex?TextureID1==tex:true) //jeśli pasuje do grupy (tex) - {if (!tex) glBindTexture(GL_TEXTURE_2D,TextureID1); - glBegin(GL_TRIANGLE_FAN); //takie kółeczko będzie - glNormal3f(0,1,0); - glTexCoord2f(0.5,0.5); //środek tekstury na środku skrzyżowania - glVertex3f(oxz.x,oxz.y,oxz.z); - for (i=SwitchExtension->iPoints-1;i>=0;--i) - //for (i=0;iiPoints;++i) - {glNormal3f(0,1,0); - u=(SwitchExtension->vPoints[i].x-oxz.x)/fTexLength; //mapowanie we współrzędnych scenerii - v=(SwitchExtension->vPoints[i].z-oxz.z)/(fTexRatio1*fTexLength); - glTexCoord2f(cosa0*u+sina0*v+0.5,-sina0*u+cosa0*v+0.5); - glVertex3f(SwitchExtension->vPoints[i].x,SwitchExtension->vPoints[i].y,SwitchExtension->vPoints[i].z); - } - glEnd(); - } - break; - } - } - break; - case 4: //McZapkie-260302 - rzeka- rendering - //Ra: rzeki na razie bez zmian, przechyłki na pewno nie mają - //Ra: przemyśleć wyrównanie u góry trawą do czworoboku - vector6 bpts1[numPts]={vector6( fHTW,0.0,0.0), vector6( fHTW,0.2,0.33), - vector6(-fHTW,0.0,0.67),vector6(-fHTW,0.0,1.0 ) }; - //Ra: dziwnie ten kształt wygląda - if (TextureID1) - if (tex?TextureID1==tex:true) //jeśli pasuje do grupy (tex) + else // gdy nie ma następnego albo jest nieodpowiednim końcem podpięty { - if (!tex) glBindTexture(GL_TEXTURE_2D,TextureID1); - Segment->RenderLoft(bpts1,numPts,fTexLength); + fHTW2 = fHTW; + side2 = side; + slop2 = slop; + rozp2 = rozp; + fTexHeight2 = fTexHeight1; + hypot2 = hypot1; + normal2 = normal1; } - if (TextureID2) - if (tex?TextureID2==tex:true) //jeśli pasuje do grupy (tex) - {//brzegi rzeki prawie jak pobocze derogi, tylko inny znak ma wysokość - //znak jest zmieniany przy wczytywaniu, więc tu musi byc minus fTexHeight - vector6 rpts1[3]={ vector6(rozp,-fTexHeight1,0.0), - vector6(fHTW+side,0.0,0.5), - vector6(fHTW,0.0,1.0) }; - vector6 rpts2[3]={ vector6(-fHTW,0.0,1.0), - vector6(-fHTW-side,0.0,0.5), - vector6(-rozp,-fTexHeight1,0.0) }; //Ra: po kiego 0.1? - if (!tex) glBindTexture(GL_TEXTURE_2D,TextureID2); //brzeg rzeki - Segment->RenderLoft(rpts1,3,fTexLength); - Segment->RenderLoft(rpts2,3,fTexLength); + double roll1, roll2; + switch (iCategoryFlag & 15) + { + case 1: // tor + { + Segment->GetRolls(roll1, roll2); + double sin1 = sin(roll1), cos1 = cos(roll1), sin2 = sin(roll2), cos2 = cos(roll2); + // zwykla szyna: //Ra: czemu główki są asymetryczne na wysokości 0.140? + vector6 rpts1[24], rpts2[24], rpts3[24], rpts4[24]; + int i; + for (i = 0; i < 12; ++i) + { + rpts1[i] = vector6((fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1, + -(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z, + +szyna[i].n.x * cos1 + szyna[i].n.y * sin1, + -szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0); + rpts2[11 - i] = vector6((-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1, + -(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z, + -szyna[i].n.x * cos1 + szyna[i].n.y * sin1, + +szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0); + } + if (iTrapezoid) // jak trapez albo przechyłki, to oddzielne punkty na końcu + for (i = 0; i < 12; ++i) + { + rpts1[12 + i] = vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, + -(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2, + szyna[i].z, +szyna[i].n.x * cos2 + szyna[i].n.y * sin2, + -szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0); + rpts2[23 - i] = vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, + -(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2, + szyna[i].z, -szyna[i].n.x * cos2 + szyna[i].n.y * sin2, + +szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0); + } + switch (eType) // dalej zależnie od typu + { + case tt_Table: // obrotnica jak zwykły tor, animacja wykonywana w RaAnimate(), tutaj tylko + // regeneracja siatek + case tt_Normal: + if (TextureID2) + if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex) + { // podsypka z podkładami jest tylko dla zwykłego toru + vector6 + bpts1[8]; // punkty głównej płaszczyzny nie przydają się do robienia boków + if (fTexLength == + 4.0) // jeśli stare mapowanie na profil 0.2 0.5 1.1 (również 6-9-9/noil) + { // stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy + // profil + if (iTrapezoid) // trapez albo przechyłki + { // podsypka z podkladami trapezowata + // ewentualnie poprawić mapowanie, żeby środek mapował się na + // 1.435/4.671 ((0.3464,0.6536) + // bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.00, normal1.x, + -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, + 0.33, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[2] = + vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.67, -normal1.x, + -normal1.y, 0.0); // prawy brzeg początku symetrycznie + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.00, -normal1.x, + -normal1.y, 0.0); // prawy skos + // przekrój końcowy + bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.00, normal2.x, + -normal2.y, 0.0); // lewy brzeg + bpts1[5] = + vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, + 0.33, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.67, + 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie + bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 1.00, -normal2.x, + -normal2.y, 0.0); // prawy skos + } + else + { + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.0, +normal1.x, + -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6(fHTW + side, -0.18, 0.33, +normal1.x, -normal1.y, + 0.0); // krawędź załamania + bpts1[2] = vector6(-fHTW - side, -0.18, 0.67, -normal1.x, -normal1.y, + 0.0); // druga + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.0, -normal1.x, + -normal1.y, 0.0); // prawy skos + } + } + else + { // mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa + // fTexLength + double max = fTexRatio2 * fTexLength; // szerokość proporcjonalna do + // długości + double map11 = + max > 0.0 ? (fHTW + side) / max : 0.25; // załamanie od strony 1 + double map12 = + max > 0.0 ? (fHTW + side + hypot1) / max : 0.5; // brzeg od strony 1 + if (iTrapezoid) // trapez albo przechyłki + { // podsypka z podkladami trapezowata + double map21 = + max > 0.0 ? (fHTW2 + side2) / max : 0.25; // załamanie od strony 2 + double map22 = max > 0.0 ? (fHTW2 + side2 + hypot2) / max : + 0.5; // brzeg od strony 2 + // ewentualnie poprawić mapowanie, żeby środek mapował się na + // 1.435/4.671 ((0.3464,0.6536) + // bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, normal1.x, + -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, + 0.5 - map11, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[2] = + vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.5 + map11, 0.0, + 1.0, 0.0); // prawy brzeg początku symetrycznie + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, + -normal1.y, 0.0); // prawy skos + // przekrój końcowy + bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.5 - map22, normal2.x, + -normal2.y, 0.0); // lewy brzeg + bpts1[5] = + vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, + 0.5 - map21, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[6] = + vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.5 + map21, + 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie + bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 0.5 + map22, -normal2.x, + -normal2.y, 0.0); // prawy skos + } + else + { + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, +normal1.x, + -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6(fHTW + side, -0.18, 0.5 - map11, +normal1.x, + -normal1.y, 0.0); // krawędź załamania + bpts1[2] = vector6(-fHTW - side, -0.18, 0.5 + map11, -normal1.x, + -normal1.y, 0.0); // druga + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, + -normal1.y, 0.0); // prawy skos + } + } + if (!tex) + glBindTexture(GL_TEXTURE_2D, TextureID2); + Segment->RenderLoft(bpts1, iTrapezoid ? -4 : 4, fTexLength); + } + if (TextureID1) + if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) + { // szyny + if (!tex) + glBindTexture(GL_TEXTURE_2D, TextureID1); + Segment->RenderLoft(rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RenderLoft(rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + } + break; + case tt_Switch: // dla zwrotnicy dwa razy szyny + if (TextureID1) // zwrotnice nie są grupowane, aby prościej było je animować + { // iglice liczone tylko dla zwrotnic + // Ra: TODO: oddzielna animacja każdej iglicy, opór na docisku + vector6 rpts3[24], rpts4[24]; + for (i = 0; i < 12; ++i) + { + rpts3[i] = vector6((fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, + -(fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, + iglica[i].z, +iglica[i].n.x * cos1 + iglica[i].n.y * sin1, + -iglica[i].n.x * sin1 + iglica[i].n.y * cos1, 0.0); + rpts4[11 - i] = + vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, + -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z, + -iglica[i].n.x * cos1 + iglica[i].n.y * sin1, + +iglica[i].n.x * sin1 + iglica[i].n.y * cos1, 0.0); + } + if (iTrapezoid) // trapez albo przechyłki, to oddzielne punkty na końcu + for (i = 0; i < 12; ++i) + { + rpts3[12 + i] = + vector6((fHTW2 + iglica[i].x) * cos2 + iglica[i].y * sin2, + -(fHTW2 + iglica[i].x) * sin2 + iglica[i].y * cos2, iglica[i].z, + +iglica[i].n.x * cos2 + iglica[i].n.y * sin2, + -iglica[i].n.x * sin2 + iglica[i].n.y * cos2, 0.0); + rpts4[23 - i] = + vector6((-fHTW2 - iglica[i].x) * cos2 + iglica[i].y * sin2, + -(-fHTW2 - iglica[i].x) * sin2 + iglica[i].y * cos2, + iglica[i].z, -iglica[i].n.x * cos2 + iglica[i].n.y * sin2, + +iglica[i].n.x * sin2 + iglica[i].n.y * cos2, 0.0); + } + // McZapkie-130302 - poprawione rysowanie szyn + if (SwitchExtension->RightSwitch) + { // zwrotnica prawa + glBindTexture(GL_TEXTURE_2D, TextureID1); + SwitchExtension->Segments[0]->RenderLoft(rpts1, nnumPts, fTexLength, + 2); // prawa szyna za iglicą + SwitchExtension->Segments[0]->RenderSwitchRail( + rpts1, rpts3, nnumPts, fTexLength, 2, + SwitchExtension->fOffset2); // prawa iglica + SwitchExtension->Segments[0]->RenderLoft( + rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała + if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje + glBindTexture(GL_TEXTURE_2D, TextureID2); + SwitchExtension->Segments[1]->RenderLoft( + rpts1, nnumPts, fTexLength); // prawa szyna normalna cała + SwitchExtension->Segments[1]->RenderLoft(rpts2, nnumPts, fTexLength, + 2); // lewa szyna za iglicą + SwitchExtension->Segments[1]->RenderSwitchRail( + rpts2, rpts4, nnumPts, fTexLength, 2, + -fMaxOffset + SwitchExtension->fOffset1); // lewa iglica + } + else + { // lewa kiedyś działała lepiej niż prawa + glBindTexture(GL_TEXTURE_2D, TextureID1); + SwitchExtension->Segments[0]->RenderLoft( + rpts1, nnumPts, fTexLength); // prawa szyna normalna cała + SwitchExtension->Segments[0]->RenderLoft(rpts2, nnumPts, fTexLength, + 2); // lewa szyna za iglicą + SwitchExtension->Segments[0]->RenderSwitchRail( + rpts2, rpts4, nnumPts, fTexLength, 2, + -SwitchExtension->fOffset2); // lewa iglica + if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje + glBindTexture(GL_TEXTURE_2D, TextureID2); + SwitchExtension->Segments[1]->RenderLoft(rpts1, nnumPts, fTexLength, + 2); // prawa szyna za iglicą + SwitchExtension->Segments[1]->RenderSwitchRail( + rpts1, rpts3, nnumPts, fTexLength, 2, + fMaxOffset - SwitchExtension->fOffset1); // prawa iglica + SwitchExtension->Segments[1]->RenderLoft( + rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała + } + } + break; + } + } // koniec obsługi torów + break; + case 2: // McZapkie-260302 - droga - rendering + // McZapkie:240702-zmieniony zakres widzialnosci + switch (eType) // dalej zależnie od typu + { + case tt_Normal: // drogi proste, bo skrzyżowania osobno + { + vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków + if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma + { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% + double max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości + double map1 = max > 0.0 ? fHTW / max : 0.5; // obcięcie tekstury od strony 1 + double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obcięcie tekstury od strony 2 + if (iTrapezoid) // trapez albo przechyłki + { // nawierzchnia trapezowata + Segment->GetRolls(roll1, roll2); + bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1, + sin(roll1), cos(roll1), 0.0); // lewy brzeg początku + bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1), + cos(roll1), 0.0); // prawy brzeg początku symetrycznie + bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2, + sin(roll2), cos(roll2), 0.0); // lewy brzeg końca + bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2), + cos(roll2), 0.0); // prawy brzeg początku symetrycznie + } + else + { + bpts1[0] = vector6(fHTW, 0.0, 0.5 - map1, 0.0, 1.0, 0.0); + bpts1[1] = vector6(-fHTW, 0.0, 0.5 + map1, 0.0, 1.0, 0.0); + } + } + if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty + if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) + { // tworzenie trójkątów nawierzchni szosy + if (!tex) + glBindTexture(GL_TEXTURE_2D, TextureID1); + Segment->RenderLoft(bpts1, iTrapezoid ? -2 : 2, fTexLength); + } + if (TextureID2) + if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex) + { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak + // w Midtown Madness 2?) + if (!tex) + glBindTexture(GL_TEXTURE_2D, TextureID2); + vector6 rpts1[6], + rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony + if (fTexHeight1 >= 0.0) + { // standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo + rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy + rpts1[1] = + vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawędź załamania + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, + 1.0); // lewy brzeg pobocza (mapowanie może być inne + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza + rpts2[1] = + vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania + rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy + if (iTrapezoid) // trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony + // odcinka + rpts1[3] = + vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza + rpts1[4] = + vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź załamania + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); + rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); + rpts2[5] = + vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza + } + } + else + { // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości + // mapowanie propocjonalne do szerokości chodnika + // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy + double d = + -fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm + double max = + fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości + double map1l = max > 0.0 ? + side / max : + 0.484375; // obcięcie tekstury od lewej strony punktu 1 + double map1r = max > 0.0 ? + slop / max : + 0.484375; // obcięcie tekstury od prawej strony punktu 1 + rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y - fTexHeight1, + 0.515625 + map1r); // prawy brzeg prawego chodnika + rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y - fTexHeight1, + 0.515625); // prawy krawężnik u góry + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, + 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, + 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y - fTexHeight1, + 0.484375); // lewy krawężnik u góry + rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y - fTexHeight1, + 0.484375 - map1l); // lewy brzeg lewego chodnika + if (iTrapezoid) // trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony + // odcinka + slop2 = fabs((iTrapezoid & 2) ? slop2 : + slop); // szerokość chodnika po prawej + double map2l = + max > 0.0 ? side2 / max : + 0.484375; // obcięcie tekstury od lewej strony punktu 2 + double map2r = + max > 0.0 ? slop2 / max : + 0.484375; // obcięcie tekstury od prawej strony punktu 2 + rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y - fTexHeight2, + 0.515625 + map2r); // prawy brzeg prawego chodnika + rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y - fTexHeight2, + 0.515625); // prawy krawężnik u góry + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, + 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, + 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y - fTexHeight2, + 0.484375); // lewy krawężnik u góry + rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y - fTexHeight2, + 0.484375 - map2l); // lewy brzeg lewego chodnika + } + } + if (iTrapezoid) // trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony + // odcinka + if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0)) + Segment->RenderLoft(rpts1, -3, fTexLength); // tylko jeśli jest z prawej + if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) + Segment->RenderLoft(rpts2, -3, fTexLength); // tylko jeśli jest z lewej + } + else + { // pobocza zwykłe, brak przechyłki + if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0)) + Segment->RenderLoft(rpts1, 3, fTexLength); + if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) + Segment->RenderLoft(rpts2, 3, fTexLength); + } + } + break; + } + case tt_Cross: // skrzyżowanie dróg rysujemy inaczej + { // ustalenie współrzędnych środka - przecięcie Point1-Point2 z CV4-Point4 + double a[4]; // kąty osi ulic wchodzących + vector3 p[4]; // punkty się przydadzą do obliczeń + // na razie połowa odległości pomiędzy Point1 i Point2, potem się dopracuje + a[0] = a[1] = 0.5; // parametr do poszukiwania przecięcia łuków + // modyfikować a[0] i a[1] tak, aby trafić na przecięcie odcinka 34 + p[0] = SwitchExtension->Segments[0]->FastGetPoint( + a[0]); // współrzędne środka pierwszego odcinka + p[1] = SwitchExtension->Segments[1]->FastGetPoint(a[1]); //-//- drugiego + // p[2]=p[1]-p[0]; //jeśli różne od zera, przeliczyć a[0] i a[1] i wyznaczyć nowe punkty + vector3 oxz = p[0]; // punkt mapowania środka tekstury skrzyżowania + p[0] = SwitchExtension->Segments[0] + ->GetDirection1(); // Point1 - pobranie wektorów kontrolnych + p[1] = SwitchExtension->Segments[1]->GetDirection2(); // Point3 (bo zamienione) + p[2] = SwitchExtension->Segments[0]->GetDirection2(); // Point2 + p[3] = SwitchExtension->Segments[1]->GetDirection1(); // Point4 (bo zamienione) + a[0] = atan2(-p[0].x, p[0].z); // kąty stycznych osi dróg + a[1] = atan2(-p[1].x, p[1].z); + a[2] = atan2(-p[2].x, p[2].z); + a[3] = atan2(-p[3].x, p[3].z); + p[0] = SwitchExtension->Segments[0] + ->FastGetPoint_0(); // Point1 - pobranie współrzędnych końców + p[1] = SwitchExtension->Segments[1]->FastGetPoint_1(); // Point3 + p[2] = SwitchExtension->Segments[0]->FastGetPoint_1(); // Point2 + p[3] = SwitchExtension->Segments[1] + ->FastGetPoint_0(); // Point4 - przy trzech drogach pokrywa się z Point1 + // 2014-07: na początek rysować brzegi jak dla łuków + // punkty brzegu nawierzchni uzyskujemy podczas renderowania boków (bez sensu, ale + // najszybciej było zrobić) + int i, j; // ile punktów (może byc różna ilość punktów między drogami) + if (!SwitchExtension->vPoints) + { // jeśli tablica punktów nie jest jeszcze utworzona, zliczamy punkty i tworzymy ją + if (SwitchExtension->iRoads == 3) // mogą być tylko 3 drogi zamiast 4 + SwitchExtension->iPoints = 5 + SwitchExtension->Segments[0]->RaSegCount() + + SwitchExtension->Segments[1]->RaSegCount() + + SwitchExtension->Segments[2]->RaSegCount(); + else + SwitchExtension->iPoints = + 5 + SwitchExtension->Segments[2]->RaSegCount() + + SwitchExtension->Segments[3]->RaSegCount() + + SwitchExtension->Segments[4]->RaSegCount() + + SwitchExtension->Segments[5]->RaSegCount(); // mogą być tylko 3 drogi + SwitchExtension->vPoints = + new vector3[SwitchExtension->iPoints]; // tablica utworzona z zapasem, ale nie + // wypełniona współrzędnymi + } + vector3 *b = + SwitchExtension->bPoints ? + NULL : + SwitchExtension + ->vPoints; // zmienna robocza, NULL gdy tablica punktów już jest wypełniona + vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków + if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma + { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% + double max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości + double map1 = max > 0.0 ? fHTW / max : 0.5; // obcięcie tekstury od strony 1 + double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obcięcie tekstury od strony 2 + // if (iTrapezoid) //trapez albo przechyłki + { // nawierzchnia trapezowata + Segment->GetRolls(roll1, roll2); + bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1, + sin(roll1), cos(roll1), 0.0); // lewy brzeg początku + bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1), + cos(roll1), 0.0); // prawy brzeg początku symetrycznie + bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2, + sin(roll2), cos(roll2), 0.0); // lewy brzeg końca + bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2), + cos(roll2), 0.0); // prawy brzeg początku symetrycznie + } + } + // najpierw renderowanie poboczy i zapamiętywanie punktów + // problem ze skrzyżowaniami jest taki, że teren chce się pogrupować wg tekstur, ale + // zaczyna od nawierzchni + // sama nawierzchnia nie wypełni tablicy punktów, bo potrzebne są pobocza + // ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie + // w swoim czasie + // if (TextureID2) + // if (tex?TextureID2==tex:true) //jeśli pasuje do grupy (tex) + { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w + // Midtown Madness 2?) + if (TextureID2) + if (!tex) + glBindTexture(GL_TEXTURE_2D, TextureID2); + vector6 rpts1[6], + rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony + // Ra 2014-07: trzeba to przerobić na pętlę i pobierać profile (przynajmniej 2..4) z + // sąsiednich dróg + if (fTexHeight1 >= 0.0) + { // standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo + rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy + rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawędź + // załamania + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, + 1.0); // lewy brzeg pobocza (mapowanie może być inne + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza + rpts2[1] = + vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania + rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy + // if (iTrapezoid) //trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony + // odcinka + rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza + rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź + // załamania + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); + rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); + rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego + // pobocza + } + } + else + { // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości + // mapowanie propocjonalne do szerokości chodnika + // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy + double d = + -fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm + double max = + fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości + double map1l = max > 0.0 ? + side / max : + 0.484375; // obcięcie tekstury od lewej strony punktu 1 + double map1r = max > 0.0 ? + slop / max : + 0.484375; // obcięcie tekstury od prawej strony punktu 1 + rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y - fTexHeight1, + 0.515625 + map1r); // prawy brzeg prawego chodnika + rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y - fTexHeight1, + 0.515625); // prawy krawężnik u góry + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, + 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, + 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y - fTexHeight1, + 0.484375); // lewy krawężnik u góry + rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y - fTexHeight1, + 0.484375 - map1l); // lewy brzeg lewego chodnika + // if (iTrapezoid) //trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony + // odcinka + slop2 = + fabs((iTrapezoid & 2) ? slop2 : slop); // szerokość chodnika po prawej + double map2l = max > 0.0 ? + side2 / max : + 0.484375; // obcięcie tekstury od lewej strony punktu 2 + double map2r = max > 0.0 ? + slop2 / max : + 0.484375; // obcięcie tekstury od prawej strony punktu 2 + rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y - fTexHeight2, + 0.515625 + map2r); // prawy brzeg prawego chodnika + rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y - fTexHeight2, + 0.515625); // prawy krawężnik u góry + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, + 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, + 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y - fTexHeight2, + 0.484375); // lewy krawężnik u góry + rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y - fTexHeight2, + 0.484375 - map2l); // lewy brzeg lewego chodnika + } + } + bool render = TextureID2 ? (tex ? TextureID2 == tex : true) : + false; // renderować nie trzeba, ale trzeba wyznaczyć + // punkty brzegowe nawierzchni + // if (iTrapezoid) //trapez albo przechyłki + if (SwitchExtension->iRoads == 4) + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka + if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) + SwitchExtension->Segments[2]->RenderLoft( + rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej + if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) + SwitchExtension->Segments[3]->RenderLoft( + rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej + if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) + SwitchExtension->Segments[4]->RenderLoft( + rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej + if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) + SwitchExtension->Segments[5]->RenderLoft( + rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej + } + else // to będzie ewentualnie dla prostego na skrzyżowaniu trzech dróg + { // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być + // prostoliniowe + if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK + SwitchExtension->Segments[2]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b, + render); // z P2 do P4 + if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK + SwitchExtension->Segments[1]->RenderLoft( + rpts2, -3, fTexLength, 0, 1, &b, render); // z P4 do P3=P1 (odwrócony) + if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK + SwitchExtension->Segments[0]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b, + render); // z P1 do P2 + /* + if ((fTexHeight1>=0.0)?true:(slop!=0.0)) + Segment->RenderLoft(rpts1,3,fTexLength); + if ((fTexHeight1>=0.0)?true:(side!=0.0)) + Segment->RenderLoft(rpts2,3,fTexLength); + */ + } + } + // renderowanie nawierzchni na końcu + double sina0 = sin(a[0]), cosa0 = cos(a[0]); + double u, v; + if (!SwitchExtension->bPoints) // jeśli tablica nie wypełniona + if (b) // ale jest wskaźnik do tablicy - może nie być? + { // coś się gubi w obliczeniach na wskaźnikach + i = (int((void *)(b)) - int((void *)(SwitchExtension->vPoints))) / + sizeof(vector3); // ustalenie liczby punktów, bo mogło wyjść inaczej niż + // policzone z góry + if (i > 0) + { // jeśli zostało to właśnie utworzone + if (SwitchExtension->iPoints > i) // jeśli wyszło mniej niż było miejsca + SwitchExtension->iPoints = i; // domknięcie wachlarza + else + --SwitchExtension->iPoints; // jak tutaj wejdzie, to błąd jest - zrobić + // miejsce na powtórzenie pierwszego punktu + // na końcu + SwitchExtension->vPoints[SwitchExtension->iPoints++] = + SwitchExtension->vPoints[0]; + SwitchExtension->bPoints = true; // tablica punktów została wypełniona + } + } + if (TextureID1) // jeśli podana tekstura nawierzchni + if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) + { + if (!tex) + glBindTexture(GL_TEXTURE_2D, TextureID1); + glBegin(GL_TRIANGLE_FAN); // takie kółeczko będzie + glNormal3f(0, 1, 0); + glTexCoord2f(0.5, 0.5); //środek tekstury na środku skrzyżowania + glVertex3f(oxz.x, oxz.y, oxz.z); + for (i = SwitchExtension->iPoints - 1; i >= 0; --i) + // for (i=0;iiPoints;++i) + { + glNormal3f(0, 1, 0); + u = (SwitchExtension->vPoints[i].x - oxz.x) / + fTexLength; // mapowanie we współrzędnych scenerii + v = (SwitchExtension->vPoints[i].z - oxz.z) / (fTexRatio1 * fTexLength); + glTexCoord2f(cosa0 * u + sina0 * v + 0.5, -sina0 * u + cosa0 * v + 0.5); + glVertex3f(SwitchExtension->vPoints[i].x, SwitchExtension->vPoints[i].y, + SwitchExtension->vPoints[i].z); + } + glEnd(); + } + break; + } + } + break; + case 4: // McZapkie-260302 - rzeka- rendering + // Ra: rzeki na razie bez zmian, przechyłki na pewno nie mają + // Ra: przemyśleć wyrównanie u góry trawą do czworoboku + vector6 bpts1[numPts] = {vector6(fHTW, 0.0, 0.0), vector6(fHTW, 0.2, 0.33), + vector6(-fHTW, 0.0, 0.67), vector6(-fHTW, 0.0, 1.0)}; + // Ra: dziwnie ten kształt wygląda + if (TextureID1) + if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) + { + if (!tex) + glBindTexture(GL_TEXTURE_2D, TextureID1); + Segment->RenderLoft(bpts1, numPts, fTexLength); + } + if (TextureID2) + if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex) + { // brzegi rzeki prawie jak pobocze derogi, tylko inny znak ma wysokość + // znak jest zmieniany przy wczytywaniu, więc tu musi byc minus fTexHeight + vector6 rpts1[3] = {vector6(rozp, -fTexHeight1, 0.0), + vector6(fHTW + side, 0.0, 0.5), vector6(fHTW, 0.0, 1.0)}; + vector6 rpts2[3] = {vector6(-fHTW, 0.0, 1.0), vector6(-fHTW - side, 0.0, 0.5), + vector6(-rozp, -fTexHeight1, 0.0)}; // Ra: po kiego 0.1? + if (!tex) + glBindTexture(GL_TEXTURE_2D, TextureID2); // brzeg rzeki + Segment->RenderLoft(rpts1, 3, fTexLength); + Segment->RenderLoft(rpts2, 3, fTexLength); + } + break; } - break; - } - if (!tex) - if (Global::bManageNodes) - glEndList(); + if (!tex) + if (Global::bManageNodes) + glEndList(); }; void TTrack::Release() { - if (DisplayListID) - glDeleteLists(DisplayListID,1); - DisplayListID=0; + if (DisplayListID) + glDeleteLists(DisplayListID, 1); + DisplayListID = 0; }; void __fastcall TTrack::Render() { - if (bVisible) //Ra: tory są renderowane sektorami i nie ma sensu każdorazowo liczyć odległości - { - if (!DisplayListID) - { - Compile(); - if (Global::bManageNodes) - ResourceManager::Register(this); - }; - SetLastUsage(Timer::GetSimulationTime()); - EnvironmentSet(); //oświetlenie nie może być skompilowane, bo może się zmieniać z czasem - glCallList(DisplayListID); - EnvironmentReset(); //ustawienie oświetlenia na zwykłe - if (InMovement()) Release(); //zwrotnica w trakcie animacji do odrysowania - }; + if (bVisible) // Ra: tory są renderowane sektorami i nie ma sensu każdorazowo liczyć odległości + { + if (!DisplayListID) + { + Compile(); + if (Global::bManageNodes) + ResourceManager::Register(this); + }; + SetLastUsage(Timer::GetSimulationTime()); + EnvironmentSet(); // oświetlenie nie może być skompilowane, bo może się zmieniać z czasem + glCallList(DisplayListID); + EnvironmentReset(); // ustawienie oświetlenia na zwykłe + if (InMovement()) + Release(); // zwrotnica w trakcie animacji do odrysowania + }; //#ifdef _DEBUG #if 0 if (DebugModeFlag && ScannedFlag) //McZapkie-230702 @@ -1575,1044 +1869,1314 @@ void __fastcall TTrack::Render() ScannedFlag=false; } #endif - //glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); - //glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); - //glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); + // glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); + // glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); + // glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); }; bool __fastcall TTrack::CheckDynamicObject(TDynamicObject *Dynamic) -{//sprawdzenie, czy pojazd jest przypisany do toru - for (int i=0;iasName!="none") - Global::pGround->WyslijString(pMyNode->asName,9); //przekazanie informacji o zwolnieniu toru - return true; - } - } - Error("Cannot remove dynamic from track"); - return false; +{ // usunięcie pojazdu z listy przypisanych do toru + for (int i = 0; i < iNumDynamics; i++) + { // sprawdzanie wszystkich po kolei + if (Dynamic == Dynamics[i]) + { // znaleziony, przepisanie następnych, żeby dziur nie było + --iNumDynamics; + for (i; i < iNumDynamics; i++) + Dynamics[i] = Dynamics[i + 1]; + if (Global::iMultiplayer) // jeśli multiplayer + if (!iNumDynamics) // jeśli już nie ma żadnego + if (pMyNode->asName != "none") + Global::pGround->WyslijString( + pMyNode->asName, 9); // przekazanie informacji o zwolnieniu toru + return true; + } + } + Error("Cannot remove dynamic from track"); + return false; } bool __fastcall TTrack::InMovement() -{//tory animowane (zwrotnica, obrotnica) mają SwitchExtension - if (SwitchExtension) - {if (eType==tt_Switch) - return SwitchExtension->bMovement; //ze zwrotnicą łatwiej - if (eType==tt_Table) - if (SwitchExtension->pModel) - {if (!SwitchExtension->CurrentIndex) return false; //0=zablokowana się nie animuje - //trzeba każdorazowo porównywać z kątem modelu - TAnimContainer *ac=SwitchExtension->pModel?SwitchExtension->pModel->GetContainer(NULL):NULL; - return ac?(ac->AngleGet()!=SwitchExtension->fOffset)||!(ac->TransGet()==SwitchExtension->vTrans):false; - //return true; //jeśli jest taki obiekt - } - } - return false; +{ // tory animowane (zwrotnica, obrotnica) mają SwitchExtension + if (SwitchExtension) + { + if (eType == tt_Switch) + return SwitchExtension->bMovement; // ze zwrotnicą łatwiej + if (eType == tt_Table) + if (SwitchExtension->pModel) + { + if (!SwitchExtension->CurrentIndex) + return false; // 0=zablokowana się nie animuje + // trzeba każdorazowo porównywać z kątem modelu + TAnimContainer *ac = + SwitchExtension->pModel ? SwitchExtension->pModel->GetContainer(NULL) : NULL; + return ac ? + (ac->AngleGet() != SwitchExtension->fOffset) || + !(ac->TransGet() == SwitchExtension->vTrans) : + false; + // return true; //jeśli jest taki obiekt + } + } + return false; }; -void __fastcall TTrack::RaAssign(TGroundNode *gn,TAnimContainer *ac) -{//Ra: wiązanie toru z modelem obrotnicy - //if (eType==tt_Table) SwitchExtension->pAnim=p; +void __fastcall TTrack::RaAssign(TGroundNode *gn, TAnimContainer *ac){ + // Ra: wiązanie toru z modelem obrotnicy + // if (eType==tt_Table) SwitchExtension->pAnim=p; }; -void __fastcall TTrack::RaAssign(TGroundNode *gn,TAnimModel *am,TEvent *done,TEvent *joined) -{//Ra: wiązanie toru z modelem obrotnicy - if (eType==tt_Table) - {SwitchExtension->pModel=am; - SwitchExtension->pMyNode=gn; - SwitchExtension->evMinus=done; //event zakończenia animacji (zadanie nowej przedłuża) - SwitchExtension->evPlus=joined; //event potwierdzenia połączenia (gdy nie znajdzie, to się nie połączy) - if (am) - if (am->GetContainer(NULL)) //może nie być? - am->GetContainer(NULL)->EventAssign(done); //zdarzenie zakończenia animacji - } +void __fastcall TTrack::RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joined) +{ // Ra: wiązanie toru z modelem obrotnicy + if (eType == tt_Table) + { + SwitchExtension->pModel = am; + SwitchExtension->pMyNode = gn; + SwitchExtension->evMinus = done; // event zakończenia animacji (zadanie nowej przedłuża) + SwitchExtension->evPlus = + joined; // event potwierdzenia połączenia (gdy nie znajdzie, to się nie połączy) + if (am) + if (am->GetContainer(NULL)) // może nie być? + am->GetContainer(NULL)->EventAssign(done); // zdarzenie zakończenia animacji + } }; int __fastcall TTrack::RaArrayPrepare() -{//przygotowanie tablic do skopiowania do VBO (zliczanie wierzchołków) - if (bVisible) //o ile w ogóle widać - switch (iCategoryFlag&15) - { - case 1: //tor - if (eType==tt_Switch) //dla zwrotnicy tylko szyny - return 48*((TextureID1?SwitchExtension->Segments[0]->RaSegCount():0)+(TextureID2?SwitchExtension->Segments[1]->RaSegCount():0)); - else //dla toru podsypka plus szyny - return (Segment->RaSegCount())*((TextureID1?48:0)+(TextureID2?8:0)); - case 2: //droga - if (eType==tt_Cross) //tylko dla skrzyżowania dróg - {//specjalny sposób obliczania liczby wierzchołków w skrzyżowaniu - //int n=0; //wierzchołki wewnętrzne do generowania nawierzchni - //int b=0; //wierzchołki do generowania boków - if (fTexHeight1>=0) //jeśli fTexHeight1<0, to są chodniki i może któregoś nie być - {//normalne pobocze, na razie się składa z - return (Segment->RaSegCount())*((TextureID1?4:0)+(TextureID2?12:0)); - } - else - return (Segment->RaSegCount())*((TextureID1?4:0)+(TextureID2?(fTexWidth!=0.0?6:0)+(fTexSlope!=0.0?6:0):0)); - } - else //standardowo dla zwykłej drogi - if (fTexHeight1>=0) //jeśli fTexHeight1<0, to są chodniki i może któregoś nie być - return (Segment->RaSegCount())*((TextureID1?4:0)+(TextureID2?12:0)); //może nie być poziomego! - else - return (Segment->RaSegCount())*((TextureID1?4:0)+(TextureID2?(fTexWidth!=0.0?6:0)+(fTexSlope!=0.0?6:0):0)); - case 4: //rzeki do przemyślenia - return (Segment->RaSegCount())*((TextureID1?4:0)+(TextureID2?12:0)); - } - return 0; +{ // przygotowanie tablic do skopiowania do VBO (zliczanie wierzchołków) + if (bVisible) // o ile w ogóle widać + switch (iCategoryFlag & 15) + { + case 1: // tor + if (eType == tt_Switch) // dla zwrotnicy tylko szyny + return 48 * ((TextureID1 ? SwitchExtension->Segments[0]->RaSegCount() : 0) + + (TextureID2 ? SwitchExtension->Segments[1]->RaSegCount() : 0)); + else // dla toru podsypka plus szyny + return (Segment->RaSegCount()) * ((TextureID1 ? 48 : 0) + (TextureID2 ? 8 : 0)); + case 2: // droga + if (eType == tt_Cross) // tylko dla skrzyżowania dróg + { // specjalny sposób obliczania liczby wierzchołków w skrzyżowaniu + // int n=0; //wierzchołki wewnętrzne do generowania nawierzchni + // int b=0; //wierzchołki do generowania boków + if (fTexHeight1 >= 0) // jeśli fTexHeight1<0, to są chodniki i może któregoś nie być + { // normalne pobocze, na razie się składa z + return (Segment->RaSegCount()) * ((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0)); + } + else + return (Segment->RaSegCount()) * + ((TextureID1 ? 4 : 0) + + (TextureID2 ? (fTexWidth != 0.0 ? 6 : 0) + (fTexSlope != 0.0 ? 6 : 0) : + 0)); + } + else // standardowo dla zwykłej drogi + if (fTexHeight1 >= 0) // jeśli fTexHeight1<0, to są chodniki i może któregoś nie być + return (Segment->RaSegCount()) * + ((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0)); // może nie być poziomego! + else + return (Segment->RaSegCount()) * + ((TextureID1 ? 4 : 0) + + (TextureID2 ? (fTexWidth != 0.0 ? 6 : 0) + (fTexSlope != 0.0 ? 6 : 0) : 0)); + case 4: // rzeki do przemyślenia + return (Segment->RaSegCount()) * ((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0)); + } + return 0; }; -void __fastcall TTrack::RaArrayFill(CVertNormTex *Vert,const CVertNormTex *Start) -{//wypełnianie tablic VBO - //Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur - double fHTW=0.5*fabs(fTrackWidth); - double side=fabs(fTexWidth); //szerokść podsypki na zewnątrz szyny albo pobocza - double slop=fabs(fTexSlope); //brzeg zewnętrzny - double rozp=fHTW+side+slop; //brzeg zewnętrzny - double hypot1=hypot(slop,fTexHeight1); //rozmiar pochylenia do liczenia normalnych - if (hypot1==0.0) hypot1=1.0; - vector3 normal1=vector3(fTexSlope/hypot1,fTexHeight1/hypot1,0.0); //wektor normalny - double fHTW2,side2,slop2,rozp2,fTexHeight2,hypot2; - vector3 normal2; - if (iTrapezoid&2) //ten bit oznacza, że istnieje odpowiednie pNext - {//Ra: jest OK - fHTW2=0.5*fabs(trNext->fTrackWidth); //połowa rozstawu/nawierzchni - side2=fabs(trNext->fTexWidth); - slop2=fabs(trNext->fTexSlope); //nie jest używane później - rozp2=fHTW2+side2+slop2; - fTexHeight2=trNext->fTexHeight1; - hypot2=hypot(slop2,fTexHeight2); - if (hypot2==0.0) hypot2=1.0; - normal2=vector3(trNext->fTexSlope/hypot2,fTexHeight2/hypot2,0.0); - } - else //gdy nie ma następnego albo jest nieodpowiednim końcem podpięty - {fHTW2=fHTW; side2=side; slop2=slop; rozp2=rozp; fTexHeight2=fTexHeight1; hypot2=hypot1; normal2=normal1;} - double roll1,roll2; - switch (iCategoryFlag&15) - { - case 1: //tor - { - if (Segment) - Segment->GetRolls(roll1,roll2); - else - roll1=roll2=0.0; //dla zwrotnic - double sin1=sin(roll1),cos1=cos(roll1),sin2=sin(roll2),cos2=cos(roll2); - // zwykla szyna: //Ra: czemu główki są asymetryczne na wysokości 0.140? - vector6 rpts1[24],rpts2[24],rpts3[24],rpts4[24]; - int i; - for (i=0;i<12;++i) - {rpts1[i] =vector6(( fHTW+szyna[i].x)*cos1+szyna[i].y*sin1,-( fHTW+szyna[i].x)*sin1+szyna[i].y*cos1,szyna[i].z ,+szyna[i].n.x*cos1+szyna[i].n.y*sin1,-szyna[i].n.x*sin1+szyna[i].n.y*cos1,0.0); - rpts2[11-i]=vector6((-fHTW-szyna[i].x)*cos1+szyna[i].y*sin1,-(-fHTW-szyna[i].x)*sin1+szyna[i].y*cos1,szyna[i].z ,-szyna[i].n.x*cos1+szyna[i].n.y*sin1,+szyna[i].n.x*sin1+szyna[i].n.y*cos1,0.0); - } - if (iTrapezoid) //trapez albo przechyłki, to oddzielne punkty na końcu - for (i=0;i<12;++i) - {rpts1[12+i]=vector6(( fHTW2+szyna[i].x)*cos2+szyna[i].y*sin2,-( fHTW2+szyna[i].x)*sin2+szyna[i].y*cos2,szyna[i].z ,+szyna[i].n.x*cos2+szyna[i].n.y*sin2,-szyna[i].n.x*sin2+szyna[i].n.y*cos2,0.0); - rpts2[23-i]=vector6((-fHTW2-szyna[i].x)*cos2+szyna[i].y*sin2,-(-fHTW2-szyna[i].x)*sin2+szyna[i].y*cos2,szyna[i].z ,-szyna[i].n.x*cos2+szyna[i].n.y*sin2,+szyna[i].n.x*sin2+szyna[i].n.y*cos2,0.0); +void __fastcall TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) +{ // wypełnianie tablic VBO + // Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur + double fHTW = 0.5 * fabs(fTrackWidth); + double side = fabs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza + double slop = fabs(fTexSlope); // brzeg zewnętrzny + double rozp = fHTW + side + slop; // brzeg zewnętrzny + double hypot1 = hypot(slop, fTexHeight1); // rozmiar pochylenia do liczenia normalnych + if (hypot1 == 0.0) + hypot1 = 1.0; + vector3 normal1 = vector3(fTexSlope / hypot1, fTexHeight1 / hypot1, 0.0); // wektor normalny + double fHTW2, side2, slop2, rozp2, fTexHeight2, hypot2; + vector3 normal2; + if (iTrapezoid & 2) // ten bit oznacza, że istnieje odpowiednie pNext + { // Ra: jest OK + fHTW2 = 0.5 * fabs(trNext->fTrackWidth); // połowa rozstawu/nawierzchni + side2 = fabs(trNext->fTexWidth); + slop2 = fabs(trNext->fTexSlope); // nie jest używane później + rozp2 = fHTW2 + side2 + slop2; + fTexHeight2 = trNext->fTexHeight1; + hypot2 = hypot(slop2, fTexHeight2); + if (hypot2 == 0.0) + hypot2 = 1.0; + normal2 = vector3(trNext->fTexSlope / hypot2, fTexHeight2 / hypot2, 0.0); } - switch (eType) //dalej zależnie od typu - { - case tt_Table: //obrotnica jak zwykły tor, tylko animacja dochodzi - SwitchExtension->iLeftVBO=Vert-Start; //indeks toru obrotnicy - case tt_Normal: - if (TextureID2) - {//podsypka z podkładami jest tylko dla zwykłego toru - vector6 bpts1[8]; //punkty głównej płaszczyzny nie przydają się do robienia boków - if (fTexLength==4.0) //jeśli stare mapowanie - {//stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil - if (iTrapezoid) //trapez albo przechyłki - {//podsypka z podkladami trapezowata - //ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 ((0.3464,0.6536) - //bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu - bpts1[0]=vector6(rozp, -fTexHeight1-0.18, 0.00,-0.707,0.707,0.0); //lewy brzeg - bpts1[1]=vector6((fHTW+side)*cos1, -(fHTW+side)*sin1-0.18, 0.33,-0.707,0.707,0.0); //krawędź załamania - bpts1[2]=vector6(-bpts1[1].x, +(fHTW+side)*sin1-0.18, 0.67,0.707,0.707,0.0); //prawy brzeg początku symetrycznie - bpts1[3]=vector6(-rozp, -fTexHeight1-0.18, 1.00,0.707,0.707,0.0); //prawy skos - //końcowy przekrój - bpts1[4]=vector6(rozp2, -fTexHeight2-0.18, 0.00,-0.707,0.707,0.0); //lewy brzeg - bpts1[5]=vector6((fHTW2+side2)*cos2,-(fHTW2+side2)*sin2-0.18,0.33,-0.707,0.707,0.0); //krawędź załamania - bpts1[6]=vector6(-bpts1[5].x, +(fHTW2+side2)*sin2-0.18,0.67,0.707,0.707,0.0); //prawy brzeg początku symetrycznie - bpts1[7]=vector6(-rozp2, -fTexHeight2-0.18, 1.00,0.707,0.707,0.0); //prawy skos - } - else - {bpts1[0]=vector6(rozp, -fTexHeight1-0.18,0.0,-0.707,0.707,0.0); //lewy brzeg - bpts1[1]=vector6(fHTW+side, -0.18,0.33,-0.707,0.707,0.0); //krawędź załamania - bpts1[2]=vector6(-fHTW-side,-0.18,0.67,0.707,0.707,0.0); //druga - bpts1[3]=vector6(-rozp, -fTexHeight1-0.18,1.0,0.707,0.707,0.0); //prawy skos - } - } - else - {//mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa fTexLength - double max=fTexRatio2*fTexLength; //szerokość proporcjonalna do długości - double map11=max>0.0?(fHTW+side)/max:0.25; //załamanie od strony 1 - double map12=max>0.0?(fHTW+side+hypot1)/max:0.5; //brzeg od strony 1 - if (iTrapezoid) //trapez albo przechyłki - {//podsypka z podkladami trapezowata - double map21=max>0.0?(fHTW2+side2)/max:0.25; //załamanie od strony 2 - double map22=max>0.0?(fHTW2+side2+hypot2)/max:0.5; //brzeg od strony 2 - //ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 ((0.3464,0.6536) - //bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu - bpts1[0]=vector6(rozp, -fTexHeight1-0.18 ,0.5-map12,normal1.x,-normal1.y,0.0); //lewy brzeg - bpts1[1]=vector6((fHTW+side)*cos1, -(fHTW+side)*sin1-0.18 ,0.5-map11,0.0,1.0,0.0); //krawędź załamania - bpts1[2]=vector6(-bpts1[1].x, +(fHTW+side)*sin1-0.18 ,0.5+map11,0.0,1.0,0.0); //prawy brzeg początku symetrycznie - bpts1[3]=vector6(-rozp, -fTexHeight1-0.18 ,0.5+map12,-normal1.x,-normal1.y,0.0); //prawy skos - //przekrój końcowy - bpts1[4]=vector6(rozp2, -fTexHeight2-0.18 ,0.5-map22,normal2.x,-normal2.y,0.0); //lewy brzeg - bpts1[5]=vector6((fHTW2+side2)*cos2,-(fHTW2+side2)*sin2-0.18,0.5-map21,0.0,1.0,0.0); //krawędź załamania - bpts1[6]=vector6(-bpts1[5].x, +(fHTW2+side2)*sin2-0.18,0.5+map21,0.0,1.0,0.0); //prawy brzeg początku symetrycznie - bpts1[7]=vector6(-rozp2, -fTexHeight2-0.18 ,0.5+map22,-normal2.x,-normal2.y,0.0); //prawy skos - } - else - {bpts1[0]=vector6(rozp, -fTexHeight1-0.18,0.5-map12,+normal1.x,-normal1.y,0.0); //lewy brzeg - bpts1[1]=vector6(fHTW+side, -0.18 ,0.5-map11,+normal1.x,-normal1.y,0.0); //krawędź załamania - bpts1[2]=vector6(-fHTW-side,-0.18 ,0.5+map11,-normal1.x,-normal1.y,0.0); //druga - bpts1[3]=vector6(-rozp, -fTexHeight1-0.18,0.5+map12,-normal1.x,-normal1.y,0.0); //prawy skos - } - } - Segment->RaRenderLoft(Vert,bpts1,iTrapezoid?-4:4,fTexLength); - } - if (TextureID1) - {// szyny - generujemy dwie, najwyżej rysować się będzie jedną - Segment->RaRenderLoft(Vert,rpts1,iTrapezoid?-nnumPts:nnumPts,fTexLength); - Segment->RaRenderLoft(Vert,rpts2,iTrapezoid?-nnumPts:nnumPts,fTexLength); - } - break; - case tt_Switch: //dla zwrotnicy dwa razy szyny - if (TextureID1) //Ra: !!!! tu jest do poprawienia - {//iglice liczone tylko dla zwrotnic - vector6 rpts3[24],rpts4[24]; - for (i=0;i<12;++i) - {rpts3[i] =vector6(+(fHTW+iglica[i].x)*cos1+iglica[i].y*sin1,-(+fHTW+iglica[i].x)*sin1+iglica[i].y*cos1,iglica[i].z); - rpts3[i+12]=vector6(+(fHTW2+szyna[i].x)*cos2+ szyna[i].y*sin2,-(+fHTW2+szyna[i].x)*sin2+iglica[i].y*cos2, szyna[i].z); - rpts4[11-i]=vector6((-fHTW-iglica[i].x)*cos1+iglica[i].y*sin1,-(-fHTW-iglica[i].x)*sin1+iglica[i].y*cos1,iglica[i].z); - rpts4[23-i]=vector6((-fHTW2-szyna[i].x)*cos2+ szyna[i].y*sin2,-(-fHTW2-szyna[i].x)*sin2+iglica[i].y*cos2, szyna[i].z); - } - if (SwitchExtension->RightSwitch) - {//nowa wersja z SPKS, ale odwrotnie lewa/prawa - SwitchExtension->iLeftVBO=Vert-Start; //indeks lewej iglicy - SwitchExtension->Segments[0]->RaRenderLoft(Vert,rpts3,-nnumPts,fTexLength,0,2,SwitchExtension->fOffset2); - SwitchExtension->Segments[0]->RaRenderLoft(Vert,rpts1,nnumPts,fTexLength,2); - SwitchExtension->Segments[0]->RaRenderLoft(Vert,rpts2,nnumPts,fTexLength); - SwitchExtension->Segments[1]->RaRenderLoft(Vert,rpts1,nnumPts,fTexLength); - SwitchExtension->iRightVBO=Vert-Start; //indeks prawej iglicy - SwitchExtension->Segments[1]->RaRenderLoft(Vert,rpts4,-nnumPts,fTexLength,0,2,-fMaxOffset+SwitchExtension->fOffset1); - SwitchExtension->Segments[1]->RaRenderLoft(Vert,rpts2,nnumPts,fTexLength,2); - } - else - {//lewa działa lepiej niż prawa - SwitchExtension->Segments[0]->RaRenderLoft(Vert,rpts1,nnumPts,fTexLength); //lewa szyna normalna cała - SwitchExtension->iLeftVBO=Vert-Start; //indeks lewej iglicy - SwitchExtension->Segments[0]->RaRenderLoft(Vert,rpts4,-nnumPts,fTexLength,0,2,-SwitchExtension->fOffset2); //prawa iglica - SwitchExtension->Segments[0]->RaRenderLoft(Vert,rpts2,nnumPts,fTexLength,2); //prawa szyna za iglicą - SwitchExtension->iRightVBO=Vert-Start; //indeks prawej iglicy - SwitchExtension->Segments[1]->RaRenderLoft(Vert,rpts3,-nnumPts,fTexLength,0,2,fMaxOffset-SwitchExtension->fOffset1); //lewa iglica - SwitchExtension->Segments[1]->RaRenderLoft(Vert,rpts1,nnumPts,fTexLength,2); //lewa szyna za iglicą - SwitchExtension->Segments[1]->RaRenderLoft(Vert,rpts2,nnumPts,fTexLength); //prawa szyna normalnie cała - } - } - break; - } - } //koniec obsługi torów - break; - case 2: //McZapkie-260302 - droga - rendering - switch (eType) //dalej zależnie od typu - { - case tt_Normal: //drogi proste, bo skrzyżowania osobno - {vector6 bpts1[4]; //punkty głównej płaszczyzny przydają się do robienia boków - if (TextureID1||TextureID2) //punkty się przydadzą, nawet jeśli nawierzchni nie ma - {//double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% - double max=(iCategoryFlag&4)?0.0:fTexLength; //test: szerokość dróg proporcjonalna do długości - double map1=max>0.0?fHTW/max:0.5; //obcięcie tekstury od strony 1 - double map2=max>0.0?fHTW2/max:0.5; //obcięcie tekstury od strony 2 - if (iTrapezoid) //trapez albo przechyłki - {//nawierzchnia trapezowata - Segment->GetRolls(roll1,roll2); - bpts1[0]=vector6(fHTW*cos(roll1),-fHTW*sin(roll1),0.5-map1); //lewy brzeg początku - bpts1[1]=vector6(-bpts1[0].x,-bpts1[0].y,0.5+map1); //prawy brzeg początku symetrycznie - bpts1[2]=vector6(fHTW2*cos(roll2),-fHTW2*sin(roll2),0.5-map2); //lewy brzeg końca - bpts1[3]=vector6(-bpts1[2].x,-bpts1[2].y,0.5+map2); //prawy brzeg początku symetrycznie - } - else - {bpts1[0]=vector6( fHTW,0.0,0.5-map1); //zawsze standardowe mapowanie - bpts1[1]=vector6(-fHTW,0.0,0.5+map1); - } - } - if (TextureID1) //jeśli podana była tekstura, generujemy trójkąty - {//tworzenie trójkątów nawierzchni szosy - Segment->RaRenderLoft(Vert,bpts1,iTrapezoid?-2:2,fTexLength); - } - if (TextureID2) - {//pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) - vector6 rpts1[6],rpts2[6]; //współrzędne przekroju i mapowania dla prawej i lewej strony - if (fTexHeight1>=0.0) - {//standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo - rpts1[0]=vector6(rozp,-fTexHeight1,0.0); //lewy brzeg podstawy - rpts1[1]=vector6(bpts1[0].x+side,bpts1[0].y,0.5), //lewa krawędź załamania - rpts1[2]=vector6(bpts1[0].x,bpts1[0].y,1.0); //lewy brzeg pobocza (mapowanie może być inne - rpts2[0]=vector6(bpts1[1].x,bpts1[1].y,1.0); //prawy brzeg pobocza - rpts2[1]=vector6(bpts1[1].x-side,bpts1[1].y,0.5); //prawa krawędź załamania - rpts2[2]=vector6(-rozp,-fTexHeight1,0.0); //prawy brzeg podstawy - if (iTrapezoid) //trapez albo przechyłki - {//pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - rpts1[3]=vector6(rozp2,-fTexHeight2,0.0); //lewy brzeg lewego pobocza - rpts1[4]=vector6(bpts1[2].x+side2,bpts1[2].y,0.5); //krawędź załamania - rpts1[5]=vector6(bpts1[2].x,bpts1[2].y,1.0); //brzeg pobocza - rpts2[3]=vector6(bpts1[3].x,bpts1[3].y,1.0); - rpts2[4]=vector6(bpts1[3].x-side2,bpts1[3].y,0.5); - rpts2[5]=vector6(-rozp2,-fTexHeight2,0.0); //prawy brzeg prawego pobocza - Segment->RaRenderLoft(Vert,rpts1,-3,fTexLength); - Segment->RaRenderLoft(Vert,rpts2,-3,fTexLength); - } - else - {//pobocza zwykłe, brak przechyłki - Segment->RaRenderLoft(Vert,rpts1,3,fTexLength); - Segment->RaRenderLoft(Vert,rpts2,3,fTexLength); - } - } - else - {//wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości - //mapowanie propocjonalne do szerokości chodnika - //krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy - double d=-fTexHeight1/3.75; //krawężnik o wysokości 150mm jest pochylony 40mm - double max=fTexRatio2*fTexLength; //test: szerokość proporcjonalna do długości - double map1l=max>0.0?side/max:0.484375; //obcięcie tekstury od lewej strony punktu 1 - double map1r=max>0.0?slop/max:0.484375; //obcięcie tekstury od prawej strony punktu 1 - double h1r=(slop>d)?-fTexHeight1:0; - double h1l=(side>d)?-fTexHeight1:0; - rpts1[0]=vector6(bpts1[0].x+slop,bpts1[0].y+h1r,0.515625+map1r ); //prawy brzeg prawego chodnika - rpts1[1]=vector6(bpts1[0].x+d, bpts1[0].y+h1r,0.515625 ); //prawy krawężnik u góry - rpts1[2]=vector6(bpts1[0].x, bpts1[0].y, 0.515625-d/2.56); //prawy krawężnik u dołu - rpts2[0]=vector6(bpts1[1].x, bpts1[1].y, 0.484375+d/2.56); //lewy krawężnik u dołu - rpts2[1]=vector6(bpts1[1].x-d, bpts1[1].y+h1l,0.484375 ); //lewy krawężnik u góry - rpts2[2]=vector6(bpts1[1].x-side,bpts1[1].y+h1l,0.484375-map1l ); //lewy brzeg lewego chodnika - if (iTrapezoid) //trapez albo przechyłki - {//pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - slop2=fabs((iTrapezoid&2)?slop2:slop); //szerokość chodnika po prawej - double map2l=max>0.0?side2/max:0.484375; //obcięcie tekstury od lewej strony punktu 2 - double map2r=max>0.0?slop2/max:0.484375; //obcięcie tekstury od prawej strony punktu 2 - double h2r=(slop2>d)?-fTexHeight2:0; - double h2l=(side2>d)?-fTexHeight2:0; - rpts1[3]=vector6(bpts1[2].x+slop2,bpts1[2].y+h2r,0.515625+map2r ); //prawy brzeg prawego chodnika - rpts1[4]=vector6(bpts1[2].x+d, bpts1[2].y+h2r,0.515625 ); //prawy krawężnik u góry - rpts1[5]=vector6(bpts1[2].x, bpts1[2].y, 0.515625-d/2.56); //prawy krawężnik u dołu - rpts2[3]=vector6(bpts1[3].x, bpts1[3].y, 0.484375+d/2.56); //lewy krawężnik u dołu - rpts2[4]=vector6(bpts1[3].x-d, bpts1[3].y+h2l,0.484375 ); //lewy krawężnik u góry - rpts2[5]=vector6(bpts1[3].x-side2,bpts1[3].y+h2l,0.484375-map2l ); //lewy brzeg lewego chodnika - if (slop!=0.0) - Segment->RaRenderLoft(Vert,rpts1,-3,fTexLength); - if (side!=0.0) - Segment->RaRenderLoft(Vert,rpts2,-3,fTexLength); - } - else - {//pobocza zwykłe, brak przechyłki - if (slop!=0.0) - Segment->RaRenderLoft(Vert,rpts1,3,fTexLength); - if (side!=0.0) - Segment->RaRenderLoft(Vert,rpts2,3,fTexLength); - } - } - } + else // gdy nie ma następnego albo jest nieodpowiednim końcem podpięty + { + fHTW2 = fHTW; + side2 = side; + slop2 = slop; + rozp2 = rozp; + fTexHeight2 = fTexHeight1; + hypot2 = hypot1; + normal2 = normal1; } - } - break; - case 4: //Ra: rzeki na razie jak drogi, przechyłki na pewno nie mają - switch (eType) //dalej zależnie od typu - { - case tt_Normal: //drogi proste, bo skrzyżowania osobno - {vector6 bpts1[4]; //punkty głównej płaszczyzny przydają się do robienia boków - if (TextureID1||TextureID2) //punkty się przydadzą, nawet jeśli nawierzchni nie ma - {//double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% - double max=(iCategoryFlag&4)?0.0:fTexLength; //test: szerokość dróg proporcjonalna do długości - double map1=max>0.0?fHTW/max:0.5; //obcięcie tekstury od strony 1 - double map2=max>0.0?fHTW2/max:0.5; //obcięcie tekstury od strony 2 - if (iTrapezoid) //trapez albo przechyłki - {//nawierzchnia trapezowata - Segment->GetRolls(roll1,roll2); - bpts1[0]=vector6(fHTW*cos(roll1),-fHTW*sin(roll1),0.5-map1); //lewy brzeg początku - bpts1[1]=vector6(-bpts1[0].x,-bpts1[0].y,0.5+map1); //prawy brzeg początku symetrycznie - bpts1[2]=vector6(fHTW2*cos(roll2),-fHTW2*sin(roll2),0.5-map2); //lewy brzeg końca - bpts1[3]=vector6(-bpts1[2].x,-bpts1[2].y,0.5+map2); //prawy brzeg początku symetrycznie - } - else - {bpts1[0]=vector6( fHTW,0.0,0.5-map1); //zawsze standardowe mapowanie - bpts1[1]=vector6(-fHTW,0.0,0.5+map1); - } - } - if (TextureID1) //jeśli podana była tekstura, generujemy trójkąty - {//tworzenie trójkątów nawierzchni szosy - Segment->RaRenderLoft(Vert,bpts1,iTrapezoid?-2:2,fTexLength); - } - if (TextureID2) - {//pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) - vector6 rpts1[6],rpts2[6]; //współrzędne przekroju i mapowania dla prawej i lewej strony - rpts1[0]=vector6(rozp,-fTexHeight1,0.0); //lewy brzeg podstawy - rpts1[1]=vector6(bpts1[0].x+side,bpts1[0].y,0.5), //lewa krawędź załamania - rpts1[2]=vector6(bpts1[0].x,bpts1[0].y,1.0); //lewy brzeg pobocza (mapowanie może być inne - rpts2[0]=vector6(bpts1[1].x,bpts1[1].y,1.0); //prawy brzeg pobocza - rpts2[1]=vector6(bpts1[1].x-side,bpts1[1].y,0.5); //prawa krawędź załamania - rpts2[2]=vector6(-rozp,-fTexHeight1,0.0); //prawy brzeg podstawy - if (iTrapezoid) //trapez albo przechyłki - {//pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - rpts1[3]=vector6(rozp2,-fTexHeight2,0.0); //lewy brzeg lewego pobocza - rpts1[4]=vector6(bpts1[2].x+side2,bpts1[2].y,0.5); //krawędź załamania - rpts1[5]=vector6(bpts1[2].x,bpts1[2].y,1.0); //brzeg pobocza - rpts2[3]=vector6(bpts1[3].x,bpts1[3].y,1.0); - rpts2[4]=vector6(bpts1[3].x-side2,bpts1[3].y,0.5); - rpts2[5]=vector6(-rozp2,-fTexHeight2,0.0); //prawy brzeg prawego pobocza - Segment->RaRenderLoft(Vert,rpts1,-3,fTexLength); - Segment->RaRenderLoft(Vert,rpts2,-3,fTexLength); - } - else - {//pobocza zwykłe, brak przechyłki - Segment->RaRenderLoft(Vert,rpts1,3,fTexLength); - Segment->RaRenderLoft(Vert,rpts2,3,fTexLength); - } - } + double roll1, roll2; + switch (iCategoryFlag & 15) + { + case 1: // tor + { + if (Segment) + Segment->GetRolls(roll1, roll2); + else + roll1 = roll2 = 0.0; // dla zwrotnic + double sin1 = sin(roll1), cos1 = cos(roll1), sin2 = sin(roll2), cos2 = cos(roll2); + // zwykla szyna: //Ra: czemu główki są asymetryczne na wysokości 0.140? + vector6 rpts1[24], rpts2[24], rpts3[24], rpts4[24]; + int i; + for (i = 0; i < 12; ++i) + { + rpts1[i] = vector6((fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1, + -(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z, + +szyna[i].n.x * cos1 + szyna[i].n.y * sin1, + -szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0); + rpts2[11 - i] = vector6((-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1, + -(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z, + -szyna[i].n.x * cos1 + szyna[i].n.y * sin1, + +szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0); + } + if (iTrapezoid) // trapez albo przechyłki, to oddzielne punkty na końcu + for (i = 0; i < 12; ++i) + { + rpts1[12 + i] = vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, + -(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2, + szyna[i].z, +szyna[i].n.x * cos2 + szyna[i].n.y * sin2, + -szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0); + rpts2[23 - i] = vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, + -(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2, + szyna[i].z, -szyna[i].n.x * cos2 + szyna[i].n.y * sin2, + +szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0); + } + switch (eType) // dalej zależnie od typu + { + case tt_Table: // obrotnica jak zwykły tor, tylko animacja dochodzi + SwitchExtension->iLeftVBO = Vert - Start; // indeks toru obrotnicy + case tt_Normal: + if (TextureID2) + { // podsypka z podkładami jest tylko dla zwykłego toru + vector6 bpts1[8]; // punkty głównej płaszczyzny nie przydają się do robienia boków + if (fTexLength == 4.0) // jeśli stare mapowanie + { // stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy + // profil + if (iTrapezoid) // trapez albo przechyłki + { // podsypka z podkladami trapezowata + // ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 + // ((0.3464,0.6536) + // bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.00, -0.707, 0.707, + 0.0); // lewy brzeg + bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, 0.33, + -0.707, 0.707, 0.0); // krawędź załamania + bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.67, 0.707, + 0.707, 0.0); // prawy brzeg początku symetrycznie + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.00, 0.707, 0.707, + 0.0); // prawy skos + // końcowy przekrój + bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.00, -0.707, 0.707, + 0.0); // lewy brzeg + bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, + 0.33, -0.707, 0.707, 0.0); // krawędź załamania + bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.67, 0.707, + 0.707, 0.0); // prawy brzeg początku symetrycznie + bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 1.00, 0.707, 0.707, + 0.0); // prawy skos + } + else + { + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.0, -0.707, 0.707, + 0.0); // lewy brzeg + bpts1[1] = vector6(fHTW + side, -0.18, 0.33, -0.707, 0.707, + 0.0); // krawędź załamania + bpts1[2] = vector6(-fHTW - side, -0.18, 0.67, 0.707, 0.707, 0.0); // druga + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.0, 0.707, 0.707, + 0.0); // prawy skos + } + } + else + { // mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa fTexLength + double max = fTexRatio2 * fTexLength; // szerokość proporcjonalna do długości + double map11 = max > 0.0 ? (fHTW + side) / max : 0.25; // załamanie od strony 1 + double map12 = + max > 0.0 ? (fHTW + side + hypot1) / max : 0.5; // brzeg od strony 1 + if (iTrapezoid) // trapez albo przechyłki + { // podsypka z podkladami trapezowata + double map21 = + max > 0.0 ? (fHTW2 + side2) / max : 0.25; // załamanie od strony 2 + double map22 = + max > 0.0 ? (fHTW2 + side2 + hypot2) / max : 0.5; // brzeg od strony 2 + // ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 + // ((0.3464,0.6536) + // bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, normal1.x, + -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, + 0.5 - map11, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.5 + map11, + 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, + -normal1.y, 0.0); // prawy skos + // przekrój końcowy + bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.5 - map22, normal2.x, + -normal2.y, 0.0); // lewy brzeg + bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, + 0.5 - map21, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.5 + map21, + 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie + bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 0.5 + map22, -normal2.x, + -normal2.y, 0.0); // prawy skos + } + else + { + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, +normal1.x, + -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6(fHTW + side, -0.18, 0.5 - map11, +normal1.x, -normal1.y, + 0.0); // krawędź załamania + bpts1[2] = vector6(-fHTW - side, -0.18, 0.5 + map11, -normal1.x, -normal1.y, + 0.0); // druga + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, + -normal1.y, 0.0); // prawy skos + } + } + Segment->RaRenderLoft(Vert, bpts1, iTrapezoid ? -4 : 4, fTexLength); + } + if (TextureID1) + { // szyny - generujemy dwie, najwyżej rysować się będzie jedną + Segment->RaRenderLoft(Vert, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RaRenderLoft(Vert, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + } + break; + case tt_Switch: // dla zwrotnicy dwa razy szyny + if (TextureID1) // Ra: !!!! tu jest do poprawienia + { // iglice liczone tylko dla zwrotnic + vector6 rpts3[24], rpts4[24]; + for (i = 0; i < 12; ++i) + { + rpts3[i] = + vector6(+(fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, + -(+fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z); + rpts3[i + 12] = + vector6(+(fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, + -(+fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); + rpts4[11 - i] = + vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, + -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z); + rpts4[23 - i] = + vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, + -(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); + } + if (SwitchExtension->RightSwitch) + { // nowa wersja z SPKS, ale odwrotnie lewa/prawa + SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy + SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts3, -nnumPts, fTexLength, 0, + 2, SwitchExtension->fOffset2); + SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts1, nnumPts, fTexLength, 2); + SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts2, nnumPts, fTexLength); + SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts1, nnumPts, fTexLength); + SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy + SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts4, -nnumPts, fTexLength, 0, + 2, -fMaxOffset + + SwitchExtension->fOffset1); + SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts2, nnumPts, fTexLength, 2); + } + else + { // lewa działa lepiej niż prawa + SwitchExtension->Segments[0]->RaRenderLoft( + Vert, rpts1, nnumPts, fTexLength); // lewa szyna normalna cała + SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy + SwitchExtension->Segments[0]->RaRenderLoft( + Vert, rpts4, -nnumPts, fTexLength, 0, 2, + -SwitchExtension->fOffset2); // prawa iglica + SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts2, nnumPts, fTexLength, + 2); // prawa szyna za iglicą + SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy + SwitchExtension->Segments[1]->RaRenderLoft( + Vert, rpts3, -nnumPts, fTexLength, 0, 2, + fMaxOffset - SwitchExtension->fOffset1); // lewa iglica + SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts1, nnumPts, fTexLength, + 2); // lewa szyna za iglicą + SwitchExtension->Segments[1]->RaRenderLoft( + Vert, rpts2, nnumPts, fTexLength); // prawa szyna normalnie cała + } + } + break; + } + } // koniec obsługi torów + break; + case 2: // McZapkie-260302 - droga - rendering + switch (eType) // dalej zależnie od typu + { + case tt_Normal: // drogi proste, bo skrzyżowania osobno + { + vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków + if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma + { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% + double max = (iCategoryFlag & 4) ? + 0.0 : + fTexLength; // test: szerokość dróg proporcjonalna do długości + double map1 = max > 0.0 ? fHTW / max : 0.5; // obcięcie tekstury od strony 1 + double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obcięcie tekstury od strony 2 + if (iTrapezoid) // trapez albo przechyłki + { // nawierzchnia trapezowata + Segment->GetRolls(roll1, roll2); + bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), + 0.5 - map1); // lewy brzeg początku + bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, + 0.5 + map1); // prawy brzeg początku symetrycznie + bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), + 0.5 - map2); // lewy brzeg końca + bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, + 0.5 + map2); // prawy brzeg początku symetrycznie + } + else + { + bpts1[0] = vector6(fHTW, 0.0, 0.5 - map1); // zawsze standardowe mapowanie + bpts1[1] = vector6(-fHTW, 0.0, 0.5 + map1); + } + } + if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty + { // tworzenie trójkątów nawierzchni szosy + Segment->RaRenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); + } + if (TextureID2) + { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w + // Midtown Madness 2?) + vector6 rpts1[6], + rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony + if (fTexHeight1 >= 0.0) + { // standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo + rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy + rpts1[1] = + vector6(bpts1[0].x + side, bpts1[0].y, 0.5), // lewa krawędź załamania + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, + 1.0); // lewy brzeg pobocza (mapowanie może być inne + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza + rpts2[1] = + vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania + rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy + if (iTrapezoid) // trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony + // odcinka + rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza + rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź + // załamania + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); + rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); + rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego + // pobocza + Segment->RaRenderLoft(Vert, rpts1, -3, fTexLength); + Segment->RaRenderLoft(Vert, rpts2, -3, fTexLength); + } + else + { // pobocza zwykłe, brak przechyłki + Segment->RaRenderLoft(Vert, rpts1, 3, fTexLength); + Segment->RaRenderLoft(Vert, rpts2, 3, fTexLength); + } + } + else + { // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości + // mapowanie propocjonalne do szerokości chodnika + // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy + double d = + -fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm + double max = + fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości + double map1l = max > 0.0 ? + side / max : + 0.484375; // obcięcie tekstury od lewej strony punktu 1 + double map1r = max > 0.0 ? + slop / max : + 0.484375; // obcięcie tekstury od prawej strony punktu 1 + double h1r = (slop > d) ? -fTexHeight1 : 0; + double h1l = (side > d) ? -fTexHeight1 : 0; + rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y + h1r, + 0.515625 + map1r); // prawy brzeg prawego chodnika + rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y + h1r, + 0.515625); // prawy krawężnik u góry + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, + 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, + 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y + h1l, + 0.484375); // lewy krawężnik u góry + rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y + h1l, + 0.484375 - map1l); // lewy brzeg lewego chodnika + if (iTrapezoid) // trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony + // odcinka + slop2 = + fabs((iTrapezoid & 2) ? slop2 : slop); // szerokość chodnika po prawej + double map2l = max > 0.0 ? + side2 / max : + 0.484375; // obcięcie tekstury od lewej strony punktu 2 + double map2r = max > 0.0 ? + slop2 / max : + 0.484375; // obcięcie tekstury od prawej strony punktu 2 + double h2r = (slop2 > d) ? -fTexHeight2 : 0; + double h2l = (side2 > d) ? -fTexHeight2 : 0; + rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y + h2r, + 0.515625 + map2r); // prawy brzeg prawego chodnika + rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y + h2r, + 0.515625); // prawy krawężnik u góry + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, + 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, + 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y + h2l, + 0.484375); // lewy krawężnik u góry + rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y + h2l, + 0.484375 - map2l); // lewy brzeg lewego chodnika + if (slop != 0.0) + Segment->RaRenderLoft(Vert, rpts1, -3, fTexLength); + if (side != 0.0) + Segment->RaRenderLoft(Vert, rpts2, -3, fTexLength); + } + else + { // pobocza zwykłe, brak przechyłki + if (slop != 0.0) + Segment->RaRenderLoft(Vert, rpts1, 3, fTexLength); + if (side != 0.0) + Segment->RaRenderLoft(Vert, rpts2, 3, fTexLength); + } + } + } + } + } + break; + case 4: // Ra: rzeki na razie jak drogi, przechyłki na pewno nie mają + switch (eType) // dalej zależnie od typu + { + case tt_Normal: // drogi proste, bo skrzyżowania osobno + { + vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków + if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma + { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% + double max = (iCategoryFlag & 4) ? + 0.0 : + fTexLength; // test: szerokość dróg proporcjonalna do długości + double map1 = max > 0.0 ? fHTW / max : 0.5; // obcięcie tekstury od strony 1 + double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obcięcie tekstury od strony 2 + if (iTrapezoid) // trapez albo przechyłki + { // nawierzchnia trapezowata + Segment->GetRolls(roll1, roll2); + bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), + 0.5 - map1); // lewy brzeg początku + bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, + 0.5 + map1); // prawy brzeg początku symetrycznie + bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), + 0.5 - map2); // lewy brzeg końca + bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, + 0.5 + map2); // prawy brzeg początku symetrycznie + } + else + { + bpts1[0] = vector6(fHTW, 0.0, 0.5 - map1); // zawsze standardowe mapowanie + bpts1[1] = vector6(-fHTW, 0.0, 0.5 + map1); + } + } + if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty + { // tworzenie trójkątów nawierzchni szosy + Segment->RaRenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); + } + if (TextureID2) + { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w + // Midtown Madness 2?) + vector6 rpts1[6], + rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony + rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy + rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5), // lewa krawędź załamania + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, + 1.0); // lewy brzeg pobocza (mapowanie może być inne + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza + rpts2[1] = vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania + rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy + if (iTrapezoid) // trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka + rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza + rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź załamania + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); + rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); + rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza + Segment->RaRenderLoft(Vert, rpts1, -3, fTexLength); + Segment->RaRenderLoft(Vert, rpts2, -3, fTexLength); + } + else + { // pobocza zwykłe, brak przechyłki + Segment->RaRenderLoft(Vert, rpts1, 3, fTexLength); + Segment->RaRenderLoft(Vert, rpts2, 3, fTexLength); + } + } + } + } + break; } - } - break; - } }; -void __fastcall TTrack::RaRenderVBO(int iPtr) -{//renderowanie z użyciem VBO - //Ra 2014-07: trzeba wymienić GL_TRIANGLE_STRIP na GL_TRIANGLES i renderować trójkąty sektora dla kolejnych tekstur! - EnvironmentSet(); - int seg; - int i; - switch (iCategoryFlag&15) - { - case 1: //tor - if (eType==tt_Switch) //dla zwrotnicy tylko szyny - {if (TextureID1) - if ((seg=SwitchExtension->Segments[0]->RaSegCount())>0) - {glBindTexture(GL_TEXTURE_2D,TextureID1); //szyny + - for (i=0;iSegments[1]->RaSegCount())>0) - {glBindTexture(GL_TEXTURE_2D,TextureID2); //szyny - - for (i=0;iRaSegCount())>0) - {if (TextureID2) - {glBindTexture(GL_TEXTURE_2D,TextureID2); //podsypka - for (i=0;iSegments[0]->RaSegCount()) > 0) + { + glBindTexture(GL_TEXTURE_2D, TextureID1); // szyny + + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24); + iPtr += 24 * seg; // pominięcie lewej szyny + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24); + iPtr += 24 * seg; // pominięcie prawej szyny + } + if (TextureID2) + if ((seg = SwitchExtension->Segments[1]->RaSegCount()) > 0) + { + glBindTexture(GL_TEXTURE_2D, TextureID2); // szyny - + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24); + iPtr += 24 * seg; // pominięcie lewej szyny + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24); + } + } + else // dla toru podsypka plus szyny + { + if ((seg = Segment->RaSegCount()) > 0) + { + if (TextureID2) + { + glBindTexture(GL_TEXTURE_2D, TextureID2); // podsypka + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 8 * i, 8); + iPtr += 8 * seg; // pominięcie podsypki + } + if (TextureID1) + { + glBindTexture(GL_TEXTURE_2D, TextureID1); // szyny + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24); + iPtr += 24 * seg; // pominięcie lewej szyny + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24); + } + } + } + break; + case 2: // droga + if ((seg = Segment->RaSegCount()) > 0) + { + if (TextureID1) + { + glBindTexture(GL_TEXTURE_2D, TextureID1); // nawierzchnia + for (i = 0; i < seg; ++i) + { + glDrawArrays(GL_TRIANGLE_STRIP, iPtr, 4); + iPtr += 4; + } + } + if (TextureID2) + { + glBindTexture(GL_TEXTURE_2D, TextureID2); // pobocze + if (fTexHeight1 >= 0.0) + { // normalna droga z poboczem + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6); + iPtr += 6 * seg; // pominięcie lewego pobocza + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6); + } + else + { // z chodnikami o różnych szerokociach + if (fTexWidth != 0.0) + { + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6); + iPtr += 6 * seg; // pominięcie lewego pobocza + } + if (fTexSlope != 0.0) + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6); + } + } + } + break; + case 4: // rzeki - jeszcze do przemyślenia + if ((seg = Segment->RaSegCount()) > 0) + { + if (TextureID1) + { + glBindTexture(GL_TEXTURE_2D, TextureID1); // nawierzchnia + for (i = 0; i < seg; ++i) + { + glDrawArrays(GL_TRIANGLE_STRIP, iPtr, 4); + iPtr += 4; + } + } + if (TextureID2) + { + glBindTexture(GL_TEXTURE_2D, TextureID2); // pobocze + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6); + iPtr += 6 * seg; // pominięcie lewego pobocza + for (i = 0; i < seg; ++i) + glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6); + } + } + break; } - } - break; - case 2: //droga - if ((seg=Segment->RaSegCount())>0) - {if (TextureID1) - {glBindTexture(GL_TEXTURE_2D,TextureID1); //nawierzchnia - for (i=0;i=0.0) - {//normalna droga z poboczem - for (i=0;iRaSegCount())>0) - {if (TextureID1) - {glBindTexture(GL_TEXTURE_2D,TextureID1); //nawierzchnia - for (i=0;iRender(); //sam sprawdza, czy VBO; zmienia kontekst VBO! - //EnvironmentReset(); +{ // renderowanie nieprzezroczystych fragmentów pojazdów + if (!iNumDynamics) + return; // po co kombinować, jeśli nie ma pojazdów? + // EnvironmentSet(); //Ra: pojazdy sobie same teraz liczą cienie + for (int i = 0; i < iNumDynamics; i++) + Dynamics[i]->Render(); // sam sprawdza, czy VBO; zmienia kontekst VBO! + // EnvironmentReset(); }; void __fastcall TTrack::RenderDynAlpha() -{//renderowanie przezroczystych fragmentów pojazdów - if (!iNumDynamics) return; //po co kombinować, jeśli nie ma pojazdów? - //EnvironmentSet(); //Ra: pojazdy sobie same teraz liczą cienie - for (int i=0;iRenderAlpha(); //sam sprawdza, czy VBO; zmienia kontekst VBO! - //EnvironmentReset(); +{ // renderowanie przezroczystych fragmentów pojazdów + if (!iNumDynamics) + return; // po co kombinować, jeśli nie ma pojazdów? + // EnvironmentSet(); //Ra: pojazdy sobie same teraz liczą cienie + for (int i = 0; i < iNumDynamics; i++) + Dynamics[i]->RenderAlpha(); // sam sprawdza, czy VBO; zmienia kontekst VBO! + // EnvironmentReset(); }; void __fastcall TTrack::RenderDynSounds() -{//odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania - for (int i=0;iRenderSounds(); +{ // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania + for (int i = 0; i < iNumDynamics; i++) + Dynamics[i]->RenderSounds(); }; //--------------------------------------------------------------------------- bool __fastcall TTrack::SetConnections(int i) -{//przepisanie aktualnych połączeń toru do odpowiedniego segmentu - if (SwitchExtension) - { - SwitchExtension->pNexts[i]=trNext; - SwitchExtension->pPrevs[i]=trPrev; - SwitchExtension->iNextDirection[i]=iNextDirection; - SwitchExtension->iPrevDirection[i]=iPrevDirection; - if (eType==tt_Switch) - {//zwrotnica jest wyłącznie w punkcie 1, więc tor od strony Prev jest zawsze ten sam - SwitchExtension->pPrevs[i^1]=trPrev; - SwitchExtension->iPrevDirection[i^1]=iPrevDirection; - } - else - if (eType==tt_Cross) - if (SwitchExtension->iRoads==3) +{ // przepisanie aktualnych połączeń toru do odpowiedniego segmentu + if (SwitchExtension) { + SwitchExtension->pNexts[i] = trNext; + SwitchExtension->pPrevs[i] = trPrev; + SwitchExtension->iNextDirection[i] = iNextDirection; + SwitchExtension->iPrevDirection[i] = iPrevDirection; + if (eType == tt_Switch) + { // zwrotnica jest wyłącznie w punkcie 1, więc tor od strony Prev jest zawsze ten sam + SwitchExtension->pPrevs[i ^ 1] = trPrev; + SwitchExtension->iPrevDirection[i ^ 1] = iPrevDirection; + } + else if (eType == tt_Cross) + if (SwitchExtension->iRoads == 3) + { + } + if (i) + Switch(0); // po przypisaniu w punkcie 4 włączyć stan zasadniczy + return true; } - if (i) Switch(0); //po przypisaniu w punkcie 4 włączyć stan zasadniczy - return true; - } - Error("Cannot set connections"); - return false; + Error("Cannot set connections"); + return false; } -bool __fastcall TTrack::Switch(int i,double t,double d) -{//przełączenie torów z uruchomieniem animacji - if (SwitchExtension) //tory przełączalne mają doklejkę - if (eType==tt_Switch) - {//przekładanie zwrotnicy jak zwykle - if (t>0.0) //prędkość liniowa ruchu iglic - SwitchExtension->fOffsetSpeed=t; //prędkość łatwiej zgrać z animacją modelu - if (d>=0.0) //dodatkowy ruch drugiej iglicy (zamknięcie nastawnicze) - SwitchExtension->fOffsetDelay=d; - i&=1; //ograniczenie błędów !!!! - SwitchExtension->fDesiredOffset=i?fMaxOffset+SwitchExtension->fOffsetDelay:-SwitchExtension->fOffsetDelay; - SwitchExtension->CurrentIndex=i; - Segment=SwitchExtension->Segments[i]; //wybranie aktywnej drogi - potrzebne to? - trNext=SwitchExtension->pNexts[i]; //przełączenie końców - trPrev=SwitchExtension->pPrevs[i]; - iNextDirection=SwitchExtension->iNextDirection[i]; - iPrevDirection=SwitchExtension->iPrevDirection[i]; - fRadius=fRadiusTable[i]; //McZapkie: wybor promienia toru - if (SwitchExtension->fVelocity<=-2) //-1 oznacza maksymalną prędkość, a dalsze ujemne to ograniczenie na bok - fVelocity=i?-SwitchExtension->fVelocity:-1; - if (SwitchExtension->pOwner?SwitchExtension->pOwner->RaTrackAnimAdd(this):true) //jeśli nie dodane do animacji - {//nie ma się co bawić - SwitchExtension->fOffset=SwitchExtension->fDesiredOffset; - RaAnimate(); //przeliczenie położenia iglic; czy zadziała na niewyświetlanym sektorze w VBO? - } - return true; - } - else if (eType==tt_Table) - {//blokowanie (0, szukanie torów) lub odblokowanie (1, rozłączenie) obrotnicy - if (i) - {//0: rozłączenie sąsiednich torów od obrotnicy - if (trPrev) //jeśli jest tor od Point1 obrotnicy - if (iPrevDirection) //0:dołączony Point1, 1:dołączony Point2 - trPrev->trNext=NULL; //rozłączamy od Point2 - else - trPrev->trPrev=NULL; //rozłączamy od Point1 - if (trNext) //jeśli jest tor od Point2 obrotnicy - if (iNextDirection) //0:dołączony Point1, 1:dołączony Point2 - trNext->trNext=NULL; //rozłączamy od Point2 - else - trNext->trPrev=NULL; //rozłączamy od Point1 - trNext=trPrev=NULL; //na końcu rozłączamy obrotnicę (wkaźniki do sąsiadów już niepotrzebne) - fVelocity=0.0; //AI, nie ruszaj się! - if (SwitchExtension->pOwner) - SwitchExtension->pOwner->RaTrackAnimAdd(this); //dodanie do listy animacyjnej - } - else - {//1: ustalenie finalnego położenia (gdy nie było animacji) - RaAnimate(); //ostatni etap animowania - //zablokowanie pozycji i połączenie do sąsiednich torów - Global::pGround->TrackJoin(SwitchExtension->pMyNode); - if (trNext||trPrev) - {fVelocity=6.0; //jazda dozwolona - if (trPrev) - if (trPrev->fVelocity==0.0) //ustawienie 0 da możliwość zatrzymania AI na obrotnicy - trPrev->VelocitySet(6.0); //odblokowanie dołączonego toru do jazdy - if (trNext) - if (trNext->fVelocity==0.0) - trNext->VelocitySet(6.0); - if (SwitchExtension->evPlus) //w starych sceneriach może nie być - Global::AddToQuery(SwitchExtension->evPlus,NULL); //potwierdzenie wykonania (np. odpala WZ) - } - } - SwitchExtension->CurrentIndex=i; //zapamiętanie stanu zablokowania - return true; - } - else if (eType==tt_Cross) - {//to jest przydatne tylko do łączenia odcinków - i&=1; - SwitchExtension->CurrentIndex=i; - Segment=SwitchExtension->Segments[i]; //wybranie aktywnej drogi - potrzebne to? - trNext=SwitchExtension->pNexts[i]; //przełączenie końców - trPrev=SwitchExtension->pPrevs[i]; - iNextDirection=SwitchExtension->iNextDirection[i]; - iPrevDirection=SwitchExtension->iPrevDirection[i]; - return true; - } - if (iCategoryFlag==1) - iDamageFlag=(iDamageFlag&127)+128*(i&1); //przełączanie wykolejenia - else - Error("Cannot switch normal track"); - return false; +bool __fastcall TTrack::Switch(int i, double t, double d) +{ // przełączenie torów z uruchomieniem animacji + if (SwitchExtension) // tory przełączalne mają doklejkę + if (eType == tt_Switch) + { // przekładanie zwrotnicy jak zwykle + if (t > 0.0) // prędkość liniowa ruchu iglic + SwitchExtension->fOffsetSpeed = t; // prędkość łatwiej zgrać z animacją modelu + if (d >= 0.0) // dodatkowy ruch drugiej iglicy (zamknięcie nastawnicze) + SwitchExtension->fOffsetDelay = d; + i &= 1; // ograniczenie błędów !!!! + SwitchExtension->fDesiredOffset = + i ? fMaxOffset + SwitchExtension->fOffsetDelay : -SwitchExtension->fOffsetDelay; + SwitchExtension->CurrentIndex = i; + Segment = SwitchExtension->Segments[i]; // wybranie aktywnej drogi - potrzebne to? + trNext = SwitchExtension->pNexts[i]; // przełączenie końców + trPrev = SwitchExtension->pPrevs[i]; + iNextDirection = SwitchExtension->iNextDirection[i]; + iPrevDirection = SwitchExtension->iPrevDirection[i]; + fRadius = fRadiusTable[i]; // McZapkie: wybor promienia toru + if (SwitchExtension->fVelocity <= + -2) //-1 oznacza maksymalną prędkość, a dalsze ujemne to ograniczenie na bok + fVelocity = i ? -SwitchExtension->fVelocity : -1; + if (SwitchExtension->pOwner ? SwitchExtension->pOwner->RaTrackAnimAdd(this) : + true) // jeśli nie dodane do animacji + { // nie ma się co bawić + SwitchExtension->fOffset = SwitchExtension->fDesiredOffset; + RaAnimate(); // przeliczenie położenia iglic; czy zadziała na niewyświetlanym + // sektorze w VBO? + } + return true; + } + else if (eType == tt_Table) + { // blokowanie (0, szukanie torów) lub odblokowanie (1, rozłączenie) obrotnicy + if (i) + { // 0: rozłączenie sąsiednich torów od obrotnicy + if (trPrev) // jeśli jest tor od Point1 obrotnicy + if (iPrevDirection) // 0:dołączony Point1, 1:dołączony Point2 + trPrev->trNext = NULL; // rozłączamy od Point2 + else + trPrev->trPrev = NULL; // rozłączamy od Point1 + if (trNext) // jeśli jest tor od Point2 obrotnicy + if (iNextDirection) // 0:dołączony Point1, 1:dołączony Point2 + trNext->trNext = NULL; // rozłączamy od Point2 + else + trNext->trPrev = NULL; // rozłączamy od Point1 + trNext = trPrev = + NULL; // na końcu rozłączamy obrotnicę (wkaźniki do sąsiadów już niepotrzebne) + fVelocity = 0.0; // AI, nie ruszaj się! + if (SwitchExtension->pOwner) + SwitchExtension->pOwner->RaTrackAnimAdd(this); // dodanie do listy animacyjnej + } + else + { // 1: ustalenie finalnego położenia (gdy nie było animacji) + RaAnimate(); // ostatni etap animowania + // zablokowanie pozycji i połączenie do sąsiednich torów + Global::pGround->TrackJoin(SwitchExtension->pMyNode); + if (trNext || trPrev) + { + fVelocity = 6.0; // jazda dozwolona + if (trPrev) + if (trPrev->fVelocity == + 0.0) // ustawienie 0 da możliwość zatrzymania AI na obrotnicy + trPrev->VelocitySet(6.0); // odblokowanie dołączonego toru do jazdy + if (trNext) + if (trNext->fVelocity == 0.0) + trNext->VelocitySet(6.0); + if (SwitchExtension->evPlus) // w starych sceneriach może nie być + Global::AddToQuery(SwitchExtension->evPlus, + NULL); // potwierdzenie wykonania (np. odpala WZ) + } + } + SwitchExtension->CurrentIndex = i; // zapamiętanie stanu zablokowania + return true; + } + else if (eType == tt_Cross) + { // to jest przydatne tylko do łączenia odcinków + i &= 1; + SwitchExtension->CurrentIndex = i; + Segment = SwitchExtension->Segments[i]; // wybranie aktywnej drogi - potrzebne to? + trNext = SwitchExtension->pNexts[i]; // przełączenie końców + trPrev = SwitchExtension->pPrevs[i]; + iNextDirection = SwitchExtension->iNextDirection[i]; + iPrevDirection = SwitchExtension->iPrevDirection[i]; + return true; + } + if (iCategoryFlag == 1) + iDamageFlag = (iDamageFlag & 127) + 128 * (i & 1); // przełączanie wykolejenia + else + Error("Cannot switch normal track"); + return false; }; -bool __fastcall TTrack::SwitchForced(int i,TDynamicObject *o) -{//rozprucie rozjazdu - if (SwitchExtension) - if (eType==tt_Switch) - {// - if (i!=SwitchExtension->CurrentIndex) - {switch (i) - {case 0: - if (SwitchExtension->evPlus) - Global::AddToQuery(SwitchExtension->evPlus,o); //dodanie do kolejki - break; - case 1: - if (SwitchExtension->evMinus) - Global::AddToQuery(SwitchExtension->evMinus,o); //dodanie do kolejki - break; - } - Switch(i); //jeśli się tu nie przełączy, to każdy pojazd powtórzy event rozrprucia - } - } - else if (eType==tt_Cross) - {//ustawienie wskaźnika na wskazany segment - Segment=SwitchExtension->Segments[i]; - } - return true; +bool __fastcall TTrack::SwitchForced(int i, TDynamicObject *o) +{ // rozprucie rozjazdu + if (SwitchExtension) + if (eType == tt_Switch) + { // + if (i != SwitchExtension->CurrentIndex) + { + switch (i) + { + case 0: + if (SwitchExtension->evPlus) + Global::AddToQuery(SwitchExtension->evPlus, o); // dodanie do kolejki + break; + case 1: + if (SwitchExtension->evMinus) + Global::AddToQuery(SwitchExtension->evMinus, o); // dodanie do kolejki + break; + } + Switch(i); // jeśli się tu nie przełączy, to każdy pojazd powtórzy event rozrprucia + } + } + else if (eType == tt_Cross) + { // ustawienie wskaźnika na wskazany segment + Segment = SwitchExtension->Segments[i]; + } + return true; }; -int __fastcall TTrack::CrossSegment(int from,int into) -{//ustawienie wskaźnika na segement w pożądanym kierunku (into) od strony (from) - //zwraca kod segmentu, z kierunkiem jazdy jako znakiem ± - int i=0; - switch (into) - {case 0: //stop - //WriteLog("Crossing from P"+AnsiString(from+1)+" into stop on "+pMyNode->asName); - break; - case 1: //left - //WriteLog("Crossing from P"+AnsiString(from+1)+" to left on "+pMyNode->asName); - i=(SwitchExtension->iRoads==4)?iLewo4[from]:iLewo3[from]; - break; - case 2: //right - //WriteLog("Crossing from P"+AnsiString(from+1)+" to right on "+pMyNode->asName); - i=(SwitchExtension->iRoads==4)?iPrawo4[from]:iPrawo3[from]; - break; - case 3: //stright - //WriteLog("Crossing from P"+AnsiString(from+1)+" to straight on "+pMyNode->asName); - i=(SwitchExtension->iRoads==4)?iProsto4[from]:iProsto3[from]; - break; - } - if (i) - {Segment=SwitchExtension->Segments[abs(i)-1]; - //WriteLog("Selected segment: "+AnsiString(abs(i)-1)); - } - return i; +int __fastcall TTrack::CrossSegment(int from, int into) +{ // ustawienie wskaźnika na segement w pożądanym kierunku (into) od strony (from) + // zwraca kod segmentu, z kierunkiem jazdy jako znakiem ± + int i = 0; + switch (into) + { + case 0: // stop + // WriteLog("Crossing from P"+AnsiString(from+1)+" into stop on "+pMyNode->asName); + break; + case 1: // left + // WriteLog("Crossing from P"+AnsiString(from+1)+" to left on "+pMyNode->asName); + i = (SwitchExtension->iRoads == 4) ? iLewo4[from] : iLewo3[from]; + break; + case 2: // right + // WriteLog("Crossing from P"+AnsiString(from+1)+" to right on "+pMyNode->asName); + i = (SwitchExtension->iRoads == 4) ? iPrawo4[from] : iPrawo3[from]; + break; + case 3: // stright + // WriteLog("Crossing from P"+AnsiString(from+1)+" to straight on "+pMyNode->asName); + i = (SwitchExtension->iRoads == 4) ? iProsto4[from] : iProsto3[from]; + break; + } + if (i) + { + Segment = SwitchExtension->Segments[abs(i) - 1]; + // WriteLog("Selected segment: "+AnsiString(abs(i)-1)); + } + return i; }; void __fastcall TTrack::RaAnimListAdd(TTrack *t) -{//dodanie toru do listy animacyjnej - if (SwitchExtension) - {if (t==this) return; //siebie nie dodajemy drugi raz do listy - if (!t->SwitchExtension) return; //nie podlega animacji - if (SwitchExtension->pNextAnim) - {if (SwitchExtension->pNextAnim==t) - return; //gdy już taki jest - else - SwitchExtension->pNextAnim->RaAnimListAdd(t); - } - else - {SwitchExtension->pNextAnim=t; - t->SwitchExtension->pNextAnim=NULL; //nowo dodawany nie może mieć ogona - } - } +{ // dodanie toru do listy animacyjnej + if (SwitchExtension) + { + if (t == this) + return; // siebie nie dodajemy drugi raz do listy + if (!t->SwitchExtension) + return; // nie podlega animacji + if (SwitchExtension->pNextAnim) + { + if (SwitchExtension->pNextAnim == t) + return; // gdy już taki jest + else + SwitchExtension->pNextAnim->RaAnimListAdd(t); + } + else + { + SwitchExtension->pNextAnim = t; + t->SwitchExtension->pNextAnim = NULL; // nowo dodawany nie może mieć ogona + } + } }; -TTrack* __fastcall TTrack::RaAnimate() -{//wykonanie rekurencyjne animacji, wywoływane przed wyświetleniem sektora - //zwraca wskaźnik toru wymagającego dalszej animacji - if (SwitchExtension->pNextAnim) - SwitchExtension->pNextAnim=SwitchExtension->pNextAnim->RaAnimate(); - bool m=true; //animacja trwa - if (eType==tt_Switch) //dla zwrotnicy tylko szyny - {double v=SwitchExtension->fDesiredOffset-SwitchExtension->fOffset; //kierunek - SwitchExtension->fOffset+=sign(v)*Timer::GetDeltaTime()*SwitchExtension->fOffsetSpeed; - //Ra: trzeba dać to do klasy... - SwitchExtension->fOffset1=SwitchExtension->fOffset; - SwitchExtension->fOffset2=SwitchExtension->fOffset; - if (SwitchExtension->fOffset1>=fMaxOffset) - SwitchExtension->fOffset1=fMaxOffset; //ograniczenie animacji zewnętrznej iglicy - if (SwitchExtension->fOffset2<=0.00) - SwitchExtension->fOffset2=0.0; //ograniczenie animacji wewnętrznej iglicy - if (v<0) - {//jak na pierwszy z torów - if (SwitchExtension->fOffset<=SwitchExtension->fDesiredOffset) - {SwitchExtension->fOffset=SwitchExtension->fDesiredOffset; - m=false; //koniec animacji - } - } - else - {//jak na drugi z torów - if (SwitchExtension->fOffset>=SwitchExtension->fDesiredOffset) - {SwitchExtension->fOffset=SwitchExtension->fDesiredOffset; - m=false; //koniec animacji - } - } - if (Global::bUseVBO) - {//dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment - if (Global::bOpenGL_1_5) //dla OpenGL 1.4 to się nie wykona poprawnie - if (TextureID1) //Ra: !!!! tu jest do poprawienia - {//iglice liczone tylko dla zwrotnic - vector6 rpts3[24],rpts4[24]; - double fHTW=0.5*fabs(fTrackWidth); - double fHTW2=fHTW; //Ra: na razie niech tak będzie - double cos1=1.0,sin1=0.0,cos2=1.0,sin2=0.0; //Ra: ... - for (int i=0;i<12;++i) - {rpts3[i] =vector6((fHTW+iglica[i].x)*cos1+iglica[i].y*sin1,-(fHTW+iglica[i].x)*sin1+iglica[i].y*cos1,iglica[i].z); - rpts3[i+12]=vector6((fHTW2+szyna[i].x)*cos2+szyna[i].y*sin2,-(fHTW2+szyna[i].x)*sin2+iglica[i].y*cos2,szyna[i].z); - rpts4[11-i]=vector6((-fHTW-iglica[i].x)*cos1+iglica[i].y*sin1,-(-fHTW-iglica[i].x)*sin1+iglica[i].y*cos1,iglica[i].z); - rpts4[23-i]=vector6((-fHTW2-szyna[i].x)*cos2+szyna[i].y*sin2,-(-fHTW2-szyna[i].x)*sin2+iglica[i].y*cos2,szyna[i].z); - } - CVertNormTex Vert[2*2*12]; //na razie 2 segmenty - CVertNormTex *v=Vert; //bo RaAnimate() modyfikuje wskaźnik - glGetBufferSubData(GL_ARRAY_BUFFER,SwitchExtension->iLeftVBO*sizeof(CVertNormTex),2*2*12*sizeof(CVertNormTex),&Vert);//pobranie fragmentu bufora VBO - if (SwitchExtension->RightSwitch) - {//nowa wersja z SPKS, ale odwrotnie lewa/prawa - SwitchExtension->Segments[0]->RaAnimate(v,rpts3,-nnumPts,fTexLength,0,2,SwitchExtension->fOffset2); - glBufferSubData(GL_ARRAY_BUFFER,SwitchExtension->iLeftVBO*sizeof(CVertNormTex),2*2*12*sizeof(CVertNormTex),&Vert); //wysłanie fragmentu bufora VBO - v=Vert; - glGetBufferSubData(GL_ARRAY_BUFFER,SwitchExtension->iRightVBO*sizeof(CVertNormTex),2*2*12*sizeof(CVertNormTex),&Vert);//pobranie fragmentu bufora VBO - SwitchExtension->Segments[1]->RaAnimate(v,rpts4,-nnumPts,fTexLength,0,2,-fMaxOffset+SwitchExtension->fOffset1); - } - else - {//oryginalnie lewa działała lepiej niż prawa - SwitchExtension->Segments[0]->RaAnimate(v,rpts4,-nnumPts,fTexLength,0,2,-SwitchExtension->fOffset2); //prawa iglica - glBufferSubData(GL_ARRAY_BUFFER,SwitchExtension->iLeftVBO*sizeof(CVertNormTex),2*2*12*sizeof(CVertNormTex),&Vert);//wysłanie fragmentu bufora VBO - v=Vert; - glGetBufferSubData(GL_ARRAY_BUFFER,SwitchExtension->iRightVBO*sizeof(CVertNormTex),2*2*12*sizeof(CVertNormTex),&Vert); //pobranie fragmentu bufora VBO - SwitchExtension->Segments[1]->RaAnimate(v,rpts3,-nnumPts,fTexLength,0,2,fMaxOffset-SwitchExtension->fOffset1); //lewa iglica - } - glBufferSubData(GL_ARRAY_BUFFER,SwitchExtension->iRightVBO*sizeof(CVertNormTex),2*2*12*sizeof(CVertNormTex),&Vert); //wysłanie fragmentu bufora VBO +TTrack *__fastcall TTrack::RaAnimate() +{ // wykonanie rekurencyjne animacji, wywoływane przed wyświetleniem sektora + // zwraca wskaźnik toru wymagającego dalszej animacji + if (SwitchExtension->pNextAnim) + SwitchExtension->pNextAnim = SwitchExtension->pNextAnim->RaAnimate(); + bool m = true; // animacja trwa + if (eType == tt_Switch) // dla zwrotnicy tylko szyny + { + double v = SwitchExtension->fDesiredOffset - SwitchExtension->fOffset; // kierunek + SwitchExtension->fOffset += sign(v) * Timer::GetDeltaTime() * SwitchExtension->fOffsetSpeed; + // Ra: trzeba dać to do klasy... + SwitchExtension->fOffset1 = SwitchExtension->fOffset; + SwitchExtension->fOffset2 = SwitchExtension->fOffset; + if (SwitchExtension->fOffset1 >= fMaxOffset) + SwitchExtension->fOffset1 = fMaxOffset; // ograniczenie animacji zewnętrznej iglicy + if (SwitchExtension->fOffset2 <= 0.00) + SwitchExtension->fOffset2 = 0.0; // ograniczenie animacji wewnętrznej iglicy + if (v < 0) + { // jak na pierwszy z torów + if (SwitchExtension->fOffset <= SwitchExtension->fDesiredOffset) + { + SwitchExtension->fOffset = SwitchExtension->fDesiredOffset; + m = false; // koniec animacji + } + } + else + { // jak na drugi z torów + if (SwitchExtension->fOffset >= SwitchExtension->fDesiredOffset) + { + SwitchExtension->fOffset = SwitchExtension->fDesiredOffset; + m = false; // koniec animacji + } + } + if (Global::bUseVBO) + { // dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment + if (Global::bOpenGL_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie + if (TextureID1) // Ra: !!!! tu jest do poprawienia + { // iglice liczone tylko dla zwrotnic + vector6 rpts3[24], rpts4[24]; + double fHTW = 0.5 * fabs(fTrackWidth); + double fHTW2 = fHTW; // Ra: na razie niech tak będzie + double cos1 = 1.0, sin1 = 0.0, cos2 = 1.0, sin2 = 0.0; // Ra: ... + for (int i = 0; i < 12; ++i) + { + rpts3[i] = + vector6((fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, + -(fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z); + rpts3[i + 12] = + vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, + -(fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); + rpts4[11 - i] = vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, + -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, + iglica[i].z); + rpts4[23 - i] = + vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, + -(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); + } + CVertNormTex Vert[2 * 2 * 12]; // na razie 2 segmenty + CVertNormTex *v = Vert; // bo RaAnimate() modyfikuje wskaźnik + glGetBufferSubData( + GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // pobranie fragmentu bufora VBO + if (SwitchExtension->RightSwitch) + { // nowa wersja z SPKS, ale odwrotnie lewa/prawa + SwitchExtension->Segments[0]->RaAnimate(v, rpts3, -nnumPts, fTexLength, 0, + 2, SwitchExtension->fOffset2); + glBufferSubData(GL_ARRAY_BUFFER, + SwitchExtension->iLeftVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), + &Vert); // wysłanie fragmentu bufora VBO + v = Vert; + glGetBufferSubData(GL_ARRAY_BUFFER, + SwitchExtension->iRightVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), + &Vert); // pobranie fragmentu bufora VBO + SwitchExtension->Segments[1]->RaAnimate(v, rpts4, -nnumPts, fTexLength, 0, + 2, -fMaxOffset + + SwitchExtension->fOffset1); + } + else + { // oryginalnie lewa działała lepiej niż prawa + SwitchExtension->Segments[0]->RaAnimate( + v, rpts4, -nnumPts, fTexLength, 0, 2, + -SwitchExtension->fOffset2); // prawa iglica + glBufferSubData(GL_ARRAY_BUFFER, + SwitchExtension->iLeftVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), + &Vert); // wysłanie fragmentu bufora VBO + v = Vert; + glGetBufferSubData(GL_ARRAY_BUFFER, + SwitchExtension->iRightVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), + &Vert); // pobranie fragmentu bufora VBO + SwitchExtension->Segments[1]->RaAnimate( + v, rpts3, -nnumPts, fTexLength, 0, 2, + fMaxOffset - SwitchExtension->fOffset1); // lewa iglica + } + glBufferSubData( + GL_ARRAY_BUFFER, SwitchExtension->iRightVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // wysłanie fragmentu bufora VBO + } + } + else // gdy Display List + Release(); // niszczenie skompilowanej listy, aby się wygenerowała nowa } - } - else //gdy Display List - Release(); //niszczenie skompilowanej listy, aby się wygenerowała nowa - } - else if (eType==tt_Table) //dla obrotnicy - szyny i podsypka - { - if (SwitchExtension->pModel&&SwitchExtension->CurrentIndex) //0=zablokowana się nie animuje - {//trzeba każdorazowo porównywać z kątem modelu - //SwitchExtension->fOffset1=SwitchExtension->pAnim?SwitchExtension->pAnim->AngleGet():0.0; //pobranie kąta z modelu - TAnimContainer *ac=SwitchExtension->pModel?SwitchExtension->pModel->GetContainer(NULL):NULL; //pobranie głównego submodelu - //if (ac) ac->EventAssign(SwitchExtension->evMinus); //event zakończenia animacji, trochę bez sensu tutaj - if (ac) - if ((ac->AngleGet()!=SwitchExtension->fOffset)||!(ac->TransGet()==SwitchExtension->vTrans)) //czy przemieściło się od ostatniego sprawdzania - {double hlen=0.5*SwitchExtension->Segments[0]->GetLength(); //połowa długości - SwitchExtension->fOffset=ac->AngleGet(); //pobranie kąta z submodelu - double sina=-hlen*sin(DegToRad(SwitchExtension->fOffset)),cosa=-hlen*cos(DegToRad(SwitchExtension->fOffset)); - SwitchExtension->vTrans=ac->TransGet(); - vector3 middle=SwitchExtension->pMyNode->pCenter+SwitchExtension->vTrans; //SwitchExtension->Segments[0]->FastGetPoint(0.5); - Segment->Init(middle+vector3(sina,0.0,cosa),middle-vector3(sina,0.0,cosa),5.0); //nowy odcinek - for (int i=0;iMove(0.000001); //minimalny ruch, aby przeliczyć pozycję i kąty - if (Global::bUseVBO) - {//dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment - //aktualizacja pojazdów na torze - if (Global::bOpenGL_1_5) //dla OpenGL 1.4 to się nie wykona poprawnie - {int size=RaArrayPrepare(); //wielkość tabeli potrzebna dla tej obrotnicy - CVertNormTex *Vert=new CVertNormTex[size]; //bufor roboczy - //CVertNormTex *v=Vert; //zmieniane przez - RaArrayFill(Vert,Vert-SwitchExtension->iLeftVBO); //iLeftVBO powinno zostać niezmienione - glBufferSubData(GL_ARRAY_BUFFER,SwitchExtension->iLeftVBO*sizeof(CVertNormTex),size*sizeof(CVertNormTex),Vert); //wysłanie fragmentu bufora VBO - } - } - else //gdy Display List - Release(); //niszczenie skompilowanej listy, aby się wygenerowała nowa - } //animacja trwa nadal - } else m=false; //koniec animacji albo w ogóle nie połączone z modelem - } - return m?this:SwitchExtension->pNextAnim; //zwraca obiekt do dalszej animacji + else if (eType == tt_Table) // dla obrotnicy - szyny i podsypka + { + if (SwitchExtension->pModel && + SwitchExtension->CurrentIndex) // 0=zablokowana się nie animuje + { // trzeba każdorazowo porównywać z kątem modelu + // SwitchExtension->fOffset1=SwitchExtension->pAnim?SwitchExtension->pAnim->AngleGet():0.0; + // //pobranie kąta z modelu + TAnimContainer *ac = SwitchExtension->pModel ? + SwitchExtension->pModel->GetContainer(NULL) : + NULL; // pobranie głównego submodelu + // if (ac) ac->EventAssign(SwitchExtension->evMinus); //event zakończenia animacji, + // trochę bez sensu tutaj + if (ac) + if ((ac->AngleGet() != SwitchExtension->fOffset) || + !(ac->TransGet() == + SwitchExtension->vTrans)) // czy przemieściło się od ostatniego sprawdzania + { + double hlen = 0.5 * SwitchExtension->Segments[0]->GetLength(); // połowa + // długości + SwitchExtension->fOffset = ac->AngleGet(); // pobranie kąta z submodelu + double sina = -hlen * sin(DegToRad(SwitchExtension->fOffset)), + cosa = -hlen * cos(DegToRad(SwitchExtension->fOffset)); + SwitchExtension->vTrans = ac->TransGet(); + vector3 middle = + SwitchExtension->pMyNode->pCenter + + SwitchExtension->vTrans; // SwitchExtension->Segments[0]->FastGetPoint(0.5); + Segment->Init(middle + vector3(sina, 0.0, cosa), + middle - vector3(sina, 0.0, cosa), 5.0); // nowy odcinek + for (int i = 0; i < iNumDynamics; i++) + Dynamics[i]->Move(0.000001); // minimalny ruch, aby przeliczyć pozycję i + // kąty + if (Global::bUseVBO) + { // dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment + // aktualizacja pojazdów na torze + if (Global::bOpenGL_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie + { + int size = + RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy + CVertNormTex *Vert = new CVertNormTex[size]; // bufor roboczy + // CVertNormTex *v=Vert; //zmieniane przez + RaArrayFill(Vert, + Vert - + SwitchExtension + ->iLeftVBO); // iLeftVBO powinno zostać niezmienione + glBufferSubData( + GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex), + size * sizeof(CVertNormTex), Vert); // wysłanie fragmentu bufora VBO + } + } + else // gdy Display List + Release(); // niszczenie skompilowanej listy, aby się wygenerowała nowa + } // animacja trwa nadal + } + else + m = false; // koniec animacji albo w ogóle nie połączone z modelem + } + return m ? this : SwitchExtension->pNextAnim; // zwraca obiekt do dalszej animacji }; //--------------------------------------------------------------------------- void __fastcall TTrack::RadioStop() -{//przekazanie pojazdom rozkazu zatrzymania - for (int i=0;iRadioStop(); +{ // przekazanie pojazdom rozkazu zatrzymania + for (int i = 0; i < iNumDynamics; i++) + Dynamics[i]->RadioStop(); }; double __fastcall TTrack::WidthTotal() -{//szerokość z poboczem - if (iCategoryFlag&2) //jesli droga - if (fTexHeight1>=0.0) //i ma boki zagięte w dół (chodnik jest w górę) - return 2.0*fabs(fTexWidth)+0.5*fabs(fTrackWidth+fTrackWidth2); //dodajemy pobocze - return 0.5*fabs(fTrackWidth+fTrackWidth2); //a tak tylko zwykła średnia szerokość +{ // szerokość z poboczem + if (iCategoryFlag & 2) // jesli droga + if (fTexHeight1 >= 0.0) // i ma boki zagięte w dół (chodnik jest w górę) + return 2.0 * fabs(fTexWidth) + + 0.5 * fabs(fTrackWidth + fTrackWidth2); // dodajemy pobocze + return 0.5 * fabs(fTrackWidth + fTrackWidth2); // a tak tylko zwykła średnia szerokość }; bool __fastcall TTrack::IsGroupable() -{//czy wyświetlanie toru może być zgrupwane z innymi - if ((eType==tt_Switch)||(eType==tt_Table)) return false; //tory ruchome nie są grupowane - if ((eEnvironment==e_canyon)||(eEnvironment==e_tunnel)) return false; //tory ze zmianą światła - return true; +{ // czy wyświetlanie toru może być zgrupwane z innymi + if ((eType == tt_Switch) || (eType == tt_Table)) + return false; // tory ruchome nie są grupowane + if ((eEnvironment == e_canyon) || (eEnvironment == e_tunnel)) + return false; // tory ze zmianą światła + return true; }; bool __fastcall Equal(vector3 v1, vector3 *v2) -{//sprawdzenie odległości punktów - //Ra: powinno być do 100cm wzdłuż toru i ze 2cm w poprzek (na prostej może nie być długiego kawałka) - //Ra: z automatycznie dodawanym stukiem, jeśli dziura jest większa niż 2mm. - if (fabs(v1.x-v2->x)>0.02) return false; //sześcian zamiast kuli - if (fabs(v1.z-v2->z)>0.02) return false; - if (fabs(v1.y-v2->y)>0.02) return false; - return true; - //return (SquareMagnitude(v1-*v2)<0.00012); //0.011^2=0.00012 +{ // sprawdzenie odległości punktów + // Ra: powinno być do 100cm wzdłuż toru i ze 2cm w poprzek (na prostej może nie być długiego + // kawałka) + // Ra: z automatycznie dodawanym stukiem, jeśli dziura jest większa niż 2mm. + if (fabs(v1.x - v2->x) > 0.02) + return false; // sześcian zamiast kuli + if (fabs(v1.z - v2->z) > 0.02) + return false; + if (fabs(v1.y - v2->y) > 0.02) + return false; + return true; + // return (SquareMagnitude(v1-*v2)<0.00012); //0.011^2=0.00012 }; int __fastcall TTrack::TestPoint(vector3 *Point) -{//sprawdzanie, czy tory można połączyć - switch (eType) - { - case tt_Normal: //zwykły odcinek - if (trPrev==NULL) - if (Equal(Segment->FastGetPoint_0(),Point)) - return 0; - if (trNext==NULL) - if (Equal(Segment->FastGetPoint_1(),Point)) - return 1; - break; - case tt_Switch: //zwrotnica - {int state=GetSwitchState(); //po co? - //Ra: TODO: jak się zmieni na bezpośrednie odwołania do segmentow zwrotnicy, - //to się wykoleja, ponieważ trNext zależy od przełożenia - Switch(0); - if (trPrev==NULL) - //if (Equal(SwitchExtension->Segments[0]->FastGetPoint_0(),Point)) - if (Equal(Segment->FastGetPoint_0(),Point)) +{ // sprawdzanie, czy tory można połączyć + switch (eType) { - Switch(state); - return 2; - } - if (trNext==NULL) - //if (Equal(SwitchExtension->Segments[0]->FastGetPoint_1(),Point)) - if (Equal(Segment->FastGetPoint_1(),Point)) + case tt_Normal: // zwykły odcinek + if (trPrev == NULL) + if (Equal(Segment->FastGetPoint_0(), Point)) + return 0; + if (trNext == NULL) + if (Equal(Segment->FastGetPoint_1(), Point)) + return 1; + break; + case tt_Switch: // zwrotnica { - Switch(state); - return 3; + int state = GetSwitchState(); // po co? + // Ra: TODO: jak się zmieni na bezpośrednie odwołania do segmentow zwrotnicy, + // to się wykoleja, ponieważ trNext zależy od przełożenia + Switch(0); + if (trPrev == NULL) + // if (Equal(SwitchExtension->Segments[0]->FastGetPoint_0(),Point)) + if (Equal(Segment->FastGetPoint_0(), Point)) + { + Switch(state); + return 2; + } + if (trNext == NULL) + // if (Equal(SwitchExtension->Segments[0]->FastGetPoint_1(),Point)) + if (Equal(Segment->FastGetPoint_1(), Point)) + { + Switch(state); + return 3; + } + Switch(1); // można by się pozbyć tego przełączania + if (trPrev == NULL) // Ra: z tym chyba nie potrzeba łączyć + // if (Equal(SwitchExtension->Segments[1]->FastGetPoint_0(),Point)) + if (Equal(Segment->FastGetPoint_0(), Point)) + { + Switch(state); // Switch(0); + return 4; + } + if (trNext == NULL) // TODO: to zależy od przełożenia zwrotnicy + // if (Equal(SwitchExtension->Segments[1]->FastGetPoint_1(),Point)) + if (Equal(Segment->FastGetPoint_1(), Point)) + { + Switch(state); // Switch(0); + return 5; + } + Switch(state); } - Switch(1); //można by się pozbyć tego przełączania - if (trPrev==NULL) //Ra: z tym chyba nie potrzeba łączyć - //if (Equal(SwitchExtension->Segments[1]->FastGetPoint_0(),Point)) - if (Equal(Segment->FastGetPoint_0(),Point)) - { - Switch(state);//Switch(0); - return 4; + break; + case tt_Cross: // skrzyżowanie dróg + // if (trPrev==NULL) + if (Equal(SwitchExtension->Segments[0]->FastGetPoint_0(), Point)) + return 2; + // if (trNext==NULL) + if (Equal(SwitchExtension->Segments[0]->FastGetPoint_1(), Point)) + return 3; + // if (trPrev==NULL) + if (Equal(SwitchExtension->Segments[1]->FastGetPoint_0(), Point)) + return 4; + // if (trNext==NULL) + if (Equal(SwitchExtension->Segments[1]->FastGetPoint_1(), Point)) + return 5; + break; } - if (trNext==NULL) //TODO: to zależy od przełożenia zwrotnicy - //if (Equal(SwitchExtension->Segments[1]->FastGetPoint_1(),Point)) - if (Equal(Segment->FastGetPoint_1(),Point)) - { - Switch(state);//Switch(0); - return 5; - } - Switch(state); - } - break; - case tt_Cross: //skrzyżowanie dróg - //if (trPrev==NULL) - if (Equal(SwitchExtension->Segments[0]->FastGetPoint_0(),Point)) - return 2; - //if (trNext==NULL) - if (Equal(SwitchExtension->Segments[0]->FastGetPoint_1(),Point)) - return 3; - //if (trPrev==NULL) - if (Equal(SwitchExtension->Segments[1]->FastGetPoint_0(),Point)) - return 4; - //if (trNext==NULL) - if (Equal(SwitchExtension->Segments[1]->FastGetPoint_1(),Point)) - return 5; - break; - } - return -1; + return -1; }; -void __fastcall TTrack::MovedUp1(double dh) -{//poprawienie przechyłki wymaga wydłużenia podsypki - fTexHeight1+=dh; -}; +void __fastcall TTrack::MovedUp1(double dh) { // poprawienie przechyłki wymaga wydłużenia podsypki fTexHeight1 += dh; }; AnsiString __fastcall TTrack::NameGet() -{//ustalenie nazwy toru - if (this) - if (pMyNode) - return pMyNode->asName; - return "none"; +{ // ustalenie nazwy toru + if (this) + if (pMyNode) + return pMyNode->asName; + return "none"; }; void __fastcall TTrack::VelocitySet(float v) -{//ustawienie prędkości z ograniczeniem do pierwotnej wartości (zapisanej w scenerii) - if (SwitchExtension?SwitchExtension->fVelocity>=0.0:false) - {//zwrotnica może mieć odgórne ograniczenie, nieprzeskakiwalne eventem - if (v>SwitchExtension->fVelocity?true:v<0.0) - return void(fVelocity=SwitchExtension->fVelocity); //maksymalnie tyle, ile było we wpisie - } - fVelocity=v; //nie ma ograniczenia +{ // ustawienie prędkości z ograniczeniem do pierwotnej wartości (zapisanej w scenerii) + if (SwitchExtension ? SwitchExtension->fVelocity >= 0.0 : false) + { // zwrotnica może mieć odgórne ograniczenie, nieprzeskakiwalne eventem + if (v > SwitchExtension->fVelocity ? true : v < 0.0) + return void(fVelocity = + SwitchExtension->fVelocity); // maksymalnie tyle, ile było we wpisie + } + fVelocity = v; // nie ma ograniczenia }; float __fastcall TTrack::VelocityGet() -{//pobranie dozwolonej prędkości podczas skanowania - return ((iDamageFlag&128)?0.0f:fVelocity); //tor uszkodzony = prędkość zerowa +{ // pobranie dozwolonej prędkości podczas skanowania + return ((iDamageFlag & 128) ? 0.0f : fVelocity); // tor uszkodzony = prędkość zerowa }; void __fastcall TTrack::ConnectionsLog() -{//wypisanie informacji o połączeniach - int i; - WriteLog("--> tt_Cross named "+pMyNode->asName); - if (eType==tt_Cross) - for (i=0;i<2;++i) - { - if (SwitchExtension->pPrevs[i]) - WriteLog("Point "+AnsiString(i+i+1)+" -> track "+SwitchExtension->pPrevs[i]->pMyNode->asName+":"+AnsiString(int(SwitchExtension->iPrevDirection[i]))); - if (SwitchExtension->pNexts[i]) - WriteLog("Point "+AnsiString(i+i+2)+" -> track "+SwitchExtension->pNexts[i]->pMyNode->asName+":"+AnsiString(int(SwitchExtension->iNextDirection[i]))); - } +{ // wypisanie informacji o połączeniach + int i; + WriteLog("--> tt_Cross named " + pMyNode->asName); + if (eType == tt_Cross) + for (i = 0; i < 2; ++i) + { + if (SwitchExtension->pPrevs[i]) + WriteLog("Point " + AnsiString(i + i + 1) + " -> track " + + SwitchExtension->pPrevs[i]->pMyNode->asName + ":" + + AnsiString(int(SwitchExtension->iPrevDirection[i]))); + if (SwitchExtension->pNexts[i]) + WriteLog("Point " + AnsiString(i + i + 2) + " -> track " + + SwitchExtension->pNexts[i]->pMyNode->asName + ":" + + AnsiString(int(SwitchExtension->iNextDirection[i]))); + } }; -TTrack* __fastcall TTrack::Neightbour(int s,double &d) -{//zwraca wskaźnik na sąsiedni tor, w kierunku określonym znakiem (s), odwraca (d) w razie niezgodności kierunku torów - TTrack *t; //nie zmieniamy kierunku (d), jeśli nie ma toru dalej - if (eType!=tt_Cross) - {//jeszcze trzeba sprawdzić zgodność - t=(s>0)?trNext:trPrev; - if (t) //o ile jest na co przejść, zmieniamy znak kierunku na nowym torze - if (t->eType==tt_Cross) - {//jeśli wjazd na skrzyżowanie, trzeba ustalić segment, bo od tego zależy zmiana kierunku (d) - //if (r) //gdy nie podano (r), to nie zmieniać (d) - // if (s*t->CrossSegment(((s>0)?iNextDirection:iPrevDirection),r)<0) - // d=-d; - } - else - {if ((s>0)?iNextDirection:!iPrevDirection) - d=-d; //następuje zmiana kierunku wózka albo kierunku skanowania - //s=((s>0)?iNextDirection:iPrevDirection)?-1:1; //kierunek toru po zmianie - } - return (t); //zwrotnica ma odpowiednio ustawione (trNext) - } - switch ((SwitchExtension->iRoads==4)?iEnds4[s+6]:iEnds3[s+6]) //numer końca 0..3, -1 to błąd - {//zjazd ze skrzyżowania - case 0: if (SwitchExtension->pPrevs[0]) if ((s>0)==SwitchExtension->iPrevDirection[0]) d=-d; return SwitchExtension->pPrevs[0]; - case 1: if (SwitchExtension->pNexts[0]) if ((s>0)==SwitchExtension->iNextDirection[0]) d=-d; return SwitchExtension->pNexts[0]; - case 2: if (SwitchExtension->pPrevs[1]) if ((s>0)==SwitchExtension->iPrevDirection[1]) d=-d; return SwitchExtension->pPrevs[1]; - case 3: if (SwitchExtension->pNexts[1]) if ((s>0)==SwitchExtension->iNextDirection[1]) d=-d; return SwitchExtension->pNexts[1]; - } - return NULL; +TTrack *__fastcall TTrack::Neightbour(int s, double &d) +{ // zwraca wskaźnik na sąsiedni tor, w kierunku określonym znakiem (s), odwraca (d) w razie + // niezgodności kierunku torów + TTrack *t; // nie zmieniamy kierunku (d), jeśli nie ma toru dalej + if (eType != tt_Cross) + { // jeszcze trzeba sprawdzić zgodność + t = (s > 0) ? trNext : trPrev; + if (t) // o ile jest na co przejść, zmieniamy znak kierunku na nowym torze + if (t->eType == tt_Cross) + { // jeśli wjazd na skrzyżowanie, trzeba ustalić segment, bo od tego zależy zmiana + // kierunku (d) + // if (r) //gdy nie podano (r), to nie zmieniać (d) + // if (s*t->CrossSegment(((s>0)?iNextDirection:iPrevDirection),r)<0) + // d=-d; + } + else + { + if ((s > 0) ? iNextDirection : !iPrevDirection) + d = -d; // następuje zmiana kierunku wózka albo kierunku skanowania + // s=((s>0)?iNextDirection:iPrevDirection)?-1:1; //kierunek toru po zmianie + } + return (t); // zwrotnica ma odpowiednio ustawione (trNext) + } + switch ((SwitchExtension->iRoads == 4) ? iEnds4[s + 6] : + iEnds3[s + 6]) // numer końca 0..3, -1 to błąd + { // zjazd ze skrzyżowania + case 0: + if (SwitchExtension->pPrevs[0]) + if ((s > 0) == SwitchExtension->iPrevDirection[0]) + d = -d; + return SwitchExtension->pPrevs[0]; + case 1: + if (SwitchExtension->pNexts[0]) + if ((s > 0) == SwitchExtension->iNextDirection[0]) + d = -d; + return SwitchExtension->pNexts[0]; + case 2: + if (SwitchExtension->pPrevs[1]) + if ((s > 0) == SwitchExtension->iPrevDirection[1]) + d = -d; + return SwitchExtension->pPrevs[1]; + case 3: + if (SwitchExtension->pNexts[1]) + if ((s > 0) == SwitchExtension->iNextDirection[1]) + d = -d; + return SwitchExtension->pNexts[1]; + } + return NULL; }; - diff --git a/Track.h b/Track.h index a9ce3222..a4a3a9df 100644 --- a/Track.h +++ b/Track.h @@ -9,13 +9,29 @@ #include #include "Classes.h" - class TEvent; -typedef enum { tt_Unknown, tt_Normal, tt_Switch, tt_Table, tt_Cross, tt_Tributary } TTrackType; -//McZapkie-100502 -typedef enum {e_unknown=-1, e_flat=0, e_mountains, e_canyon, e_tunnel, e_bridge, e_bank} TEnvironmentType; -//Ra: opracować alternatywny system cieni/świateł z definiowaniem koloru oświetlenia w halach +typedef enum +{ + tt_Unknown, + tt_Normal, + tt_Switch, + tt_Table, + tt_Cross, + tt_Tributary +} TTrackType; +// McZapkie-100502 +typedef enum +{ + e_unknown = -1, + e_flat = 0, + e_mountains, + e_canyon, + e_tunnel, + e_bridge, + e_bank +} TEnvironmentType; +// Ra: opracować alternatywny system cieni/świateł z definiowaniem koloru oświetlenia w halach class TTrack; class TGroundNode; @@ -23,201 +39,216 @@ class TSubRect; class TTraction; class TSwitchExtension -{//dodatkowe dane do toru, który jest zwrotnicą -public: - __fastcall TSwitchExtension(TTrack *owner,int what); - __fastcall ~TSwitchExtension(); - TSegment *Segments[6]; //dwa tory od punktu 1, pozostałe dwa od 2? Ra 140101: 6 połączeń dla skrzyżowań - //TTrack *trNear[4]; //tory dołączone do punktów 1, 2, 3 i 4 - //dotychczasowe [2]+[2] wskaźniki zamienić na nowe [4] - TTrack *pNexts[2]; //tory dołączone do punktów 2 i 4 - TTrack *pPrevs[2]; //tory dołączone do punktów 1 i 3 - int iNextDirection[2]; //to też z [2]+[2] przerobić na [4] - int iPrevDirection[2]; - int CurrentIndex; //dla zwrotnicy - double fOffset,fDesiredOffset; //aktualne i docelowe położenie napędu iglic - double fOffsetSpeed; //prędkość liniowa ruchu iglic - double fOffsetDelay; //opóźnienie ruchu drugiej iglicy względem pierwszej - union - { - struct - {//zmienne potrzebne tylko dla zwrotnicy - double fOffset1,fOffset2; //przesunięcia iglic - 0=na wprost - bool RightSwitch; //czy zwrotnica w prawo - }; - struct - {//zmienne potrzebne tylko dla obrotnicy/przesuwnicy - TGroundNode *pMyNode; //dla obrotnicy do wtórnego podłączania torów - //TAnimContainer *pAnim; //animator modelu dla obrotnicy - TAnimModel *pModel; //na razie model - }; - struct - {//zmienne dla skrzyżowania - vector3 *vPoints; //tablica wierzchołków nawierzchni, generowana przez pobocze - int iPoints; //liczba faktycznie użytych wierzchołków nawierzchni - bool bPoints; //czy utworzone? - int iRoads; //ile dróg się spotyka? - }; - }; - bool bMovement; //czy w trakcie animacji - int iLeftVBO,iRightVBO; //indeksy iglic w VBO - TSubRect *pOwner; //sektor, któremu trzeba zgłosić animację - TTrack *pNextAnim; //następny tor do animowania - TEvent *evPlus,*evMinus; //zdarzenia sygnalizacji rozprucia - float fVelocity; //maksymalne ograniczenie prędkości (ustawianej eventem) - vector3 vTrans; //docelowa translacja przesuwnicy -private: +{ // dodatkowe dane do toru, który jest zwrotnicą + public: + __fastcall TSwitchExtension(TTrack *owner, int what); + __fastcall ~TSwitchExtension(); + TSegment *Segments[6]; // dwa tory od punktu 1, pozostałe dwa od 2? Ra 140101: 6 połączeń dla + // skrzyżowań + // TTrack *trNear[4]; //tory dołączone do punktów 1, 2, 3 i 4 + // dotychczasowe [2]+[2] wskaźniki zamienić na nowe [4] + TTrack *pNexts[2]; // tory dołączone do punktów 2 i 4 + TTrack *pPrevs[2]; // tory dołączone do punktów 1 i 3 + int iNextDirection[2]; // to też z [2]+[2] przerobić na [4] + int iPrevDirection[2]; + int CurrentIndex; // dla zwrotnicy + double fOffset, fDesiredOffset; // aktualne i docelowe położenie napędu iglic + double fOffsetSpeed; // prędkość liniowa ruchu iglic + double fOffsetDelay; // opóźnienie ruchu drugiej iglicy względem pierwszej + union + { + struct + { // zmienne potrzebne tylko dla zwrotnicy + double fOffset1, fOffset2; // przesunięcia iglic - 0=na wprost + bool RightSwitch; // czy zwrotnica w prawo + }; + struct + { // zmienne potrzebne tylko dla obrotnicy/przesuwnicy + TGroundNode *pMyNode; // dla obrotnicy do wtórnego podłączania torów + // TAnimContainer *pAnim; //animator modelu dla obrotnicy + TAnimModel *pModel; // na razie model + }; + struct + { // zmienne dla skrzyżowania + vector3 *vPoints; // tablica wierzchołków nawierzchni, generowana przez pobocze + int iPoints; // liczba faktycznie użytych wierzchołków nawierzchni + bool bPoints; // czy utworzone? + int iRoads; // ile dróg się spotyka? + }; + }; + bool bMovement; // czy w trakcie animacji + int iLeftVBO, iRightVBO; // indeksy iglic w VBO + TSubRect *pOwner; // sektor, któremu trzeba zgłosić animację + TTrack *pNextAnim; // następny tor do animowania + TEvent *evPlus, *evMinus; // zdarzenia sygnalizacji rozprucia + float fVelocity; // maksymalne ograniczenie prędkości (ustawianej eventem) + vector3 vTrans; // docelowa translacja przesuwnicy + private: }; -const int iMaxNumDynamics=40; //McZapkie-100303 +const int iMaxNumDynamics = 40; // McZapkie-100303 class TIsolated -{//obiekt zbierający zajętości z kilku odcinków - int iAxles; //ilość osi na odcinkach obsługiwanych przez obiekt - TIsolated *pNext; //odcinki izolowane są trzymane w postaci listy jednikierunkowej - static TIsolated *pRoot; //początek listy -public: - AnsiString asName; //nazwa obiektu, baza do nazw eventów - TEvent *evBusy; //zdarzenie wyzwalane po zajęciu grupy - TEvent *evFree; //zdarzenie wyzwalane po całkowitym zwolnieniu zajętości grupy - TMemCell *pMemCell; //automatyczna komórka pamięci, która współpracuje z odcinkiem izolowanym - __fastcall TIsolated(); - __fastcall TIsolated(const AnsiString &n,TIsolated *i); - __fastcall ~TIsolated(); - static TIsolated* __fastcall Find(const AnsiString &n); //znalezienie obiektu albo utworzenie nowego - void __fastcall Modify(int i,TDynamicObject *o); //dodanie lub odjęcie osi - bool __fastcall Busy() { return (iAxles>0); }; - static TIsolated* __fastcall Root() { return (pRoot); }; - TIsolated* __fastcall Next() { return (pNext); }; +{ // obiekt zbierający zajętości z kilku odcinków + int iAxles; // ilość osi na odcinkach obsługiwanych przez obiekt + TIsolated *pNext; // odcinki izolowane są trzymane w postaci listy jednikierunkowej + static TIsolated *pRoot; // początek listy + public: + AnsiString asName; // nazwa obiektu, baza do nazw eventów + TEvent *evBusy; // zdarzenie wyzwalane po zajęciu grupy + TEvent *evFree; // zdarzenie wyzwalane po całkowitym zwolnieniu zajętości grupy + TMemCell *pMemCell; // automatyczna komórka pamięci, która współpracuje z odcinkiem izolowanym + __fastcall TIsolated(); + __fastcall TIsolated(const AnsiString &n, TIsolated *i); + __fastcall ~TIsolated(); + static TIsolated *__fastcall Find( + const AnsiString &n); // znalezienie obiektu albo utworzenie nowego + void __fastcall Modify(int i, TDynamicObject *o); // dodanie lub odjęcie osi + bool __fastcall Busy() { return (iAxles > 0); }; + static TIsolated *__fastcall Root() { return (pRoot); }; + TIsolated *__fastcall Next() { return (pNext); }; }; class TTrack : public Resource -{//trajektoria ruchu - opakowanie -private: - TSwitchExtension *SwitchExtension; //dodatkowe dane do toru, który jest zwrotnicą - TSegment *Segment; - TTrack *trNext; //odcinek od strony punktu 2 - to powinno być w segmencie - TTrack *trPrev; //odcinek od strony punktu 1 - //McZapkie-070402: dodalem zmienne opisujace rozmiary tekstur - GLuint TextureID1; //tekstura szyn albo nawierzchni - GLuint TextureID2; //tekstura automatycznej podsypki albo pobocza - float fTexLength; //długość powtarzania tekstury w metrach - float fTexRatio1; //proporcja rozmiarów tekstury dla nawierzchni drogi - float fTexRatio2; //proporcja rozmiarów tekstury dla chodnika - float fTexHeight1; //wysokość brzegu względem trajektorii - float fTexWidth; //szerokość boku - float fTexSlope; - double fRadiusTable[2]; //dwa promienie, drugi dla zwrotnicy - int iTrapezoid; //0-standard, 1-przechyłka, 2-trapez, 3-oba - GLuint DisplayListID; - TIsolated *pIsolated; //obwód izolowany obsługujący zajęcia/zwolnienia grupy torów - TGroundNode *pMyNode; //Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode -public: - int iNumDynamics; - TDynamicObject *Dynamics[iMaxNumDynamics]; - int iEvents; //Ra: flaga informująca o obecności eventów - TEvent *evEventall0; //McZapkie-140302: wyzwalany gdy pojazd stoi - TEvent *evEventall1; - TEvent *evEventall2; - TEvent *evEvent0; //McZapkie-280503: wyzwalany tylko gdy headdriver - TEvent *evEvent1; - TEvent *evEvent2; - AnsiString asEventall0Name; //nazwy eventów - AnsiString asEventall1Name; - AnsiString asEventall2Name; - AnsiString asEvent0Name; - AnsiString asEvent1Name; - AnsiString asEvent2Name; - int iNextDirection; //0:Point1, 1:Point2, 3:do odchylonego na zwrotnicy - int iPrevDirection; - TTrackType eType; - int iCategoryFlag; //0x100 - usuwanie pojazów - float fTrackWidth; //szerokość w punkcie 1 - float fTrackWidth2; //szerokość w punkcie 2 (głównie drogi i rzeki) - float fFriction; //współczynnik tarcia - float fSoundDistance; - int iQualityFlag; - int iDamageFlag; - TEnvironmentType eEnvironment; //dźwięk i oświetlenie - bool bVisible; //czy rysowany - int iAction; //czy modyfikowany eventami (specjalna obsługa przy skanowaniu) - float fOverhead; //informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem prędkości -private: - double fVelocity; //prędkość dla AI (powyżej rośnie prawdopowobieństwo wykolejenia) -public: - //McZapkie-100502: - double fTrackLength; //długość z wpisu, nigdzie nie używana - double fRadius; //promień, dla zwrotnicy kopiowany z tabeli - bool ScannedFlag; //McZapkie: do zaznaczania kolorem torów skanowanych przez AI - TTraction *hvOverhead; //drut zasilający do szybkiego znalezienia (nie używany) - TGroundNode *nFouling[2]; //współrzędne ukresu albo oporu kozła - TTrack *trColides; //tor kolizyjny, na którym trzeba sprawdzać pojazdy pod kątem zderzenia +{ // trajektoria ruchu - opakowanie + private: + TSwitchExtension *SwitchExtension; // dodatkowe dane do toru, który jest zwrotnicą + TSegment *Segment; + TTrack *trNext; // odcinek od strony punktu 2 - to powinno być w segmencie + TTrack *trPrev; // odcinek od strony punktu 1 + // McZapkie-070402: dodalem zmienne opisujace rozmiary tekstur + GLuint TextureID1; // tekstura szyn albo nawierzchni + GLuint TextureID2; // tekstura automatycznej podsypki albo pobocza + float fTexLength; // długość powtarzania tekstury w metrach + float fTexRatio1; // proporcja rozmiarów tekstury dla nawierzchni drogi + float fTexRatio2; // proporcja rozmiarów tekstury dla chodnika + float fTexHeight1; // wysokość brzegu względem trajektorii + float fTexWidth; // szerokość boku + float fTexSlope; + double fRadiusTable[2]; // dwa promienie, drugi dla zwrotnicy + int iTrapezoid; // 0-standard, 1-przechyłka, 2-trapez, 3-oba + GLuint DisplayListID; + TIsolated *pIsolated; // obwód izolowany obsługujący zajęcia/zwolnienia grupy torów + TGroundNode * + pMyNode; // Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode + public: + int iNumDynamics; + TDynamicObject *Dynamics[iMaxNumDynamics]; + int iEvents; // Ra: flaga informująca o obecności eventów + TEvent *evEventall0; // McZapkie-140302: wyzwalany gdy pojazd stoi + TEvent *evEventall1; + TEvent *evEventall2; + TEvent *evEvent0; // McZapkie-280503: wyzwalany tylko gdy headdriver + TEvent *evEvent1; + TEvent *evEvent2; + AnsiString asEventall0Name; // nazwy eventów + AnsiString asEventall1Name; + AnsiString asEventall2Name; + AnsiString asEvent0Name; + AnsiString asEvent1Name; + AnsiString asEvent2Name; + int iNextDirection; // 0:Point1, 1:Point2, 3:do odchylonego na zwrotnicy + int iPrevDirection; + TTrackType eType; + int iCategoryFlag; // 0x100 - usuwanie pojazów + float fTrackWidth; // szerokość w punkcie 1 + float fTrackWidth2; // szerokość w punkcie 2 (głównie drogi i rzeki) + float fFriction; // współczynnik tarcia + float fSoundDistance; + int iQualityFlag; + int iDamageFlag; + TEnvironmentType eEnvironment; // dźwięk i oświetlenie + bool bVisible; // czy rysowany + int iAction; // czy modyfikowany eventami (specjalna obsługa przy skanowaniu) + float fOverhead; // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i + // ograniczeniem prędkości + private: + double fVelocity; // prędkość dla AI (powyżej rośnie prawdopowobieństwo wykolejenia) + public: + // McZapkie-100502: + double fTrackLength; // długość z wpisu, nigdzie nie używana + double fRadius; // promień, dla zwrotnicy kopiowany z tabeli + bool ScannedFlag; // McZapkie: do zaznaczania kolorem torów skanowanych przez AI + TTraction *hvOverhead; // drut zasilający do szybkiego znalezienia (nie używany) + TGroundNode *nFouling[2]; // współrzędne ukresu albo oporu kozła + TTrack *trColides; // tor kolizyjny, na którym trzeba sprawdzać pojazdy pod kątem zderzenia - __fastcall TTrack(TGroundNode *g); - __fastcall ~TTrack(); - void __fastcall Init(); - static TTrack* __fastcall Create400m(int what,double dx); - TTrack* __fastcall NullCreate(int dir); - inline bool __fastcall IsEmpty() { return (iNumDynamics<=0); }; - void __fastcall ConnectPrevPrev(TTrack *pNewPrev,int typ); - void __fastcall ConnectPrevNext(TTrack *pNewPrev,int typ); - void __fastcall ConnectNextPrev(TTrack *pNewNext,int typ); - void __fastcall ConnectNextNext(TTrack *pNewNext,int typ); - inline double __fastcall Length() { return Segment->GetLength(); }; - inline TSegment* __fastcall CurrentSegment() { return Segment; }; - inline TTrack* __fastcall CurrentNext() {return (trNext);}; - inline TTrack* __fastcall CurrentPrev() {return (trPrev);}; - TTrack* __fastcall Neightbour(int s,double &d); - bool __fastcall SetConnections(int i); - bool __fastcall Switch(int i,double t=-1.0,double d=-1.0); - bool __fastcall SwitchForced(int i,TDynamicObject *o); - int __fastcall CrossSegment(int from,int into); - inline int __fastcall GetSwitchState() { return (SwitchExtension?SwitchExtension->CurrentIndex:-1); }; - void __fastcall Load(cParser *parser, vector3 pOrigin,AnsiString name); - bool __fastcall AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2); - bool __fastcall AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2); - bool __fastcall AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus); - bool __fastcall CheckDynamicObject(TDynamicObject *Dynamic); - bool __fastcall AddDynamicObject(TDynamicObject *Dynamic); - bool __fastcall RemoveDynamicObject(TDynamicObject *Dynamic); - void __fastcall MoveMe(vector3 pPosition); + __fastcall TTrack(TGroundNode *g); + __fastcall ~TTrack(); + void __fastcall Init(); + static TTrack *__fastcall Create400m(int what, double dx); + TTrack *__fastcall NullCreate(int dir); + inline bool __fastcall IsEmpty() { return (iNumDynamics <= 0); }; + void __fastcall ConnectPrevPrev(TTrack *pNewPrev, int typ); + void __fastcall ConnectPrevNext(TTrack *pNewPrev, int typ); + void __fastcall ConnectNextPrev(TTrack *pNewNext, int typ); + void __fastcall ConnectNextNext(TTrack *pNewNext, int typ); + inline double __fastcall Length() { return Segment->GetLength(); }; + inline TSegment *__fastcall CurrentSegment() { return Segment; }; + inline TTrack *__fastcall CurrentNext() { return (trNext); }; + inline TTrack *__fastcall CurrentPrev() { return (trPrev); }; + TTrack *__fastcall Neightbour(int s, double &d); + bool __fastcall SetConnections(int i); + bool __fastcall Switch(int i, double t = -1.0, double d = -1.0); + bool __fastcall SwitchForced(int i, TDynamicObject *o); + int __fastcall CrossSegment(int from, int into); + inline int __fastcall GetSwitchState() + { + return (SwitchExtension ? SwitchExtension->CurrentIndex : -1); + }; + void __fastcall Load(cParser *parser, vector3 pOrigin, AnsiString name); + bool __fastcall AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2); + bool __fastcall AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2); + bool __fastcall AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus); + bool __fastcall CheckDynamicObject(TDynamicObject *Dynamic); + bool __fastcall AddDynamicObject(TDynamicObject *Dynamic); + bool __fastcall RemoveDynamicObject(TDynamicObject *Dynamic); + void __fastcall MoveMe(vector3 pPosition); - void Release(); - void __fastcall Compile(GLuint tex=0); + void Release(); + void __fastcall Compile(GLuint tex = 0); - void __fastcall Render(); //renderowanie z Display Lists - int __fastcall RaArrayPrepare(); //zliczanie rozmiaru dla VBO sektroa - void __fastcall RaArrayFill(CVertNormTex *Vert,const CVertNormTex *Start); //wypełnianie VBO - void __fastcall RaRenderVBO(int iPtr); //renderowanie z VBO sektora - void __fastcall RenderDyn(); //renderowanie nieprzezroczystych pojazdów (oba tryby) - void __fastcall RenderDynAlpha(); //renderowanie przezroczystych pojazdów (oba tryby) - void __fastcall RenderDynSounds(); //odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania + void __fastcall Render(); // renderowanie z Display Lists + int __fastcall RaArrayPrepare(); // zliczanie rozmiaru dla VBO sektroa + void __fastcall RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start); // wypełnianie VBO + void __fastcall RaRenderVBO(int iPtr); // renderowanie z VBO sektora + void __fastcall RenderDyn(); // renderowanie nieprzezroczystych pojazdów (oba tryby) + void __fastcall RenderDynAlpha(); // renderowanie przezroczystych pojazdów (oba tryby) + void __fastcall RenderDynSounds(); // odtwarzanie dźwięków pojazdów jest niezależne od ich + // wyświetlania - void __fastcall RaOwnerSet(TSubRect *o) - {if (SwitchExtension) SwitchExtension->pOwner=o;}; - bool __fastcall InMovement(); //czy w trakcie animacji? - void __fastcall RaAssign(TGroundNode *gn,TAnimContainer *ac); - void __fastcall RaAssign(TGroundNode *gn,TAnimModel *am,TEvent *done,TEvent *joined); - void __fastcall RaAnimListAdd(TTrack *t); - TTrack* __fastcall RaAnimate(); + void __fastcall RaOwnerSet(TSubRect *o) + { + if (SwitchExtension) + SwitchExtension->pOwner = o; + }; + bool __fastcall InMovement(); // czy w trakcie animacji? + void __fastcall RaAssign(TGroundNode *gn, TAnimContainer *ac); + void __fastcall RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joined); + void __fastcall RaAnimListAdd(TTrack *t); + TTrack *__fastcall RaAnimate(); - void __fastcall RadioStop(); - void __fastcall AxleCounter(int i,TDynamicObject *o) - {if (pIsolated) pIsolated->Modify(i,o);}; //dodanie lub odjęcie osi - AnsiString __fastcall IsolatedName(); - bool __fastcall IsolatedEventsAssign(TEvent *busy,TEvent *free); - double __fastcall WidthTotal(); - GLuint TextureGet(int i) {return i?TextureID1:TextureID2;}; - bool __fastcall IsGroupable(); - int __fastcall TestPoint(vector3 *Point); - void __fastcall MovedUp1(double dh); - AnsiString __fastcall NameGet(); - void __fastcall VelocitySet(float v); - float __fastcall VelocityGet(); - void __fastcall ConnectionsLog(); -private: - void __fastcall EnvironmentSet(); - void __fastcall EnvironmentReset(); + void __fastcall RadioStop(); + void __fastcall AxleCounter(int i, TDynamicObject *o) + { + if (pIsolated) + pIsolated->Modify(i, o); + }; // dodanie lub odjęcie osi + AnsiString __fastcall IsolatedName(); + bool __fastcall IsolatedEventsAssign(TEvent *busy, TEvent *free); + double __fastcall WidthTotal(); + GLuint TextureGet(int i) { return i ? TextureID1 : TextureID2; }; + bool __fastcall IsGroupable(); + int __fastcall TestPoint(vector3 *Point); + void __fastcall MovedUp1(double dh); + AnsiString __fastcall NameGet(); + void __fastcall VelocitySet(float v); + float __fastcall VelocityGet(); + void __fastcall ConnectionsLog(); + + private: + void __fastcall EnvironmentSet(); + void __fastcall EnvironmentReset(); }; //--------------------------------------------------------------------------- diff --git a/Traction.cpp b/Traction.cpp index e389275c..c80f9b08 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -5,8 +5,8 @@ */ -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Traction.h" @@ -88,153 +88,166 @@ jawnie nazw sekcji z sąsiedniego przęsła). */ - TTraction::TTraction() { - pPoint1=pPoint2=pPoint3=pPoint4=vector3(0,0,0); - //vFront=vector3(0,0,1); - //vUp=vector3(0,1,0); - //vLeft=vector3(1,0,0); - fHeightDifference=0; - iNumSections=0; - iLines=0; -// dwFlags= 0; - Wires=2; -// fU=fR= 0; - uiDisplayList=0; - asPowerSupplyName=""; -// mdPole= NULL; -// ReplacableSkinID= 0; - hvNext[0]=hvNext[1]=NULL; - iLast=1; //że niby ostatni drut - psPowered=psPower[0]=psPower[1]=NULL; //na początku zasilanie nie podłączone - psSection=NULL; //na początku nie podłączone - hvParallel=NULL; //normalnie brak bieżni wspólnej - fResistance[0]=fResistance[1]=-1.0; //trzeba dopiero policzyć - iTries=0; //ile razy próbować podłączyć, ustawiane później + pPoint1 = pPoint2 = pPoint3 = pPoint4 = vector3(0, 0, 0); + // vFront=vector3(0,0,1); + // vUp=vector3(0,1,0); + // vLeft=vector3(1,0,0); + fHeightDifference = 0; + iNumSections = 0; + iLines = 0; + // dwFlags= 0; + Wires = 2; + // fU=fR= 0; + uiDisplayList = 0; + asPowerSupplyName = ""; + // mdPole= NULL; + // ReplacableSkinID= 0; + hvNext[0] = hvNext[1] = NULL; + iLast = 1; //że niby ostatni drut + psPowered = psPower[0] = psPower[1] = NULL; // na początku zasilanie nie podłączone + psSection = NULL; // na początku nie podłączone + hvParallel = NULL; // normalnie brak bieżni wspólnej + fResistance[0] = fResistance[1] = -1.0; // trzeba dopiero policzyć + iTries = 0; // ile razy próbować podłączyć, ustawiane później } TTraction::~TTraction() { - if (!Global::bUseVBO) - glDeleteLists(uiDisplayList,1); + if (!Global::bUseVBO) + glDeleteLists(uiDisplayList, 1); } void __fastcall TTraction::Optimize() { - if (Global::bUseVBO) return; - uiDisplayList=glGenLists(1); - glNewList(uiDisplayList,GL_COMPILE); + if (Global::bUseVBO) + return; + uiDisplayList = glGenLists(1); + glNewList(uiDisplayList, GL_COMPILE); - glBindTexture(GL_TEXTURE_2D, 0); -// glColor3ub(0,0,0); McZapkie: to do render + glBindTexture(GL_TEXTURE_2D, 0); + // glColor3ub(0,0,0); McZapkie: to do render -// glPushMatrix(); -// glTranslatef(pPosition.x,pPosition.y,pPosition.z); + // glPushMatrix(); + // glTranslatef(pPosition.x,pPosition.y,pPosition.z); - if (Wires!=0) - { - //Dlugosc odcinka trakcji 'Winger - double ddp=hypot(pPoint2.x-pPoint1.x,pPoint2.z-pPoint1.z); + if (Wires != 0) + { + // Dlugosc odcinka trakcji 'Winger + double ddp = hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z); - if (Wires==2) WireOffset=0; - //Przewoz jezdny 1 'Marcin - glBegin(GL_LINE_STRIP); - glVertex3f(pPoint1.x-(pPoint2.z/ddp-pPoint1.z/ddp)*WireOffset,pPoint1.y,pPoint1.z-(-pPoint2.x/ddp+pPoint1.x/ddp)*WireOffset); - glVertex3f(pPoint2.x-(pPoint2.z/ddp-pPoint1.z/ddp)*WireOffset,pPoint2.y,pPoint2.z-(-pPoint2.x/ddp+pPoint1.x/ddp)*WireOffset); - glEnd(); - //Nie wiem co 'Marcin - vector3 pt1,pt2,pt3,pt4,v1,v2; - v1= pPoint4-pPoint3; - v2= pPoint2-pPoint1; - float step= 0; - if (iNumSections>0) - step= 1.0f/(float)iNumSections; - float f= step; - float mid= 0.5; - float t; + if (Wires == 2) + WireOffset = 0; + // Przewoz jezdny 1 'Marcin + glBegin(GL_LINE_STRIP); + glVertex3f(pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint1.y, + pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + glVertex3f(pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint2.y, + pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + glEnd(); + // Nie wiem co 'Marcin + vector3 pt1, pt2, pt3, pt4, v1, v2; + v1 = pPoint4 - pPoint3; + v2 = pPoint2 - pPoint1; + float step = 0; + if (iNumSections > 0) + step = 1.0f / (float)iNumSections; + float f = step; + float mid = 0.5; + float t; - //Przewod nosny 'Marcin - if (Wires != 1) - { - glBegin(GL_LINE_STRIP); - glVertex3f(pPoint3.x,pPoint3.y,pPoint3.z); - for (int i=0; i 2) - { - glBegin(GL_LINE_STRIP); - glVertex3f(pPoint1.x+(pPoint2.z/ddp-pPoint1.z/ddp)*WireOffset,pPoint1.y,pPoint1.z+(-pPoint2.x/ddp+pPoint1.x/ddp)*WireOffset); - glVertex3f(pPoint2.x+(pPoint2.z/ddp-pPoint1.z/ddp)*WireOffset,pPoint2.y,pPoint2.z+(-pPoint2.x/ddp+pPoint1.x/ddp)*WireOffset); - glEnd(); - } + // Drugi przewod jezdny 'Winger + if (Wires > 2) + { + glBegin(GL_LINE_STRIP); + glVertex3f(pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint1.y, + pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + glVertex3f(pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint2.y, + pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + glEnd(); + } - f= step; - - if (Wires == 4) - { - glBegin(GL_LINE_STRIP); - glVertex3f(pPoint3.x,pPoint3.y-0.65f*fHeightDifference,pPoint3.z); - for (int i=0; i1.2) linealpha=1.2; //zbyt grube nie są dobre - glLineWidth(linealpha); - if (linealpha>1.0) linealpha = 1.0; - //McZapkie-261102: kolor zalezy od materialu i zasniedzenia - float r,g,b; - switch (Material) - {//Ra: kolory podzieliłem przez 2, bo po zmianie ambient za jasne były - //trzeba uwzględnić kierunek świecenia Słońca - tylko ze Słońcem widać kolor - case 1: - if (TestFlag(DamageFlag,1)) + // McZapkie: ustalanie przezroczystosci i koloru linii: + if (Wires != 0 && !TestFlag(DamageFlag, 128)) // rysuj jesli sa druty i nie zerwana { - r=0.00000; g=0.32549; b=0.2882353; //zielona miedź + // glDisable(GL_LIGHTING); //aby nie używało wektorów normalnych do kolorowania + glColor4f(0, 0, 0, 1); // jak nieznany kolor to czarne nieprzezroczyste + if (!Global::bSmoothTraction) + glDisable(GL_LINE_SMOOTH); // na liniach kiepsko wygląda - robi gradient + float linealpha = 5000 * WireThickness / (mgn + 1.0); //*WireThickness + if (linealpha > 1.2) + linealpha = 1.2; // zbyt grube nie są dobre + glLineWidth(linealpha); + if (linealpha > 1.0) + linealpha = 1.0; + // McZapkie-261102: kolor zalezy od materialu i zasniedzenia + float r, g, b; + switch (Material) + { // Ra: kolory podzieliłem przez 2, bo po zmianie ambient za jasne były + // trzeba uwzględnić kierunek świecenia Słońca - tylko ze Słońcem widać kolor + case 1: + if (TestFlag(DamageFlag, 1)) + { + r = 0.00000; + g = 0.32549; + b = 0.2882353; // zielona miedź + } + else + { + r = 0.35098; + g = 0.22549; + b = 0.1; // czerwona miedź + } + break; + case 2: + if (TestFlag(DamageFlag, 1)) + { + r = 0.10; + g = 0.10; + b = 0.10; // czarne Al + } + else + { + r = 0.25; + g = 0.25; + b = 0.25; // srebrne Al + } + break; + // tymczasowo pokazanie zasilanych odcinków + case 4: + r = 0.5; + g = 0.5; + b = 1.0; + break; // niebieskie z podłączonym zasilaniem + case 5: + r = 1.0; + g = 0.0; + b = 0.0; + break; // czerwone z podłączonym zasilaniem 1 + case 6: + r = 0.0; + g = 1.0; + b = 0.0; + break; // zielone z podłączonym zasilaniem 2 + case 7: + r = 1.0; + g = 1.0; + b = 0.0; + break; //żółte z podłączonym zasilaniem z obu stron + } + if (DebugModeFlag) + if (hvParallel) + { // jeśli z bieżnią wspólną, to dodatkowo przyciemniamy + r *= 0.6; + g *= 0.6; + b *= 0.6; + } + r *= Global::ambientDayLight[0]; // w zaleźności od koloru swiatła + g *= Global::ambientDayLight[1]; + b *= Global::ambientDayLight[2]; + if (linealpha > 1.0) + linealpha = 1.0; // trzeba ograniczyć do <=1 + glColor4f(r, g, b, linealpha); + if (!uiDisplayList) + Optimize(); // generowanie DL w miarę potrzeby + glCallList(uiDisplayList); + glLineWidth(1.0); + glEnable(GL_LINE_SMOOTH); + // glEnable(GL_LIGHTING); //bez tego się modele nie oświetlają } - else - { - r=0.35098; g=0.22549; b=0.1; //czerwona miedź - } - break; - case 2: - if (TestFlag(DamageFlag,1)) - { - r=0.10; g=0.10; b=0.10; //czarne Al - } - else - { - r=0.25; g=0.25; b=0.25; //srebrne Al - } - break; - //tymczasowo pokazanie zasilanych odcinków - case 4: r=0.5; g=0.5; b=1.0; break; //niebieskie z podłączonym zasilaniem - case 5: r=1.0; g=0.0; b=0.0; break; //czerwone z podłączonym zasilaniem 1 - case 6: r=0.0; g=1.0; b=0.0; break; //zielone z podłączonym zasilaniem 2 - case 7: r=1.0; g=1.0; b=0.0; break; //żółte z podłączonym zasilaniem z obu stron - } - if (DebugModeFlag) - if (hvParallel) - {//jeśli z bieżnią wspólną, to dodatkowo przyciemniamy - r*=0.6; g*=0.6; b*=0.6; - } - r*=Global::ambientDayLight[0]; //w zaleźności od koloru swiatła - g*=Global::ambientDayLight[1]; - b*=Global::ambientDayLight[2]; - if (linealpha>1.0) linealpha=1.0; //trzeba ograniczyć do <=1 - glColor4f(r,g,b,linealpha); - if (!uiDisplayList) - Optimize(); //generowanie DL w miarę potrzeby - glCallList(uiDisplayList); - glLineWidth(1.0); - glEnable(GL_LINE_SMOOTH); - //glEnable(GL_LIGHTING); //bez tego się modele nie oświetlają - } } int __fastcall TTraction::RaArrayPrepare() -{//przygotowanie tablic do skopiowania do VBO (zliczanie wierzchołków) - //if (bVisible) //o ile w ogóle widać - switch (Wires) - { - case 1: iLines=2; break; - case 2: iLines=iNumSections?4*(iNumSections)-2+2:4; break; - case 3: iLines=iNumSections?4*(iNumSections)-2+4:6; break; - case 4: iLines=iNumSections?4*(iNumSections)-2+6:8; break; - default: iLines=0; - } - //else iLines=0; - return iLines; +{ // przygotowanie tablic do skopiowania do VBO (zliczanie wierzchołków) + // if (bVisible) //o ile w ogóle widać + switch (Wires) + { + case 1: + iLines = 2; + break; + case 2: + iLines = iNumSections ? 4 * (iNumSections)-2 + 2 : 4; + break; + case 3: + iLines = iNumSections ? 4 * (iNumSections)-2 + 4 : 6; + break; + case 4: + iLines = iNumSections ? 4 * (iNumSections)-2 + 6 : 8; + break; + default: + iLines = 0; + } + // else iLines=0; + return iLines; }; -void __fastcall TTraction::RaArrayFill(CVertNormTex *Vert) -{//wypełnianie tablic VBO - CVertNormTex *old=Vert; - double ddp=hypot(pPoint2.x-pPoint1.x,pPoint2.z-pPoint1.z); - if (Wires==2) WireOffset=0; - //jezdny - Vert->x=pPoint1.x-(pPoint2.z/ddp-pPoint1.z/ddp)*WireOffset; - Vert->y=pPoint1.y; - Vert->z=pPoint1.z-(-pPoint2.x/ddp+pPoint1.x/ddp)*WireOffset; - ++Vert; - Vert->x=pPoint2.x-(pPoint2.z/ddp-pPoint1.z/ddp)*WireOffset; - Vert->y=pPoint2.y; - Vert->z=pPoint2.z-(-pPoint2.x/ddp+pPoint1.x/ddp)*WireOffset; - ++Vert; - //Nie wiem co 'Marcin - vector3 pt1,pt2,pt3,pt4,v1,v2; - v1=pPoint4-pPoint3; - v2=pPoint2-pPoint1; - float step=0; - if (iNumSections>0) - step=1.0f/(float)iNumSections; - float f=step; - float mid=0.5; - float t; - //Przewod nosny 'Marcin - if (Wires>1) - {//lina nośna w kawałkach - Vert->x=pPoint3.x; - Vert->y=pPoint3.y; - Vert->z=pPoint3.z; - ++Vert; - for (int i=0;ix=pt3.x; - Vert->y=pt3.y-sqrt(t)*fHeightDifference; - Vert->z=pt3.z; - ++Vert; - Vert->x=pt3.x; //drugi raz, bo nie jest line_strip - Vert->y=pt3.y-sqrt(t)*fHeightDifference; - Vert->z=pt3.z; - ++Vert; - f+=step; - } - Vert->x=pPoint4.x; - Vert->y=pPoint4.y; - Vert->z=pPoint4.z; - ++Vert; - } - //Drugi przewod jezdny 'Winger - if (Wires==3) - { - Vert->x=pPoint1.x+(pPoint2.z/ddp-pPoint1.z/ddp)*WireOffset; - Vert->y=pPoint1.y; - Vert->z=pPoint1.z+(-pPoint2.x/ddp+pPoint1.x/ddp)*WireOffset; - ++Vert; - Vert->x=pPoint2.x+(pPoint2.z/ddp-pPoint1.z/ddp)*WireOffset; - Vert->y=pPoint2.y; - Vert->z=pPoint2.z+(-pPoint2.x/ddp+pPoint1.x/ddp)*WireOffset; - ++Vert; - } - f=step; - //Przewody pionowe (wieszaki) 'Marcin, poprawki na 2 przewody jezdne 'Winger - if (Wires>1) - { - for (int i=0;ix=pt3.x; - Vert->y=pt3.y-sqrt(t)*fHeightDifference; - Vert->z=pt3.z; - ++Vert; - if ((i%2)==0) - { - Vert->x=pt4.x-(pPoint2.z/ddp-pPoint1.z/ddp)*WireOffset; - Vert->y=pt4.y; - Vert->z=pt4.z-(-pPoint2.x/ddp+pPoint1.x/ddp)*WireOffset; - } - else - { - Vert->x=pt4.x+(pPoint2.z/ddp-pPoint1.z/ddp)*WireOffset; - Vert->y=pt4.y; - Vert->z=pt4.z+(-pPoint2.x/ddp+pPoint1.x/ddp)*WireOffset; - } - ++Vert; - f+=step; - } - } - if ((Vert-old)!=iLines) - WriteLog("!!! Wygenerowano punktów "+AnsiString(Vert-old)+", powinno być "+AnsiString(iLines)); +void __fastcall TTraction::RaArrayFill(CVertNormTex *Vert) +{ // wypełnianie tablic VBO + CVertNormTex *old = Vert; + double ddp = hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z); + if (Wires == 2) + WireOffset = 0; + // jezdny + Vert->x = pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; + Vert->y = pPoint1.y; + Vert->z = pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; + ++Vert; + Vert->x = pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; + Vert->y = pPoint2.y; + Vert->z = pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; + ++Vert; + // Nie wiem co 'Marcin + vector3 pt1, pt2, pt3, pt4, v1, v2; + v1 = pPoint4 - pPoint3; + v2 = pPoint2 - pPoint1; + float step = 0; + if (iNumSections > 0) + step = 1.0f / (float)iNumSections; + float f = step; + float mid = 0.5; + float t; + // Przewod nosny 'Marcin + if (Wires > 1) + { // lina nośna w kawałkach + Vert->x = pPoint3.x; + Vert->y = pPoint3.y; + Vert->z = pPoint3.z; + ++Vert; + for (int i = 0; i < iNumSections - 1; i++) + { + pt3 = pPoint3 + v1 * f; + t = (1 - fabs(f - mid) * 2); + Vert->x = pt3.x; + Vert->y = pt3.y - sqrt(t) * fHeightDifference; + Vert->z = pt3.z; + ++Vert; + Vert->x = pt3.x; // drugi raz, bo nie jest line_strip + Vert->y = pt3.y - sqrt(t) * fHeightDifference; + Vert->z = pt3.z; + ++Vert; + f += step; + } + Vert->x = pPoint4.x; + Vert->y = pPoint4.y; + Vert->z = pPoint4.z; + ++Vert; + } + // Drugi przewod jezdny 'Winger + if (Wires == 3) + { + Vert->x = pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; + Vert->y = pPoint1.y; + Vert->z = pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; + ++Vert; + Vert->x = pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; + Vert->y = pPoint2.y; + Vert->z = pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; + ++Vert; + } + f = step; + // Przewody pionowe (wieszaki) 'Marcin, poprawki na 2 przewody jezdne 'Winger + if (Wires > 1) + { + for (int i = 0; i < iNumSections - 1; i++) + { + pt3 = pPoint3 + v1 * f; + pt4 = pPoint1 + v2 * f; + t = (1 - fabs(f - mid) * 2); + Vert->x = pt3.x; + Vert->y = pt3.y - sqrt(t) * fHeightDifference; + Vert->z = pt3.z; + ++Vert; + if ((i % 2) == 0) + { + Vert->x = pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; + Vert->y = pt4.y; + Vert->z = pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; + } + else + { + Vert->x = pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; + Vert->y = pt4.y; + Vert->z = pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; + } + ++Vert; + f += step; + } + } + if ((Vert - old) != iLines) + WriteLog("!!! Wygenerowano punktów " + AnsiString(Vert - old) + ", powinno być " + + AnsiString(iLines)); }; -void __fastcall TTraction::RenderVBO(float mgn,int iPtr) -{//renderowanie z użyciem VBO - if (Wires!=0 && !TestFlag(DamageFlag,128)) //rysuj jesli sa druty i nie zerwana - { - glBindTexture(GL_TEXTURE_2D,0); - glDisable(GL_LIGHTING); //aby nie używało wektorów normalnych do kolorowania - glColor4f(0,0,0,1); //jak nieznany kolor to czarne nieprzezroczyste - if (!Global::bSmoothTraction) - glDisable(GL_LINE_SMOOTH); //na liniach kiepsko wygląda - robi gradient - float linealpha=5000*WireThickness/(mgn+1.0); //*WireThickness - if (linealpha>1.2) linealpha=1.2; //zbyt grube nie są dobre - glLineWidth(linealpha); - //McZapkie-261102: kolor zalezy od materialu i zasniedzenia - float r,g,b; - switch (Material) - {//Ra: kolory podzieliłem przez 2, bo po zmianie ambient za jasne były - //trzeba uwzględnić kierunek świecenia Słońca - tylko ze Słońcem widać kolor - case 1: - if (TestFlag(DamageFlag,1)) +void __fastcall TTraction::RenderVBO(float mgn, int iPtr) +{ // renderowanie z użyciem VBO + if (Wires != 0 && !TestFlag(DamageFlag, 128)) // rysuj jesli sa druty i nie zerwana { - r=0.00000; g=0.32549; b=0.2882353; //zielona miedź + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_LIGHTING); // aby nie używało wektorów normalnych do kolorowania + glColor4f(0, 0, 0, 1); // jak nieznany kolor to czarne nieprzezroczyste + if (!Global::bSmoothTraction) + glDisable(GL_LINE_SMOOTH); // na liniach kiepsko wygląda - robi gradient + float linealpha = 5000 * WireThickness / (mgn + 1.0); //*WireThickness + if (linealpha > 1.2) + linealpha = 1.2; // zbyt grube nie są dobre + glLineWidth(linealpha); + // McZapkie-261102: kolor zalezy od materialu i zasniedzenia + float r, g, b; + switch (Material) + { // Ra: kolory podzieliłem przez 2, bo po zmianie ambient za jasne były + // trzeba uwzględnić kierunek świecenia Słońca - tylko ze Słońcem widać kolor + case 1: + if (TestFlag(DamageFlag, 1)) + { + r = 0.00000; + g = 0.32549; + b = 0.2882353; // zielona miedź + } + else + { + r = 0.35098; + g = 0.22549; + b = 0.1; // czerwona miedź + } + break; + case 2: + if (TestFlag(DamageFlag, 1)) + { + r = 0.10; + g = 0.10; + b = 0.10; // czarne Al + } + else + { + r = 0.25; + g = 0.25; + b = 0.25; // srebrne Al + } + break; + // tymczasowo pokazanie zasilanych odcinków + case 4: + r = 0.5; + g = 0.5; + b = 1.0; + break; // niebieskie z podłączonym zasilaniem + case 5: + r = 1.0; + g = 0.0; + b = 0.0; + break; // czerwone z podłączonym zasilaniem 1 + case 6: + r = 0.0; + g = 1.0; + b = 0.0; + break; // zielone z podłączonym zasilaniem 2 + case 7: + r = 1.0; + g = 1.0; + b = 0.0; + break; //żółte z podłączonym zasilaniem z obu stron + } + r = r * Global::ambientDayLight[0]; // w zaleznosci od koloru swiatla + g = g * Global::ambientDayLight[1]; + b = b * Global::ambientDayLight[2]; + if (linealpha > 1.0) + linealpha = 1.0; // trzeba ograniczyć do <=1 + glColor4f(r, g, b, linealpha); + glDrawArrays(GL_LINES, iPtr, iLines); + glLineWidth(1.0); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_LIGHTING); // bez tego się modele nie oświetlają } - else - { - r=0.35098; g=0.22549; b=0.1; //czerwona miedź - } - break; - case 2: - if (TestFlag(DamageFlag,1)) - { - r=0.10; g=0.10; b=0.10; //czarne Al - } - else - { - r=0.25; g=0.25; b=0.25; //srebrne Al - } - break; - //tymczasowo pokazanie zasilanych odcinków - case 4: r=0.5; g=0.5; b=1.0; break; //niebieskie z podłączonym zasilaniem - case 5: r=1.0; g=0.0; b=0.0; break; //czerwone z podłączonym zasilaniem 1 - case 6: r=0.0; g=1.0; b=0.0; break; //zielone z podłączonym zasilaniem 2 - case 7: r=1.0; g=1.0; b=0.0; break; //żółte z podłączonym zasilaniem z obu stron - } - r=r*Global::ambientDayLight[0]; //w zaleznosci od koloru swiatla - g=g*Global::ambientDayLight[1]; - b=b*Global::ambientDayLight[2]; - if (linealpha>1.0) linealpha=1.0; //trzeba ograniczyć do <=1 - glColor4f(r,g,b,linealpha); - glDrawArrays(GL_LINES,iPtr,iLines); - glLineWidth(1.0); - glEnable(GL_LINE_SMOOTH); - glEnable(GL_LIGHTING); //bez tego się modele nie oświetlają - } }; int __fastcall TTraction::TestPoint(vector3 *Point) -{//sprawdzanie, czy przęsła można połączyć - if (!hvNext[0]) - if (pPoint1.Equal(Point)) - return 0; - if (!hvNext[1]) - if (pPoint2.Equal(Point)) - return 1; - return -1; +{ // sprawdzanie, czy przęsła można połączyć + if (!hvNext[0]) + if (pPoint1.Equal(Point)) + return 0; + if (!hvNext[1]) + if (pPoint2.Equal(Point)) + return 1; + return -1; }; -void __fastcall TTraction::Connect(int my,TTraction *with,int to) -{//łączenie segmentu (with) od strony (my) do jego (to) - if (my) - {//do mojego Point2 - hvNext[1]=with; - iNext[1]=to; - } - else - {//do mojego Point1 - hvNext[0]=with; - iNext[0]=to; - } - if (to) - {//do jego Point2 - with->hvNext[1]=this; - with->iNext[1]=my; - } - else - {//do jego Point1 - with->hvNext[0]=this; - with->iNext[0]=my; - } - if (hvNext[0]) //jeśli z obu stron podłączony - if (hvNext[1]) - iLast=0; //to nie jest ostatnim - if (with->hvNext[0]) //temu też, bo drugi raz łączenie się nie nie wykona - if (with->hvNext[1]) - with->iLast=0; //to nie jest ostatnim +void __fastcall TTraction::Connect(int my, TTraction *with, int to) +{ //łączenie segmentu (with) od strony (my) do jego (to) + if (my) + { // do mojego Point2 + hvNext[1] = with; + iNext[1] = to; + } + else + { // do mojego Point1 + hvNext[0] = with; + iNext[0] = to; + } + if (to) + { // do jego Point2 + with->hvNext[1] = this; + with->iNext[1] = my; + } + else + { // do jego Point1 + with->hvNext[0] = this; + with->iNext[0] = my; + } + if (hvNext[0]) // jeśli z obu stron podłączony + if (hvNext[1]) + iLast = 0; // to nie jest ostatnim + if (with->hvNext[0]) // temu też, bo drugi raz łączenie się nie nie wykona + if (with->hvNext[1]) + with->iLast = 0; // to nie jest ostatnim }; bool __fastcall TTraction::WhereIs() -{//ustalenie przedostatnich przęseł - if (iLast) return (iLast==1); //ma już ustaloną informację o położeniu - if (hvNext[0]?hvNext[0]->iLast==1:false) //jeśli poprzedni jest ostatnim - iLast=2; //jest przedostatnim - else - if (hvNext[1]?hvNext[1]->iLast==1:false) //jeśli następny jest ostatnim - iLast=2; //jest przedostatnim - return (iLast==1); //ostatnie będą dostawać zasilanie +{ // ustalenie przedostatnich przęseł + if (iLast) + return (iLast == 1); // ma już ustaloną informację o położeniu + if (hvNext[0] ? hvNext[0]->iLast == 1 : false) // jeśli poprzedni jest ostatnim + iLast = 2; // jest przedostatnim + else if (hvNext[1] ? hvNext[1]->iLast == 1 : false) // jeśli następny jest ostatnim + iLast = 2; // jest przedostatnim + return (iLast == 1); // ostatnie będą dostawać zasilanie }; void __fastcall TTraction::Init() -{//przeliczenie parametrów - vParametric=pPoint2-pPoint1; //wektor mnożników parametru dla równania parametrycznego +{ // przeliczenie parametrów + vParametric = pPoint2 - pPoint1; // wektor mnożników parametru dla równania parametrycznego }; -void __fastcall TTraction::ResistanceCalc(int d,double r,TTractionPowerSource *ps) -{//(this) jest przęsłem zasilanym, o rezystancji (r), policzyć rezystancję zastępczą sąsiednich - if (d>=0) - {//podążanie we wskazanym kierunku - TTraction *t=hvNext[d],*p; - if (ps) - psPower[d^1]=ps; //podłączenie podanego - else - ps=psPower[d^1]; //zasilacz od przeciwnej strony niż idzie analiza - d=iNext[d]; //kierunek - //double r; //sumaryczna rezystancja - if (DebugModeFlag) //tylko podczas testów - Material=4; //pokazanie, że to przęsło ma podłączone zasilanie - while (t?!t->psPower[d]:false) //jeśli jest jakiś kolejny i nie ma ustalonego zasilacza - {//ustawienie zasilacza i policzenie rezystancji zastępczej - if (DebugModeFlag) //tylko podczas testów - if (t->Material!=4) //przęsła zasilającego nie modyfikować - {if (t->Material<4) t->Material=4; //tymczasowo, aby zmieniła kolor - t->Material|=d?2:1; //kolor zależny od strony, z której jest zasilanie +void __fastcall TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) +{ //(this) jest przęsłem zasilanym, o rezystancji (r), policzyć rezystancję zastępczą sąsiednich + if (d >= 0) + { // podążanie we wskazanym kierunku + TTraction *t = hvNext[d], *p; + if (ps) + psPower[d ^ 1] = ps; // podłączenie podanego + else + ps = psPower[d ^ 1]; // zasilacz od przeciwnej strony niż idzie analiza + d = iNext[d]; // kierunek + // double r; //sumaryczna rezystancja + if (DebugModeFlag) // tylko podczas testów + Material = 4; // pokazanie, że to przęsło ma podłączone zasilanie + while (t ? !t->psPower[d] : false) // jeśli jest jakiś kolejny i nie ma ustalonego zasilacza + { // ustawienie zasilacza i policzenie rezystancji zastępczej + if (DebugModeFlag) // tylko podczas testów + if (t->Material != 4) // przęsła zasilającego nie modyfikować + { + if (t->Material < 4) + t->Material = 4; // tymczasowo, aby zmieniła kolor + t->Material |= d ? 2 : 1; // kolor zależny od strony, z której jest zasilanie + } + t->psPower[d] = ps; // skopiowanie wskaźnika zasilacza od danej strony + t->fResistance[d] = r; // wpisanie rezystancji w kierunku tego zasilacza + r += t->fResistivity * Length3(t->vParametric); // doliczenie oporu kolejnego odcinka + p = t; // zapamiętanie dotychczasowego + t = p->hvNext[d ^ 1]; // podążanie w tę samą stronę + d = p->iNext[d ^ 1]; + // w przypadku zapętlenia sieci może się zawiesić? + } + } + else + { // podążanie w obu kierunkach, można by rekurencją, ale szkoda zasobów + r = 0.5 * fResistivity * + Length3(vParametric); // powiedzmy, że w zasilanym przęśle jest połowa + if (fResistance[0] == 0.0) + ResistanceCalc(0, r); // do tyłu (w stronę Point1) + if (fResistance[1] == 0.0) + ResistanceCalc(1, r); // do przodu (w stronę Point2) } - t->psPower[d]=ps; //skopiowanie wskaźnika zasilacza od danej strony - t->fResistance[d]=r; //wpisanie rezystancji w kierunku tego zasilacza - r+=t->fResistivity*Length3(t->vParametric); //doliczenie oporu kolejnego odcinka - p=t; //zapamiętanie dotychczasowego - t=p->hvNext[d^1]; //podążanie w tę samą stronę - d=p->iNext[d^1]; - //w przypadku zapętlenia sieci może się zawiesić? - } - } - else - {//podążanie w obu kierunkach, można by rekurencją, ale szkoda zasobów - r=0.5*fResistivity*Length3(vParametric); //powiedzmy, że w zasilanym przęśle jest połowa - if (fResistance[0]==0.0) ResistanceCalc(0,r); //do tyłu (w stronę Point1) - if (fResistance[1]==0.0) ResistanceCalc(1,r); //do przodu (w stronę Point2) - } }; void __fastcall TTraction::PowerSet(TTractionPowerSource *ps) -{//podłączenie przęsła do zasilacza - if (ps->bSection) - psSection=ps; //ustalenie sekcji zasilania - else - {//ustalenie punktu zasilania (nie ma jeszcze połączeń między przęsłami) - psPowered=ps; //ustawienie bezpośredniego zasilania dla przęsła - psPower[0]=psPower[1]=ps; //a to chyba nie jest dobry pomysł, bo nawet zasilane przęsło powinno mieć wskazania na inne - fResistance[0]=fResistance[1]=0.0; //a liczy się tylko rezystancja zasilacza - } +{ // podłączenie przęsła do zasilacza + if (ps->bSection) + psSection = ps; // ustalenie sekcji zasilania + else + { // ustalenie punktu zasilania (nie ma jeszcze połączeń między przęsłami) + psPowered = ps; // ustawienie bezpośredniego zasilania dla przęsła + psPower[0] = psPower[1] = ps; // a to chyba nie jest dobry pomysł, bo nawet zasilane przęsło + // powinno mieć wskazania na inne + fResistance[0] = fResistance[1] = 0.0; // a liczy się tylko rezystancja zasilacza + } }; -double __fastcall TTraction::VoltageGet(double u,double i) -{//pobranie napięcia na przęśle po podłączeniu do niego rezystancji (res) - na razie jest to prąd - if (!psSection) - if (!psPowered) - return NominalVoltage; //jak nie ma zasilacza, to napięcie podane w przęśle - //na początek można założyć, że wszystkie podstacje mają to samo napięcie i nie płynie prąd pomiędzy nimi - //dla danego przęsła mamy 3 źródła zasilania - //1. zasilacz psPower[0] z rezystancją fResistance[0] oraz jego wewnętrzną - //2. zasilacz psPower[1] z rezystancją fResistance[1] oraz jego wewnętrzną - //3. zasilacz psPowered z jego wewnętrzną rezystancją dla przęseł zasilanych bezpośrednio - double res=(i!=0.0)?fabs(u/i):10000.0; - if (psPowered) return psPowered->CurrentGet(res)*res; //yB: dla zasilanego nie baw się w gwiazdy, tylko bierz bezpośrednio - double r0t,r1t,r0g,r1g; - double u0,u1,i0,i1; - r0t=fResistance[0]; //średni pomysł, ale lepsze niż nic - r1t=fResistance[1]; //bo nie uwzględnia spadków z innych pojazdów - if (psPower[0]&&psPower[1]) - {//gdy przęsło jest zasilane z obu stron - mamy trójkąt: res, r0t, r1t - //yB: Gdy wywali podstacja, to zaczyna się robić nieciekawie - napięcie w sekcji na jednym końcu jest równe zasilaniu, - //yB: a na drugim końcu jest równe 0. Kolejna sprawa to rozróżnienie uszynienia sieci na podstacji/odłączniku (czyli - //yB: potencjał masy na sieci) od braku zasilania (czyli odłączenie źródła od sieci i brak jego wpływu na napięcie). - if ((r0t>0.0)&&(r1t>0.0)) - {//rezystancje w mianowniku nie mogą być zerowe - r0g=res+r0t+(res*r0t)/r1t; //przeliczenie z trójkąta na gwiazdę - r1g=res+r1t+(res*r1t)/r0t; - //pobierane są prądy dla każdej rezystancji, a suma jest mnożona przez rezystancję pojazdu w celu uzyskania napięcia - i0=psPower[0]->CurrentGet(r0g); //oddzielnie dla sprawdzenia - i1=psPower[1]->CurrentGet(r1g); - return (i0+i1)*res; - } - else if (r0t>=0.0) - return psPower[0]->CurrentGet(res+r0t)*res; - else if (r1t>=0.0) - return psPower[1]->CurrentGet(res+r1t)*res; - else - return 0.0; //co z tym zrobić? - } - else if (psPower[0]&&(r0t>=0.0)) - {//jeśli odcinek podłączony jest tylko z jednej strony - return psPower[0]->CurrentGet(res+r0t)*res; - } - else if (psPower[1]&&(r1t>=0.0)) - return psPower[1]->CurrentGet(res+r1t)*res; - return 0.0; //gdy nie podłączony wcale? +double __fastcall TTraction::VoltageGet(double u, double i) +{ // pobranie napięcia na przęśle po podłączeniu do niego rezystancji (res) - na razie jest to prąd + if (!psSection) + if (!psPowered) + return NominalVoltage; // jak nie ma zasilacza, to napięcie podane w przęśle + // na początek można założyć, że wszystkie podstacje mają to samo napięcie i nie płynie prąd + // pomiędzy nimi + // dla danego przęsła mamy 3 źródła zasilania + // 1. zasilacz psPower[0] z rezystancją fResistance[0] oraz jego wewnętrzną + // 2. zasilacz psPower[1] z rezystancją fResistance[1] oraz jego wewnętrzną + // 3. zasilacz psPowered z jego wewnętrzną rezystancją dla przęseł zasilanych bezpośrednio + double res = (i != 0.0) ? fabs(u / i) : 10000.0; + if (psPowered) + return psPowered->CurrentGet(res) * + res; // yB: dla zasilanego nie baw się w gwiazdy, tylko bierz bezpośrednio + double r0t, r1t, r0g, r1g; + double u0, u1, i0, i1; + r0t = fResistance[0]; //średni pomysł, ale lepsze niż nic + r1t = fResistance[1]; // bo nie uwzględnia spadków z innych pojazdów + if (psPower[0] && psPower[1]) + { // gdy przęsło jest zasilane z obu stron - mamy trójkąt: res, r0t, r1t + // yB: Gdy wywali podstacja, to zaczyna się robić nieciekawie - napięcie w sekcji na jednym + // końcu jest równe zasilaniu, + // yB: a na drugim końcu jest równe 0. Kolejna sprawa to rozróżnienie uszynienia sieci na + // podstacji/odłączniku (czyli + // yB: potencjał masy na sieci) od braku zasilania (czyli odłączenie źródła od sieci i brak + // jego wpływu na napięcie). + if ((r0t > 0.0) && (r1t > 0.0)) + { // rezystancje w mianowniku nie mogą być zerowe + r0g = res + r0t + (res * r0t) / r1t; // przeliczenie z trójkąta na gwiazdę + r1g = res + r1t + (res * r1t) / r0t; + // pobierane są prądy dla każdej rezystancji, a suma jest mnożona przez rezystancję + // pojazdu w celu uzyskania napięcia + i0 = psPower[0]->CurrentGet(r0g); // oddzielnie dla sprawdzenia + i1 = psPower[1]->CurrentGet(r1g); + return (i0 + i1) * res; + } + else if (r0t >= 0.0) + return psPower[0]->CurrentGet(res + r0t) * res; + else if (r1t >= 0.0) + return psPower[1]->CurrentGet(res + r1t) * res; + else + return 0.0; // co z tym zrobić? + } + else if (psPower[0] && (r0t >= 0.0)) + { // jeśli odcinek podłączony jest tylko z jednej strony + return psPower[0]->CurrentGet(res + r0t) * res; + } + else if (psPower[1] && (r1t >= 0.0)) + return psPower[1]->CurrentGet(res + r1t) * res; + return 0.0; // gdy nie podłączony wcale? }; diff --git a/Traction.h b/Traction.h index 83f89c9f..20f5abc6 100644 --- a/Traction.h +++ b/Traction.h @@ -9,69 +9,72 @@ using namespace Math3D; -class TTractionPowerSource; +class TTractionPowerSource; -class TTraction -{//drut zasilający, dla wskaźników używać przedrostka "hv" -private: - //vector3 vUp,vFront,vLeft; - //matrix4x4 mMatrix; - //matryca do wyliczania pozycji drutu w zależności od [X,Y,kąt] w scenerii: - // - x: odległość w bok (czy odbierak się nie zsunął) - // - y: przyjmuje wartość <0,1>, jeśli pod drutem (wzdłuż) - // - z: wysokość bezwzględna drutu w danym miejsu -public: //na razie - TTractionPowerSource *psPower[2]; //najbliższe zasilacze z obu kierunków - TTractionPowerSource *psPowered; //ustawione tylko dla bezpośrednio zasilanego przęsła - TTraction *hvNext[2]; //łączenie drutów w sieć - int iNext[2]; //do którego końca się łączy - int iLast; //ustawiony bit 0, jeśli jest ostatnim drutem w sekcji; bit1 - przedostatni -public: - GLuint uiDisplayList; - vector3 pPoint1,pPoint2,pPoint3,pPoint4; - vector3 vParametric; //współczynniki równania parametrycznego odcinka - double fHeightDifference;//,fMiddleHeight; - //int iCategory,iMaterial,iDamageFlag; - //float fU,fR,fMaxI,fWireThickness; - int iNumSections; - int iLines; //ilosc linii dla VBO - float NominalVoltage; - float MaxCurrent; - float fResistivity; //[om/m], przeliczone z [om/km] - DWORD Material; //1: Cu, 2: Al - float WireThickness; - DWORD DamageFlag; //1: zasniedziale, 128: zerwana - int Wires; - float WireOffset; - AnsiString asPowerSupplyName; //McZapkie: nazwa podstacji trakcyjnej - TTractionPowerSource *psSection; //zasilacz (opcjonalnie może to być pulpit sterujący EL2 w hali!) - AnsiString asParallel; //nazwa przęsła, z którym może być bieżnia wspólna - TTraction *hvParallel; //jednokierunkowa i zapętlona lista przęseł ewentualnej bieżni wspólnej - float fResistance[2]; //rezystancja zastępcza do punktu zasilania (0: przęsło zasilane, <0: do policzenia) - int iTries; - //bool bVisible; - //DWORD dwFlags; +class TTraction +{ // drut zasilający, dla wskaźników używać przedrostka "hv" + private: + // vector3 vUp,vFront,vLeft; + // matrix4x4 mMatrix; + // matryca do wyliczania pozycji drutu w zależności od [X,Y,kąt] w scenerii: + // - x: odległość w bok (czy odbierak się nie zsunął) + // - y: przyjmuje wartość <0,1>, jeśli pod drutem (wzdłuż) + // - z: wysokość bezwzględna drutu w danym miejsu + public: // na razie + TTractionPowerSource *psPower[2]; // najbliższe zasilacze z obu kierunków + TTractionPowerSource *psPowered; // ustawione tylko dla bezpośrednio zasilanego przęsła + TTraction *hvNext[2]; //łączenie drutów w sieć + int iNext[2]; // do którego końca się łączy + int iLast; // ustawiony bit 0, jeśli jest ostatnim drutem w sekcji; bit1 - przedostatni + public: + GLuint uiDisplayList; + vector3 pPoint1, pPoint2, pPoint3, pPoint4; + vector3 vParametric; // współczynniki równania parametrycznego odcinka + double fHeightDifference; //,fMiddleHeight; + // int iCategory,iMaterial,iDamageFlag; + // float fU,fR,fMaxI,fWireThickness; + int iNumSections; + int iLines; // ilosc linii dla VBO + float NominalVoltage; + float MaxCurrent; + float fResistivity; //[om/m], przeliczone z [om/km] + DWORD Material; // 1: Cu, 2: Al + float WireThickness; + DWORD DamageFlag; // 1: zasniedziale, 128: zerwana + int Wires; + float WireOffset; + AnsiString asPowerSupplyName; // McZapkie: nazwa podstacji trakcyjnej + TTractionPowerSource * + psSection; // zasilacz (opcjonalnie może to być pulpit sterujący EL2 w hali!) + AnsiString asParallel; // nazwa przęsła, z którym może być bieżnia wspólna + TTraction *hvParallel; // jednokierunkowa i zapętlona lista przęseł ewentualnej bieżni wspólnej + float fResistance[2]; // rezystancja zastępcza do punktu zasilania (0: przęsło zasilane, <0: do + // policzenia) + int iTries; + // bool bVisible; + // DWORD dwFlags; void __fastcall Optimize(); TTraction(); ~TTraction(); -// virtual void __fastcall InitCenter(vector3 Angles, vector3 pOrigin); -// virtual bool __fastcall Hit(double x, double z, vector3 &hitPoint, vector3 &hitDirection) { return TNode::Hit(x,z,hitPoint,hitDirection); }; - // virtual bool __fastcall Move(double dx, double dy, double dz) { return false; }; -// virtual void __fastcall SelectedRender(); - void __fastcall RenderDL(float mgn); - int __fastcall RaArrayPrepare(); - void __fastcall RaArrayFill(CVertNormTex *Vert); - void __fastcall RenderVBO(float mgn,int iPtr); - int __fastcall TestPoint(vector3 *Point); - void __fastcall Connect(int my,TTraction *with,int to); - void __fastcall Init(); - bool __fastcall WhereIs(); - void __fastcall ResistanceCalc(int d=-1,double r=0,TTractionPowerSource *ps=NULL); - void __fastcall PowerSet(TTractionPowerSource *ps); - double __fastcall VoltageGet(double u,double i); + // virtual void __fastcall InitCenter(vector3 Angles, vector3 pOrigin); + // virtual bool __fastcall Hit(double x, double z, vector3 &hitPoint, vector3 &hitDirection) + // { return TNode::Hit(x,z,hitPoint,hitDirection); }; + // virtual bool __fastcall Move(double dx, double dy, double dz) { return false; }; + // virtual void __fastcall SelectedRender(); + void __fastcall RenderDL(float mgn); + int __fastcall RaArrayPrepare(); + void __fastcall RaArrayFill(CVertNormTex *Vert); + void __fastcall RenderVBO(float mgn, int iPtr); + int __fastcall TestPoint(vector3 *Point); + void __fastcall Connect(int my, TTraction *with, int to); + void __fastcall Init(); + bool __fastcall WhereIs(); + void __fastcall ResistanceCalc(int d = -1, double r = 0, TTractionPowerSource *ps = NULL); + void __fastcall PowerSet(TTractionPowerSource *ps); + double __fastcall VoltageGet(double u, double i); }; //--------------------------------------------------------------------------- #endif diff --git a/TractionPower.cpp b/TractionPower.cpp index e5ad7e9a..e42da57c 100644 --- a/TractionPower.cpp +++ b/TractionPower.cpp @@ -6,9 +6,8 @@ */ - -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Mover.h" @@ -24,131 +23,137 @@ __fastcall TTractionPowerSource::TTractionPowerSource() { - NominalVoltage=0; - VoltageFrequency=0; - InternalRes=0.2; - MaxOutputCurrent=0; - FastFuseTimeOut=1; - FastFuseRepetition=3; - SlowFuseTimeOut=60; - Recuperation=false; + NominalVoltage = 0; + VoltageFrequency = 0; + InternalRes = 0.2; + MaxOutputCurrent = 0; + FastFuseTimeOut = 1; + FastFuseRepetition = 3; + SlowFuseTimeOut = 60; + Recuperation = false; - TotalAdmitance=1e-10; //10Mom - jakaś tam upływność - TotalPreviousAdmitance=1e-10; //zero jest szkodliwe - OutputVoltage=0; - FastFuse=false; - SlowFuse=false; - FuseTimer=0; - FuseCounter=0; - psNode[0]=NULL; //sekcje zostaną podłączone do zasilaczy - psNode[1]=NULL; - bSection=false; //sekcja nie jest źródłem zasilania, tylko grupuje przęsła + TotalAdmitance = 1e-10; // 10Mom - jakaś tam upływność + TotalPreviousAdmitance = 1e-10; // zero jest szkodliwe + OutputVoltage = 0; + FastFuse = false; + SlowFuse = false; + FuseTimer = 0; + FuseCounter = 0; + psNode[0] = NULL; // sekcje zostaną podłączone do zasilaczy + psNode[1] = NULL; + bSection = false; // sekcja nie jest źródłem zasilania, tylko grupuje przęsła }; -__fastcall TTractionPowerSource::~TTractionPowerSource() -{ -}; +__fastcall TTractionPowerSource::~TTractionPowerSource(){}; -void __fastcall TTractionPowerSource::Init(double u,double i) -{//ustawianie zasilacza przy braku w scenerii - NominalVoltage=u; - VoltageFrequency=0; - MaxOutputCurrent=i; +void __fastcall TTractionPowerSource::Init(double u, double i) +{ // ustawianie zasilacza przy braku w scenerii + NominalVoltage = u; + VoltageFrequency = 0; + MaxOutputCurrent = i; }; bool __fastcall 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; + 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 __fastcall TTractionPowerSource::Render() -{ - return true; -}; +bool __fastcall TTractionPowerSource::Render() { return true; }; bool __fastcall TTractionPowerSource::Update(double dt) -{//powinno być wykonane raz na krok fizyki - if (NominalVoltage*TotalPreviousAdmitance>MaxOutputCurrent) //iloczyn napięcia i admitancji daje prąd - { - FastFuse=true; - FuseCounter+=1; - if (FuseCounter>FastFuseRepetition) - {SlowFuse=true; - ErrorLog("Power overload: \""+gMyNode->asName+"\" disabled for "+AnsiString(SlowFuseTimeOut)+"s"); - } - else - ErrorLog("Power overload: \""+gMyNode->asName+"\" disabled for "+AnsiString(FastFuseTimeOut)+"s"); - FuseTimer=0; - } - if (FastFuse||SlowFuse) - {//jeśli któryś z bezpieczników zadziałał - TotalAdmitance=0; - FuseTimer+=dt; - if (!SlowFuse) - {//gdy szybki, odczekać krótko i załączyć - if (FuseTimer>FastFuseTimeOut) - FastFuse=false; - } - else - if (FuseTimer>SlowFuseTimeOut) - {SlowFuse=false; - FuseCounter=0; //dajemy znów szansę - } - } - TotalPreviousAdmitance=TotalAdmitance; //używamy admitancji z poprzedniego kroku - if (TotalPreviousAdmitance==0.0) - TotalPreviousAdmitance=1e-10; //przynajmniej minimalna upływność - TotalAdmitance=1e-10; //a w aktualnym kroku sumujemy admitancję - return true; +{ // powinno być wykonane raz na krok fizyki + if (NominalVoltage * TotalPreviousAdmitance > + MaxOutputCurrent) // iloczyn napięcia i admitancji daje prąd + { + FastFuse = true; + FuseCounter += 1; + if (FuseCounter > FastFuseRepetition) + { + SlowFuse = true; + ErrorLog("Power overload: \"" + gMyNode->asName + "\" disabled for " + + AnsiString(SlowFuseTimeOut) + "s"); + } + else + ErrorLog("Power overload: \"" + gMyNode->asName + "\" disabled for " + + AnsiString(FastFuseTimeOut) + "s"); + FuseTimer = 0; + } + if (FastFuse || SlowFuse) + { // jeśli któryś z bezpieczników zadziałał + TotalAdmitance = 0; + FuseTimer += dt; + if (!SlowFuse) + { // gdy szybki, odczekać krótko i załączyć + if (FuseTimer > FastFuseTimeOut) + FastFuse = false; + } + else if (FuseTimer > SlowFuseTimeOut) + { + SlowFuse = false; + FuseCounter = 0; // dajemy znów szansę + } + } + TotalPreviousAdmitance = TotalAdmitance; // używamy admitancji z poprzedniego kroku + if (TotalPreviousAdmitance == 0.0) + TotalPreviousAdmitance = 1e-10; // przynajmniej minimalna upływność + TotalAdmitance = 1e-10; // a w aktualnym kroku sumujemy admitancję + return true; }; double __fastcall TTractionPowerSource::CurrentGet(double res) -{//pobranie wartości prądu przypadającego na rezystancję (res) - //niech pamięta poprzednią admitancję i wg niej przydziela prąd - if (SlowFuse||FastFuse) - {//czekanie na zanik obciążenia sekcji - if (res<100.0) //liczenie czasu dopiero, gdy obciążenie zniknie - FuseTimer=0; - return 0; - } - if ((res>0)||((res<0)&&(Recuperation))) - TotalAdmitance+=1.0/res; //połączenie równoległe rezystancji jest równoważne sumie admitancji - TotalCurrent=(TotalPreviousAdmitance!=0.0)?NominalVoltage/(InternalRes+1.0/TotalPreviousAdmitance):0.0; //napięcie dzielone przez sumę rezystancji wewnętrznej i obciążenia - OutputVoltage=NominalVoltage-InternalRes*TotalCurrent; //napięcie na obciążeniu - return TotalCurrent/(res*TotalPreviousAdmitance); //prąd proporcjonalny do udziału (1/res) w całkowitej admitancji +{ // pobranie wartości prądu przypadającego na rezystancję (res) + // niech pamięta poprzednią admitancję i wg niej przydziela prąd + if (SlowFuse || FastFuse) + { // czekanie na zanik obciążenia sekcji + if (res < 100.0) // liczenie czasu dopiero, gdy obciążenie zniknie + FuseTimer = 0; + return 0; + } + if ((res > 0) || ((res < 0) && (Recuperation))) + TotalAdmitance += + 1.0 / res; // połączenie równoległe rezystancji jest równoważne sumie admitancji + TotalCurrent = (TotalPreviousAdmitance != 0.0) ? + NominalVoltage / (InternalRes + 1.0 / TotalPreviousAdmitance) : + 0.0; // napięcie dzielone przez sumę rezystancji wewnętrznej i obciążenia + OutputVoltage = NominalVoltage - InternalRes * TotalCurrent; // napięcie na obciążeniu + return TotalCurrent / (res * TotalPreviousAdmitance); // prąd proporcjonalny do udziału (1/res) + // w całkowitej admitancji }; void __fastcall TTractionPowerSource::PowerSet(TTractionPowerSource *ps) -{//wskazanie zasilacza w obiekcie sekcji - if (!psNode[0]) - psNode[0]=ps; - else if (!psNode[1]) - psNode[1]=ps; - //else ErrorLog("nie może być więcej punktów zasilania niż dwa"); +{ // wskazanie zasilacza w obiekcie sekcji + if (!psNode[0]) + psNode[0] = ps; + else if (!psNode[1]) + psNode[1] = ps; + // else ErrorLog("nie może być więcej punktów zasilania niż dwa"); }; //--------------------------------------------------------------------------- diff --git a/TractionPower.h b/TractionPower.h index a75e6e91..d7ee5e55 100644 --- a/TractionPower.h +++ b/TractionPower.h @@ -8,41 +8,41 @@ class TGroundNode; class TTractionPowerSource { -private: - double NominalVoltage; - double VoltageFrequency; - double InternalRes; - double MaxOutputCurrent; - double FastFuseTimeOut; - int FastFuseRepetition; - double SlowFuseTimeOut; - bool Recuperation; + private: + double NominalVoltage; + double VoltageFrequency; + double InternalRes; + double MaxOutputCurrent; + double FastFuseTimeOut; + int FastFuseRepetition; + double SlowFuseTimeOut; + bool Recuperation; - double TotalCurrent; - double TotalAdmitance; - double TotalPreviousAdmitance; - double OutputVoltage; - bool FastFuse; - bool SlowFuse; - double FuseTimer; - int FuseCounter; -protected: + double TotalCurrent; + double TotalAdmitance; + double TotalPreviousAdmitance; + double OutputVoltage; + bool FastFuse; + bool SlowFuse; + double FuseTimer; + int FuseCounter; -public: //zmienne publiczne - TTractionPowerSource *psNode[2]; //zasilanie na końcach dla sekcji - bool bSection; //czy jest sekcją - TGroundNode *gMyNode; //Ra 2015-03: znowu prowizorka, aby mieć nazwę do logowania -public: - //AnsiString asName; - __fastcall TTractionPowerSource(); - __fastcall ~TTractionPowerSource(); - void __fastcall Init(double u,double i); - bool __fastcall Load(cParser *parser); - bool __fastcall Render(); - bool __fastcall Update(double dt); - double __fastcall CurrentGet(double res); - void __fastcall VoltageSet(double v) {NominalVoltage=v;}; - void __fastcall PowerSet(TTractionPowerSource *ps); + protected: + public: // zmienne publiczne + TTractionPowerSource *psNode[2]; // zasilanie na końcach dla sekcji + bool bSection; // czy jest sekcją + TGroundNode *gMyNode; // Ra 2015-03: znowu prowizorka, aby mieć nazwę do logowania + public: + // AnsiString asName; + __fastcall TTractionPowerSource(); + __fastcall ~TTractionPowerSource(); + void __fastcall Init(double u, double i); + bool __fastcall Load(cParser *parser); + bool __fastcall Render(); + bool __fastcall Update(double dt); + double __fastcall CurrentGet(double res); + void __fastcall VoltageSet(double v) { NominalVoltage = v; }; + void __fastcall PowerSet(TTractionPowerSource *ps); }; //--------------------------------------------------------------------------- diff --git a/Train.cpp b/Train.cpp index 8db41bcd..12179d96 100644 --- a/Train.cpp +++ b/Train.cpp @@ -5,8 +5,8 @@ */ -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "Train.h" @@ -23,5257 +23,5637 @@ using namespace Timer; __fastcall TCab::TCab() { - CabPos1.x=-1.0; CabPos1.y=1.0; CabPos1.z=1.0; - CabPos2.x=1.0; CabPos2.y=1.0; CabPos2.z=-1.0; - bEnabled=false; - bOccupied=true; - dimm_r=dimm_g=dimm_b=1; - intlit_r=intlit_g=intlit_b=0; - intlitlow_r=intlitlow_g=intlitlow_b=0; - iGaugesMax=100; //95 - trzeba pobierać to z pliku konfiguracyjnego - ggList=new TGauge[iGaugesMax]; - iGauges=0; //na razie nie są dodane - iButtonsMax=60; //55 - trzeba pobierać to z pliku konfiguracyjnego - btList=new TButton[iButtonsMax]; - iButtons=0; + CabPos1.x = -1.0; + CabPos1.y = 1.0; + CabPos1.z = 1.0; + CabPos2.x = 1.0; + CabPos2.y = 1.0; + CabPos2.z = -1.0; + bEnabled = false; + bOccupied = true; + dimm_r = dimm_g = dimm_b = 1; + intlit_r = intlit_g = intlit_b = 0; + intlitlow_r = intlitlow_g = intlitlow_b = 0; + iGaugesMax = 100; // 95 - trzeba pobierać to z pliku konfiguracyjnego + ggList = new TGauge[iGaugesMax]; + iGauges = 0; // na razie nie są dodane + iButtonsMax = 60; // 55 - trzeba pobierać to z pliku konfiguracyjnego + btList = new TButton[iButtonsMax]; + iButtons = 0; } -void __fastcall TCab::Init(double Initx1,double Inity1,double Initz1,double Initx2,double Inity2,double Initz2,bool InitEnabled,bool InitOccupied) +void __fastcall TCab::Init(double Initx1, double Inity1, double Initz1, double Initx2, + double Inity2, double Initz2, bool InitEnabled, bool InitOccupied) { - CabPos1.x=Initx1; CabPos1.y=Inity1; CabPos1.z=Initz1; - CabPos2.x=Initx2; CabPos2.y=Inity2; CabPos2.z=Initz2; - bEnabled=InitEnabled; - bOccupied=InitOccupied; + CabPos1.x = Initx1; + CabPos1.y = Inity1; + CabPos1.z = Initz1; + CabPos2.x = Initx2; + CabPos2.y = Inity2; + CabPos2.z = Initz2; + bEnabled = InitEnabled; + bOccupied = InitOccupied; } void __fastcall TCab::Load(TQueryParserComp *Parser) { - AnsiString str=Parser->GetNextSymbol().LowerCase(); - if (str==AnsiString("cablight")) - { - dimm_r=Parser->GetNextSymbol().ToDouble(); - dimm_g=Parser->GetNextSymbol().ToDouble(); - dimm_b=Parser->GetNextSymbol().ToDouble(); - intlit_r=Parser->GetNextSymbol().ToDouble(); - intlit_g=Parser->GetNextSymbol().ToDouble(); - intlit_b=Parser->GetNextSymbol().ToDouble(); - intlitlow_r=Parser->GetNextSymbol().ToDouble(); - intlitlow_g=Parser->GetNextSymbol().ToDouble(); - intlitlow_b=Parser->GetNextSymbol().ToDouble(); - str=Parser->GetNextSymbol().LowerCase(); - } - CabPos1.x=str.ToDouble(); - CabPos1.y=Parser->GetNextSymbol().ToDouble(); - CabPos1.z=Parser->GetNextSymbol().ToDouble(); - CabPos2.x=Parser->GetNextSymbol().ToDouble(); - CabPos2.y=Parser->GetNextSymbol().ToDouble(); - CabPos2.z=Parser->GetNextSymbol().ToDouble(); + AnsiString str = Parser->GetNextSymbol().LowerCase(); + if (str == AnsiString("cablight")) + { + dimm_r = Parser->GetNextSymbol().ToDouble(); + dimm_g = Parser->GetNextSymbol().ToDouble(); + dimm_b = Parser->GetNextSymbol().ToDouble(); + intlit_r = Parser->GetNextSymbol().ToDouble(); + intlit_g = Parser->GetNextSymbol().ToDouble(); + intlit_b = Parser->GetNextSymbol().ToDouble(); + intlitlow_r = Parser->GetNextSymbol().ToDouble(); + intlitlow_g = Parser->GetNextSymbol().ToDouble(); + intlitlow_b = Parser->GetNextSymbol().ToDouble(); + str = Parser->GetNextSymbol().LowerCase(); + } + CabPos1.x = str.ToDouble(); + CabPos1.y = Parser->GetNextSymbol().ToDouble(); + CabPos1.z = Parser->GetNextSymbol().ToDouble(); + CabPos2.x = Parser->GetNextSymbol().ToDouble(); + CabPos2.y = Parser->GetNextSymbol().ToDouble(); + CabPos2.z = Parser->GetNextSymbol().ToDouble(); - bEnabled=True; - bOccupied=True; + bEnabled = True; + bOccupied = True; } __fastcall TCab::~TCab() { - delete[] ggList; - delete[] btList; + delete[] ggList; + delete[] btList; }; -TGauge* __fastcall TCab::Gauge(int n) -{//pobranie adresu obiektu aniomowanego ruchem - if (n<0) - {//rezerwacja wolnego - ggList[iGauges].Clear(); - return ggList+iGauges++; - } - else if (nMechanik) - DynamicObject->Mechanik->TakeControl(true); //likwidacja kabiny wymaga przejęcia przez AI + if (DynamicObject) + if (DynamicObject->Mechanik) + DynamicObject->Mechanik->TakeControl( + true); // likwidacja kabiny wymaga przejęcia przez AI } -bool __fastcall TTrain::Init(TDynamicObject *NewDynamicObject,bool e3d) -{//powiązanie ręcznego sterowania kabiną z pojazdem - //Global::pUserDynamic=NewDynamicObject; //pojazd renderowany bez trzęsienia - DynamicSet(NewDynamicObject); - if (!e3d) - if (DynamicObject->Mechanik==NULL) - return false; - //if (DynamicObject->Mechanik->AIControllFlag==AIdriver) - // return false; - DynamicObject->MechInside=true; +bool __fastcall TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d) +{ // powiązanie ręcznego sterowania kabiną z pojazdem + // Global::pUserDynamic=NewDynamicObject; //pojazd renderowany bez trzęsienia + DynamicSet(NewDynamicObject); + if (!e3d) + if (DynamicObject->Mechanik == NULL) + return false; + // if (DynamicObject->Mechanik->AIControllFlag==AIdriver) + // return false; + DynamicObject->MechInside = true; -/* iPozSzereg=28; - for (int i=1; iMainCtrlPosNo; i++) - { - if (mvControlled->RList[i].Bn>1) - { - iPozSzereg=i-1; - i=mvControlled->MainCtrlPosNo+1; - } - } -*/ - MechSpring.Init(0,500); - vMechVelocity=vector3(0,0,0); - pMechOffset=vector3(-0.4,3.3,5.5); - fMechCroach=0.5; - fMechSpringX=1; - fMechSpringY=0.1; - fMechSpringZ=0.1; - fMechMaxSpring=0.15; - fMechRoll=0.05; - fMechPitch=0.1; - fMainRelayTimer=0; //Hunter, do k...y nędzy, ustawiaj wartości początkowe zmiennych! + /* iPozSzereg=28; + for (int i=1; iMainCtrlPosNo; i++) + { + if (mvControlled->RList[i].Bn>1) + { + iPozSzereg=i-1; + i=mvControlled->MainCtrlPosNo+1; + } + } + */ + MechSpring.Init(0, 500); + vMechVelocity = vector3(0, 0, 0); + pMechOffset = vector3(-0.4, 3.3, 5.5); + fMechCroach = 0.5; + fMechSpringX = 1; + fMechSpringY = 0.1; + fMechSpringZ = 0.1; + fMechMaxSpring = 0.15; + fMechRoll = 0.05; + fMechPitch = 0.1; + fMainRelayTimer = 0; // Hunter, do k...y nędzy, ustawiaj wartości początkowe zmiennych! - if (!LoadMMediaFile(DynamicObject->asBaseDir+DynamicObject->MoverParameters->TypeName+".mmd")) - return false; + if (!LoadMMediaFile(DynamicObject->asBaseDir + DynamicObject->MoverParameters->TypeName + + ".mmd")) + return false; -//McZapkie: w razie wykolejenia -// dsbDerailment=TSoundsManager::GetFromName("derail.wav"); -//McZapkie: jazda luzem: -// dsbRunningNoise=TSoundsManager::GetFromName("runningnoise.wav"); + // McZapkie: w razie wykolejenia + // dsbDerailment=TSoundsManager::GetFromName("derail.wav"); + // McZapkie: jazda luzem: + // dsbRunningNoise=TSoundsManager::GetFromName("runningnoise.wav"); -// McZapkie? - dzwieki slyszalne tylko wewnatrz kabiny - generowane przez obiekt sterowany: + // McZapkie? - dzwieki slyszalne tylko wewnatrz kabiny - generowane przez obiekt sterowany: + // McZapkie-080302 sWentylatory.Init("wenton.wav","went.wav","wentoff.wav"); + // McZapkie-010302 + // sCompressor.Init("compressor-start.wav","compressor.wav","compressor-stop.wav"); -//McZapkie-080302 sWentylatory.Init("wenton.wav","went.wav","wentoff.wav"); -//McZapkie-010302 -// sCompressor.Init("compressor-start.wav","compressor.wav","compressor-stop.wav"); + // sHorn1.Init("horn1.wav",0.3); + // sHorn2.Init("horn2.wav",0.3); -// sHorn1.Init("horn1.wav",0.3); -// sHorn2.Init("horn2.wav",0.3); + // sHorn1.Init("horn1-start.wav","horn1.wav","horn1-stop.wav"); + // sHorn2.Init("horn2-start.wav","horn2.wav","horn2-stop.wav"); -// sHorn1.Init("horn1-start.wav","horn1.wav","horn1-stop.wav"); -// sHorn2.Init("horn2-start.wav","horn2.wav","horn2-stop.wav"); - -// sConverter.Init("converter.wav",1.5); //NBMX obsluga przez AdvSound - iCabn=0; - //Ra: taka proteza - przesłanie kierunku do członów connected - if (mvControlled->ActiveDir>0) - {//było do przodu - mvControlled->DirectionBackward(); - mvControlled->DirectionForward(); - } - else if (mvControlled->ActiveDir<0) - {mvControlled->DirectionForward(); - mvControlled->DirectionBackward(); - } - return true; + // sConverter.Init("converter.wav",1.5); //NBMX obsluga przez AdvSound + iCabn = 0; + // Ra: taka proteza - przesłanie kierunku do członów connected + if (mvControlled->ActiveDir > 0) + { // było do przodu + mvControlled->DirectionBackward(); + mvControlled->DirectionForward(); + } + else if (mvControlled->ActiveDir < 0) + { + mvControlled->DirectionForward(); + mvControlled->DirectionBackward(); + } + return true; } - void __fastcall TTrain::OnKeyDown(int cKey) -{//naciśnięcie klawisza - bool isEztOer; - isEztOer=((mvControlled->TrainType==dt_EZT)&&(mvControlled->Battery==true)&&(mvControlled->EpFuse==true)&&(mvOccupied->BrakeSubsystem==ss_ESt)&&(mvControlled->ActiveDir!=0)); //od yB - //isEztOer=(mvControlled->TrainType==dt_EZT)&&(mvControlled->Mains)&&(mvOccupied->BrakeSubsystem==ss_ESt)&&(mvControlled->ActiveDir!=0); - //isEztOer=((mvControlled->TrainType==dt_EZT)&&(mvControlled->Battery==true)&&(mvControlled->EpFuse==true)&&(mvOccupied->BrakeSubsystem==Oerlikon)&&(mvControlled->ActiveDir!=0)); +{ // naciśnięcie klawisza + bool isEztOer; + isEztOer = ((mvControlled->TrainType == dt_EZT) && (mvControlled->Battery == true) && + (mvControlled->EpFuse == true) && (mvOccupied->BrakeSubsystem == ss_ESt) && + (mvControlled->ActiveDir != 0)); // od yB + // isEztOer=(mvControlled->TrainType==dt_EZT)&&(mvControlled->Mains)&&(mvOccupied->BrakeSubsystem==ss_ESt)&&(mvControlled->ActiveDir!=0); + // isEztOer=((mvControlled->TrainType==dt_EZT)&&(mvControlled->Battery==true)&&(mvControlled->EpFuse==true)&&(mvOccupied->BrakeSubsystem==Oerlikon)&&(mvControlled->ActiveDir!=0)); - if (GetAsyncKeyState(VK_SHIFT)<0) - {//wciśnięty [Shift] - if (cKey==Global::Keys[k_IncMainCtrlFAST]) //McZapkie-200702: szybkie przelaczanie na poz. bezoporowa - { - if (mvControlled->IncMainCtrl(2)) - { - dsbNastawnikJazdy->SetCurrentPosition(0); - dsbNastawnikJazdy->Play(0,0,0); - } - } - else - if (cKey==Global::Keys[k_DirectionBackward]) - { - if (mvControlled->Radio==false) - if (GetAsyncKeyState(VK_CONTROL)>=0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - mvControlled->Radio=true; - } - } - else + if (GetAsyncKeyState(VK_SHIFT) < 0) + { // wciśnięty [Shift] + if (cKey == Global::Keys[k_IncMainCtrlFAST]) // McZapkie-200702: szybkie przelaczanie na + // poz. bezoporowa + { + if (mvControlled->IncMainCtrl(2)) + { + dsbNastawnikJazdy->SetCurrentPosition(0); + dsbNastawnikJazdy->Play(0, 0, 0); + } + } + else if (cKey == Global::Keys[k_DirectionBackward]) + { + if (mvControlled->Radio == false) + if (GetAsyncKeyState(VK_CONTROL) >= 0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + mvControlled->Radio = true; + } + } + else - if (cKey==Global::Keys[k_DecMainCtrlFAST]) - if (mvControlled->DecMainCtrl(2)) - { - dsbNastawnikJazdy->SetCurrentPosition(0); - dsbNastawnikJazdy->Play(0,0,0); - } - else; - else - if (cKey==Global::Keys[k_IncScndCtrlFAST]) - if (mvControlled->IncScndCtrl(2)) - { - if (dsbNastawnikBocz) //hunter-081211 - { - dsbNastawnikBocz->SetCurrentPosition(0); - dsbNastawnikBocz->Play(0,0,0); - } - else if (!dsbNastawnikBocz) - { - dsbNastawnikJazdy->SetCurrentPosition(0); - dsbNastawnikJazdy->Play(0,0,0); - } - } - else; - else - if (cKey==Global::Keys[k_DecScndCtrlFAST]) - if (mvControlled->DecScndCtrl(2)) - { - if (dsbNastawnikBocz) //hunter-081211 - { - dsbNastawnikBocz->SetCurrentPosition(0); - dsbNastawnikBocz->Play(0,0,0); - } - else if (!dsbNastawnikBocz) - { - dsbNastawnikJazdy->SetCurrentPosition(0); - dsbNastawnikJazdy->Play(0,0,0); - } - } - else; - else - if (cKey==Global::Keys[k_IncLocalBrakeLevelFAST]) - if (mvOccupied->IncLocalBrakeLevel(2)); - else; - else - if (cKey==Global::Keys[k_DecLocalBrakeLevelFAST]) - if (mvOccupied->DecLocalBrakeLevel(2)); - else; - // McZapkie-240302 - wlaczanie glownego obwodu klawiszem M+shift - //----------- - //hunter-141211: wyl. szybki zalaczony przeniesiony do TTrain::Update() - /* if (cKey==Global::Keys[k_Main]) - { - ggMainOnButton.PutValue(1); - if (mvControlled->MainSwitch(true)) - { - if (mvControlled->EngineType==DieselEngine) - dsbDieselIgnition->Play(0,0,0); - else - dsbNastawnikJazdy->Play(0,0,0); - } - } - else */ - if (cKey==Global::Keys[k_Battery]) - { - //if (((mvControlled->TrainType==dt_EZT)||(mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->EngineType==DieselElectric))&&(!mvControlled->Battery)) - if (!mvControlled->Battery) - {//wyłącznik jest też w SN61, ewentualnie załączać prąd na stałe z poziomu FIZ - if (mvOccupied->BatterySwitch(true)) //bateria potrzebna np. do zapalenia świateł + if (cKey == Global::Keys[k_DecMainCtrlFAST]) + if (mvControlled->DecMainCtrl(2)) + { + dsbNastawnikJazdy->SetCurrentPosition(0); + dsbNastawnikJazdy->Play(0, 0, 0); + } + else + ; + else if (cKey == Global::Keys[k_IncScndCtrlFAST]) + if (mvControlled->IncScndCtrl(2)) + { + if (dsbNastawnikBocz) // hunter-081211 + { + dsbNastawnikBocz->SetCurrentPosition(0); + dsbNastawnikBocz->Play(0, 0, 0); + } + else if (!dsbNastawnikBocz) + { + dsbNastawnikJazdy->SetCurrentPosition(0); + dsbNastawnikJazdy->Play(0, 0, 0); + } + } + else + ; + else if (cKey == Global::Keys[k_DecScndCtrlFAST]) + if (mvControlled->DecScndCtrl(2)) + { + if (dsbNastawnikBocz) // hunter-081211 + { + dsbNastawnikBocz->SetCurrentPosition(0); + dsbNastawnikBocz->Play(0, 0, 0); + } + else if (!dsbNastawnikBocz) + { + dsbNastawnikJazdy->SetCurrentPosition(0); + dsbNastawnikJazdy->Play(0, 0, 0); + } + } + else + ; + else if (cKey == Global::Keys[k_IncLocalBrakeLevelFAST]) + if (mvOccupied->IncLocalBrakeLevel(2)) + ; + else + ; + else if (cKey == Global::Keys[k_DecLocalBrakeLevelFAST]) + if (mvOccupied->DecLocalBrakeLevel(2)) + ; + else + ; + // McZapkie-240302 - wlaczanie glownego obwodu klawiszem M+shift + //----------- + // hunter-141211: wyl. szybki zalaczony przeniesiony do TTrain::Update() + /* if (cKey==Global::Keys[k_Main]) { - dsbSwitch->Play(0,0,0); - if (TestFlag(mvOccupied->SecuritySystem.SystemType,2)) //Ra: znowu w kabinie jest coś, co być nie powinno! - { - SetFlag(mvOccupied->SecuritySystem.Status,s_active); - SetFlag(mvOccupied->SecuritySystem.Status,s_SHPalarm); - } + ggMainOnButton.PutValue(1); + if (mvControlled->MainSwitch(true)) + { + if (mvControlled->EngineType==DieselEngine) + dsbDieselIgnition->Play(0,0,0); + else + dsbNastawnikJazdy->Play(0,0,0); + } } - } - } - else - if (cKey==Global::Keys[k_StLinOff]) - { - if(mvControlled->TrainType==dt_EZT) - { - if ((mvControlled->Signalling==false)) - { - dsbSwitch->Play(0,0,0); - mvControlled->Signalling=true; - } - } - } - else - if (cKey==Global::Keys[k_Sand]) - { - if(mvControlled->TrainType==dt_EZT) - { - if (!mvControlled->DoorSignalling) + else */ + if (cKey == Global::Keys[k_Battery]) { - dsbSwitch->Play(0,0,0); - mvControlled->DoorSignalling=true; + // if + // (((mvControlled->TrainType==dt_EZT)||(mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->EngineType==DieselElectric))&&(!mvControlled->Battery)) + if (!mvControlled->Battery) + { // wyłącznik jest też w SN61, ewentualnie załączać prąd na stałe z poziomu FIZ + if (mvOccupied->BatterySwitch(true)) // bateria potrzebna np. do zapalenia świateł + { + dsbSwitch->Play(0, 0, 0); + if (TestFlag(mvOccupied->SecuritySystem.SystemType, + 2)) // Ra: znowu w kabinie jest coś, co być nie powinno! + { + SetFlag(mvOccupied->SecuritySystem.Status, s_active); + SetFlag(mvOccupied->SecuritySystem.Status, s_SHPalarm); + } + } + } } - } - } - if (cKey==Global::Keys[k_Main]) - { - if (fabs(ggMainOnButton.GetValue())<0.001) - if (dsbSwitch) + else if (cKey == Global::Keys[k_StLinOff]) { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); + if (mvControlled->TrainType == dt_EZT) + { + if ((mvControlled->Signalling == false)) + { + dsbSwitch->Play(0, 0, 0); + mvControlled->Signalling = true; + } + } } - } - else - //----------- + else if (cKey == Global::Keys[k_Sand]) + { + if (mvControlled->TrainType == dt_EZT) + { + if (!mvControlled->DoorSignalling) + { + dsbSwitch->Play(0, 0, 0); + mvControlled->DoorSignalling = true; + } + } + } + if (cKey == Global::Keys[k_Main]) + { + if (fabs(ggMainOnButton.GetValue()) < 0.001) + if (dsbSwitch) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + //----------- - if (cKey==Global::Keys[k_BrakeProfile]) //McZapkie-240302-B: przelacznik opoznienia hamowania - {//yB://ABu: male poprawki, zeby bylo mozna ustawic dowolny wagon - int CouplNr=-2; - if (!FreeFlyModeFlag) - { - if (GetAsyncKeyState(VK_CONTROL)<0) - if (mvOccupied->BrakeDelaySwitch(bdelay_R+bdelay_M)) - { - dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); - dsbPneumaticRelay->Play(0,0,0); - } - else; - else - if (mvOccupied->BrakeDelaySwitch(bdelay_P)) - { - dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); - dsbPneumaticRelay->Play(0,0,0); - } - } - else - { - TDynamicObject *temp; - temp=(DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(),-1, 1500, CouplNr)); - if (temp==NULL) - { - CouplNr=-2; - temp=(DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(),1, 1500, CouplNr)); - } - if (temp) - { - if (GetAsyncKeyState(VK_CONTROL)<0) - if (temp->MoverParameters->BrakeDelaySwitch(bdelay_R+bdelay_M)) - { - dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); - dsbPneumaticRelay->Play(0,0,0); - } - else; + if (cKey == + Global::Keys[k_BrakeProfile]) // McZapkie-240302-B: przelacznik opoznienia hamowania + { // yB://ABu: male poprawki, zeby bylo mozna ustawic dowolny wagon + int CouplNr = -2; + if (!FreeFlyModeFlag) + { + if (GetAsyncKeyState(VK_CONTROL) < 0) + if (mvOccupied->BrakeDelaySwitch(bdelay_R + bdelay_M)) + { + dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); + dsbPneumaticRelay->Play(0, 0, 0); + } else - if (temp->MoverParameters->BrakeDelaySwitch(bdelay_P)) - { - dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); - dsbPneumaticRelay->Play(0,0,0); - } + ; + else if (mvOccupied->BrakeDelaySwitch(bdelay_P)) + { + dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); + dsbPneumaticRelay->Play(0, 0, 0); + } + } + else + { + TDynamicObject *temp; + temp = (DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, 1500, + CouplNr)); + if (temp == NULL) + { + CouplNr = -2; + temp = (DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, + CouplNr)); + } + if (temp) + { + if (GetAsyncKeyState(VK_CONTROL) < 0) + if (temp->MoverParameters->BrakeDelaySwitch(bdelay_R + bdelay_M)) + { + dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); + dsbPneumaticRelay->Play(0, 0, 0); + } + else + ; + else if (temp->MoverParameters->BrakeDelaySwitch(bdelay_P)) + { + dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); + dsbPneumaticRelay->Play(0, 0, 0); + } + } + } + } + else + //----------- + // hunter-261211: przetwornica i sprzezarka przeniesione do TTrain::Update() + /* if (cKey==Global::Keys[k_Converter]) //NBMX 14-09-2003: przetwornica wl + { + if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) || + (mvControlled->EnginePowerSource.SourceType!=CurrentCollector) || + (!Global::bLiveTraction)) + if (mvControlled->ConverterSwitch(true)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0,0,0); } - } - } - else - //----------- - //hunter-261211: przetwornica i sprzezarka przeniesione do TTrain::Update() - /* if (cKey==Global::Keys[k_Converter]) //NBMX 14-09-2003: przetwornica wl - { - if ((mvControlled->PantFrontVolt) || (mvControlled->PantRearVolt) || (mvControlled->EnginePowerSource.SourceType!=CurrentCollector) || (!Global::bLiveTraction)) - if (mvControlled->ConverterSwitch(true)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - if (cKey==Global::Keys[k_Compressor]) //NBMX 14-09-2003: sprezarka wl - { - if ((mvControlled->ConverterFlag) || (mvControlled->CompressorPower<2)) - if (mvControlled->CompressorSwitch(true)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else */ + } + else + if (cKey==Global::Keys[k_Compressor]) //NBMX 14-09-2003: sprezarka wl + { + if ((mvControlled->ConverterFlag) || (mvControlled->CompressorPower<2)) + if (mvControlled->CompressorSwitch(true)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0,0,0); + } + } + else */ - if (cKey==Global::Keys[k_Converter]) - { - if (ggConverterButton.GetValue()==0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - //if ((cKey==Global::Keys[k_Compressor])&&((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->TrainType==dt_EZT))) //hunter-110212: poprawka dla EZT - if ((cKey==Global::Keys[k_Compressor])&&(mvControlled->CompressorPower<2)) //hunter-091012: tak jest poprawnie - { - if (ggCompressorButton.GetValue()==0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else if (cKey==Global::Keys[k_SmallCompressor]) //Winger 160404: mala sprezarka wl - {//Ra: dźwięk, gdy razem z [Shift] - if ((mvControlled->TrainType&dt_EZT)?mvControlled==mvOccupied:!mvOccupied->ActiveCab) //tylko w maszynowym - if (Console::Pressed(VK_CONTROL)) //z [Ctrl] - mvControlled->bPantKurek3=true; //zbiornik pantografu połączony jest ze zbiornikiem głównym (pompowanie nie ma sensu) - else if (!mvControlled->PantCompFlag) //jeśli wyłączona - if (mvControlled->Battery) //jeszcze musi być załączona bateria - if (mvControlled->PantPress<4.8) //piszą, że to tak nie działa - { - mvControlled->PantCompFlag=true; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); //dźwięk tylko po naciśnięciu klawisza - } - } - else if (cKey==VkKeyScan('q')) //ze Shiftem - włączenie AI - {//McZapkie-240302 - wlaczanie automatycznego pilota (zadziala tylko w trybie debugmode) - if (DynamicObject->Mechanik) - { + if (cKey == Global::Keys[k_Converter]) + { + if (ggConverterButton.GetValue() == 0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + // if + // ((cKey==Global::Keys[k_Compressor])&&((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->TrainType==dt_EZT))) + // //hunter-110212: poprawka dla EZT + if ((cKey == Global::Keys[k_Compressor]) && + (mvControlled->CompressorPower < 2)) // hunter-091012: tak jest poprawnie + { + if (ggCompressorButton.GetValue() == 0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else if (cKey == Global::Keys[k_SmallCompressor]) // Winger 160404: mala sprezarka wl + { // Ra: dźwięk, gdy razem z [Shift] + if ((mvControlled->TrainType & dt_EZT) ? mvControlled == mvOccupied : + !mvOccupied->ActiveCab) // tylko w maszynowym + if (Console::Pressed(VK_CONTROL)) // z [Ctrl] + mvControlled->bPantKurek3 = true; // zbiornik pantografu połączony jest ze + // zbiornikiem głównym (pompowanie nie ma + // sensu) + else if (!mvControlled->PantCompFlag) // jeśli wyłączona + if (mvControlled->Battery) // jeszcze musi być załączona bateria + if (mvControlled->PantPress < 4.8) // piszą, że to tak nie działa + { + mvControlled->PantCompFlag = true; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); // dźwięk tylko po naciśnięciu klawisza + } + } + else if (cKey == VkKeyScan('q')) // ze Shiftem - włączenie AI + { // McZapkie-240302 - wlaczanie automatycznego pilota (zadziala tylko w trybie debugmode) + if (DynamicObject->Mechanik) + { + if (DebugModeFlag) + if (DynamicObject->Mechanik + ->AIControllFlag) //żeby nie trzeba było rozłączać dla zresetowania + DynamicObject->Mechanik->TakeControl(false); + DynamicObject->Mechanik->TakeControl(true); + } + } + else if (cKey == Global::Keys[k_MaxCurrent]) // McZapkie-160502: F - wysoki rozruch + { + if ((mvControlled->EngineType == DieselElectric) && (mvControlled->ShuntModeAllow) && + (mvControlled->MainCtrlPos == 0)) + { + mvControlled->ShuntMode = true; + } + if (mvControlled->CurrentSwitch(true)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + /* Ra: przeniesione do Mover.cpp + if (mvControlled->TrainType!=dt_EZT) //to powinno być w fizyce, a nie w kabinie! + if (mvControlled->MinCurrentSwitch(true)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0,0,0); + } + */ + } + else if (cKey == Global::Keys[k_CurrentAutoRelay]) // McZapkie-241002: G - wlaczanie PSR + { + if (mvControlled->AutoRelaySwitch(true)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else if (cKey == Global::Keys[k_FailedEngineCutOff]) // McZapkie-060103: E - wylaczanie + // sekcji silnikow + { + if (mvControlled->CutOffEngine()) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else if (cKey == Global::Keys[k_OpenLeft]) // NBMX 17-09-2003: otwieranie drzwi + { + if (mvOccupied->DoorOpenCtrl == 1) + if (mvOccupied->CabNo < 0 ? mvOccupied->DoorRight(true) : + mvOccupied->DoorLeft(true)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (dsbDoorOpen) + { + dsbDoorOpen->SetCurrentPosition(0); + dsbDoorOpen->Play(0, 0, 0); + } + } + } + else if (cKey == Global::Keys[k_OpenRight]) // NBMX 17-09-2003: otwieranie drzwi + { + if (mvOccupied->DoorCloseCtrl == 1) + if (mvOccupied->CabNo < 0 ? mvOccupied->DoorLeft(true) : + mvOccupied->DoorRight(true)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (dsbDoorOpen) + { + dsbDoorOpen->SetCurrentPosition(0); + dsbDoorOpen->Play(0, 0, 0); + } + } + } + else + //----------- + // hunter-131211: dzwiek dla przelacznika universala podniesionego + // hunter-091012: ubajerowanie swiatla w kabinie (wyrzucenie przyciemnienia pod Univ4) + if (cKey == Global::Keys[k_Univ3]) + { + if (Console::Pressed(VK_CONTROL)) + { + if (bCabLight == false) //(ggCabLightButton.GetValue()==0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + { + if (ggUniversal3Button.GetValue() == 0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + /* + if (Console::Pressed(VK_CONTROL)) + {//z [Ctrl] zapalamy albo gasimy światełko w kabinie + if (iCabLightFlag<2) ++iCabLightFlag; //zapalenie + } + */ + } + } + else + //----------- + // hunter-091012: dzwiek dla przyciemnienia swiatelka w kabinie + if (cKey == Global::Keys[k_Univ4]) + { + if (Console::Pressed(VK_CONTROL)) + { + if (bCabLightDim == false) //(ggCabLightDimButton.GetValue()==0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + } + else + //----------- + if (cKey == Global::Keys[k_PantFrontUp]) + { // Winger 160204: podn. przedn. pantografu + if (mvOccupied->ActiveCab == + 1) //||((mvOccupied->ActiveCab<1)&&((mvControlled->TrainType&(dt_ET40|dt_ET41|dt_ET42|dt_EZT))==0))) + { // przedni gdy w kabinie 1 lub (z wyjątkiem ET40, ET41, ET42 i EZT) gdy w kabinie -1 + mvControlled->PantFrontSP = false; + if (mvControlled->PantFront(true)) + if (mvControlled->PantFrontStart != 1) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + // if + // ((mvOccupied->ActiveCab<1)&&(mvControlled->TrainType&(dt_ET40|dt_ET41|dt_ET42|dt_EZT))) + { // w kabinie -1 dla ET40, ET41, ET42 i EZT + mvControlled->PantRearSP = false; + if (mvControlled->PantRear(true)) + if (mvControlled->PantRearStart != 1) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + } + else if (cKey == Global::Keys[k_PantRearUp]) + { // Winger 160204: podn. tyln. pantografu względem kierunku jazdy + if (mvOccupied->ActiveCab == + 1) //||((mvOccupied->ActiveCab<1)&&((mvControlled->TrainType&(dt_ET40|dt_ET41|dt_ET42|dt_EZT))==0))) + { // tylny gdy w kabinie 1 lub (z wyjątkiem ET40, ET41, ET42 i EZT) gdy w kabinie -1 + mvControlled->PantRearSP = false; + if (mvControlled->PantRear(true)) + if (mvControlled->PantRearStart != 1) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + // if + // ((mvOccupied->ActiveCab<1)&&(mvControlled->TrainType&(dt_ET40|dt_ET41|dt_ET42|dt_EZT))) + { // przedni w kabinie -1 dla ET40, ET41, ET42 i EZT + mvControlled->PantFrontSP = false; + if (mvControlled->PantFront(true)) + if (mvControlled->PantFrontStart != 1) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + } + else if (cKey == Global::Keys[k_Active]) // yB 300407: przelacznik rozrzadu + { // Ra 2014-06: uruchomiłem to, aby aktywować czuwak w zajmowanym członie, a wyłączyć w + // innych + // Ra 2014-03: aktywacja czuwaka przepięta na ustawienie kierunku w mvOccupied + // if (mvControlled->Battery) //jeśli bateria jest już załączona + // mvOccupied->BatterySwitch(true); //to w ten oto durny sposób aktywuje się CA/SHP + // if (mvControlled->CabActivisation()) + // { + // dsbSwitch->SetVolume(DSBVOLUME_MAX); + // dsbSwitch->Play(0,0,0); + // } + } + else if (cKey == Global::Keys[k_Heating]) // Winger 020304: ogrzewanie skladu - wlaczenie + { // Ra 2014-09: w trybie latania obsługa jest w World.cpp + if (!FreeFlyModeFlag) + { + if ((mvControlled->Heating == false) && + ((mvControlled->EngineType == ElectricSeriesMotor) && + (mvControlled->Mains == true) || + (mvControlled->ConverterFlag))) + { + mvControlled->Heating = true; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + } + else + // ABu 060205: dzielo Wingera po malutkim liftingu: + if (cKey == Global::Keys[k_LeftSign]) // lewe swiatlo - włączenie + { + if ((GetAsyncKeyState(VK_CONTROL) < 0) && + (ggRearLeftLightButton.SubModel)) // hunter-230112 - z controlem zapala z tylu + { + //------------------------------ + if (mvOccupied->ActiveCab == 1) + { // kabina 1 + if (((DynamicObject->iLights[1]) & 3) == 0) + { + DynamicObject->iLights[1] |= 1; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearLeftLightButton.PutValue(1); + } + if (((DynamicObject->iLights[1]) & 3) == 2) + { + DynamicObject->iLights[1] &= (255 - 2); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRearLeftEndLightButton.SubModel) + { + ggRearLeftEndLightButton.PutValue(0); + ggRearLeftLightButton.PutValue(0); + } + else + ggRearLeftLightButton.PutValue(0); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[0]) & 3) == 0) + { + DynamicObject->iLights[0] |= 1; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearLeftLightButton.PutValue(1); + } + if (((DynamicObject->iLights[0]) & 3) == 2) + { + DynamicObject->iLights[0] &= (255 - 2); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRearLeftEndLightButton.SubModel) + { + ggRearLeftEndLightButton.PutValue(0); + ggRearLeftLightButton.PutValue(0); + } + else + ggRearLeftLightButton.PutValue(0); + } + } + //---------------------- + } + else + { + if (mvOccupied->ActiveCab == 1) + { // kabina 1 + if (((DynamicObject->iLights[0]) & 3) == 0) + { + DynamicObject->iLights[0] |= 1; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggLeftLightButton.PutValue(1); + } + if (((DynamicObject->iLights[0]) & 3) == 2) + { + DynamicObject->iLights[0] &= (255 - 2); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggLeftEndLightButton.SubModel) + { + ggLeftEndLightButton.PutValue(0); + ggLeftLightButton.PutValue(0); + } + else + ggLeftLightButton.PutValue(0); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[1]) & 3) == 0) + { + DynamicObject->iLights[1] |= 1; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggLeftLightButton.PutValue(1); + } + if (((DynamicObject->iLights[1]) & 3) == 2) + { + DynamicObject->iLights[1] &= (255 - 2); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggLeftEndLightButton.SubModel) + { + ggLeftEndLightButton.PutValue(0); + ggLeftLightButton.PutValue(0); + } + else + ggLeftLightButton.PutValue(0); + } + } + } //----------- + } + else if (cKey == Global::Keys[k_UpperSign]) // ABu 060205: światło górne - włączenie + { + if ((GetAsyncKeyState(VK_CONTROL) < 0) && + (ggRearUpperLightButton.SubModel)) // hunter-230112 - z controlem zapala z tylu + { + //------------------------------ + if ((mvOccupied->ActiveCab) == 1) + { // kabina 1 + if (((DynamicObject->iLights[1]) & 12) == 0) + { + DynamicObject->iLights[1] |= 4; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearUpperLightButton.PutValue(1); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[0]) & 12) == 0) + { + DynamicObject->iLights[0] |= 4; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearUpperLightButton.PutValue(1); + } + } + } //------------------------------ + else + { + if ((mvOccupied->ActiveCab) == 1) + { // kabina 1 + if (((DynamicObject->iLights[0]) & 12) == 0) + { + DynamicObject->iLights[0] |= 4; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggUpperLightButton.PutValue(1); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[1]) & 12) == 0) + { + DynamicObject->iLights[1] |= 4; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggUpperLightButton.PutValue(1); + } + } + } + } + else if (cKey == + Global::Keys[k_RightSign]) // Winger 070304: swiatla tylne (koncowki) - wlaczenie + { + if ((GetAsyncKeyState(VK_CONTROL) < 0) && + (ggRearRightLightButton.SubModel)) // hunter-230112 - z controlem zapala z tylu + { + //------------------------------ + if (mvOccupied->ActiveCab == 1) + { // kabina 1 + if (((DynamicObject->iLights[1]) & 48) == 0) + { + DynamicObject->iLights[1] |= 16; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearRightLightButton.PutValue(1); + } + if (((DynamicObject->iLights[1]) & 48) == 32) + { + DynamicObject->iLights[1] &= (255 - 32); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRearRightEndLightButton.SubModel) + { + ggRearRightEndLightButton.PutValue(0); + ggRearRightLightButton.PutValue(0); + } + else + ggRearRightLightButton.PutValue(0); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[0]) & 48) == 0) + { + DynamicObject->iLights[0] |= 16; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearRightLightButton.PutValue(1); + } + if (((DynamicObject->iLights[0]) & 48) == 32) + { + DynamicObject->iLights[0] &= (255 - 32); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRearRightEndLightButton.SubModel) + { + ggRearRightEndLightButton.PutValue(0); + ggRearRightLightButton.PutValue(0); + } + else + ggRearRightLightButton.PutValue(0); + } + } + } //------------------------------ + else + { + if (mvOccupied->ActiveCab == 1) + { // kabina 1 + if (((DynamicObject->iLights[0]) & 48) == 0) + { + DynamicObject->iLights[0] |= 16; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRightLightButton.PutValue(1); + } + if (((DynamicObject->iLights[0]) & 48) == 32) + { + DynamicObject->iLights[0] &= (255 - 32); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRightEndLightButton.SubModel) + { + ggRightEndLightButton.PutValue(0); + ggRightLightButton.PutValue(0); + } + else + ggRightLightButton.PutValue(0); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[1]) & 48) == 0) + { + DynamicObject->iLights[1] |= 16; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRightLightButton.PutValue(1); + } + if (((DynamicObject->iLights[1]) & 48) == 32) + { + DynamicObject->iLights[1] &= (255 - 32); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRightEndLightButton.SubModel) + { + ggRightEndLightButton.PutValue(0); + ggRightLightButton.PutValue(0); + } + else + ggRightLightButton.PutValue(0); + } + } + } + } + } + else // McZapkie-240302 - klawisze bez shifta + { + if (cKey == Global::Keys[k_IncMainCtrl]) + { + if (mvControlled->IncMainCtrl(1)) + { + dsbNastawnikJazdy->SetCurrentPosition(0); + dsbNastawnikJazdy->Play(0, 0, 0); + } + } + else if (cKey == Global::Keys[k_DecMainCtrl]) + if (mvControlled->DecMainCtrl(1)) + { + dsbNastawnikJazdy->SetCurrentPosition(0); + dsbNastawnikJazdy->Play(0, 0, 0); + } + else + ; + else if (cKey == Global::Keys[k_IncScndCtrl]) + // if (MoverParameters->ScndCtrlPosScndCtrlPosNo) + // if (mvControlled->EnginePowerSource.SourceType==CurrentCollector) + if (mvControlled->ShuntMode) + { + mvControlled->AnPos += (GetDeltaTime() / 0.85f); + if (mvControlled->AnPos > 1) + mvControlled->AnPos = 1; + } + else if (mvControlled->IncScndCtrl(1)) + { + if (dsbNastawnikBocz) // hunter-081211 + { + dsbNastawnikBocz->SetCurrentPosition(0); + dsbNastawnikBocz->Play(0, 0, 0); + } + else if (!dsbNastawnikBocz) + { + dsbNastawnikJazdy->SetCurrentPosition(0); + dsbNastawnikJazdy->Play(0, 0, 0); + } + } + else + ; + else if (cKey == Global::Keys[k_DecScndCtrl]) + // if (mvControlled->EnginePowerSource.SourceType==CurrentCollector) + if (mvControlled->ShuntMode) + { + mvControlled->AnPos -= (GetDeltaTime() / 0.55f); + if (mvControlled->AnPos < 0) + mvControlled->AnPos = 0; + } + else + + if (mvControlled->DecScndCtrl(1)) + // if (MoverParameters->ScndCtrlPos>0) + { + if (dsbNastawnikBocz) // hunter-081211 + { + dsbNastawnikBocz->SetCurrentPosition(0); + dsbNastawnikBocz->Play(0, 0, 0); + } + else if (!dsbNastawnikBocz) + { + dsbNastawnikJazdy->SetCurrentPosition(0); + dsbNastawnikJazdy->Play(0, 0, 0); + } + } + else + ; + else if (cKey == Global::Keys[k_IncLocalBrakeLevel]) + { // Ra 2014-09: w trybie latania obsługa jest w World.cpp + if (!FreeFlyModeFlag) + { + if (GetAsyncKeyState(VK_CONTROL) < 0) + if ((mvOccupied->LocalBrake == ManualBrake) || (mvOccupied->MBrake == true)) + { + mvOccupied->IncManualBrakeLevel(1); + } + else + ; + else if (mvOccupied->LocalBrake != ManualBrake) + mvOccupied->IncLocalBrakeLevel(1); + } + } + else if (cKey == Global::Keys[k_DecLocalBrakeLevel]) + { // Ra 2014-06: wersja dla swobodnego latania przeniesiona do World.cpp + if (!FreeFlyModeFlag) + { + if (GetAsyncKeyState(VK_CONTROL) < 0) + if ((mvOccupied->LocalBrake == ManualBrake) || (mvOccupied->MBrake == true)) + mvOccupied->DecManualBrakeLevel(1); + else + ; + else // Ra 1014-06: AI potrafi zahamować pomocniczym mimo jego braku - odhamować + // jakoś trzeba + if ((mvOccupied->LocalBrake != ManualBrake) || mvOccupied->LocalBrakePos) + mvOccupied->DecLocalBrakeLevel(1); + } + } + else if ((cKey == Global::Keys[k_IncBrakeLevel]) && (mvOccupied->BrakeHandle != FV4a)) + // if (mvOccupied->IncBrakeLevel()) + if (mvOccupied->BrakeLevelAdd( + Global::fBrakeStep)) // nieodpowiedni warunek; true, jeśli można dalej kręcić + { + keybrakecount = 0; + if ((isEztOer) && (mvOccupied->BrakeCtrlPos < 3)) + { // Ra: uzależnić dźwięk od zmiany stanu EP, nie od klawisza + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + } + else + ; + else if ((cKey == Global::Keys[k_DecBrakeLevel]) && (mvOccupied->BrakeHandle != FV4a)) + { + // nową wersję dostarczył ZiomalCl ("fixed looped sound in ezt when using NUM_9 key") + if ((mvOccupied->BrakeCtrlPos > -1) || (keybrakecount > 1)) + { + + if ((isEztOer) && (mvControlled->Mains) && (mvOccupied->BrakeCtrlPos != -1)) + { // Ra: uzależnić dźwięk od zmiany stanu EP, nie od klawisza + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + // mvOccupied->DecBrakeLevel(); + mvOccupied->BrakeLevelAdd(-Global::fBrakeStep); + } + else + keybrakecount += 1; + // koniec wersji dostarczonej przez ZiomalCl + /* wersja poprzednia - ten pierwszy if ze średnikiem nie działał jak warunek + if ((mvOccupied->BrakeCtrlPos>-1)|| (keybrakecount>1)) + { + if (mvOccupied->DecBrakeLevel()); + { + if ((isEztOer) && (mvOccupied->BrakeCtrlPos<2)&&(keybrakecount<=1)) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0,0,0); + } + } + } + else keybrakecount+=1; + */ + } + else if (cKey == Global::Keys[k_EmergencyBrake]) + { + // while (mvOccupied->IncBrakeLevel()); + mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EB)); + if (mvOccupied->BrakeCtrlPosNo <= 0.1) // hamulec bezpieczeństwa dla wagonów + mvOccupied->EmergencyBrakeFlag = true; + } + else if (cKey == Global::Keys[k_Brake3]) + { + if ((isEztOer) && ((mvOccupied->BrakeCtrlPos == 1) || (mvOccupied->BrakeCtrlPos == -1))) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + // while (mvOccupied->BrakeCtrlPos>mvOccupied->BrakeCtrlPosNo-1 && + // mvOccupied->DecBrakeLevel()); + // while (mvOccupied->BrakeCtrlPosBrakeCtrlPosNo-1 && + // mvOccupied->IncBrakeLevel()); + mvOccupied->BrakeLevelSet(mvOccupied->BrakeCtrlPosNo - 1); + } + else if (cKey == Global::Keys[k_Brake2]) + { + if ((isEztOer) && ((mvOccupied->BrakeCtrlPos == 1) || (mvOccupied->BrakeCtrlPos == -1))) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + // while (mvOccupied->BrakeCtrlPos>mvOccupied->BrakeCtrlPosNo/2 && + // mvOccupied->DecBrakeLevel()); + // while (mvOccupied->BrakeCtrlPosBrakeCtrlPosNo/2 && + // mvOccupied->IncBrakeLevel()); + mvOccupied->BrakeLevelSet(mvOccupied->BrakeCtrlPosNo / 2 + + (mvOccupied->BrakeHandle == FV4a ? 1 : 0)); + if (GetAsyncKeyState(VK_CONTROL) < 0) + mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_NP)); // yB: czy ten stos + // funkcji nie + // powinien być jako + // oddzielna funkcja + // movera? + } + else if (cKey == Global::Keys[k_Brake1]) + { + if ((isEztOer) && (mvOccupied->BrakeCtrlPos != 1)) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + // while (mvOccupied->BrakeCtrlPos>1 && mvOccupied->DecBrakeLevel()); + // while (mvOccupied->BrakeCtrlPos<1 && mvOccupied->IncBrakeLevel()); + mvOccupied->BrakeLevelSet(1); + } + else if (cKey == Global::Keys[k_Brake0]) + { + if (Console::Pressed(VK_CONTROL)) + { + mvOccupied->BrakeCtrlPos2 = 0; // wyrownaj kapturek + } + else + { + if ((isEztOer) && + ((mvOccupied->BrakeCtrlPos == 1) || (mvOccupied->BrakeCtrlPos == -1))) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + // while (mvOccupied->BrakeCtrlPos>0 && mvOccupied->DecBrakeLevel()); + // while (mvOccupied->BrakeCtrlPos<0 && mvOccupied->IncBrakeLevel()); + mvOccupied->BrakeLevelSet(0); + } + } + else if (cKey == Global::Keys[k_WaveBrake]) //[Num.] + { + if ((isEztOer) && (mvControlled->Mains) && (mvOccupied->BrakeCtrlPos != -1)) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + // while (mvOccupied->BrakeCtrlPos>-1 && mvOccupied->DecBrakeLevel()); + // while (mvOccupied->BrakeCtrlPos<-1 && mvOccupied->IncBrakeLevel()); + mvOccupied->BrakeLevelSet(-1); + } + else + //--------------- + // hunter-131211: zbicie czuwaka przeniesione do TTrain::Update() + if (cKey == Global::Keys[k_Czuwak]) + { // Ra: tu został tylko dźwięk + // dsbBuzzer->Stop(); + // if (mvOccupied->SecuritySystemReset()) + if (fabs(ggSecurityResetButton.GetValue()) < 0.001) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + // ggSecurityResetButton.PutValue(1); + } + else + //--------------- + // hunter-221211: hamulec przeciwposlizgowy przeniesiony do TTrain::Update() + if (cKey == Global::Keys[k_AntiSlipping]) + { + if (mvOccupied->BrakeSystem != ElectroPneumatic) + { + // if (mvControlled->AntiSlippingButton()) + if (fabs(ggAntiSlipButton.GetValue()) < 0.001) + { + // Dlaczego bylo '-50'??? + // dsbSwitch->SetVolume(-50); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + // ggAntiSlipButton.PutValue(1); + } + } + else + //--------------- + + if (cKey == Global::Keys[k_Fuse]) + { + if (GetAsyncKeyState(VK_CONTROL) < 0) // z controlem + { + ggConverterFuseButton.PutValue(1); // hunter-261211 + if ((mvControlled->Mains == false) && (ggConverterButton.GetValue() == 0)) + mvControlled->ConvOvldFlag = false; + } + else + { + ggFuseButton.PutValue(1); + mvControlled->FuseOn(); + } + } + else + // McZapkie-240302 - zmiana kierunku: 'd' do przodu, 'r' do tylu + if (cKey == Global::Keys[k_DirectionForward]) + { + if (mvOccupied->DirectionForward()) + { + //------------ + // hunter-121211: dzwiek kierunkowego + if (dsbReverserKey) + { + dsbReverserKey->SetCurrentPosition(0); + dsbReverserKey->SetVolume(DSBVOLUME_MAX); + dsbReverserKey->Play(0, 0, 0); + } + else if (!dsbReverserKey) + if (dsbSwitch) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + //------------ + if (mvOccupied->ActiveDir) // jeśli kierunek niezerowy + if (DynamicObject->Mechanik) // na wszelki wypadek + DynamicObject->Mechanik->CheckVehicles( + Change_direction); // aktualizacja skrajnych pojazdów w składzie + } + } + else if (cKey == Global::Keys[k_DirectionBackward]) // r + { + if (GetAsyncKeyState(VK_CONTROL) < 0) + { // wciśnięty [Ctrl] + if (mvControlled->Radio == true) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + mvControlled->Radio = false; + } + } + else if (mvOccupied->DirectionBackward()) + { + //------------ + // hunter-121211: dzwiek kierunkowego + if (dsbReverserKey) + { + dsbReverserKey->SetCurrentPosition(0); + dsbReverserKey->SetVolume(DSBVOLUME_MAX); + dsbReverserKey->Play(0, 0, 0); + } + else if (!dsbReverserKey) + if (dsbSwitch) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + //------------ + if (mvOccupied->ActiveDir) // jeśli kierunek niezerowy + if (DynamicObject->Mechanik) // na wszelki wypadek + DynamicObject->Mechanik->CheckVehicles( + Change_direction); // aktualizacja skrajnych pojazdów w składzie + } + } + else + // McZapkie-240302 - wylaczanie glownego obwodu + //----------- + // hunter-141211: wyl. szybki wylaczony przeniesiony do TTrain::Update() + if (cKey == Global::Keys[k_Main]) + { + if (fabs(ggMainOffButton.GetValue()) < 0.001) + if (dsbSwitch) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + + if (cKey == Global::Keys[k_Battery]) + { + // if ((mvControlled->TrainType==dt_EZT) || + // (mvControlled->EngineType==ElectricSeriesMotor)|| + // (mvControlled->EngineType==DieselElectric)) + if (mvOccupied->BatterySwitch(false)) + { // ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora + dsbSwitch->Play(0, 0, 0); + // mvOccupied->SecuritySystem.Status=0; + mvControlled->PantFront(false); + mvControlled->PantRear(false); + } + } + + //----------- + // if (cKey==Global::Keys[k_Active]) //yB 300407: przelacznik rozrzadu + // { + // if (mvControlled->CabDeactivisation()) + // { + // dsbSwitch->SetVolume(DSBVOLUME_MAX); + // dsbSwitch->Play(0,0,0); + // } + // } + // else + if (cKey == Global::Keys[k_BrakeProfile]) + { // yB://ABu: male poprawki, zeby bylo mozna ustawic dowolny wagon + int CouplNr = -2; + if (!FreeFlyModeFlag) + { + if (GetAsyncKeyState(VK_CONTROL) < 0) + if (mvOccupied->BrakeDelaySwitch(bdelay_R)) + { + dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); + dsbPneumaticRelay->Play(0, 0, 0); + } + else + ; + else if (mvOccupied->BrakeDelaySwitch(bdelay_G)) + { + dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); + dsbPneumaticRelay->Play(0, 0, 0); + } + } + else + { + TDynamicObject *temp; + temp = (DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, 1500, + CouplNr)); + if (temp == NULL) + { + CouplNr = -2; + temp = (DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, + CouplNr)); + } + if (temp) + { + if (GetAsyncKeyState(VK_CONTROL) < 0) + if (temp->MoverParameters->BrakeDelaySwitch(bdelay_R)) + { + dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); + dsbPneumaticRelay->Play(0, 0, 0); + } + else + ; + else if (temp->MoverParameters->BrakeDelaySwitch(bdelay_G)) + { + dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); + dsbPneumaticRelay->Play(0, 0, 0); + } + } + } + } + else + //----------- + // hunter-261211: przetwornica i sprzezarka przeniesione do TTrain::Update() + if (cKey == Global::Keys[k_Converter]) + { + if (ggConverterButton.GetValue() != 0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + // if + // ((cKey==Global::Keys[k_Compressor])&&((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->TrainType==dt_EZT))) + // //hunter-110212: poprawka dla EZT + if ((cKey == Global::Keys[k_Compressor]) && + (mvControlled->CompressorPower < 2)) // hunter-091012: tak jest poprawnie + { + if (ggCompressorButton.GetValue() != 0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + //----------- + if (cKey == Global::Keys[k_Releaser]) // odluzniacz + { + if (!FreeFlyModeFlag) + { + if ((mvControlled->EngineType == ElectricSeriesMotor) || + (mvControlled->EngineType == DieselElectric) || + (mvControlled->EngineType == ElectricInductionMotor)) + if (mvControlled->TrainType != dt_EZT) + if (mvOccupied->BrakeCtrlPosNo > 0) + { + ggReleaserButton.PutValue(1); + if (mvOccupied->BrakeReleaser(1)) + { + dsbPneumaticRelay->SetVolume(-80); + dsbPneumaticRelay->Play(0, 0, 0); + } + } + } + } + else if (cKey == Global::Keys[k_SmallCompressor]) // Winger 160404: mala sprezarka wl + { // Ra: bez [Shift] też dać dźwięk + if ((mvControlled->TrainType & dt_EZT) ? mvControlled == mvOccupied : + !mvOccupied->ActiveCab) // tylko w maszynowym + if (Console::Pressed(VK_CONTROL)) // z [Ctrl] + mvControlled->bPantKurek3 = false; // zbiornik pantografu połączony jest z małą + // sprężarką (pompowanie ma sens, ale potem + // trzeba przełączyć) + else if (!mvControlled->PantCompFlag) // jeśli wyłączona + if (mvControlled->Battery) // jeszcze musi być załączona bateria + if (mvControlled->PantPress < 4.8) // piszą, że to tak nie działa + { + mvControlled->PantCompFlag = true; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); // dźwięk tylko po naciśnięciu klawisza + } + } + // McZapkie-240302 - wylaczanie automatycznego pilota (w trybie ~debugmode mozna tylko raz) + else if (cKey == VkKeyScan('q')) // bez Shift + { + if (DynamicObject->Mechanik) + DynamicObject->Mechanik->TakeControl(false); + } + else if (cKey == Global::Keys[k_MaxCurrent]) // McZapkie-160502: f - niski rozruch + { + if ((mvControlled->EngineType == DieselElectric) && (mvControlled->ShuntModeAllow) && + (mvControlled->MainCtrlPos == 0)) + { + mvControlled->ShuntMode = false; + } + if (mvControlled->CurrentSwitch(false)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + /* Ra: przeniesione do Mover.cpp + if (mvControlled->TrainType!=dt_EZT) + if (mvControlled->MinCurrentSwitch(false)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0,0,0); + } + */ + } + else if (cKey == Global::Keys[k_CurrentAutoRelay]) // McZapkie-241002: g - wylaczanie PSR + { + if (mvControlled->AutoRelaySwitch(false)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + // hunter-201211: piasecznica poprawiona oraz przeniesiona do TTrain::Update() + if (cKey == Global::Keys[k_Sand]) + { + /* + if (mvControlled->TrainType!=dt_EZT) + { + if (mvControlled->SandDoseOn()) + if (mvControlled->SandDose) + { + dsbPneumaticRelay->SetVolume(-30); + dsbPneumaticRelay->Play(0,0,0); + } + } + */ + if (mvControlled->TrainType == dt_EZT) + { + if (mvControlled->DoorSignalling) + { + dsbSwitch->Play(0, 0, 0); + mvControlled->DoorSignalling = false; + } + } + } + else if (cKey == Global::Keys[k_CabForward]) + { + if (!CabChange(1)) + if (TestFlag(DynamicObject->MoverParameters->Couplers[0].CouplingFlag, + ctrain_passenger)) + { // przejscie do nastepnego pojazdu + Global::changeDynObj = DynamicObject->PrevConnected; + Global::changeDynObj->MoverParameters->ActiveCab = + DynamicObject->PrevConnectedNo ? -1 : 1; + } + if (DynamicObject->MoverParameters->ActiveCab) + mvControlled->PantCompFlag = false; // wyjście z maszynowego wyłącza sprężarkę + } + else if (cKey == Global::Keys[k_CabBackward]) + { + if (!CabChange(-1)) + if (TestFlag(DynamicObject->MoverParameters->Couplers[1].CouplingFlag, + ctrain_passenger)) + { // przejscie do poprzedniego + Global::changeDynObj = DynamicObject->NextConnected; + Global::changeDynObj->MoverParameters->ActiveCab = + DynamicObject->NextConnectedNo ? -1 : 1; + } + if (DynamicObject->MoverParameters->ActiveCab) + mvControlled->PantCompFlag = + false; // wyjście z maszynowego wyłącza sprężarkę pomocniczą + } + else if (cKey == Global::Keys[k_Couple]) + { // ABu051104: male zmiany, zeby mozna bylo laczyc odlegle wagony + // da sie zoptymalizowac, ale nie ma na to czasu :( + if (iCabn > 0) + { + if (!FreeFlyModeFlag) // tryb 'kabinowy' + { /* + if (mvControlled->Couplers[iCabn-1].CouplingFlag==0) + { + if + (mvControlled->Attach(iCabn-1,mvControlled->Couplers[iCabn-1].Connected,ctrain_coupler)) + { + dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); + dsbCouplerAttach->Play(0,0,0); + //ABu: aha, a guzik, nie dziala i nie bedzie, a przydalo by sie cos takiego: + //DynamicObject->NextConnected=mvControlled->Couplers[iCabn-1].Connected; + //DynamicObject->PrevConnected=mvControlled->Couplers[iCabn-1].Connected; + } + } + else + if (!TestFlag(mvControlled->Couplers[iCabn-1].CouplingFlag,ctrain_pneumatic)) + { + //ABu021104: zeby caly czas bylo widac sprzegi: + if + (mvControlled->Attach(iCabn-1,mvControlled->Couplers[iCabn-1].Connected,mvControlled->Couplers[iCabn-1].CouplingFlag+ctrain_pneumatic)) + //if + (mvControlled->Attach(iCabn-1,mvControlled->Couplers[iCabn-1].Connected,ctrain_pneumatic)) + { + rsHiss.Play(1,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); + } + }*/ + } + else + { // tryb freefly + int CouplNr = -1; // normalnie żaden ze sprzęgów + TDynamicObject *tmp; + tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, + CouplNr); + if (tmp == NULL) + tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, + 1500, CouplNr); + if (tmp && (CouplNr != -1)) + { + if (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag == + 0) // najpierw hak + { + if ((tmp->MoverParameters->Couplers[CouplNr] + .Connected->Couplers[CouplNr] + .AllowedFlag & + tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & + ctrain_coupler) == ctrain_coupler) + if (tmp->MoverParameters->Attach( + CouplNr, 2, + tmp->MoverParameters->Couplers[CouplNr].Connected, + ctrain_coupler)) + { + // tmp->MoverParameters->Couplers[CouplNr].Render=true; + // //podłączony sprzęg będzie widoczny + if (DynamicObject->Mechanik) // na wszelki wypadek + DynamicObject->Mechanik->CheckVehicles( + Connect); // aktualizacja flag kierunku w składzie + dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); + dsbCouplerAttach->Play(0, 0, 0); + } + else + WriteLog("Mechanical coupling failed."); + } + else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, + ctrain_pneumatic)) // pneumatyka + { + if ((tmp->MoverParameters->Couplers[CouplNr] + .Connected->Couplers[CouplNr] + .AllowedFlag & + tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & + ctrain_pneumatic) == ctrain_pneumatic) + if (tmp->MoverParameters->Attach( + CouplNr, 2, + tmp->MoverParameters->Couplers[CouplNr].Connected, + tmp->MoverParameters->Couplers[CouplNr].CouplingFlag + + ctrain_pneumatic)) + { + rsHiss.Play(1, DSBPLAY_LOOPING, true, tmp->GetPosition()); + DynamicObject->SetPneumatic(CouplNr, + 1); // Ra: to mi się nie podoba !!!! + tmp->SetPneumatic(CouplNr, 1); + } + } + else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, + ctrain_scndpneumatic)) // zasilajacy + { + if ((tmp->MoverParameters->Couplers[CouplNr] + .Connected->Couplers[CouplNr] + .AllowedFlag & + tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & + ctrain_scndpneumatic) == ctrain_scndpneumatic) + if (tmp->MoverParameters->Attach( + CouplNr, 2, + tmp->MoverParameters->Couplers[CouplNr].Connected, + tmp->MoverParameters->Couplers[CouplNr].CouplingFlag + + ctrain_scndpneumatic)) + { + // rsHiss.Play(1,DSBPLAY_LOOPING,true,tmp->GetPosition()); + dsbCouplerDetach->SetVolume(DSBVOLUME_MAX); + dsbCouplerDetach->Play(0, 0, 0); + DynamicObject->SetPneumatic(CouplNr, + 0); // Ra: to mi się nie podoba !!!! + tmp->SetPneumatic(CouplNr, 0); + } + } + else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, + ctrain_controll)) // ukrotnionko + { + if ((tmp->MoverParameters->Couplers[CouplNr] + .Connected->Couplers[CouplNr] + .AllowedFlag & + tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & + ctrain_controll) == ctrain_controll) + if (tmp->MoverParameters->Attach( + CouplNr, 2, + tmp->MoverParameters->Couplers[CouplNr].Connected, + tmp->MoverParameters->Couplers[CouplNr].CouplingFlag + + ctrain_controll)) + { + dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); + dsbCouplerAttach->Play(0, 0, 0); + } + } + else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, + ctrain_passenger)) // mostek + { + if ((tmp->MoverParameters->Couplers[CouplNr] + .Connected->Couplers[CouplNr] + .AllowedFlag & + tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & + ctrain_passenger) == ctrain_passenger) + if (tmp->MoverParameters->Attach( + CouplNr, 2, + tmp->MoverParameters->Couplers[CouplNr].Connected, + tmp->MoverParameters->Couplers[CouplNr].CouplingFlag + + ctrain_passenger)) + { + // rsHiss.Play(1,DSBPLAY_LOOPING,true,tmp->GetPosition()); + dsbCouplerDetach->SetVolume(DSBVOLUME_MAX); + dsbCouplerDetach->Play(0, 0, 0); + DynamicObject->SetPneumatic(CouplNr, 0); + tmp->SetPneumatic(CouplNr, 0); + } + } + } + } + } + } + else if (cKey == Global::Keys[k_DeCouple]) + { // ABu051104: male zmiany, zeby mozna bylo rozlaczac odlegle wagony + if (iCabn > 0) + { + if (!FreeFlyModeFlag) // tryb 'kabinowy' (pozwala również rozłączyć sprzęgi + // zablokowane) + { + if (DynamicObject->DettachStatus(iCabn - 1) < 0) // jeśli jest co odczepić + if (DynamicObject->Dettach(iCabn - 1)) // iCab==1:przód,iCab==2:tył + { + dsbCouplerDetach->SetVolume(DSBVOLUME_MAX); // w kabinie ten dźwięk? + dsbCouplerDetach->Play(0, 0, 0); + } + } + else + { // tryb freefly + int CouplNr = -1; + TDynamicObject *tmp; + tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, + CouplNr); + if (tmp == NULL) + tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, + 1500, CouplNr); + if (tmp && (CouplNr != -1)) + { + if ((tmp->MoverParameters->Couplers[CouplNr].CouplingFlag & ctrain_depot) == + 0) // jeżeli sprzęg niezablokowany + if (tmp->DettachStatus(CouplNr) < 0) // jeśli jest co odczepić i się da + if (!tmp->Dettach(CouplNr)) + { // dźwięk odczepiania + dsbCouplerDetach->SetVolume(DSBVOLUME_MAX); + dsbCouplerDetach->Play(0, 0, 0); + } + } + } + if (DynamicObject->Mechanik) // na wszelki wypadek + DynamicObject->Mechanik->CheckVehicles( + Disconnect); // aktualizacja skrajnych pojazdów w składzie + } + } + else if (cKey == Global::Keys[k_CloseLeft]) // NBMX 17-09-2003: zamykanie drzwi + { + if (mvOccupied->CabNo < 0 ? mvOccupied->DoorRight(false) : mvOccupied->DoorLeft(false)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (dsbDoorClose) + { + dsbDoorClose->SetCurrentPosition(0); + dsbDoorClose->Play(0, 0, 0); + } + } + } + else if (cKey == Global::Keys[k_CloseRight]) // NBMX 17-09-2003: zamykanie drzwi + { + if (mvOccupied->CabNo < 0 ? mvOccupied->DoorLeft(false) : mvOccupied->DoorRight(false)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (dsbDoorClose) + { + dsbDoorClose->SetCurrentPosition(0); + dsbDoorClose->Play(0, 0, 0); + } + } + } + else + //----------- + // hunter-131211: dzwiek dla przelacznika universala + // hunter-091012: ubajerowanie swiatla w kabinie (wyrzucenie przyciemnienia pod Univ4) + if (cKey == Global::Keys[k_Univ3]) + { + if (Console::Pressed(VK_CONTROL)) + { + if (bCabLight == true) //(ggCabLightButton.GetValue()!=0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + { + if (ggUniversal3Button.GetValue() != 0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + /* + if (Console::Pressed(VK_CONTROL)) + {//z [Ctrl] zapalamy albo gasimy światełko w kabinie + if (iCabLightFlag) --iCabLightFlag; //gaszenie + } */ + } + } + else + //----------- + // hunter-091012: dzwiek dla przyciemnienia swiatelka w kabinie + if (cKey == Global::Keys[k_Univ4]) + { + if (Console::Pressed(VK_CONTROL)) + { + if (bCabLightDim == true) //(ggCabLightDimButton.GetValue()!=0) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + } + //----------- + else if (cKey == Global::Keys[k_PantFrontDown]) // Winger 160204: opuszczanie prz. patyka + { + if (mvOccupied->ActiveCab == + 1) //||((mvOccupied->ActiveCab<1)&&(mvControlled->TrainType!=dt_ET40)&&(mvControlled->TrainType!=dt_ET41)&&(mvControlled->TrainType!=dt_ET42)&&(mvControlled->TrainType!=dt_EZT))) + { + // if (!mvControlled->PantFrontUp) //jeśli był opuszczony + // if () //jeśli połamany + // //to powtórzone opuszczanie naprawia + if (mvControlled->PantFront(false)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + // if + // ((mvOccupied->ActiveCab<1)&&((mvControlled->TrainType==dt_ET40)||(mvControlled->TrainType==dt_ET41)||(mvControlled->TrainType==dt_ET42)||(mvControlled->TrainType==dt_EZT))) + { + if (mvControlled->PantRear(false)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + } + else if (cKey == Global::Keys[k_PantRearDown]) // Winger 160204: opuszczanie tyl. patyka + { + if (mvOccupied->ActiveCab == + 1) //||((mvOccupied->ActiveCab<1)&&(mvControlled->TrainType!=dt_ET40)&&(mvControlled->TrainType!=dt_ET41)&&(mvControlled->TrainType!=dt_ET42)&&(mvControlled->TrainType!=dt_EZT))) + { + if (mvControlled->PantSwitchType == "impulse") + ggPantFrontButtonOff.PutValue(1); + if (mvControlled->PantRear(false)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + else + // if + // ((mvOccupied->ActiveCab<1)&&((mvControlled->TrainType==dt_ET40)||(mvControlled->TrainType==dt_ET41)||(mvControlled->TrainType==dt_ET42)||(mvControlled->TrainType==dt_EZT))) + { + /* if (mvControlled->PantSwitchType=="impulse") + ggPantRearButtonOff.PutValue(1); */ + if (mvControlled->PantFront(false)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + } + } + } + else if (cKey == Global::Keys[k_Heating]) // Winger 020304: ogrzewanie - wylaczenie + { // Ra 2014-09: w trybie latania obsługa jest w World.cpp + if (!FreeFlyModeFlag) + { + if (mvControlled->Heating == true) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + mvControlled->Heating = false; + } + } + } + else if (cKey == Global::Keys[k_LeftSign]) // ABu 060205: lewe swiatlo - wylaczenie + { + if ((GetAsyncKeyState(VK_CONTROL) < 0) && + (ggRearLeftLightButton.SubModel)) // hunter-230112 - z controlem gasi z tylu + { + //------------------------------ + if (mvOccupied->ActiveCab == 1) + { // kabina 1 + if (((DynamicObject->iLights[1]) & 3) == 0) + { + DynamicObject->iLights[1] |= 2; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRearLeftEndLightButton.SubModel) + { + ggRearLeftEndLightButton.PutValue(1); + ggRearLeftLightButton.PutValue(0); + } + else + ggRearLeftLightButton.PutValue(-1); + } + if (((DynamicObject->iLights[1]) & 3) == 1) + { + DynamicObject->iLights[1] &= (255 - 1); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearLeftLightButton.PutValue(0); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[0]) & 3) == 0) + { + DynamicObject->iLights[0] |= 2; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRearLeftEndLightButton.SubModel) + { + ggRearLeftEndLightButton.PutValue(1); + ggRearLeftLightButton.PutValue(0); + } + else + ggRearLeftLightButton.PutValue(-1); + } + if (((DynamicObject->iLights[1]) & 3) == 1) + { + DynamicObject->iLights[1] &= (255 - 1); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggLeftLightButton.PutValue(0); + } + } + } //------------------------------ + else + { + if (mvOccupied->ActiveCab == 1) + { // kabina 1 + if (((DynamicObject->iLights[0]) & 3) == 0) + { + DynamicObject->iLights[0] |= 2; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggLeftEndLightButton.SubModel) + { + ggLeftEndLightButton.PutValue(1); + ggLeftLightButton.PutValue(0); + } + else + ggLeftLightButton.PutValue(-1); + } + if (((DynamicObject->iLights[0]) & 3) == 1) + { + DynamicObject->iLights[0] &= (255 - 1); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggLeftLightButton.PutValue(0); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[1]) & 3) == 0) + { + DynamicObject->iLights[1] |= 2; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggLeftEndLightButton.SubModel) + { + ggLeftEndLightButton.PutValue(1); + ggLeftLightButton.PutValue(0); + } + else + ggLeftLightButton.PutValue(-1); + } + if (((DynamicObject->iLights[1]) & 3) == 1) + { + DynamicObject->iLights[1] &= (255 - 1); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggLeftLightButton.PutValue(0); + } + } + } + } + else if (cKey == Global::Keys[k_UpperSign]) // ABu 060205: światło górne - wyłączenie + { + if ((GetAsyncKeyState(VK_CONTROL) < 0) && + (ggRearUpperLightButton.SubModel)) // hunter-230112 - z controlem gasi z tylu + { + //------------------------------ + if (mvOccupied->ActiveCab == 1) + { // kabina 1 + if (((DynamicObject->iLights[1]) & 12) == 4) + { + DynamicObject->iLights[1] &= (255 - 4); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearUpperLightButton.PutValue(0); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[0]) & 12) == 4) + { + DynamicObject->iLights[0] &= (255 - 4); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearUpperLightButton.PutValue(0); + } + } + } //------------------------------ + else + { + if (mvOccupied->ActiveCab == 1) + { // kabina 1 + if (((DynamicObject->iLights[0]) & 12) == 4) + { + DynamicObject->iLights[0] &= (255 - 4); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggUpperLightButton.PutValue(0); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[1]) & 12) == 4) + { + DynamicObject->iLights[1] &= (255 - 4); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggUpperLightButton.PutValue(0); + } + } + } + } + if (cKey == Global::Keys[k_RightSign]) // Winger 070304: swiatla tylne (koncowki) - + // wlaczenie + { + if ((GetAsyncKeyState(VK_CONTROL) < 0) && + (ggRearRightLightButton.SubModel)) // hunter-230112 - z controlem gasi z tylu + { + //------------------------------ + if (mvOccupied->ActiveCab == 1) + { // kabina 1 (od strony 0) + if (((DynamicObject->iLights[1]) & 48) == 0) + { + DynamicObject->iLights[1] |= 32; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRearRightEndLightButton.SubModel) + { + ggRearRightEndLightButton.PutValue(1); + ggRearRightLightButton.PutValue(0); + } + else + ggRearRightLightButton.PutValue(-1); + } + if (((DynamicObject->iLights[1]) & 48) == 16) + { + DynamicObject->iLights[1] &= (255 - 16); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearRightLightButton.PutValue(0); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[0]) & 48) == 0) + { + DynamicObject->iLights[0] |= 32; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRearRightEndLightButton.SubModel) + { + ggRearRightEndLightButton.PutValue(1); + ggRearRightLightButton.PutValue(0); + } + else + ggRearRightLightButton.PutValue(-1); + } + if (((DynamicObject->iLights[0]) & 48) == 16) + { + DynamicObject->iLights[0] &= (255 - 16); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRearRightLightButton.PutValue(0); + } + } + } //------------------------------ + else + { + if (mvOccupied->ActiveCab == 1) + { // kabina 0 + if (((DynamicObject->iLights[0]) & 48) == 0) + { + DynamicObject->iLights[0] |= 32; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRightEndLightButton.SubModel) + { + ggRightEndLightButton.PutValue(1); + ggRightLightButton.PutValue(0); + } + else + ggRightLightButton.PutValue(-1); + } + if (((DynamicObject->iLights[0]) & 48) == 16) + { + DynamicObject->iLights[0] &= (255 - 16); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRightLightButton.PutValue(0); + } + } + else + { // kabina -1 + if (((DynamicObject->iLights[1]) & 48) == 0) + { + DynamicObject->iLights[1] |= 32; + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (ggRightEndLightButton.SubModel) + { + ggRightEndLightButton.PutValue(1); + ggRightLightButton.PutValue(0); + } + else + ggRightLightButton.PutValue(-1); + } + if (((DynamicObject->iLights[1]) & 48) == 16) + { + DynamicObject->iLights[1] &= (255 - 16); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ggRightLightButton.PutValue(0); + } + } + } + } + else if (cKey == Global::Keys[k_StLinOff]) // Winger 110904: wylacznik st. liniowych + { + if ((mvControlled->TrainType != dt_EZT) && (mvControlled->TrainType != dt_EP05) && + (mvControlled->TrainType != dt_ET40)) + { + ggStLinOffButton.PutValue(1); // Ra: było Fuse... + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + if (mvControlled->MainCtrlPosNo > 0) + { + mvControlled->StLinFlag = + false; // yBARC - zmienione na przeciwne, bo true to zalaczone + dsbRelay->SetVolume(DSBVOLUME_MAX); + dsbRelay->Play(0, 0, 0); + } + } + if (mvControlled->TrainType == dt_EZT) + { + if (mvControlled->Signalling == true) + { + dsbSwitch->Play(0, 0, 0); + mvControlled->Signalling = false; + } + } + } + else + { + // McZapkie: poruszanie sie po kabinie, w updatemechpos zawarte sa wiezy + + // double dt=Timer::GetDeltaTime(); + if (mvOccupied->ActiveCab < 0) + fMechCroach = -0.5; + else + fMechCroach = 0.5; + // if (!GetAsyncKeyState(VK_SHIFT)<0) // bez shifta + if (!Console::Pressed(VK_CONTROL)) // gdy [Ctrl] zwolniony (dodatkowe widoki) + { + if (cKey == Global::Keys[k_MechLeft]) + { + vMechMovement.x += fMechCroach; + if (DynamicObject->Mechanik) + if (!FreeFlyModeFlag) //żeby nie mieszać obserwując z zewnątrz + DynamicObject->Mechanik->RouteSwitch(1); // na skrzyżowaniu skręci w + // lewo + } + else if (cKey == Global::Keys[k_MechRight]) + { + vMechMovement.x -= fMechCroach; + if (DynamicObject->Mechanik) + if (!FreeFlyModeFlag) //żeby nie mieszać obserwując z zewnątrz + DynamicObject->Mechanik->RouteSwitch( + 2); // na skrzyżowaniu skręci w prawo + } + else if (cKey == Global::Keys[k_MechBackward]) + { + vMechMovement.z -= fMechCroach; + // if (DynamicObject->Mechanik) + // if (!FreeFlyModeFlag) //żeby nie mieszać obserwując z zewnątrz + // DynamicObject->Mechanik->RouteSwitch(0); //na skrzyżowaniu stanie i poczeka + } + else if (cKey == Global::Keys[k_MechForward]) + { + vMechMovement.z += fMechCroach; + if (DynamicObject->Mechanik) + if (!FreeFlyModeFlag) //żeby nie mieszać obserwując z zewnątrz + DynamicObject->Mechanik->RouteSwitch( + 3); // na skrzyżowaniu pojedzie prosto + } + else if (cKey == Global::Keys[k_MechUp]) + pMechOffset.y += 0.2; // McZapkie-120302 - wstawanie + else if (cKey == Global::Keys[k_MechDown]) + pMechOffset.y -= 0.2; // McZapkie-120302 - siadanie + } + } + + // else if (DebugModeFlag) - if (DynamicObject->Mechanik->AIControllFlag) //żeby nie trzeba było rozłączać dla zresetowania - DynamicObject->Mechanik->TakeControl(false); - DynamicObject->Mechanik->TakeControl(true); - } - } - else if (cKey==Global::Keys[k_MaxCurrent]) //McZapkie-160502: F - wysoki rozruch - { - if ((mvControlled->EngineType==DieselElectric)&&(mvControlled->ShuntModeAllow) && (mvControlled->MainCtrlPos==0)) - { - mvControlled->ShuntMode=true; - } - if (mvControlled->CurrentSwitch(true)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } -/* Ra: przeniesione do Mover.cpp - if (mvControlled->TrainType!=dt_EZT) //to powinno być w fizyce, a nie w kabinie! - if (mvControlled->MinCurrentSwitch(true)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } -*/ - } - else if (cKey==Global::Keys[k_CurrentAutoRelay]) //McZapkie-241002: G - wlaczanie PSR - { - if (mvControlled->AutoRelaySwitch(true)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - if (cKey==Global::Keys[k_FailedEngineCutOff]) //McZapkie-060103: E - wylaczanie sekcji silnikow - { - if (mvControlled->CutOffEngine()) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - if (cKey==Global::Keys[k_OpenLeft]) //NBMX 17-09-2003: otwieranie drzwi - { - if (mvOccupied->DoorOpenCtrl==1) - if (mvOccupied->CabNo<0?mvOccupied->DoorRight(true):mvOccupied->DoorLeft(true)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (dsbDoorOpen) - { - dsbDoorOpen->SetCurrentPosition(0); - dsbDoorOpen->Play(0,0,0); - } - } - } - else - if (cKey==Global::Keys[k_OpenRight]) //NBMX 17-09-2003: otwieranie drzwi - { - if (mvOccupied->DoorCloseCtrl==1) - if (mvOccupied->CabNo<0?mvOccupied->DoorLeft(true):mvOccupied->DoorRight(true)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (dsbDoorOpen) - { - dsbDoorOpen->SetCurrentPosition(0); - dsbDoorOpen->Play(0,0,0); - } - } - } - else - //----------- - //hunter-131211: dzwiek dla przelacznika universala podniesionego - //hunter-091012: ubajerowanie swiatla w kabinie (wyrzucenie przyciemnienia pod Univ4) - if (cKey==Global::Keys[k_Univ3]) - { - if (Console::Pressed(VK_CONTROL)) - { - if (bCabLight==false)//(ggCabLightButton.GetValue()==0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - { - if (ggUniversal3Button.GetValue()==0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - /* - if (Console::Pressed(VK_CONTROL)) - {//z [Ctrl] zapalamy albo gasimy światełko w kabinie - if (iCabLightFlag<2) ++iCabLightFlag; //zapalenie - } - */ - } - } - else - //----------- - //hunter-091012: dzwiek dla przyciemnienia swiatelka w kabinie - if (cKey==Global::Keys[k_Univ4]) - { - if (Console::Pressed(VK_CONTROL)) - { - if (bCabLightDim==false) //(ggCabLightDimButton.GetValue()==0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - } - else - //----------- - if (cKey==Global::Keys[k_PantFrontUp]) - {//Winger 160204: podn. przedn. pantografu - if (mvOccupied->ActiveCab==1)//||((mvOccupied->ActiveCab<1)&&((mvControlled->TrainType&(dt_ET40|dt_ET41|dt_ET42|dt_EZT))==0))) - {//przedni gdy w kabinie 1 lub (z wyjątkiem ET40, ET41, ET42 i EZT) gdy w kabinie -1 - mvControlled->PantFrontSP=false; - if (mvControlled->PantFront(true)) - if (mvControlled->PantFrontStart!=1) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - //if ((mvOccupied->ActiveCab<1)&&(mvControlled->TrainType&(dt_ET40|dt_ET41|dt_ET42|dt_EZT))) - {//w kabinie -1 dla ET40, ET41, ET42 i EZT - mvControlled->PantRearSP=false; - if(mvControlled->PantRear(true)) - if(mvControlled->PantRearStart!=1) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - } - else - if (cKey==Global::Keys[k_PantRearUp]) - {//Winger 160204: podn. tyln. pantografu względem kierunku jazdy - if (mvOccupied->ActiveCab==1)//||((mvOccupied->ActiveCab<1)&&((mvControlled->TrainType&(dt_ET40|dt_ET41|dt_ET42|dt_EZT))==0))) - {//tylny gdy w kabinie 1 lub (z wyjątkiem ET40, ET41, ET42 i EZT) gdy w kabinie -1 - mvControlled->PantRearSP=false; - if (mvControlled->PantRear(true)) - if (mvControlled->PantRearStart!=1) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - //if ((mvOccupied->ActiveCab<1)&&(mvControlled->TrainType&(dt_ET40|dt_ET41|dt_ET42|dt_EZT))) - {//przedni w kabinie -1 dla ET40, ET41, ET42 i EZT - mvControlled->PantFrontSP=false; - if(mvControlled->PantFront(true)) - if (mvControlled->PantFrontStart!=1) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - } - else - if (cKey==Global::Keys[k_Active]) //yB 300407: przelacznik rozrzadu - {//Ra 2014-06: uruchomiłem to, aby aktywować czuwak w zajmowanym członie, a wyłączyć w innych - //Ra 2014-03: aktywacja czuwaka przepięta na ustawienie kierunku w mvOccupied - //if (mvControlled->Battery) //jeśli bateria jest już załączona - // mvOccupied->BatterySwitch(true); //to w ten oto durny sposób aktywuje się CA/SHP -// if (mvControlled->CabActivisation()) -// { -// dsbSwitch->SetVolume(DSBVOLUME_MAX); -// dsbSwitch->Play(0,0,0); -// } - } - else - if (cKey==Global::Keys[k_Heating]) //Winger 020304: ogrzewanie skladu - wlaczenie - {//Ra 2014-09: w trybie latania obsługa jest w World.cpp - if (!FreeFlyModeFlag) - { - if ((mvControlled->Heating==false)&&((mvControlled->EngineType==ElectricSeriesMotor)&&(mvControlled->Mains==true)||(mvControlled->ConverterFlag))) - { - mvControlled->Heating=true; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - } - else - //ABu 060205: dzielo Wingera po malutkim liftingu: - if (cKey==Global::Keys[k_LeftSign]) //lewe swiatlo - włączenie - { - if ((GetAsyncKeyState(VK_CONTROL)<0)&&(ggRearLeftLightButton.SubModel)) //hunter-230112 - z controlem zapala z tylu - { - //------------------------------ - if (mvOccupied->ActiveCab==1) - {//kabina 1 - if (((DynamicObject->iLights[1])&3)==0) - { - DynamicObject->iLights[1]|=1; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearLeftLightButton.PutValue(1); - } - if (((DynamicObject->iLights[1])&3)==2) - { - DynamicObject->iLights[1]&=(255-2); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRearLeftEndLightButton.SubModel) - { - ggRearLeftEndLightButton.PutValue(0); - ggRearLeftLightButton.PutValue(0); - } - else - ggRearLeftLightButton.PutValue(0); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[0])&3)==0) - { - DynamicObject->iLights[0]|=1; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearLeftLightButton.PutValue(1); - } - if (((DynamicObject->iLights[0])&3)==2) - { - DynamicObject->iLights[0]&=(255-2); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRearLeftEndLightButton.SubModel) - { - ggRearLeftEndLightButton.PutValue(0); - ggRearLeftLightButton.PutValue(0); - } - else - ggRearLeftLightButton.PutValue(0); - } - } - //---------------------- - } - else - { - if (mvOccupied->ActiveCab==1) - {//kabina 1 - if (((DynamicObject->iLights[0])&3)==0) - { - DynamicObject->iLights[0]|=1; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggLeftLightButton.PutValue(1); - } - if (((DynamicObject->iLights[0])&3)==2) - { - DynamicObject->iLights[0]&=(255-2); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggLeftEndLightButton.SubModel) - { - ggLeftEndLightButton.PutValue(0); - ggLeftLightButton.PutValue(0); - } - else - ggLeftLightButton.PutValue(0); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[1])&3)==0) - { - DynamicObject->iLights[1]|=1; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggLeftLightButton.PutValue(1); - } - if (((DynamicObject->iLights[1])&3)==2) - { - DynamicObject->iLights[1]&=(255-2); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggLeftEndLightButton.SubModel) - { - ggLeftEndLightButton.PutValue(0); - ggLeftLightButton.PutValue(0); - } - else - ggLeftLightButton.PutValue(0); - } - } - } //----------- - } - else - if (cKey==Global::Keys[k_UpperSign]) //ABu 060205: światło górne - włączenie - { - if ((GetAsyncKeyState(VK_CONTROL)<0)&&(ggRearUpperLightButton.SubModel)) //hunter-230112 - z controlem zapala z tylu - { - //------------------------------ - if ((mvOccupied->ActiveCab)==1) - { //kabina 1 - if (((DynamicObject->iLights[1])&12)==0) - { - DynamicObject->iLights[1]|=4; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearUpperLightButton.PutValue(1); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[0])&12)==0) - { - DynamicObject->iLights[0]|=4; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearUpperLightButton.PutValue(1); - } - } - } //------------------------------ - else - { - if ((mvOccupied->ActiveCab)==1) - { //kabina 1 - if (((DynamicObject->iLights[0])&12)==0) - { - DynamicObject->iLights[0]|=4; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggUpperLightButton.PutValue(1); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[1])&12)==0) - { - DynamicObject->iLights[1]|=4; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggUpperLightButton.PutValue(1); - } - } - } - } - else - if (cKey==Global::Keys[k_RightSign]) //Winger 070304: swiatla tylne (koncowki) - wlaczenie - { - if ((GetAsyncKeyState(VK_CONTROL)<0)&&(ggRearRightLightButton.SubModel)) //hunter-230112 - z controlem zapala z tylu - { - //------------------------------ - if (mvOccupied->ActiveCab==1) - {//kabina 1 - if (((DynamicObject->iLights[1])&48)==0) - { - DynamicObject->iLights[1]|=16; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearRightLightButton.PutValue(1); - } - if (((DynamicObject->iLights[1])&48)==32) - { - DynamicObject->iLights[1]&=(255-32); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRearRightEndLightButton.SubModel) - { - ggRearRightEndLightButton.PutValue(0); - ggRearRightLightButton.PutValue(0); - } - else - ggRearRightLightButton.PutValue(0); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[0])&48)==0) - { - DynamicObject->iLights[0]|=16; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearRightLightButton.PutValue(1); - } - if (((DynamicObject->iLights[0])&48)==32) - { - DynamicObject->iLights[0]&=(255-32); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRearRightEndLightButton.SubModel) - { - ggRearRightEndLightButton.PutValue(0); - ggRearRightLightButton.PutValue(0); - } - else - ggRearRightLightButton.PutValue(0); - } - } - } //------------------------------ - else - { - if (mvOccupied->ActiveCab==1) - {//kabina 1 - if (((DynamicObject->iLights[0])&48)==0) - { - DynamicObject->iLights[0]|=16; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRightLightButton.PutValue(1); - } - if (((DynamicObject->iLights[0])&48)==32) - { - DynamicObject->iLights[0]&=(255-32); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRightEndLightButton.SubModel) - { - ggRightEndLightButton.PutValue(0); - ggRightLightButton.PutValue(0); - } - else - ggRightLightButton.PutValue(0); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[1])&48)==0) - { - DynamicObject->iLights[1]|=16; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRightLightButton.PutValue(1); - } - if (((DynamicObject->iLights[1])&48)==32) - { - DynamicObject->iLights[1]&=(255-32); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRightEndLightButton.SubModel) - { - ggRightEndLightButton.PutValue(0); - ggRightLightButton.PutValue(0); - } - else - ggRightLightButton.PutValue(0); - } - } - } - } - } - else //McZapkie-240302 - klawisze bez shifta - { - if (cKey==Global::Keys[k_IncMainCtrl]) - { - if (mvControlled->IncMainCtrl(1)) - { - dsbNastawnikJazdy->SetCurrentPosition(0); - dsbNastawnikJazdy->Play(0,0,0); - } - } - else if (cKey==Global::Keys[k_DecMainCtrl]) - if (mvControlled->DecMainCtrl(1)) - { - dsbNastawnikJazdy->SetCurrentPosition(0); - dsbNastawnikJazdy->Play(0,0,0); - } - else; - else - if (cKey==Global::Keys[k_IncScndCtrl]) -// if (MoverParameters->ScndCtrlPosScndCtrlPosNo) -// if (mvControlled->EnginePowerSource.SourceType==CurrentCollector) - if (mvControlled->ShuntMode) - { - mvControlled->AnPos+=(GetDeltaTime()/0.85f); - if (mvControlled->AnPos > 1) - mvControlled->AnPos=1; - } - else - if (mvControlled->IncScndCtrl(1)) - { - if (dsbNastawnikBocz) //hunter-081211 - { - dsbNastawnikBocz->SetCurrentPosition(0); - dsbNastawnikBocz->Play(0,0,0); - } - else if (!dsbNastawnikBocz) - { - dsbNastawnikJazdy->SetCurrentPosition(0); - dsbNastawnikJazdy->Play(0,0,0); - } - } - else; - else - if (cKey==Global::Keys[k_DecScndCtrl]) - // if (mvControlled->EnginePowerSource.SourceType==CurrentCollector) - if (mvControlled->ShuntMode) - { - mvControlled->AnPos-=(GetDeltaTime()/0.55f); - if (mvControlled->AnPos < 0) - mvControlled->AnPos=0; - } - else - - if (mvControlled->DecScndCtrl(1)) - // if (MoverParameters->ScndCtrlPos>0) - { - if (dsbNastawnikBocz) //hunter-081211 - { - dsbNastawnikBocz->SetCurrentPosition(0); - dsbNastawnikBocz->Play(0,0,0); - } - else if (!dsbNastawnikBocz) - { - dsbNastawnikJazdy->SetCurrentPosition(0); - dsbNastawnikJazdy->Play(0,0,0); - } - } - else; - else - if (cKey==Global::Keys[k_IncLocalBrakeLevel]) - {//Ra 2014-09: w trybie latania obsługa jest w World.cpp - if (!FreeFlyModeFlag) - { - if (GetAsyncKeyState(VK_CONTROL)<0) - if ((mvOccupied->LocalBrake==ManualBrake)||(mvOccupied->MBrake==true)) - { - mvOccupied->IncManualBrakeLevel(1); - } - else; - else if (mvOccupied->LocalBrake!=ManualBrake) - mvOccupied->IncLocalBrakeLevel(1); - } - } - else - if (cKey==Global::Keys[k_DecLocalBrakeLevel]) - {//Ra 2014-06: wersja dla swobodnego latania przeniesiona do World.cpp - if (!FreeFlyModeFlag) - { - if (GetAsyncKeyState(VK_CONTROL)<0) - if ((mvOccupied->LocalBrake==ManualBrake)||(mvOccupied->MBrake==true)) - mvOccupied->DecManualBrakeLevel(1); - else; - else //Ra 1014-06: AI potrafi zahamować pomocniczym mimo jego braku - odhamować jakoś trzeba - if ((mvOccupied->LocalBrake!=ManualBrake)||mvOccupied->LocalBrakePos) - mvOccupied->DecLocalBrakeLevel(1); - } - } - else - if ((cKey==Global::Keys[k_IncBrakeLevel])&&(mvOccupied->BrakeHandle!=FV4a)) - //if (mvOccupied->IncBrakeLevel()) - if (mvOccupied->BrakeLevelAdd(Global::fBrakeStep)) //nieodpowiedni warunek; true, jeśli można dalej kręcić - { - keybrakecount=0; - if ((isEztOer) && (mvOccupied->BrakeCtrlPos<3)) - {//Ra: uzależnić dźwięk od zmiany stanu EP, nie od klawisza - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); - } - } - else; - else - if ((cKey==Global::Keys[k_DecBrakeLevel])&&(mvOccupied->BrakeHandle!=FV4a)) - { -//nową wersję dostarczył ZiomalCl ("fixed looped sound in ezt when using NUM_9 key") - if ((mvOccupied->BrakeCtrlPos>-1) || (keybrakecount>1)) - { - - if ((isEztOer) && (mvControlled->Mains) && (mvOccupied->BrakeCtrlPos!=-1)) - {//Ra: uzależnić dźwięk od zmiany stanu EP, nie od klawisza - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); - } - //mvOccupied->DecBrakeLevel(); - mvOccupied->BrakeLevelAdd(-Global::fBrakeStep); - - } - else keybrakecount+=1; -//koniec wersji dostarczonej przez ZiomalCl -/* wersja poprzednia - ten pierwszy if ze średnikiem nie działał jak warunek - if ((mvOccupied->BrakeCtrlPos>-1)|| (keybrakecount>1)) - { - if (mvOccupied->DecBrakeLevel()); - { - if ((isEztOer) && (mvOccupied->BrakeCtrlPos<2)&&(keybrakecount<=1)) - { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); - } - } - } - else keybrakecount+=1; -*/ - } - else - if (cKey==Global::Keys[k_EmergencyBrake]) - { - //while (mvOccupied->IncBrakeLevel()); - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EB)); - if(mvOccupied->BrakeCtrlPosNo<=0.1) //hamulec bezpieczeństwa dla wagonów - mvOccupied->EmergencyBrakeFlag=true; - } - else - if (cKey==Global::Keys[k_Brake3]) - { - if ((isEztOer) && ((mvOccupied->BrakeCtrlPos==1)||(mvOccupied->BrakeCtrlPos==-1))) + { // przesuwanie składu o 100m + TDynamicObject *d = DynamicObject; + if (cKey == VkKeyScan('[')) { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); + while (d) + { + d->Move(100.0 * d->DirectionGet()); + d = d->Next(); // pozostałe też + } + d = DynamicObject->Prev(); + while (d) + { + d->Move(100.0 * d->DirectionGet()); + d = d->Prev(); // w drugą stronę też + } } - //while (mvOccupied->BrakeCtrlPos>mvOccupied->BrakeCtrlPosNo-1 && mvOccupied->DecBrakeLevel()); - //while (mvOccupied->BrakeCtrlPosBrakeCtrlPosNo-1 && mvOccupied->IncBrakeLevel()); - mvOccupied->BrakeLevelSet(mvOccupied->BrakeCtrlPosNo-1); - } - else - if (cKey==Global::Keys[k_Brake2]) - { - if ((isEztOer) && ((mvOccupied->BrakeCtrlPos==1)||(mvOccupied->BrakeCtrlPos==-1))) - { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); - } - //while (mvOccupied->BrakeCtrlPos>mvOccupied->BrakeCtrlPosNo/2 && mvOccupied->DecBrakeLevel()); - //while (mvOccupied->BrakeCtrlPosBrakeCtrlPosNo/2 && mvOccupied->IncBrakeLevel()); - mvOccupied->BrakeLevelSet(mvOccupied->BrakeCtrlPosNo/2+(mvOccupied->BrakeHandle==FV4a?1:0)); - if (GetAsyncKeyState(VK_CONTROL)<0) - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_NP)); //yB: czy ten stos funkcji nie powinien być jako oddzielna funkcja movera? - } - else - if (cKey==Global::Keys[k_Brake1]) - { - if ((isEztOer)&& (mvOccupied->BrakeCtrlPos!=1)) + else if (cKey == VkKeyScan(']')) { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); - } - //while (mvOccupied->BrakeCtrlPos>1 && mvOccupied->DecBrakeLevel()); - //while (mvOccupied->BrakeCtrlPos<1 && mvOccupied->IncBrakeLevel()); - mvOccupied->BrakeLevelSet(1); - } - else - if (cKey==Global::Keys[k_Brake0]) - { - if (Console::Pressed(VK_CONTROL)) - { - mvOccupied->BrakeCtrlPos2= 0; //wyrownaj kapturek - } - else - { - if ((isEztOer) && ((mvOccupied->BrakeCtrlPos==1)||(mvOccupied->BrakeCtrlPos==-1))) - { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); - } - //while (mvOccupied->BrakeCtrlPos>0 && mvOccupied->DecBrakeLevel()); - //while (mvOccupied->BrakeCtrlPos<0 && mvOccupied->IncBrakeLevel()); - mvOccupied->BrakeLevelSet(0); - } - } - else - if (cKey==Global::Keys[k_WaveBrake]) //[Num.] - { - if ((isEztOer) && (mvControlled->Mains) && (mvOccupied->BrakeCtrlPos!=-1)) - { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); - } - //while (mvOccupied->BrakeCtrlPos>-1 && mvOccupied->DecBrakeLevel()); - //while (mvOccupied->BrakeCtrlPos<-1 && mvOccupied->IncBrakeLevel()); - mvOccupied->BrakeLevelSet(-1); - } - else - //--------------- - //hunter-131211: zbicie czuwaka przeniesione do TTrain::Update() - if (cKey==Global::Keys[k_Czuwak]) - {//Ra: tu został tylko dźwięk - //dsbBuzzer->Stop(); - //if (mvOccupied->SecuritySystemReset()) - if (fabs(ggSecurityResetButton.GetValue())<0.001) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - //ggSecurityResetButton.PutValue(1); - } - else - //--------------- - //hunter-221211: hamulec przeciwposlizgowy przeniesiony do TTrain::Update() - if (cKey==Global::Keys[k_AntiSlipping]) - { - if (mvOccupied->BrakeSystem!=ElectroPneumatic) - { - //if (mvControlled->AntiSlippingButton()) - if (fabs(ggAntiSlipButton.GetValue())<0.001) - { - //Dlaczego bylo '-50'??? - //dsbSwitch->SetVolume(-50); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - //ggAntiSlipButton.PutValue(1); - } - } - else - //--------------- - - if (cKey==Global::Keys[k_Fuse]) - { - if (GetAsyncKeyState(VK_CONTROL)<0) //z controlem - { - ggConverterFuseButton.PutValue(1); //hunter-261211 - if ((mvControlled->Mains==false)&&(ggConverterButton.GetValue()==0)) - mvControlled->ConvOvldFlag=false; - } - else - { - ggFuseButton.PutValue(1); - mvControlled->FuseOn(); - } - } - else - // McZapkie-240302 - zmiana kierunku: 'd' do przodu, 'r' do tylu - if (cKey==Global::Keys[k_DirectionForward]) - { - if (mvOccupied->DirectionForward()) - { - //------------ - //hunter-121211: dzwiek kierunkowego - if (dsbReverserKey) - { - dsbReverserKey->SetCurrentPosition(0); - dsbReverserKey->SetVolume(DSBVOLUME_MAX); - dsbReverserKey->Play(0,0,0); - } - else if (!dsbReverserKey) - if (dsbSwitch) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - //------------ - if (mvOccupied->ActiveDir) //jeśli kierunek niezerowy - if (DynamicObject->Mechanik) //na wszelki wypadek - DynamicObject->Mechanik->CheckVehicles(Change_direction); //aktualizacja skrajnych pojazdów w składzie - } - } - else - if (cKey==Global::Keys[k_DirectionBackward]) //r - { - if (GetAsyncKeyState(VK_CONTROL)<0) - {//wciśnięty [Ctrl] - if (mvControlled->Radio==true) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - mvControlled->Radio=false; - } - } - else - if (mvOccupied->DirectionBackward()) - { - //------------ - //hunter-121211: dzwiek kierunkowego - if (dsbReverserKey) - { - dsbReverserKey->SetCurrentPosition(0); - dsbReverserKey->SetVolume(DSBVOLUME_MAX); - dsbReverserKey->Play(0,0,0); - } - else if (!dsbReverserKey) - if (dsbSwitch) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - //------------ - if (mvOccupied->ActiveDir) //jeśli kierunek niezerowy - if (DynamicObject->Mechanik) //na wszelki wypadek - DynamicObject->Mechanik->CheckVehicles(Change_direction); //aktualizacja skrajnych pojazdów w składzie - } - } - else - // McZapkie-240302 - wylaczanie glownego obwodu - //----------- - //hunter-141211: wyl. szybki wylaczony przeniesiony do TTrain::Update() - if (cKey==Global::Keys[k_Main]) - { - if (fabs(ggMainOffButton.GetValue())<0.001) - if (dsbSwitch) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - - if (cKey==Global::Keys[k_Battery]) - { - //if ((mvControlled->TrainType==dt_EZT) || (mvControlled->EngineType==ElectricSeriesMotor)|| (mvControlled->EngineType==DieselElectric)) - if (mvOccupied->BatterySwitch(false)) - {//ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora - dsbSwitch->Play(0,0,0); - //mvOccupied->SecuritySystem.Status=0; - mvControlled->PantFront(false); - mvControlled->PantRear(false); - } - } - - //----------- -// if (cKey==Global::Keys[k_Active]) //yB 300407: przelacznik rozrzadu -// { -// if (mvControlled->CabDeactivisation()) -// { -// dsbSwitch->SetVolume(DSBVOLUME_MAX); -// dsbSwitch->Play(0,0,0); -// } -// } -// else - if (cKey==Global::Keys[k_BrakeProfile]) - {//yB://ABu: male poprawki, zeby bylo mozna ustawic dowolny wagon - int CouplNr=-2; - if (!FreeFlyModeFlag) - { - if (GetAsyncKeyState(VK_CONTROL)<0) - if (mvOccupied->BrakeDelaySwitch(bdelay_R)) - { - dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); - dsbPneumaticRelay->Play(0,0,0); - } - else; - else - if (mvOccupied->BrakeDelaySwitch(bdelay_G)) - { - dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); - dsbPneumaticRelay->Play(0,0,0); - } - } - else - { - TDynamicObject *temp; - temp=(DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(),-1, 1500, CouplNr)); - if (temp==NULL) - { - CouplNr=-2; - temp=(DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(),1, 1500, CouplNr)); - } - if (temp) - { - if (GetAsyncKeyState(VK_CONTROL)<0) - if (temp->MoverParameters->BrakeDelaySwitch(bdelay_R)) - { - dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); - dsbPneumaticRelay->Play(0,0,0); - } - else; - else - if (temp->MoverParameters->BrakeDelaySwitch(bdelay_G)) - { - dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); - dsbPneumaticRelay->Play(0,0,0); - } - } - } - - } - else - //----------- - //hunter-261211: przetwornica i sprzezarka przeniesione do TTrain::Update() - if (cKey==Global::Keys[k_Converter]) - { - if (ggConverterButton.GetValue()!=0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - //if ((cKey==Global::Keys[k_Compressor])&&((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->TrainType==dt_EZT))) //hunter-110212: poprawka dla EZT - if ((cKey==Global::Keys[k_Compressor])&&(mvControlled->CompressorPower<2)) //hunter-091012: tak jest poprawnie - { - if (ggCompressorButton.GetValue()!=0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - //----------- - if (cKey==Global::Keys[k_Releaser]) //odluzniacz - { - if (!FreeFlyModeFlag) - { - if ((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->EngineType==DieselElectric)||(mvControlled->EngineType==ElectricInductionMotor)) - if (mvControlled->TrainType!=dt_EZT) - if (mvOccupied->BrakeCtrlPosNo>0) - { - ggReleaserButton.PutValue(1); - if (mvOccupied->BrakeReleaser(1)) - { - dsbPneumaticRelay->SetVolume(-80); - dsbPneumaticRelay->Play(0,0,0); - } - } - } - } - else if (cKey==Global::Keys[k_SmallCompressor]) //Winger 160404: mala sprezarka wl - {//Ra: bez [Shift] też dać dźwięk - if ((mvControlled->TrainType&dt_EZT)?mvControlled==mvOccupied:!mvOccupied->ActiveCab) //tylko w maszynowym - if (Console::Pressed(VK_CONTROL)) //z [Ctrl] - mvControlled->bPantKurek3=false; //zbiornik pantografu połączony jest z małą sprężarką (pompowanie ma sens, ale potem trzeba przełączyć) - else if (!mvControlled->PantCompFlag) //jeśli wyłączona - if (mvControlled->Battery) //jeszcze musi być załączona bateria - if (mvControlled->PantPress<4.8) //piszą, że to tak nie działa - { - mvControlled->PantCompFlag=true; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); //dźwięk tylko po naciśnięciu klawisza - } - } - //McZapkie-240302 - wylaczanie automatycznego pilota (w trybie ~debugmode mozna tylko raz) - else if (cKey==VkKeyScan('q')) //bez Shift - { - if (DynamicObject->Mechanik) - DynamicObject->Mechanik->TakeControl(false); - } - else - if (cKey==Global::Keys[k_MaxCurrent]) //McZapkie-160502: f - niski rozruch - { - if ((mvControlled->EngineType==DieselElectric) && (mvControlled->ShuntModeAllow) && (mvControlled->MainCtrlPos==0)) - { - mvControlled->ShuntMode=false; - } - if (mvControlled->CurrentSwitch(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } -/* Ra: przeniesione do Mover.cpp - if (mvControlled->TrainType!=dt_EZT) - if (mvControlled->MinCurrentSwitch(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } -*/ - } - else - if (cKey==Global::Keys[k_CurrentAutoRelay]) //McZapkie-241002: g - wylaczanie PSR - { - if (mvControlled->AutoRelaySwitch(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - //hunter-201211: piasecznica poprawiona oraz przeniesiona do TTrain::Update() - if (cKey==Global::Keys[k_Sand]) - { - /* - if (mvControlled->TrainType!=dt_EZT) - { - if (mvControlled->SandDoseOn()) - if (mvControlled->SandDose) - { - dsbPneumaticRelay->SetVolume(-30); - dsbPneumaticRelay->Play(0,0,0); + while (d) + { + d->Move(-100.0 * d->DirectionGet()); + d = d->Next(); // pozostałe też + } + d = DynamicObject->Prev(); + while (d) + { + d->Move(-100.0 * d->DirectionGet()); + d = d->Prev(); // w drugą stronę też + } } } - */ - if (mvControlled->TrainType==dt_EZT) - { - if (mvControlled->DoorSignalling) - { - dsbSwitch->Play(0,0,0); - mvControlled->DoorSignalling=false; - } + if (cKey == VkKeyScan('-')) + { // zmniejszenie numeru kanału radiowego + if (iRadioChannel > 0) + --iRadioChannel; // 0=wyłączony } - } - else - if (cKey==Global::Keys[k_CabForward]) - { - if (!CabChange(1)) - if (TestFlag(DynamicObject->MoverParameters->Couplers[0].CouplingFlag,ctrain_passenger)) - {//przejscie do nastepnego pojazdu - Global::changeDynObj=DynamicObject->PrevConnected; - Global::changeDynObj->MoverParameters->ActiveCab=DynamicObject->PrevConnectedNo?-1:1; + else if (cKey == VkKeyScan('=')) + { // zmniejszenie numeru kanału radiowego + if (iRadioChannel < 8) + ++iRadioChannel; // 0=wyłączony } - if (DynamicObject->MoverParameters->ActiveCab) - mvControlled->PantCompFlag=false; //wyjście z maszynowego wyłącza sprężarkę - } - else if (cKey==Global::Keys[k_CabBackward]) - { - if (!CabChange(-1)) - if (TestFlag(DynamicObject->MoverParameters->Couplers[1].CouplingFlag,ctrain_passenger)) - {//przejscie do poprzedniego - Global::changeDynObj=DynamicObject->NextConnected; - Global::changeDynObj->MoverParameters->ActiveCab=DynamicObject->NextConnectedNo?-1:1; - } - if (DynamicObject->MoverParameters->ActiveCab) - mvControlled->PantCompFlag=false; //wyjście z maszynowego wyłącza sprężarkę pomocniczą - } - else - if (cKey==Global::Keys[k_Couple]) - {//ABu051104: male zmiany, zeby mozna bylo laczyc odlegle wagony - //da sie zoptymalizowac, ale nie ma na to czasu :( - if (iCabn>0) - { - if (!FreeFlyModeFlag) //tryb 'kabinowy' - {/* - if (mvControlled->Couplers[iCabn-1].CouplingFlag==0) - { - if (mvControlled->Attach(iCabn-1,mvControlled->Couplers[iCabn-1].Connected,ctrain_coupler)) - { - dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); - dsbCouplerAttach->Play(0,0,0); - //ABu: aha, a guzik, nie dziala i nie bedzie, a przydalo by sie cos takiego: - //DynamicObject->NextConnected=mvControlled->Couplers[iCabn-1].Connected; - //DynamicObject->PrevConnected=mvControlled->Couplers[iCabn-1].Connected; - } - } - else - if (!TestFlag(mvControlled->Couplers[iCabn-1].CouplingFlag,ctrain_pneumatic)) - { - //ABu021104: zeby caly czas bylo widac sprzegi: - if (mvControlled->Attach(iCabn-1,mvControlled->Couplers[iCabn-1].Connected,mvControlled->Couplers[iCabn-1].CouplingFlag+ctrain_pneumatic)) - //if (mvControlled->Attach(iCabn-1,mvControlled->Couplers[iCabn-1].Connected,ctrain_pneumatic)) - { - rsHiss.Play(1,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - }*/ - } - else - {//tryb freefly - int CouplNr=-1; //normalnie żaden ze sprzęgów - TDynamicObject *tmp; - tmp=DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(),1,1500,CouplNr); - if (tmp==NULL) - tmp=DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(),-1,1500,CouplNr); - if (tmp&&(CouplNr!=-1)) - { - if (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag==0) //najpierw hak - { - if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag&tmp->MoverParameters->Couplers[CouplNr].AllowedFlag&ctrain_coupler)==ctrain_coupler) - if (tmp->MoverParameters->Attach(CouplNr,2,tmp->MoverParameters->Couplers[CouplNr].Connected,ctrain_coupler)) - { - //tmp->MoverParameters->Couplers[CouplNr].Render=true; //podłączony sprzęg będzie widoczny - if (DynamicObject->Mechanik) //na wszelki wypadek - DynamicObject->Mechanik->CheckVehicles(Connect); //aktualizacja flag kierunku w składzie - dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); - dsbCouplerAttach->Play(0,0,0); - } - else - WriteLog("Mechanical coupling failed."); - } - else - if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag,ctrain_pneumatic)) //pneumatyka - { - if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag&tmp->MoverParameters->Couplers[CouplNr].AllowedFlag&ctrain_pneumatic)==ctrain_pneumatic) - if (tmp->MoverParameters->Attach(CouplNr,2,tmp->MoverParameters->Couplers[CouplNr].Connected,tmp->MoverParameters->Couplers[CouplNr].CouplingFlag+ctrain_pneumatic)) - { - rsHiss.Play(1,DSBPLAY_LOOPING,true,tmp->GetPosition()); - DynamicObject->SetPneumatic(CouplNr,1); //Ra: to mi się nie podoba !!!! - tmp->SetPneumatic(CouplNr,1); - } - } - else - if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag,ctrain_scndpneumatic)) //zasilajacy - { - if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag&tmp->MoverParameters->Couplers[CouplNr].AllowedFlag&ctrain_scndpneumatic)==ctrain_scndpneumatic) - if (tmp->MoverParameters->Attach(CouplNr,2,tmp->MoverParameters->Couplers[CouplNr].Connected,tmp->MoverParameters->Couplers[CouplNr].CouplingFlag+ctrain_scndpneumatic)) - { -// rsHiss.Play(1,DSBPLAY_LOOPING,true,tmp->GetPosition()); - dsbCouplerDetach->SetVolume(DSBVOLUME_MAX); - dsbCouplerDetach->Play(0,0,0); - DynamicObject->SetPneumatic(CouplNr,0); //Ra: to mi się nie podoba !!!! - tmp->SetPneumatic(CouplNr,0); - } - } - else - if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag,ctrain_controll)) //ukrotnionko - { - if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag&tmp->MoverParameters->Couplers[CouplNr].AllowedFlag&ctrain_controll)==ctrain_controll) - if (tmp->MoverParameters->Attach(CouplNr,2,tmp->MoverParameters->Couplers[CouplNr].Connected,tmp->MoverParameters->Couplers[CouplNr].CouplingFlag+ctrain_controll)) - { - dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); - dsbCouplerAttach->Play(0,0,0); - } - } - else - if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag,ctrain_passenger)) //mostek - { - if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag&tmp->MoverParameters->Couplers[CouplNr].AllowedFlag&ctrain_passenger)==ctrain_passenger) - if (tmp->MoverParameters->Attach(CouplNr,2,tmp->MoverParameters->Couplers[CouplNr].Connected,tmp->MoverParameters->Couplers[CouplNr].CouplingFlag+ctrain_passenger)) - { -// rsHiss.Play(1,DSBPLAY_LOOPING,true,tmp->GetPosition()); - dsbCouplerDetach->SetVolume(DSBVOLUME_MAX); - dsbCouplerDetach->Play(0,0,0); - DynamicObject->SetPneumatic(CouplNr,0); - tmp->SetPneumatic(CouplNr,0); - } - } - } - } - } - } - else - if (cKey==Global::Keys[k_DeCouple]) - { //ABu051104: male zmiany, zeby mozna bylo rozlaczac odlegle wagony - if (iCabn>0) - { - if (!FreeFlyModeFlag) //tryb 'kabinowy' (pozwala również rozłączyć sprzęgi zablokowane) - { - if (DynamicObject->DettachStatus(iCabn-1)<0) //jeśli jest co odczepić - if (DynamicObject->Dettach(iCabn-1)) //iCab==1:przód,iCab==2:tył - { - dsbCouplerDetach->SetVolume(DSBVOLUME_MAX); //w kabinie ten dźwięk? - dsbCouplerDetach->Play(0,0,0); - } - } - else - {//tryb freefly - int CouplNr=-1; - TDynamicObject *tmp; - tmp=DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(),1,1500,CouplNr); - if (tmp==NULL) - tmp=DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(),-1,1500,CouplNr); - if (tmp&&(CouplNr!=-1)) - { - if ((tmp->MoverParameters->Couplers[CouplNr].CouplingFlag&ctrain_depot)==0) //jeżeli sprzęg niezablokowany - if (tmp->DettachStatus(CouplNr)<0) //jeśli jest co odczepić i się da - if (!tmp->Dettach(CouplNr)) - {//dźwięk odczepiania - dsbCouplerDetach->SetVolume(DSBVOLUME_MAX); - dsbCouplerDetach->Play(0,0,0); - } - } - } - if (DynamicObject->Mechanik) //na wszelki wypadek - DynamicObject->Mechanik->CheckVehicles(Disconnect); //aktualizacja skrajnych pojazdów w składzie - } - } - else - if (cKey==Global::Keys[k_CloseLeft]) //NBMX 17-09-2003: zamykanie drzwi - { - if (mvOccupied->CabNo<0?mvOccupied->DoorRight(false):mvOccupied->DoorLeft(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (dsbDoorClose) - { - dsbDoorClose->SetCurrentPosition(0); - dsbDoorClose->Play(0,0,0); - } - } - } - else if (cKey==Global::Keys[k_CloseRight]) //NBMX 17-09-2003: zamykanie drzwi - { - if (mvOccupied->CabNo<0?mvOccupied->DoorLeft(false):mvOccupied->DoorRight(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (dsbDoorClose) - { - dsbDoorClose->SetCurrentPosition(0); - dsbDoorClose->Play(0,0,0); - } - } - } - else - //----------- - //hunter-131211: dzwiek dla przelacznika universala - //hunter-091012: ubajerowanie swiatla w kabinie (wyrzucenie przyciemnienia pod Univ4) - if (cKey==Global::Keys[k_Univ3]) - { - if (Console::Pressed(VK_CONTROL)) - { - if (bCabLight==true)//(ggCabLightButton.GetValue()!=0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - { - if (ggUniversal3Button.GetValue()!=0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - /* - if (Console::Pressed(VK_CONTROL)) - {//z [Ctrl] zapalamy albo gasimy światełko w kabinie - if (iCabLightFlag) --iCabLightFlag; //gaszenie - } */ - } - } - else - //----------- - //hunter-091012: dzwiek dla przyciemnienia swiatelka w kabinie - if (cKey==Global::Keys[k_Univ4]) - { - if (Console::Pressed(VK_CONTROL)) - { - if (bCabLightDim==true) //(ggCabLightDimButton.GetValue()!=0) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - } - //----------- - else - if (cKey==Global::Keys[k_PantFrontDown]) //Winger 160204: opuszczanie prz. patyka - { - if (mvOccupied->ActiveCab==1)//||((mvOccupied->ActiveCab<1)&&(mvControlled->TrainType!=dt_ET40)&&(mvControlled->TrainType!=dt_ET41)&&(mvControlled->TrainType!=dt_ET42)&&(mvControlled->TrainType!=dt_EZT))) - { - //if (!mvControlled->PantFrontUp) //jeśli był opuszczony - // if () //jeśli połamany - // //to powtórzone opuszczanie naprawia - if (mvControlled->PantFront(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - //if ((mvOccupied->ActiveCab<1)&&((mvControlled->TrainType==dt_ET40)||(mvControlled->TrainType==dt_ET41)||(mvControlled->TrainType==dt_ET42)||(mvControlled->TrainType==dt_EZT))) - { - if (mvControlled->PantRear(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - } - else if (cKey==Global::Keys[k_PantRearDown]) //Winger 160204: opuszczanie tyl. patyka - { - if (mvOccupied->ActiveCab==1)//||((mvOccupied->ActiveCab<1)&&(mvControlled->TrainType!=dt_ET40)&&(mvControlled->TrainType!=dt_ET41)&&(mvControlled->TrainType!=dt_ET42)&&(mvControlled->TrainType!=dt_EZT))) - { - if (mvControlled->PantSwitchType=="impulse") - ggPantFrontButtonOff.PutValue(1); - if (mvControlled->PantRear(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - else - //if ((mvOccupied->ActiveCab<1)&&((mvControlled->TrainType==dt_ET40)||(mvControlled->TrainType==dt_ET41)||(mvControlled->TrainType==dt_ET42)||(mvControlled->TrainType==dt_EZT))) - { - /* if (mvControlled->PantSwitchType=="impulse") - ggPantRearButtonOff.PutValue(1); */ - if (mvControlled->PantFront(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - } - } - } - else if (cKey==Global::Keys[k_Heating]) //Winger 020304: ogrzewanie - wylaczenie - {//Ra 2014-09: w trybie latania obsługa jest w World.cpp - if (!FreeFlyModeFlag) - { - if (mvControlled->Heating==true) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - mvControlled->Heating=false; - } - } - } - else - if (cKey==Global::Keys[k_LeftSign]) //ABu 060205: lewe swiatlo - wylaczenie - { - if ((GetAsyncKeyState(VK_CONTROL)<0)&&(ggRearLeftLightButton.SubModel)) //hunter-230112 - z controlem gasi z tylu - { - //------------------------------ - if (mvOccupied->ActiveCab==1) - {//kabina 1 - if (((DynamicObject->iLights[1])&3)==0) - { - DynamicObject->iLights[1]|=2; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRearLeftEndLightButton.SubModel) - { - ggRearLeftEndLightButton.PutValue(1); - ggRearLeftLightButton.PutValue(0); - } - else - ggRearLeftLightButton.PutValue(-1); - } - if (((DynamicObject->iLights[1])&3)==1) - { - DynamicObject->iLights[1]&=(255-1); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearLeftLightButton.PutValue(0); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[0])&3)==0) - { - DynamicObject->iLights[0]|=2; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRearLeftEndLightButton.SubModel) - { - ggRearLeftEndLightButton.PutValue(1); - ggRearLeftLightButton.PutValue(0); - } - else - ggRearLeftLightButton.PutValue(-1); - } - if (((DynamicObject->iLights[1])&3)==1) - { - DynamicObject->iLights[1]&=(255-1); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggLeftLightButton.PutValue(0); - } - } - } //------------------------------ - else - { - if (mvOccupied->ActiveCab==1) - {//kabina 1 - if (((DynamicObject->iLights[0])&3)==0) - { - DynamicObject->iLights[0]|=2; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggLeftEndLightButton.SubModel) - { - ggLeftEndLightButton.PutValue(1); - ggLeftLightButton.PutValue(0); - } - else - ggLeftLightButton.PutValue(-1); - } - if (((DynamicObject->iLights[0])&3)==1) - { - DynamicObject->iLights[0]&=(255-1); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggLeftLightButton.PutValue(0); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[1])&3)==0) - { - DynamicObject->iLights[1]|=2; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggLeftEndLightButton.SubModel) - { - ggLeftEndLightButton.PutValue(1); - ggLeftLightButton.PutValue(0); - } - else - ggLeftLightButton.PutValue(-1); - } - if (((DynamicObject->iLights[1])&3)==1) - { - DynamicObject->iLights[1]&=(255-1); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggLeftLightButton.PutValue(0); - } - } - } - } - else - if (cKey==Global::Keys[k_UpperSign]) //ABu 060205: światło górne - wyłączenie - { - if ((GetAsyncKeyState(VK_CONTROL)<0)&&(ggRearUpperLightButton.SubModel)) //hunter-230112 - z controlem gasi z tylu - { - //------------------------------ - if (mvOccupied->ActiveCab==1) - {//kabina 1 - if (((DynamicObject->iLights[1])&12)==4) - { - DynamicObject->iLights[1]&=(255-4); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearUpperLightButton.PutValue(0); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[0])&12)==4) - { - DynamicObject->iLights[0]&=(255-4); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearUpperLightButton.PutValue(0); - } - } - } //------------------------------ - else - { - if (mvOccupied->ActiveCab==1) - {//kabina 1 - if (((DynamicObject->iLights[0])&12)==4) - { - DynamicObject->iLights[0]&=(255-4); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggUpperLightButton.PutValue(0); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[1])&12)==4) - { - DynamicObject->iLights[1]&=(255-4); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggUpperLightButton.PutValue(0); - } - } - } - } - if (cKey==Global::Keys[k_RightSign]) //Winger 070304: swiatla tylne (koncowki) - wlaczenie - { - if ((GetAsyncKeyState(VK_CONTROL)<0)&&(ggRearRightLightButton.SubModel)) //hunter-230112 - z controlem gasi z tylu - { - //------------------------------ - if (mvOccupied->ActiveCab==1) - {//kabina 1 (od strony 0) - if (((DynamicObject->iLights[1])&48)==0) - { - DynamicObject->iLights[1]|=32; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRearRightEndLightButton.SubModel) - { - ggRearRightEndLightButton.PutValue(1); - ggRearRightLightButton.PutValue(0); - } - else - ggRearRightLightButton.PutValue(-1); - } - if (((DynamicObject->iLights[1])&48)==16) - { - DynamicObject->iLights[1]&=(255-16); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearRightLightButton.PutValue(0); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[0])&48)==0) - { - DynamicObject->iLights[0]|=32; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRearRightEndLightButton.SubModel) - { - ggRearRightEndLightButton.PutValue(1); - ggRearRightLightButton.PutValue(0); - } - else - ggRearRightLightButton.PutValue(-1); - } - if (((DynamicObject->iLights[0])&48)==16) - { - DynamicObject->iLights[0]&=(255-16); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRearRightLightButton.PutValue(0); - } - } - } //------------------------------ - else - { - if (mvOccupied->ActiveCab==1) - { //kabina 0 - if (((DynamicObject->iLights[0])&48)==0) - { - DynamicObject->iLights[0]|=32; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRightEndLightButton.SubModel) - { - ggRightEndLightButton.PutValue(1); - ggRightLightButton.PutValue(0); - } - else - ggRightLightButton.PutValue(-1); - } - if (((DynamicObject->iLights[0])&48)==16) - { - DynamicObject->iLights[0]&=(255-16); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRightLightButton.PutValue(0); - } - } - else - {//kabina -1 - if (((DynamicObject->iLights[1])&48)==0) - { - DynamicObject->iLights[1]|=32; - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (ggRightEndLightButton.SubModel) - { - ggRightEndLightButton.PutValue(1); - ggRightLightButton.PutValue(0); - } - else - ggRightLightButton.PutValue(-1); - } - if (((DynamicObject->iLights[1])&48)==16) - { - DynamicObject->iLights[1]&=(255-16); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ggRightLightButton.PutValue(0); - } - } - } - } - else - if (cKey==Global::Keys[k_StLinOff]) //Winger 110904: wylacznik st. liniowych - { - if ((mvControlled->TrainType!=dt_EZT)&&(mvControlled->TrainType!=dt_EP05)&& (mvControlled->TrainType!=dt_ET40)) - { - ggStLinOffButton.PutValue(1); //Ra: było Fuse... - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - if (mvControlled->MainCtrlPosNo>0) - { - mvControlled->StLinFlag=false; //yBARC - zmienione na przeciwne, bo true to zalaczone - dsbRelay->SetVolume(DSBVOLUME_MAX); - dsbRelay->Play(0,0,0); - } - } - if(mvControlled->TrainType==dt_EZT) - { - if(mvControlled->Signalling==true) - { - dsbSwitch->Play(0,0,0); - mvControlled->Signalling=false; - } - } - } - else - { - //McZapkie: poruszanie sie po kabinie, w updatemechpos zawarte sa wiezy - - //double dt=Timer::GetDeltaTime(); - if (mvOccupied->ActiveCab<0) - fMechCroach=-0.5; - else - fMechCroach=0.5; -// if (!GetAsyncKeyState(VK_SHIFT)<0) // bez shifta - if (!Console::Pressed(VK_CONTROL)) //gdy [Ctrl] zwolniony (dodatkowe widoki) - { - if (cKey==Global::Keys[k_MechLeft]) - {vMechMovement.x+=fMechCroach; - if (DynamicObject->Mechanik) - if (!FreeFlyModeFlag) //żeby nie mieszać obserwując z zewnątrz - DynamicObject->Mechanik->RouteSwitch(1); //na skrzyżowaniu skręci w lewo - } - else - if (cKey==Global::Keys[k_MechRight]) - {vMechMovement.x-=fMechCroach; - if (DynamicObject->Mechanik) - if (!FreeFlyModeFlag) //żeby nie mieszać obserwując z zewnątrz - DynamicObject->Mechanik->RouteSwitch(2); //na skrzyżowaniu skręci w prawo - } - else - if (cKey==Global::Keys[k_MechBackward]) - {vMechMovement.z-=fMechCroach; - //if (DynamicObject->Mechanik) - // if (!FreeFlyModeFlag) //żeby nie mieszać obserwując z zewnątrz - // DynamicObject->Mechanik->RouteSwitch(0); //na skrzyżowaniu stanie i poczeka - } - else - if (cKey==Global::Keys[k_MechForward]) - {vMechMovement.z+=fMechCroach; - if (DynamicObject->Mechanik) - if (!FreeFlyModeFlag) //żeby nie mieszać obserwując z zewnątrz - DynamicObject->Mechanik->RouteSwitch(3); //na skrzyżowaniu pojedzie prosto - } - else - if (cKey==Global::Keys[k_MechUp]) - pMechOffset.y+=0.2; //McZapkie-120302 - wstawanie - else - if (cKey==Global::Keys[k_MechDown]) - pMechOffset.y-=0.2; //McZapkie-120302 - siadanie - } - } - - // else - if (DebugModeFlag) - {//przesuwanie składu o 100m - TDynamicObject *d=DynamicObject; - if (cKey==VkKeyScan('[')) - {while (d) - {d->Move(100.0*d->DirectionGet()); - d=d->Next(); //pozostałe też - } - d=DynamicObject->Prev(); - while (d) - {d->Move(100.0*d->DirectionGet()); - d=d->Prev(); //w drugą stronę też - } - } - else - if (cKey==VkKeyScan(']')) - {while (d) - {d->Move(-100.0*d->DirectionGet()); - d=d->Next(); //pozostałe też - } - d=DynamicObject->Prev(); - while (d) - {d->Move(-100.0*d->DirectionGet()); - d=d->Prev(); //w drugą stronę też - } - } - } - if (cKey==VkKeyScan('-')) - {//zmniejszenie numeru kanału radiowego - if (iRadioChannel>0) --iRadioChannel; //0=wyłączony } - else if (cKey==VkKeyScan('=')) - {//zmniejszenie numeru kanału radiowego - if (iRadioChannel<8) ++iRadioChannel; //0=wyłączony - } - } } void __fastcall TTrain::OnKeyUp(int cKey) -{//zwolnienie klawisza - if (GetAsyncKeyState(VK_SHIFT)<0) - {//wciśnięty [Shift] - } - else - { - if (cKey==Global::Keys[k_StLinOff]) //Winger 110904: wylacznik st. liniowych - {//zwolnienie klawisza daje powrót przycisku do zwykłego stanu - if ((mvControlled->TrainType!=dt_EZT)&&(mvControlled->TrainType!=dt_EP05)&& (mvControlled->TrainType!=dt_ET40)) - ggStLinOffButton.PutValue(0); - } - } +{ // zwolnienie klawisza + if (GetAsyncKeyState(VK_SHIFT) < 0) + { // wciśnięty [Shift] + } + else + { + if (cKey == Global::Keys[k_StLinOff]) // Winger 110904: wylacznik st. liniowych + { // zwolnienie klawisza daje powrót przycisku do zwykłego stanu + if ((mvControlled->TrainType != dt_EZT) && (mvControlled->TrainType != dt_EP05) && + (mvControlled->TrainType != dt_ET40)) + ggStLinOffButton.PutValue(0); + } + } }; void __fastcall TTrain::UpdateMechPosition(double dt) -{//Ra: mechanik powinien być telepany niezależnie od pozycji pojazdu - //Ra: trzeba zrobić model bujania głową i wczepić go do pojazdu +{ // Ra: mechanik powinien być telepany niezależnie od pozycji pojazdu + // Ra: trzeba zrobić model bujania głową i wczepić go do pojazdu - //DynamicObject->vFront=DynamicObject->GetDirection(); //to jest już policzone + // DynamicObject->vFront=DynamicObject->GetDirection(); //to jest już policzone - //Ra: tu by się przydało uwzględnić rozkład sił: - // - na postoju horyzont prosto, kabina skosem - // - przy szybkiej jeździe kabina prosto, horyzont pochylony + // Ra: tu by się przydało uwzględnić rozkład sił: + // - na postoju horyzont prosto, kabina skosem + // - przy szybkiej jeździe kabina prosto, horyzont pochylony - vector3 pNewMechPosition; - //McZapkie: najpierw policzę pozycję w/m kabiny + vector3 pNewMechPosition; + // McZapkie: najpierw policzę pozycję w/m kabiny - //ABu: rzucamy kabina tylko przy duzym FPS! - //Mala histereza, zeby bez przerwy nie przelaczalo przy FPS~17 - //Granice mozna ustalic doswiadczalnie. Ja proponuje 14:20 - double r1,r2,r3; - int iVel=DynamicObject->GetVelocity(); - if (iVel>150) iVel=150; - if (!Global::iSlowMotion //musi być pełna prędkość - &&(pMechOffset.y<4.0)) //Ra 15-01: przy oglądaniu pantografu bujanie przeszkadza - { - if (!(random((GetFPS()+1)/15)>0)) - { - if ((iVel>0) && (random(155-iVel)<16)) - { - r1=(double(random(iVel*2)-iVel)/((iVel*2)*4))*fMechSpringX; - r2=(double(random(iVel*2)-iVel)/((iVel*2)*4))*fMechSpringY; - r3=(double(random(iVel*2)-iVel)/((iVel*2)*4))*fMechSpringZ; - MechSpring.ComputateForces(vector3(r1,r2,r3),pMechShake); - // MechSpring.ComputateForces(vector3(double(random(200)-100)/200,double(random(200)-100)/200,double(random(200)-100)/500),pMechShake); - } - else - MechSpring.ComputateForces(vector3(-mvControlled->AccN*dt,mvControlled->AccV*dt*10,-mvControlled->AccS*dt),pMechShake); - } - vMechVelocity-=(MechSpring.vForce2+vMechVelocity*100)*(fMechSpringX+fMechSpringY+fMechSpringZ)/(200); + // ABu: rzucamy kabina tylko przy duzym FPS! + // Mala histereza, zeby bez przerwy nie przelaczalo przy FPS~17 + // Granice mozna ustalic doswiadczalnie. Ja proponuje 14:20 + double r1, r2, r3; + int iVel = DynamicObject->GetVelocity(); + if (iVel > 150) + iVel = 150; + if (!Global::iSlowMotion // musi być pełna prędkość + && (pMechOffset.y < 4.0)) // Ra 15-01: przy oglądaniu pantografu bujanie przeszkadza + { + if (!(random((GetFPS() + 1) / 15) > 0)) + { + if ((iVel > 0) && (random(155 - iVel) < 16)) + { + r1 = (double(random(iVel * 2) - iVel) / ((iVel * 2) * 4)) * fMechSpringX; + r2 = (double(random(iVel * 2) - iVel) / ((iVel * 2) * 4)) * fMechSpringY; + r3 = (double(random(iVel * 2) - iVel) / ((iVel * 2) * 4)) * fMechSpringZ; + MechSpring.ComputateForces(vector3(r1, r2, r3), pMechShake); + // MechSpring.ComputateForces(vector3(double(random(200)-100)/200,double(random(200)-100)/200,double(random(200)-100)/500),pMechShake); + } + else + MechSpring.ComputateForces(vector3(-mvControlled->AccN * dt, + mvControlled->AccV * dt * 10, + -mvControlled->AccS * dt), + pMechShake); + } + vMechVelocity -= (MechSpring.vForce2 + vMechVelocity * 100) * + (fMechSpringX + fMechSpringY + fMechSpringZ) / (200); - //McZapkie: - pMechShake+=vMechVelocity*dt; - //Ra 2015-01: dotychczasowe rzucanie - pMechOffset+=vMechMovement*dt; - if ((pMechShake.y>fMechMaxSpring) || (pMechShake.y<-fMechMaxSpring)) - vMechVelocity.y=-vMechVelocity.y; - //ABu011104: 5*pMechShake.y, zeby ladnie pudlem rzucalo :) - pNewMechPosition=pMechOffset+vector3(pMechShake.x,5*pMechShake.y,pMechShake.z); - vMechMovement=0.5*vMechMovement; - } - else - {//hamowanie rzucania przy spadku FPS - pMechShake-=pMechShake*Min0R(dt,1); //po tym chyba potrafią zostać jakieś ułamki, które powodują zjazd - pMechOffset+=vMechMovement*dt; - vMechVelocity.y=0.5*vMechVelocity.y; - pNewMechPosition=pMechOffset+vector3(pMechShake.x,5*pMechShake.y,pMechShake.z); - vMechMovement=0.5*vMechMovement; - } - //numer kabiny (-1: kabina B) - if (DynamicObject->Mechanik) //może nie być? - if (DynamicObject->Mechanik->AIControllFlag) //jeśli prowadzi AI - {//Ra: przesiadka, jeśli AI zmieniło kabinę (a człon?)... - if (iCabn!=(DynamicObject->MoverParameters->ActiveCab==-1?2:DynamicObject->MoverParameters->ActiveCab)) - InitializeCab(DynamicObject->MoverParameters->ActiveCab,DynamicObject->asBaseDir+DynamicObject->MoverParameters->TypeName+".mmd"); - } - iCabn=(DynamicObject->MoverParameters->ActiveCab==-1?2:DynamicObject->MoverParameters->ActiveCab); - if (!DebugModeFlag) - {//sprawdzaj więzy //Ra: nie tu! - if (pNewMechPosition.xCabine[iCabn].CabPos2.x) pNewMechPosition.x=Cabine[iCabn].CabPos2.x; - if (pNewMechPosition.zCabine[iCabn].CabPos2.z) pNewMechPosition.z=Cabine[iCabn].CabPos2.z; - if (pNewMechPosition.y>Cabine[iCabn].CabPos1.y+1.8) pNewMechPosition.y=Cabine[iCabn].CabPos1.y+1.8; - if (pNewMechPosition.y fMechMaxSpring) || (pMechShake.y < -fMechMaxSpring)) + vMechVelocity.y = -vMechVelocity.y; + // ABu011104: 5*pMechShake.y, zeby ladnie pudlem rzucalo :) + pNewMechPosition = pMechOffset + vector3(pMechShake.x, 5 * pMechShake.y, pMechShake.z); + vMechMovement = 0.5 * vMechMovement; + } + else + { // hamowanie rzucania przy spadku FPS + pMechShake -= + pMechShake * + Min0R(dt, 1); // po tym chyba potrafią zostać jakieś ułamki, które powodują zjazd + pMechOffset += vMechMovement * dt; + vMechVelocity.y = 0.5 * vMechVelocity.y; + pNewMechPosition = pMechOffset + vector3(pMechShake.x, 5 * pMechShake.y, pMechShake.z); + vMechMovement = 0.5 * vMechMovement; + } + // numer kabiny (-1: kabina B) + if (DynamicObject->Mechanik) // może nie być? + if (DynamicObject->Mechanik->AIControllFlag) // jeśli prowadzi AI + { // Ra: przesiadka, jeśli AI zmieniło kabinę (a człon?)... + if (iCabn != (DynamicObject->MoverParameters->ActiveCab == -1 ? + 2 : + DynamicObject->MoverParameters->ActiveCab)) + InitializeCab(DynamicObject->MoverParameters->ActiveCab, + DynamicObject->asBaseDir + DynamicObject->MoverParameters->TypeName + + ".mmd"); + } + iCabn = (DynamicObject->MoverParameters->ActiveCab == -1 ? + 2 : + DynamicObject->MoverParameters->ActiveCab); + if (!DebugModeFlag) + { // sprawdzaj więzy //Ra: nie tu! + if (pNewMechPosition.x < Cabine[iCabn].CabPos1.x) + pNewMechPosition.x = Cabine[iCabn].CabPos1.x; + if (pNewMechPosition.x > Cabine[iCabn].CabPos2.x) + pNewMechPosition.x = Cabine[iCabn].CabPos2.x; + if (pNewMechPosition.z < Cabine[iCabn].CabPos1.z) + pNewMechPosition.z = Cabine[iCabn].CabPos1.z; + if (pNewMechPosition.z > Cabine[iCabn].CabPos2.z) + pNewMechPosition.z = Cabine[iCabn].CabPos2.z; + if (pNewMechPosition.y > Cabine[iCabn].CabPos1.y + 1.8) + pNewMechPosition.y = Cabine[iCabn].CabPos1.y + 1.8; + if (pNewMechPosition.y < Cabine[iCabn].CabPos1.y + 0.5) + pNewMechPosition.y = Cabine[iCabn].CabPos2.y + 0.5; - if (pMechOffset.xCabine[iCabn].CabPos2.x) pMechOffset.x=Cabine[iCabn].CabPos2.x; - if (pMechOffset.zCabine[iCabn].CabPos2.z) pMechOffset.z=Cabine[iCabn].CabPos2.z; - if (pMechOffset.y>Cabine[iCabn].CabPos1.y+1.8) pMechOffset.y=Cabine[iCabn].CabPos1.y+1.8; - if (pMechOffset.ymMatrix*pNewMechPosition; //położenie względem środka pojazdu w układzie scenerii - pMechPosition+=DynamicObject->GetPosition(); + if (pMechOffset.x < Cabine[iCabn].CabPos1.x) + pMechOffset.x = Cabine[iCabn].CabPos1.x; + if (pMechOffset.x > Cabine[iCabn].CabPos2.x) + pMechOffset.x = Cabine[iCabn].CabPos2.x; + if (pMechOffset.z < Cabine[iCabn].CabPos1.z) + pMechOffset.z = Cabine[iCabn].CabPos1.z; + if (pMechOffset.z > Cabine[iCabn].CabPos2.z) + pMechOffset.z = Cabine[iCabn].CabPos2.z; + if (pMechOffset.y > Cabine[iCabn].CabPos1.y + 1.8) + pMechOffset.y = Cabine[iCabn].CabPos1.y + 1.8; + if (pMechOffset.y < Cabine[iCabn].CabPos1.y + 0.5) + pMechOffset.y = Cabine[iCabn].CabPos2.y + 0.5; + } + pMechPosition = DynamicObject->mMatrix * + pNewMechPosition; // położenie względem środka pojazdu w układzie scenerii + pMechPosition += DynamicObject->GetPosition(); }; bool __fastcall TTrain::Update() { - DWORD stat; - double dt=Timer::GetDeltaTime(); - if (DynamicObject->mdKabina) - {//Ra: TODO: odczyty klawiatury/pulpitu nie powinny być uzależnione od istnienia modelu kabiny - tor=DynamicObject->GetTrack(); //McZapkie-180203 - //McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol - float maxtacho=3; - fTachoVelocity=Min0R(fabs(11.31*mvControlled->WheelDiameter*mvControlled->nrot),mvControlled->Vmax*1.05); - {//skacze osobna zmienna - float ff=floor(GlobalTime->mr); //skacze co sekunde - pol sekundy pomiar, pol sekundy ustawienie - if (ff!=fTachoTimer) //jesli w tej sekundzie nie zmienial - { - if (fTachoVelocity>1) //jedzie - fTachoVelocityJump=fTachoVelocity+(2-random(3)+random(3))*0.5; - else fTachoVelocityJump=0; //stoi - fTachoTimer=ff; //juz zmienil - } - } - if (fTachoVelocity>1) //McZapkie-270503: podkrecanie tachometru - { - if (fTachoCount0) - fTachoCount-=dt*0.66; //schodz powoli - niektore haslery to ze 4 sekundy potrafia stukac - -/* Ra: to by trzeba było przemyśleć, zmienione na szybko problemy robi - //McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol - double vel=fabs(11.31*mvControlled->WheelDiameter*mvControlled->nrot); - if (iSekunda!=floor(GlobalTime->mr)||(vel<1.0)) - {fTachoVelocity=vel; - if (fTachoVelocity>1.0) //McZapkie-270503: podkrecanie tachometru - { - if (fTachoCount0) - fTachoCount-=dt; - if (mvControlled->TrainType==dt_EZT) - //dla EZT wskazówka porusza się niestabilnie - if (fTachoVelocity>7.0) - {fTachoVelocity=floor(0.5+fTachoVelocity+random(5)-random(5)); //*floor(0.2*fTachoVelocity); - if (fTachoVelocity<0.0) fTachoVelocity=0.0; - } - iSekunda=floor(GlobalTime->mr); - } -*/ - //Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są ewentualnie na PoKeys - if (mvControlled->EngineType!=DieselElectric) //Ra 2014-09: czy taki rozdział ma sens? - fHVoltage=mvControlled->RunningTraction.TractionVoltage; //Winger czy to nie jest zle? *mvControlled->Mains); - else - fHVoltage=mvControlled->Voltage; - if (ShowNextCurrent) - {//jeśli pokazywać drugi człon - if (mvSecond) - {//o ile jest ten drugi - fHCurrent[0]=mvSecond->ShowCurrent(0)*1.05; - fHCurrent[1]=mvSecond->ShowCurrent(1)*1.05; - fHCurrent[2]=mvSecond->ShowCurrent(2)*1.05; - fHCurrent[3]=mvSecond->ShowCurrent(3)*1.05; - } - else - fHCurrent[0]=fHCurrent[1]=fHCurrent[2]=fHCurrent[3]=0.0; //gdy nie ma człona - } - else - {//normalne pokazywanie - fHCurrent[0]=mvControlled->ShowCurrent(0); - fHCurrent[1]=mvControlled->ShowCurrent(1); - fHCurrent[2]=mvControlled->ShowCurrent(2); - fHCurrent[3]=mvControlled->ShowCurrent(3); - } - if (Global::iFeedbackMode==4) - {//wykonywać tylko gdy wyprowadzone na pulpit - Console::ValueSet(0,mvOccupied->Compressor); //Ra: sterowanie miernikiem: zbiornik główny - Console::ValueSet(1,mvOccupied->PipePress); //Ra: sterowanie miernikiem: przewód główny - Console::ValueSet(2,mvOccupied->BrakePress); //Ra: sterowanie miernikiem: cylinder hamulcowy - Console::ValueSet(3,fHVoltage); //woltomierz wysokiego napięcia - Console::ValueSet(4,fHCurrent[2]); //Ra: sterowanie miernikiem: drugi amperomierz - Console::ValueSet(5,fHCurrent[(mvControlled->TrainType&dt_EZT)?0:1]); //pierwszy amperomierz; dla EZT prąd całkowity - Console::ValueSet(6,fTachoVelocity); ////Ra: prędkość na pin 43 - wyjście analogowe (to nie jest PWM); skakanie zapewnia mechanika napędu - } - - //hunter-080812: wyrzucanie szybkiego na elektrykach gdy nie ma napiecia przy dowolnym ustawieniu kierunkowego - //Ra: to już jest w T_MoverParameters::TractionForce(), ale zależy od kierunku - if (mvControlled->EngineType==ElectricSeriesMotor) - if (fabs(mvControlled->RunningTraction.TractionVoltage)<0.5*mvControlled->EnginePowerSource.MaxVoltage) //minimalne napięcie pobierać z FIZ? - mvControlled->MainSwitch(false); - - //hunter-091012: swiatlo - if (bCabLight==true) - { - if (bCabLightDim==true) - iCabLightFlag=1; - else - iCabLightFlag=2; - } - else iCabLightFlag=0; - - //------------------ - //hunter-261211: nadmiarowy przetwornicy i ogrzewania - //Ra 15-01: to musi stąd wylecieć - zależności nie mogą być w kabinie - if (mvControlled->ConverterFlag==true) - { - fConverterTimer+=dt; - if ((mvControlled->CompressorFlag==true)&&(mvControlled->CompressorPower==1)&&((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->TrainType==dt_EZT))&&(DynamicObject->Controller==Humandriver)) //hunter-110212: poprawka dla EZT - { //hunter-091012: poprawka (zmiana warunku z CompressorPower /rozne od 0/ na /rowne 1/) - if (fConverterTimerConvOvldFlag=true; - mvControlled->MainSwitch(false); + DWORD stat; + double dt = Timer::GetDeltaTime(); + if (DynamicObject->mdKabina) + { // Ra: TODO: odczyty klawiatury/pulpitu nie powinny być uzależnione od istnienia modelu kabiny + tor = DynamicObject->GetTrack(); // McZapkie-180203 + // McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol + float maxtacho = 3; + fTachoVelocity = Min0R(fabs(11.31 * mvControlled->WheelDiameter * mvControlled->nrot), + mvControlled->Vmax * 1.05); + { // skacze osobna zmienna + float ff = floor( + GlobalTime->mr); // skacze co sekunde - pol sekundy pomiar, pol sekundy ustawienie + if (ff != fTachoTimer) // jesli w tej sekundzie nie zmienial + { + if (fTachoVelocity > 1) // jedzie + fTachoVelocityJump = fTachoVelocity + (2 - random(3) + random(3)) * 0.5; + else + fTachoVelocityJump = 0; // stoi + fTachoTimer = ff; // juz zmienil + } } - else if (fConverterTimer>=fConverterPrzekaznik) - mvControlled->CompressorSwitch(true); - } - } - else - fConverterTimer=0; - //------------------ - - - double vol=0; -// int freq=1; - double dfreq; - -//McZapkie-280302 - syczenie - if ((mvOccupied->BrakeHandle==FV4a)||(mvOccupied->BrakeHandle==FVel6)) - { - if (rsHiss.AM!=0) //upuszczanie z PG - { - fPPress=(1*fPPress+mvOccupied->Handle->GetSound(s_fv4a_b))/(2); - if (fPPress>0) - { - vol=2*rsHiss.AM*fPPress; - } - if (vol>0.001) - { - rsHiss.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsHiss.Stop(); - } - } - if (rsHissU.AM!=0) //upuszczanie z PG - { - fNPress=(1*fNPress+mvOccupied->Handle->GetSound(s_fv4a_u))/(2); - if (fNPress>0) - { - vol=rsHissU.AM*fNPress; - } - if (vol>0.001) - { - rsHissU.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsHissU.Stop(); - } - } - if (rsHissE.AM!=0) //upuszczanie przy naglym - { - vol=mvOccupied->Handle->GetSound(s_fv4a_e)*rsHissE.AM; - if (vol>0.001) - { - rsHissE.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsHissE.Stop(); - } - } - if (rsHissX.AM!=0) //upuszczanie sterujacego fala - { - vol=mvOccupied->Handle->GetSound(s_fv4a_x)*rsHissX.AM; - if (vol>0.001) - { - rsHissX.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsHissX.Stop(); - } - } - if (rsHissT.AM!=0) //upuszczanie z czasowego - { - vol=mvOccupied->Handle->GetSound(s_fv4a_t)*rsHissT.AM; - if (vol>0.001) - { - rsHissT.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsHissT.Stop(); - } - } - - } //koniec FV4a - else //jesli nie FV4a - { - if (rsHiss.AM!=0) //upuszczanie z PG - { - fPPress=(4*fPPress+Max0R(mvOccupied->dpLocalValve,mvOccupied->dpMainValve))/(4+1); - if (fPPress>0) - { - vol=2*rsHiss.AM*fPPress*0.01; - } - if (vol>0.01) - { - rsHiss.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsHiss.Stop(); - } - } - if (rsHissU.AM!=0) //napelnianie PG - { - fNPress=(4*fNPress+Min0R(mvOccupied->dpLocalValve,mvOccupied->dpMainValve))/(4+1); - if (fNPress<0) - { - vol=-2*rsHissU.AM*fNPress*0.004; - } - if (vol>0.01) - { - rsHissU.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsHissU.Stop(); - } - } - } //koniec nie FV4a - -//Winger-160404 - syczenie pomocniczego (luzowanie) -/* if (rsSBHiss.AM!=0) - { - fSPPress=(mvOccupied->LocalBrakeRatio())-(mvOccupied->LocalBrakePos); - if (fSPPress>0) - { - vol=2*rsSBHiss.AM*fSPPress; - } - if (vol>0.1) - { - rsSBHiss.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsSBHiss.Stop(); - } - } -*/ -//szum w czasie jazdy - vol=0.0; - dfreq=1.0; - if (rsRunningNoise.AM!=0) - { - if (DynamicObject->GetVelocity()!=0) + if (fTachoVelocity > 1) // McZapkie-270503: podkrecanie tachometru { - if (!TestFlag(mvOccupied->DamageFlag,dtrain_wheelwear)) //McZpakie-221103: halas zalezny od kola + if (fTachoCount < maxtacho) + fTachoCount += dt * 3; // szybciej zacznij stukac + } + else if (fTachoCount > 0) + fTachoCount -= + dt * 0.66; // schodz powoli - niektore haslery to ze 4 sekundy potrafia stukac + + /* Ra: to by trzeba było przemyśleć, zmienione na szybko problemy robi + //McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol + double vel=fabs(11.31*mvControlled->WheelDiameter*mvControlled->nrot); + if (iSekunda!=floor(GlobalTime->mr)||(vel<1.0)) + {fTachoVelocity=vel; + if (fTachoVelocity>1.0) //McZapkie-270503: podkrecanie tachometru { - dfreq=rsRunningNoise.FM*mvOccupied->Vel+rsRunningNoise.FA; - vol=rsRunningNoise.AM*mvOccupied->Vel+rsRunningNoise.AA; - switch (tor->eEnvironment) + if (fTachoCount0) + fTachoCount-=dt; + if (mvControlled->TrainType==dt_EZT) + //dla EZT wskazówka porusza się niestabilnie + if (fTachoVelocity>7.0) + {fTachoVelocity=floor(0.5+fTachoVelocity+random(5)-random(5)); + //*floor(0.2*fTachoVelocity); + if (fTachoVelocity<0.0) fTachoVelocity=0.0; + } + iSekunda=floor(GlobalTime->mr); + } + */ + // Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są ewentualnie na + // PoKeys + if (mvControlled->EngineType != DieselElectric) // Ra 2014-09: czy taki rozdział ma sens? + fHVoltage = mvControlled->RunningTraction + .TractionVoltage; // Winger czy to nie jest zle? *mvControlled->Mains); + else + fHVoltage = mvControlled->Voltage; + if (ShowNextCurrent) + { // jeśli pokazywać drugi człon + if (mvSecond) + { // o ile jest ten drugi + fHCurrent[0] = mvSecond->ShowCurrent(0) * 1.05; + fHCurrent[1] = mvSecond->ShowCurrent(1) * 1.05; + fHCurrent[2] = mvSecond->ShowCurrent(2) * 1.05; + fHCurrent[3] = mvSecond->ShowCurrent(3) * 1.05; + } + else + fHCurrent[0] = fHCurrent[1] = fHCurrent[2] = fHCurrent[3] = 0.0; // gdy nie ma + // człona + } + else + { // normalne pokazywanie + fHCurrent[0] = mvControlled->ShowCurrent(0); + fHCurrent[1] = mvControlled->ShowCurrent(1); + fHCurrent[2] = mvControlled->ShowCurrent(2); + fHCurrent[3] = mvControlled->ShowCurrent(3); + } + if (Global::iFeedbackMode == 4) + { // wykonywać tylko gdy wyprowadzone na pulpit + Console::ValueSet(0, + mvOccupied->Compressor); // Ra: sterowanie miernikiem: zbiornik główny + Console::ValueSet(1, mvOccupied->PipePress); // Ra: sterowanie miernikiem: przewód + // główny + Console::ValueSet( + 2, mvOccupied->BrakePress); // Ra: sterowanie miernikiem: cylinder hamulcowy + Console::ValueSet(3, fHVoltage); // woltomierz wysokiego napięcia + Console::ValueSet(4, fHCurrent[2]); // Ra: sterowanie miernikiem: drugi amperomierz + Console::ValueSet( + 5, fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1]); // pierwszy amperomierz; + // dla EZT prąd całkowity + Console::ValueSet(6, fTachoVelocity); ////Ra: prędkość na pin 43 - wyjście analogowe (to + ///nie jest PWM); skakanie zapewnia mechanika + ///napędu + } + + // hunter-080812: wyrzucanie szybkiego na elektrykach gdy nie ma napiecia przy dowolnym + // ustawieniu kierunkowego + // Ra: to już jest w T_MoverParameters::TractionForce(), ale zależy od kierunku + if (mvControlled->EngineType == ElectricSeriesMotor) + if (fabs(mvControlled->RunningTraction.TractionVoltage) < + 0.5 * + mvControlled->EnginePowerSource + .MaxVoltage) // minimalne napięcie pobierać z FIZ? + mvControlled->MainSwitch(false); + + // hunter-091012: swiatlo + if (bCabLight == true) + { + if (bCabLightDim == true) + iCabLightFlag = 1; + else + iCabLightFlag = 2; + } + else + iCabLightFlag = 0; + + //------------------ + // hunter-261211: nadmiarowy przetwornicy i ogrzewania + // Ra 15-01: to musi stąd wylecieć - zależności nie mogą być w kabinie + if (mvControlled->ConverterFlag == true) + { + fConverterTimer += dt; + if ((mvControlled->CompressorFlag == true) && (mvControlled->CompressorPower == 1) && + ((mvControlled->EngineType == ElectricSeriesMotor) || + (mvControlled->TrainType == dt_EZT)) && + (DynamicObject->Controller == Humandriver)) // hunter-110212: poprawka dla EZT + { // hunter-091012: poprawka (zmiana warunku z CompressorPower /rozne od 0/ na /rowne + // 1/) + if (fConverterTimer < fConverterPrzekaznik) + { + mvControlled->ConvOvldFlag = true; + mvControlled->MainSwitch(false); + } + else if (fConverterTimer >= fConverterPrzekaznik) + mvControlled->CompressorSwitch(true); + } + } + else + fConverterTimer = 0; + //------------------ + + double vol = 0; + // int freq=1; + double dfreq; + + // McZapkie-280302 - syczenie + if ((mvOccupied->BrakeHandle == FV4a) || (mvOccupied->BrakeHandle == FVel6)) + { + if (rsHiss.AM != 0) // upuszczanie z PG + { + fPPress = (1 * fPPress + mvOccupied->Handle->GetSound(s_fv4a_b)) / (2); + if (fPPress > 0) + { + vol = 2 * rsHiss.AM * fPPress; + } + if (vol > 0.001) + { + rsHiss.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + } + else + { + rsHiss.Stop(); + } + } + if (rsHissU.AM != 0) // upuszczanie z PG + { + fNPress = (1 * fNPress + mvOccupied->Handle->GetSound(s_fv4a_u)) / (2); + if (fNPress > 0) + { + vol = rsHissU.AM * fNPress; + } + if (vol > 0.001) + { + rsHissU.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + } + else + { + rsHissU.Stop(); + } + } + if (rsHissE.AM != 0) // upuszczanie przy naglym + { + vol = mvOccupied->Handle->GetSound(s_fv4a_e) * rsHissE.AM; + if (vol > 0.001) + { + rsHissE.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + } + else + { + rsHissE.Stop(); + } + } + if (rsHissX.AM != 0) // upuszczanie sterujacego fala + { + vol = mvOccupied->Handle->GetSound(s_fv4a_x) * rsHissX.AM; + if (vol > 0.001) + { + rsHissX.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + } + else + { + rsHissX.Stop(); + } + } + if (rsHissT.AM != 0) // upuszczanie z czasowego + { + vol = mvOccupied->Handle->GetSound(s_fv4a_t) * rsHissT.AM; + if (vol > 0.001) + { + rsHissT.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + } + else + { + rsHissT.Stop(); + } + } + + } // koniec FV4a + else // jesli nie FV4a + { + if (rsHiss.AM != 0) // upuszczanie z PG + { + fPPress = (4 * fPPress + Max0R(mvOccupied->dpLocalValve, mvOccupied->dpMainValve)) / + (4 + 1); + if (fPPress > 0) + { + vol = 2 * rsHiss.AM * fPPress * 0.01; + } + if (vol > 0.01) + { + rsHiss.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + } + else + { + rsHiss.Stop(); + } + } + if (rsHissU.AM != 0) // napelnianie PG + { + fNPress = (4 * fNPress + Min0R(mvOccupied->dpLocalValve, mvOccupied->dpMainValve)) / + (4 + 1); + if (fNPress < 0) + { + vol = -2 * rsHissU.AM * fNPress * 0.004; + } + if (vol > 0.01) + { + rsHissU.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + } + else + { + rsHissU.Stop(); + } + } + } // koniec nie FV4a + + // Winger-160404 - syczenie pomocniczego (luzowanie) + /* if (rsSBHiss.AM!=0) + { + fSPPress=(mvOccupied->LocalBrakeRatio())-(mvOccupied->LocalBrakePos); + if (fSPPress>0) + { + vol=2*rsSBHiss.AM*fSPPress; + } + if (vol>0.1) + { + rsSBHiss.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); + } + else + { + rsSBHiss.Stop(); + } + } + */ + // szum w czasie jazdy + vol = 0.0; + dfreq = 1.0; + if (rsRunningNoise.AM != 0) + { + if (DynamicObject->GetVelocity() != 0) + { + if (!TestFlag(mvOccupied->DamageFlag, + dtrain_wheelwear)) // McZpakie-221103: halas zalezny od kola + { + dfreq = rsRunningNoise.FM * mvOccupied->Vel + rsRunningNoise.FA; + vol = rsRunningNoise.AM * mvOccupied->Vel + rsRunningNoise.AA; + switch (tor->eEnvironment) + { + case e_tunnel: + { + vol *= 3; + dfreq *= 0.95; + } + break; + case e_canyon: + { + vol *= 1.1; + } + break; + case e_bridge: + { + vol *= 2; + dfreq *= 0.98; + } + break; + } + } + else // uszkodzone kolo (podkucie) + if (fabs(mvOccupied->nrot) > 0.01) + { + dfreq = rsRunningNoise.FM * mvOccupied->Vel + rsRunningNoise.FA; + vol = rsRunningNoise.AM * mvOccupied->Vel + rsRunningNoise.AA; + switch (tor->eEnvironment) + { + case e_tunnel: + { + vol *= 2; + } + break; + case e_canyon: + { + vol *= 1.1; + } + break; + case e_bridge: + { + vol *= 1.5; + } + break; + } + } + if (fabs(mvOccupied->nrot) > 0.01) + vol *= 1 + + mvOccupied->UnitBrakeForce / + (1 + mvOccupied->MaxBrakeForce); // hamulce wzmagaja halas + vol = vol * (20.0 + tor->iDamageFlag) / 21; + rsRunningNoise.AdjFreq(dfreq, 0); + rsRunningNoise.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + } + else + rsRunningNoise.Stop(); + } + + if (rsBrake.AM != 0) + { + if ((!mvOccupied->SlippingWheels) && (mvOccupied->UnitBrakeForce > 10.0) && + (DynamicObject->GetVelocity() > 0.01)) + { + // vol=rsBrake.AA+rsBrake.AM*(DynamicObject->GetVelocity()*100+mvOccupied->UnitBrakeForce); + vol = + rsBrake.AM * sqrt((DynamicObject->GetVelocity() * mvOccupied->UnitBrakeForce)); + dfreq = rsBrake.FA + rsBrake.FM * DynamicObject->GetVelocity(); + rsBrake.AdjFreq(dfreq, 0); + rsBrake.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + } + else + { + rsBrake.Stop(); + } + } + + if (rsEngageSlippery.AM != 0) + { + if /*((fabs(mvControlled->dizel_engagedeltaomega)>0.2) && */ ( + mvControlled->dizel_engage > 0.1) + { + if (fabs(mvControlled->dizel_engagedeltaomega) > 0.2) + { + dfreq = rsEngageSlippery.FA + + rsEngageSlippery.FM * fabs(mvControlled->dizel_engagedeltaomega); + vol = rsEngageSlippery.AA + rsEngageSlippery.AM * (mvControlled->dizel_engage); + } + else + { + dfreq = + 1; // rsEngageSlippery.FA+0.7*rsEngageSlippery.FM*(fabs(mvControlled->enrot)+mvControlled->nmax); + if (mvControlled->dizel_engage > 0.2) + vol = + rsEngageSlippery.AA + + 0.2 * rsEngageSlippery.AM * (mvControlled->enrot / mvControlled->nmax); + else + vol = 0; + } + rsEngageSlippery.AdjFreq(dfreq, 0); + rsEngageSlippery.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + } + else + { + rsEngageSlippery.Stop(); + } + } + + if (FreeFlyModeFlag) + rsFadeSound.Stop(); // wyłącz to cholerne cykanie! + else + rsFadeSound.Play(1, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); + + // McZapkie! - to wazne - SoundFlag wystawiane jest przez moje moduly + // gdy zachodza pewne wydarzenia komentowane dzwiekiem. + // Mysle ze wystarczy sprawdzac a potem zerowac SoundFlag tutaj + // a nie w DynObject - gdyby cos poszlo zle to po co szarpac dzwiekiem co 10ms. + + if (TestFlag(mvOccupied->SoundFlag, + sound_relay)) // przekaznik - gdy bezpiecznik, automatyczny rozruch itp + { + if (mvOccupied->EventFlag || TestFlag(mvOccupied->SoundFlag, sound_loud)) + { + mvOccupied->EventFlag = false; // Ra: w kabinie? + dsbRelay->SetVolume(DSBVOLUME_MAX); + } + else + { + dsbRelay->SetVolume(-40); + } + if (!TestFlag(mvOccupied->SoundFlag, sound_manyrelay)) + dsbRelay->Play(0, 0, 0); + else + { + if (TestFlag(mvOccupied->SoundFlag, sound_loud)) + dsbWejscie_na_bezoporow->Play(0, 0, 0); + else + dsbWejscie_na_drugi_uklad->Play(0, 0, 0); + } + } + // potem dorobic bufory, sprzegi jako RealSound. + if (TestFlag(mvOccupied->SoundFlag, sound_bufferclamp)) // zderzaki uderzaja o siebie + { + if (TestFlag(mvOccupied->SoundFlag, sound_loud)) + dsbBufferClamp->SetVolume(DSBVOLUME_MAX); + else + dsbBufferClamp->SetVolume(-20); + dsbBufferClamp->Play(0, 0, 0); + } + if (dsbCouplerStretch) + if (TestFlag(mvOccupied->SoundFlag, sound_couplerstretch)) // sprzegi sie rozciagaja + { + if (TestFlag(mvOccupied->SoundFlag, sound_loud)) + dsbCouplerStretch->SetVolume(DSBVOLUME_MAX); + else + dsbCouplerStretch->SetVolume(-20); + dsbCouplerStretch->Play(0, 0, 0); + } + + if (mvOccupied->SoundFlag == 0) + if (mvOccupied->EventFlag) + if (TestFlag(mvOccupied->DamageFlag, dtrain_wheelwear)) + { // Ra: przenieść do DynObj! + if (rsRunningNoise.AM != 0) + { + rsRunningNoise.Stop(); + // float aa=rsRunningNoise.AA; + float am = rsRunningNoise.AM; + float fa = rsRunningNoise.FA; + float fm = rsRunningNoise.FM; + rsRunningNoise.Init("lomotpodkucia.wav", -1, 0, 0, 0, + true); // MC: zmiana szumu na lomot + if (rsRunningNoise.AM == 1) + rsRunningNoise.AM = am; + rsRunningNoise.AA = 0.7; + rsRunningNoise.FA = fa; + rsRunningNoise.FM - fm; + } + mvOccupied->EventFlag = false; + } + + mvOccupied->SoundFlag = 0; + /* + for (int b=0; b<2; b++) //MC: aby zerowac stukanie przekaznikow w czlonie silnikowym + if (TestFlag(mvControlled->Couplers[b].CouplingFlag,ctrain_controll)) + if (mvControlled->Couplers[b].Connected.Power>0.01) + mvControlled->Couplers[b]->Connected->SoundFlag=0; + */ + + // McZapkie! - koniec obslugi dzwiekow z mover.pas + + // youBy - prad w drugim czlonie: galaz lub calosc + { + TDynamicObject *tmp; + tmp = NULL; + if (DynamicObject->NextConnected) + if ((TestFlag(mvControlled->Couplers[1].CouplingFlag, ctrain_controll)) && + (mvOccupied->ActiveCab == 1)) + tmp = DynamicObject->NextConnected; + if (DynamicObject->PrevConnected) + if ((TestFlag(mvControlled->Couplers[0].CouplingFlag, ctrain_controll)) && + (mvOccupied->ActiveCab == -1)) + tmp = DynamicObject->PrevConnected; + if (tmp) + if (tmp->MoverParameters->Power > 0) + { + if (ggI1B.SubModel) + { + ggI1B.UpdateValue(tmp->MoverParameters->ShowCurrent(1)); + ggI1B.Update(); + } + if (ggI2B.SubModel) + { + ggI2B.UpdateValue(tmp->MoverParameters->ShowCurrent(2)); + ggI2B.Update(); + } + if (ggI3B.SubModel) + { + ggI3B.UpdateValue(tmp->MoverParameters->ShowCurrent(3)); + ggI3B.Update(); + } + if (ggItotalB.SubModel) + { + ggItotalB.UpdateValue(tmp->MoverParameters->ShowCurrent(0)); + ggItotalB.Update(); + } + } + } + /* + //McZapkie-240302 ggVelocity.UpdateValue(DynamicObject->GetVelocity()); + //fHaslerTimer+=dt; + //if (fHaslerTimer>fHaslerTime) + {//Ra: ryzykowne jest to, gdyż może się nie uaktualniać prędkość + //Ra: prędkość się powinna zaokrąglać tam gdzie się liczy fTachoVelocity + if (ggVelocity.SubModel) + {//ZiomalCl: wskazanie Haslera w kabinie A ze zwloka czasowa oraz odpowiednia + tolerancja + //Nalezy sie zastanowic na przyszlosc nad rozroznieniem predkosciomierzy (dokladnosc + wskazan, zwloka czasowa wskazania, inne funkcje) + //ZiomalCl: W ezt typu stare EN57 wskazania haslera sa mniej dokladne (linka) + //ggVelocity.UpdateValue(fTachoVelocity>2?fTachoVelocity+0.5-random(mvControlled->TrainType==dt_EZT?5:2)/2:0); + ggVelocity.UpdateValue(Min0R(fTachoVelocity,mvControlled->Vmax*1.05)); //ograniczenie + maksymalnego wskazania na analogowym + ggVelocity.Update(); + } + if (ggVelocityDgt.SubModel) + {//Ra 2014-07: prędkościomierz cyfrowy + ggVelocityDgt.UpdateValue(fTachoVelocity); + ggVelocityDgt.Update(); + } + if (ggVelocity_B.SubModel) + {//ZiomalCl: wskazanie Haslera w kabinie B ze zwloka czasowa oraz odpowiednia + tolerancja + //Nalezy sie zastanowic na przyszlosc nad rozroznieniem predkosciomierzy (dokladnosc + wskazan, zwloka czasowa wskazania, inne funkcje) + //Velocity_B.UpdateValue(fTachoVelocity>2?fTachoVelocity+0.5-random(mvControlled->TrainType==dt_EZT?5:2)/2:0); + ggVelocity_B.UpdateValue(fTachoVelocity); + ggVelocity_B.Update(); + } + //fHaslerTimer-=fHaslerTime; //1.2s (???) + } + */ + // McZapkie-300302: zegarek + if (ggClockMInd.SubModel) + { + ggClockSInd.UpdateValue(int(GlobalTime->mr)); + ggClockSInd.Update(); + ggClockMInd.UpdateValue(GlobalTime->mm); + ggClockMInd.Update(); + ggClockHInd.UpdateValue(GlobalTime->hh + GlobalTime->mm / 60.0); + ggClockHInd.Update(); + } + + Cabine[iCabn].Update(); // nowy sposób ustawienia animacji + if (ggZbS.SubModel) + { + ggZbS.UpdateValue(mvOccupied->Handle->GetCP()); + ggZbS.Update(); + } + + // youBy - napiecie na silnikach + if (ggEngineVoltage.SubModel) + { + if (mvControlled->DynamicBrakeFlag) + { + ggEngineVoltage.UpdateValue(abs(mvControlled->Im * 5)); + } + else + { + int x; + if ((mvControlled->TrainType == dt_ET42) && + (mvControlled->Imax == mvControlled->ImaxHi)) + x = 1; + else + x = 2; + if ((mvControlled->RList[mvControlled->MainCtrlActualPos].Mn > 0) && + (abs(mvControlled->Im) > 0)) + { + ggEngineVoltage.UpdateValue( + (x * (mvControlled->RunningTraction.TractionVoltage - + mvControlled->RList[mvControlled->MainCtrlActualPos].R * + abs(mvControlled->Im)) / + mvControlled->RList[mvControlled->MainCtrlActualPos].Mn)); + } + else + { + ggEngineVoltage.UpdateValue(0); + } + } + ggEngineVoltage.Update(); + } + + // Winger 140404 - woltomierz NN + if (ggLVoltage.SubModel) + { + if (mvControlled->Battery == true) + ggLVoltage.UpdateValue(mvControlled->BatteryVoltage); + else + ggLVoltage.UpdateValue(0); + ggLVoltage.Update(); + } + + if (mvControlled->EngineType == DieselElectric) + { // ustawienie zmiennych dla silnika spalinowego + fEngine[1] = mvControlled->ShowEngineRotation(1); + fEngine[2] = mvControlled->ShowEngineRotation(2); + // if (ggEnrot1m.SubModel) + //{ + // ggEnrot1m.UpdateValue(mvControlled->ShowEngineRotation(1)); + // ggEnrot1m.Update(); + //} + // if (ggEnrot2m.SubModel) + //{ + // ggEnrot2m.UpdateValue(mvControlled->ShowEngineRotation(2)); + // ggEnrot2m.Update(); + //} + } + + else if (mvControlled->EngineType == DieselEngine) + { // albo dla innego spalinowego + fEngine[1] = mvControlled->ShowEngineRotation(1); + fEngine[2] = mvControlled->ShowEngineRotation(2); + fEngine[3] = mvControlled->ShowEngineRotation(3); + // if (ggEnrot1m.SubModel) + //{ + // ggEnrot1m.UpdateValue(mvControlled->ShowEngineRotation(1)); + // ggEnrot1m.Update(); + //} + // if (ggEnrot2m.SubModel) + //{ + // ggEnrot2m.UpdateValue(mvControlled->ShowEngineRotation(2)); + // ggEnrot2m.Update(); + //} + // if (ggEnrot3m.SubModel) + // if (mvControlled->Couplers[1].Connected) + // { + // ggEnrot3m.UpdateValue(mvControlled->ShowEngineRotation(3)); + // ggEnrot3m.Update(); + // } + // if (ggEngageRatio.SubModel) + //{ + // ggEngageRatio.UpdateValue(mvControlled->dizel_engage); + // ggEngageRatio.Update(); + //} + if (ggMainGearStatus.SubModel) + { + if (mvControlled->Mains) + ggMainGearStatus.UpdateValue(1.1 - + fabs(mvControlled->dizel_automaticgearstatus)); + else + ggMainGearStatus.UpdateValue(0); + ggMainGearStatus.Update(); + } + if (ggIgnitionKey.SubModel) + { + ggIgnitionKey.UpdateValue(mvControlled->dizel_enginestart); + ggIgnitionKey.Update(); + } + } + + if (mvControlled->SlippingWheels) + { // Ra 2014-12: lokomotywy 181/182 dostają SlippingWheels po zahamowaniu powyżej 2.85 bara + // i buczały + double veldiff = (DynamicObject->GetVelocity() - fTachoVelocity) / mvControlled->Vmax; + if (veldiff < + -0.01) // 1% Vmax rezerwy, żeby 181/182 nie buczały po zahamowaniu, ale to proteza + { + if (fabs(mvControlled->Im) > 10.0) + btLampkaPoslizg.TurnOn(); + rsSlippery.Play(-rsSlippery.AM * veldiff + rsSlippery.AA, DSBPLAY_LOOPING, true, + DynamicObject->GetPosition()); + if (mvControlled->TrainType == + dt_181) // alarm przy poslizgu dla 181/182 - BOMBARDIER + if (dsbSlipAlarm) + dsbSlipAlarm->Play(0, 0, DSBPLAY_LOOPING); + } + else + { + if ((mvOccupied->UnitBrakeForce > 100.0) && (DynamicObject->GetVelocity() > 1.0)) + { + rsSlippery.Play(rsSlippery.AM * veldiff + rsSlippery.AA, DSBPLAY_LOOPING, true, + DynamicObject->GetPosition()); + if (mvControlled->TrainType == dt_181) + if (dsbSlipAlarm) + dsbSlipAlarm->Stop(); + } + } + } + else + { + btLampkaPoslizg.TurnOff(); + rsSlippery.Stop(); + if (mvControlled->TrainType == dt_181) + if (dsbSlipAlarm) + dsbSlipAlarm->Stop(); + } + + if (mvControlled->Mains) + { + btLampkaWylSzybki.TurnOn(); + btLampkaOpory.Turn(mvControlled->StLinFlag ? mvControlled->ResistorsFlagCheck() : + false); + btLampkaBezoporowa.Turn(mvControlled->ResistorsFlagCheck() || + (mvControlled->MainCtrlActualPos == 0)); // do EU04 + if ((mvControlled->Itot != 0) || (mvOccupied->BrakePress > 2) || + (mvOccupied->PipePress < 3.6)) + btLampkaStyczn.TurnOff(); // Ra: czy to jest udawanie działania styczników + // liniowych? + else if (mvOccupied->BrakePress < 1) + btLampkaStyczn.TurnOn(); // mozna prowadzic rozruch + if (((TestFlag(mvControlled->Couplers[1].CouplingFlag, ctrain_controll)) && + (mvControlled->CabNo == 1)) || + ((TestFlag(mvControlled->Couplers[0].CouplingFlag, ctrain_controll)) && + (mvControlled->CabNo == -1))) + btLampkaUkrotnienie.TurnOn(); + else + btLampkaUkrotnienie.TurnOff(); + + // if ((TestFlag(mvControlled->BrakeStatus,+b_Rused+b_Ractive)))//Lampka + // drugiego stopnia hamowania + btLampkaHamPosp.Turn((TestFlag(mvOccupied->BrakeStatus, 1))); // lampka drugiego stopnia + // hamowania //TODO: + // youBy wyciągnąć flagę + // wysokiego stopnia + + // hunter-111211: wylacznik cisnieniowy - Ra: tutaj? w kabinie? //yBARC - + // omujborzegrzesiuzniszczylesmicalydzien + // if (mvControlled->TrainType!=dt_EZT) + // if (((mvOccupied->BrakePress > 2) || ( mvOccupied->PipePress < 3.6 )) && ( + // mvControlled->MainCtrlPos != 0 )) + // mvControlled->StLinFlag=true; + //------- + + // hunter-121211: lampka zanikowo-pradowego wentylatorow: + btLampkaNadmWent.Turn((mvControlled->RventRot < 5.0) && + mvControlled->ResistorsFlagCheck()); + //------- + + btLampkaNadmSil.Turn(mvControlled->FuseFlagCheck()); + btLampkaWysRozr.Turn(mvControlled->Imax == mvControlled->ImaxHi); + if (((mvControlled->ScndCtrlActualPos > 0) || + ((mvControlled->RList[mvControlled->MainCtrlActualPos].ScndAct != 0) && + (mvControlled->RList[mvControlled->MainCtrlActualPos].ScndAct != 255))) && + (!mvControlled->DelayCtrlFlag)) + btLampkaBoczniki.TurnOn(); + else + btLampkaBoczniki.TurnOff(); + + btLampkaNapNastHam.Turn(mvControlled->ActiveDir != + 0); // napiecie na nastawniku hamulcowym + btLampkaSprezarka.Turn(mvControlled->CompressorFlag); // mutopsitka dziala + // boczniki + unsigned char scp; // Ra: dopisałem "unsigned" + // Ra: w SU45 boczniki wchodzą na MainCtrlPos, a nie na MainCtrlActualPos - pokićkał + // ktoś? + scp = mvControlled->RList[mvControlled->MainCtrlPos].ScndAct; + scp = (scp == 255 ? 0 : scp); // Ra: whatta hella is this? + if ((mvControlled->ScndCtrlPos > 0) || (mvControlled->ScndInMain) && (scp > 0)) + { // boczniki pojedynczo + btLampkaBocznik1.TurnOn(); + btLampkaBocznik2.Turn(mvControlled->ScndCtrlPos > 1); + btLampkaBocznik3.Turn(mvControlled->ScndCtrlPos > 2); + btLampkaBocznik4.Turn(mvControlled->ScndCtrlPos > 3); + } + else + { // wyłączone wszystkie cztery + btLampkaBocznik1.TurnOff(); + btLampkaBocznik2.TurnOff(); + btLampkaBocznik3.TurnOff(); + btLampkaBocznik4.TurnOff(); + } + /* + { //sprezarka w drugim wozie + bool comptemp=false; + if (DynamicObject->NextConnected) + if (TestFlag(mvControlled->Couplers[1].CouplingFlag,ctrain_controll)) + comptemp=DynamicObject->NextConnected->MoverParameters->CompressorFlag; + if ((DynamicObject->PrevConnected) && (!comptemp)) + if (TestFlag(mvControlled->Couplers[0].CouplingFlag,ctrain_controll)) + comptemp=DynamicObject->PrevConnected->MoverParameters->CompressorFlag; + btLampkaSprezarkaB.Turn(comptemp); + */ + } + else // wylaczone + { + btLampkaWylSzybki.TurnOff(); + btLampkaOpory.TurnOff(); + btLampkaStyczn.TurnOff(); + btLampkaNadmSil.TurnOff(); + btLampkaUkrotnienie.TurnOff(); + btLampkaHamPosp.TurnOff(); + btLampkaBoczniki.TurnOff(); + btLampkaNapNastHam.TurnOff(); + btLampkaSprezarka.TurnOff(); + btLampkaBezoporowa.TurnOff(); + } + if (mvControlled->Signalling == true) + { + + if ((mvOccupied->BrakePress >= 0.145f) && (mvControlled->Battery == true) && + (mvControlled->Signalling == true)) + { + btLampkaHamowanie1zes.TurnOn(); + } + if (mvControlled->BrakePress < 0.075f) + { + btLampkaHamowanie1zes.TurnOff(); + } + } + else + { + btLampkaHamowanie1zes.TurnOff(); + } + btLampkaBlokadaDrzwi.Turn(mvControlled->DoorSignalling ? + mvOccupied->DoorBlockedFlag() && mvControlled->Battery : + false); + + { // yB - wskazniki drugiego czlonu + TDynamicObject * + tmp; //=mvControlled->mvSecond; //Ra 2014-07: trzeba to jeszcze wyjąć z kabiny... + // Ra 2014-07: no nie ma potrzeby szukać tego w każdej klatce + tmp = NULL; + if ((TestFlag(mvControlled->Couplers[1].CouplingFlag, ctrain_controll)) && + (mvOccupied->ActiveCab > 0)) + tmp = DynamicObject->NextConnected; + if ((TestFlag(mvControlled->Couplers[0].CouplingFlag, ctrain_controll)) && + (mvOccupied->ActiveCab < 0)) + tmp = DynamicObject->PrevConnected; + + if (tmp) + if (tmp->MoverParameters->Mains) + { + btLampkaWylSzybkiB.TurnOn(); + btLampkaOporyB.Turn(tmp->MoverParameters->ResistorsFlagCheck()); + btLampkaBezoporowaB.Turn( + tmp->MoverParameters->ResistorsFlagCheck() || + (tmp->MoverParameters->MainCtrlActualPos == 0)); // do EU04 + if ((tmp->MoverParameters->Itot != 0) || + (tmp->MoverParameters->BrakePress > 0.2) || + (tmp->MoverParameters->PipePress < 0.36)) + btLampkaStycznB.TurnOff(); // + else if (tmp->MoverParameters->BrakePress < 0.1) + btLampkaStycznB.TurnOn(); // mozna prowadzic rozruch + + //----------------- + // //hunter-271211: brak jazdy w drugim czlonie, gdy w pierwszym tez nie + // ma (i odwrotnie) - Ra: tutaj? w kabinie? + // if (tmp->MoverParameters->TrainType!=dt_EZT) + // if (((tmp->MoverParameters->BrakePress > 2) || ( + // tmp->MoverParameters->PipePress < 3.6 )) && ( + // tmp->MoverParameters->MainCtrlPos != 0 )) + // { + // tmp->MoverParameters->MainCtrlActualPos=0; //inaczej StLinFlag nie + // zmienia sie na false w drugim pojezdzie + // //tmp->MoverParameters->StLinFlag=true; + // mvControlled->StLinFlag=true; + // } + // if (mvControlled->StLinFlag==true) + // tmp->MoverParameters->MainCtrlActualPos=0; + // //tmp->MoverParameters->StLinFlag=true; + + //----------------- + // hunter-271211: sygnalizacja poslizgu w pierwszym pojezdzie, gdy wystapi w + // drugim + btLampkaPoslizg.Turn(tmp->MoverParameters->SlippingWheels); + //----------------- + + btLampkaSprezarkaB.Turn( + tmp->MoverParameters->CompressorFlag); // mutopsitka dziala + if ((tmp->MoverParameters->BrakePress >= 0.145f * 10) && + (mvControlled->Battery == true) && (mvControlled->Signalling == true)) + { + btLampkaHamowanie2zes.TurnOn(); + } + if ((tmp->MoverParameters->BrakePress < 0.075f * 10) || + (mvControlled->Battery == false) || (mvControlled->Signalling == false)) + { + btLampkaHamowanie2zes.TurnOff(); + } + btLampkaNadmPrzetwB.Turn( + tmp->MoverParameters->ConvOvldFlag); // nadmiarowy przetwornicy? + btLampkaPrzetwB.Turn( + !tmp->MoverParameters->ConverterFlag); // zalaczenie przetwornicy + } + else // wylaczone + { + btLampkaWylSzybkiB.TurnOff(); + btLampkaOporyB.TurnOff(); + btLampkaStycznB.TurnOff(); + btLampkaSprezarkaB.TurnOff(); + btLampkaBezoporowaB.TurnOff(); + btLampkaHamowanie2zes.TurnOff(); + btLampkaNadmPrzetwB.TurnOn(); + btLampkaPrzetwB.TurnOff(); + } + + // hunter-261211: jakis stary kod (i niezgodny z prawda), zahaszowalem + // if (tmp) + // if (tmp->MoverParameters->ConverterFlag==true) + // btLampkaNadmPrzetwB.TurnOff(); + // else + // btLampkaNadmPrzetwB.TurnOn(); + + } //**************************************************** */ + if (mvControlled->Battery) + { + switch (mvControlled->TrainType) + { // zależnie od typu lokomotywy + case dt_EZT: + btLampkaHamienie.Turn((mvControlled->BrakePress >= 0.2) && + mvControlled->Signalling); + break; + case dt_ET41: // odhamowanie drugiego członu + if (mvSecond) // bo może komuś przyjść do głowy jeżdżenie jednym członem + btLampkaHamienie.Turn(mvSecond->BrakePress < 0.4); + break; + default: + btLampkaHamienie.Turn((mvOccupied->BrakePress >= 0.1) || + mvControlled->DynamicBrakeFlag); + } + // KURS90 + btLampkaMaxSila.Turn(abs(mvControlled->Im) >= 350); + btLampkaPrzekrMaxSila.Turn(abs(mvControlled->Im) >= 450); + btLampkaRadio.Turn(mvControlled->Radio); + btLampkaHamulecReczny.Turn(mvOccupied->ManualBrakePos > 0); + // NBMX wrzesien 2003 - drzwi oraz sygnał odjazdu + btLampkaDoorLeft.Turn(mvOccupied->DoorLeftOpened); + btLampkaDoorRight.Turn(mvOccupied->DoorRightOpened); + btLampkaNapNastHam.Turn((mvControlled->ActiveDir != 0) && + (mvOccupied->EpFuse)); // napiecie na nastawniku hamulcowym + btLampkaForward.Turn(mvControlled->ActiveDir > 0); // jazda do przodu + btLampkaBackward.Turn(mvControlled->ActiveDir < 0); // jazda do tyłu + } + else + { // gdy bateria wyłączona + btLampkaHamienie.TurnOff(); + btLampkaMaxSila.TurnOff(); + btLampkaPrzekrMaxSila.TurnOff(); + btLampkaRadio.TurnOff(); + btLampkaHamulecReczny.TurnOff(); + btLampkaDoorLeft.TurnOff(); + btLampkaDoorRight.TurnOff(); + btLampkaNapNastHam.TurnOff(); + btLampkaForward.TurnOff(); + btLampkaBackward.TurnOff(); + } + // McZapkie-080602: obroty (albo translacje) regulatorow + if (ggMainCtrl.SubModel) + { + if (mvControlled->CoupledCtrl) + ggMainCtrl.UpdateValue( + double(mvControlled->MainCtrlPos + mvControlled->ScndCtrlPos)); + else + ggMainCtrl.UpdateValue(double(mvControlled->MainCtrlPos)); + ggMainCtrl.Update(); + } + if (ggMainCtrlAct.SubModel) + { + if (mvControlled->CoupledCtrl) + ggMainCtrlAct.UpdateValue( + double(mvControlled->MainCtrlActualPos + mvControlled->ScndCtrlActualPos)); + else + ggMainCtrlAct.UpdateValue(double(mvControlled->MainCtrlActualPos)); + ggMainCtrlAct.Update(); + } + if (ggScndCtrl.SubModel) + { // Ra: od byte odejmowane boolean i konwertowane potem na double? + ggScndCtrl.UpdateValue( + double(mvControlled->ScndCtrlPos - + ((mvControlled->TrainType == dt_ET42) && mvControlled->DynamicBrakeFlag))); + ggScndCtrl.Update(); + } + if (ggDirKey.SubModel) + { + if (mvControlled->TrainType != dt_EZT) + ggDirKey.UpdateValue(double(mvControlled->ActiveDir)); + else + ggDirKey.UpdateValue(double(mvControlled->ActiveDir) + + double(mvControlled->Imin == mvControlled->IminHi)); + ggDirKey.Update(); + } + if (ggBrakeCtrl.SubModel) + { + if (DynamicObject->Mechanik ? + (DynamicObject->Mechanik->AIControllFlag ? false : Global::iFeedbackMode == 4) : + false) // nie blokujemy AI + { // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba + double b = Console::AnalogGet(0); // odczyt z pulpitu i modyfikacja pozycji kranu + if ((b >= 0.0) && ((mvOccupied->BrakeHandle == FV4a) || + (mvOccupied->BrakeHandle == + FVel6))) // może można usunąć ograniczenie do FV4a i FVel6? + { + b = (((Global::fCalibrateIn[0][3] * b) + Global::fCalibrateIn[0][2]) * b + + Global::fCalibrateIn[0][1]) * + b + + Global::fCalibrateIn[0][0]; + if (b < -2.0) + b = -2.0; + else if (b > mvOccupied->BrakeCtrlPosNo) + b = mvOccupied->BrakeCtrlPosNo; + ggBrakeCtrl.UpdateValue(b); // przesów bez zaokrąglenia + mvOccupied->BrakeLevelSet(b); + } + // else //standardowa prodedura z kranem powiązanym z klawiaturą + // ggBrakeCtrl.UpdateValue(double(mvOccupied->BrakeCtrlPos)); + } + // else //standardowa prodedura z kranem powiązanym z klawiaturą + // ggBrakeCtrl.UpdateValue(double(mvOccupied->BrakeCtrlPos)); + ggBrakeCtrl.UpdateValue(mvOccupied->fBrakeCtrlPos); + ggBrakeCtrl.Update(); + } + if (ggLocalBrake.SubModel) + { + if (DynamicObject->Mechanik ? + (DynamicObject->Mechanik->AIControllFlag ? false : Global::iFeedbackMode == 4) : + false) // nie blokujemy AI + { // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba + double b = Console::AnalogGet(1); // odczyt z pulpitu i modyfikacja pozycji kranu + if ((b >= 0.0) && (mvOccupied->BrakeLocHandle == FD1)) + { + b = (((Global::fCalibrateIn[1][3] * b) + Global::fCalibrateIn[1][2]) * b + + Global::fCalibrateIn[1][1]) * + b + + Global::fCalibrateIn[1][0]; + if (b < 0.0) + b = 0.0; + else if (b > Hamulce::LocalBrakePosNo) + b = Hamulce::LocalBrakePosNo; + ggLocalBrake.UpdateValue(b); // przesów bez zaokrąglenia + mvOccupied->LocalBrakePos = + int(1.09 * b); // sposób zaokrąglania jest do ustalenia + } + else // standardowa prodedura z kranem powiązanym z klawiaturą + ggLocalBrake.UpdateValue(double(mvOccupied->LocalBrakePos)); + } + else // standardowa prodedura z kranem powiązanym z klawiaturą + ggLocalBrake.UpdateValue(double(mvOccupied->LocalBrakePos)); + ggLocalBrake.Update(); + } + if (ggManualBrake.SubModel != NULL) + { + ggManualBrake.UpdateValue(double(mvOccupied->ManualBrakePos)); + ggManualBrake.Update(); + } + if (ggBrakeProfileCtrl.SubModel) + { + ggBrakeProfileCtrl.UpdateValue( + double(mvOccupied->BrakeDelayFlag == 4 ? 2 : mvOccupied->BrakeDelayFlag - 1)); + ggBrakeProfileCtrl.Update(); + } + if (ggBrakeProfileG.SubModel) + { + ggBrakeProfileG.UpdateValue(double(mvOccupied->BrakeDelayFlag == bdelay_G ? 1 : 0)); + ggBrakeProfileG.Update(); + } + if (ggBrakeProfileR.SubModel) + { + ggBrakeProfileR.UpdateValue(double(mvOccupied->BrakeDelayFlag == bdelay_R ? 1 : 0)); + ggBrakeProfileR.Update(); + } + + if (ggMaxCurrentCtrl.SubModel) + { + ggMaxCurrentCtrl.UpdateValue(double(mvControlled->Imax == mvControlled->ImaxHi)); + ggMaxCurrentCtrl.Update(); + } + + // NBMX wrzesien 2003 - drzwi + if (ggDoorLeftButton.SubModel) + { + ggDoorLeftButton.PutValue(mvOccupied->DoorLeftOpened ? 1 : 0); + ggDoorLeftButton.Update(); + } + if (ggDoorRightButton.SubModel) + { + ggDoorRightButton.PutValue(mvOccupied->DoorRightOpened ? 1 : 0); + ggDoorRightButton.Update(); + } + if (ggDepartureSignalButton.SubModel) + { + // ggDepartureSignalButton.UpdateValue(double()); + ggDepartureSignalButton.Update(); + } + + // NBMX dzwignia sprezarki + if (ggCompressorButton.SubModel) // hunter-261211: poprawka + ggCompressorButton.Update(); + if (ggMainButton.SubModel) + ggMainButton.Update(); + if (ggRadioButton.SubModel) + { + ggRadioButton.PutValue(mvControlled->Radio ? 1 : 0); + ggRadioButton.Update(); + } + if (ggConverterButton.SubModel) + ggConverterButton.Update(); + if (ggConverterOffButton.SubModel) + ggConverterOffButton.Update(); + + if (((DynamicObject->iLights[0]) == 0) && ((DynamicObject->iLights[1]) == 0)) + { + ggRightLightButton.PutValue(0); + ggLeftLightButton.PutValue(0); + ggUpperLightButton.PutValue(0); + ggRightEndLightButton.PutValue(0); + ggLeftEndLightButton.PutValue(0); + } + + //--------- + // hunter-101211: poprawka na zle obracajace sie przelaczniki + /* + if (((DynamicObject->iLights[0]&1)==1) + ||((DynamicObject->iLights[1]&1)==1)) + ggLeftLightButton.PutValue(1); + if (((DynamicObject->iLights[0]&16)==16) + ||((DynamicObject->iLights[1]&16)==16)) + ggRightLightButton.PutValue(1); + if (((DynamicObject->iLights[0]&4)==4) + ||((DynamicObject->iLights[1]&4)==4)) + ggUpperLightButton.PutValue(1); + + if (((DynamicObject->iLights[0]&2)==2) + ||((DynamicObject->iLights[1]&2)==2)) + if (ggLeftEndLightButton.SubModel) + { + ggLeftEndLightButton.PutValue(1); + ggLeftLightButton.PutValue(0); + } + else + ggLeftLightButton.PutValue(-1); + + if (((DynamicObject->iLights[0]&32)==32) + ||((DynamicObject->iLights[1]&32)==32)) + if (ggRightEndLightButton.SubModel) + { + ggRightEndLightButton.PutValue(1); + ggRightLightButton.PutValue(0); + } + else + ggRightLightButton.PutValue(-1); + */ + + //-------------- + // hunter-230112 + + // REFLEKTOR LEWY + // glowne oswietlenie + if ((DynamicObject->iLights[0] & 1) == 1) + if ((mvOccupied->ActiveCab) == 1) + ggLeftLightButton.PutValue(1); + else if ((mvOccupied->ActiveCab) == -1) + ggRearLeftLightButton.PutValue(1); + + if ((DynamicObject->iLights[1] & 1) == 1) + if ((mvOccupied->ActiveCab) == -1) + ggLeftLightButton.PutValue(1); + else if ((mvOccupied->ActiveCab) == 1) + ggRearLeftLightButton.PutValue(1); + + // końcówki + if ((DynamicObject->iLights[0] & 2) == 2) + if ((mvOccupied->ActiveCab) == 1) + { + if (ggLeftEndLightButton.SubModel) + { + ggLeftEndLightButton.PutValue(1); + ggLeftLightButton.PutValue(0); + } + else + ggLeftLightButton.PutValue(-1); + } + else if ((mvOccupied->ActiveCab) == -1) + { + if (ggRearLeftEndLightButton.SubModel) + { + ggRearLeftEndLightButton.PutValue(1); + ggRearLeftLightButton.PutValue(0); + } + else + ggRearLeftLightButton.PutValue(-1); + } + + if ((DynamicObject->iLights[1] & 2) == 2) + if ((mvOccupied->ActiveCab) == -1) + { + if (ggLeftEndLightButton.SubModel) + { + ggLeftEndLightButton.PutValue(1); + ggLeftLightButton.PutValue(0); + } + else + ggLeftLightButton.PutValue(-1); + } + else if ((mvOccupied->ActiveCab) == 1) + { + if (ggRearLeftEndLightButton.SubModel) + { + ggRearLeftEndLightButton.PutValue(1); + ggRearLeftLightButton.PutValue(0); + } + else + ggRearLeftLightButton.PutValue(-1); + } + //-------------- + // REFLEKTOR GORNY + if ((DynamicObject->iLights[0] & 4) == 4) + if ((mvOccupied->ActiveCab) == 1) + ggUpperLightButton.PutValue(1); + else if ((mvOccupied->ActiveCab) == -1) + ggRearUpperLightButton.PutValue(1); + + if ((DynamicObject->iLights[1] & 4) == 4) + if ((mvOccupied->ActiveCab) == -1) + ggUpperLightButton.PutValue(1); + else if ((mvOccupied->ActiveCab) == 1) + ggRearUpperLightButton.PutValue(1); + //-------------- + // REFLEKTOR PRAWY + // główne oświetlenie + if ((DynamicObject->iLights[0] & 16) == 16) + if ((mvOccupied->ActiveCab) == 1) + ggRightLightButton.PutValue(1); + else if ((mvOccupied->ActiveCab) == -1) + ggRearRightLightButton.PutValue(1); + + if ((DynamicObject->iLights[1] & 16) == 16) + if ((mvOccupied->ActiveCab) == -1) + ggRightLightButton.PutValue(1); + else if ((mvOccupied->ActiveCab) == 1) + ggRearRightLightButton.PutValue(1); + + // końcówki + if ((DynamicObject->iLights[0] & 32) == 32) + if ((mvOccupied->ActiveCab) == 1) + { + if (ggRightEndLightButton.SubModel) + { + ggRightEndLightButton.PutValue(1); + ggRightLightButton.PutValue(0); + } + else + ggRightLightButton.PutValue(-1); + } + else if ((mvOccupied->ActiveCab) == -1) + { + if (ggRearRightEndLightButton.SubModel) + { + ggRearRightEndLightButton.PutValue(1); + ggRearRightLightButton.PutValue(0); + } + else + ggRearRightLightButton.PutValue(-1); + } + + if ((DynamicObject->iLights[1] & 32) == 32) + if ((mvOccupied->ActiveCab) == -1) + { + if (ggRightEndLightButton.SubModel) + { + ggRightEndLightButton.PutValue(1); + ggRightLightButton.PutValue(0); + } + else + ggRightLightButton.PutValue(-1); + } + else if ((mvOccupied->ActiveCab) == 1) + { + if (ggRearRightEndLightButton.SubModel) + { + ggRearRightEndLightButton.PutValue(1); + ggRearRightLightButton.PutValue(0); + } + else + ggRearRightLightButton.PutValue(-1); + } + + //--------- + // Winger 010304 - pantografy + if (ggPantFrontButton.SubModel) + { + if (mvControlled->PantFrontUp) + ggPantFrontButton.PutValue(1); + else + ggPantFrontButton.PutValue(0); + ggPantFrontButton.Update(); + } + if (ggPantRearButton.SubModel) + { + ggPantRearButton.PutValue(mvControlled->PantRearUp ? 1 : 0); + ggPantRearButton.Update(); + } + if (ggPantFrontButtonOff.SubModel) + { + ggPantFrontButtonOff.Update(); + } + // Winger 020304 - ogrzewanie + //---------- + // hunter-080812: poprawka na ogrzewanie w elektrykach - usuniete uzaleznienie od + // przetwornicy + if (ggTrainHeatingButton.SubModel) + { + if (mvControlled->Heating) + { + ggTrainHeatingButton.PutValue(1); + // if (mvControlled->ConverterFlag==true) + // btLampkaOgrzewanieSkladu.TurnOn(); + } + else + { + ggTrainHeatingButton.PutValue(0); + // btLampkaOgrzewanieSkladu.TurnOff(); + } + ggTrainHeatingButton.Update(); + } + if (ggSignallingButton.SubModel != NULL) + { + ggSignallingButton.PutValue(mvControlled->Signalling ? 1 : 0); + ggSignallingButton.Update(); + } + if (ggDoorSignallingButton.SubModel != NULL) + { + ggDoorSignallingButton.PutValue(mvControlled->DoorSignalling ? 1 : 0); + ggDoorSignallingButton.Update(); + } + // if (ggDistCounter.SubModel) + //{//Ra 2014-07: licznik kilometrów + // ggDistCounter.PutValue(mvControlled->DistCounter); + // ggDistCounter.Update(); + //} + if ((((mvControlled->EngineType == ElectricSeriesMotor) && (mvControlled->Mains == true) && + (mvControlled->ConvOvldFlag == false)) || + (mvControlled->ConverterFlag)) && + (mvControlled->Heating == true)) + btLampkaOgrzewanieSkladu.TurnOn(); + else + btLampkaOgrzewanieSkladu.TurnOff(); + + //---------- + // hunter-261211: jakis stary kod (i niezgodny z prawda), + // zahaszowalem i poprawilem + // youBy-220913: ale przyda sie do lampki samej przetwornicy + btLampkaPrzetw.Turn(!mvControlled->ConverterFlag); + btLampkaNadmPrzetw.Turn(mvControlled->ConvOvldFlag); + //---------- + + // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa + if (mvOccupied->SecuritySystem.Status > 0) + { + if (fBlinkTimer > fCzuwakBlink) + fBlinkTimer = -fCzuwakBlink; + else + fBlinkTimer += dt; + + // hunter-091012: dodanie testu czuwaka + if ((TestFlag(mvOccupied->SecuritySystem.Status, s_aware)) || + (TestFlag(mvOccupied->SecuritySystem.Status, s_CAtest))) + { + btLampkaCzuwaka.Turn(fBlinkTimer > 0); + } + else + btLampkaCzuwaka.TurnOff(); + btLampkaSHP.Turn(TestFlag(mvOccupied->SecuritySystem.Status, s_active)); + + // hunter-091012: rozdzielenie alarmow + // if (TestFlag(mvOccupied->SecuritySystem.Status,s_alarm)) + if (TestFlag(mvOccupied->SecuritySystem.Status, s_CAalarm) || + TestFlag(mvOccupied->SecuritySystem.Status, s_SHPalarm)) + { + dsbBuzzer->GetStatus(&stat); + if (!(stat & DSBSTATUS_PLAYING)) + dsbBuzzer->Play(0, 0, DSBPLAY_LOOPING); + } + else + { + dsbBuzzer->GetStatus(&stat); + if (stat & DSBSTATUS_PLAYING) + dsbBuzzer->Stop(); + } + } + else // wylaczone + { + btLampkaCzuwaka.TurnOff(); + btLampkaSHP.TurnOff(); + dsbBuzzer->GetStatus(&stat); + if (stat & DSBSTATUS_PLAYING) + dsbBuzzer->Stop(); + } + + //****************************************** + // przelaczniki + + if (Console::Pressed(Global::Keys[k_Horn])) + { + if (Console::Pressed(VK_SHIFT)) + { + SetFlag(mvOccupied->WarningSignal, 2); + mvOccupied->WarningSignal &= (255 - 1); + if (ggHornButton.SubModel) + ggHornButton.UpdateValue(1); + } + else + { + SetFlag(mvOccupied->WarningSignal, 1); + mvOccupied->WarningSignal &= (255 - 2); + if (ggHornButton.SubModel) + ggHornButton.UpdateValue(-1); + } + } + else + { + mvOccupied->WarningSignal = 0; + if (ggHornButton.SubModel) + ggHornButton.UpdateValue(0); + } + + if (Console::Pressed(Global::Keys[k_Horn2])) + if (Global::Keys[k_Horn2] != Global::Keys[k_Horn]) + { + SetFlag(mvOccupied->WarningSignal, 2); + } + + //---------------- + // hunter-141211: wyl. szybki zalaczony i wylaczony przeniesiony z OnKeyPress() + if (Console::Pressed(VK_SHIFT) && Console::Pressed(Global::Keys[k_Main])) + { + fMainRelayTimer += dt; + ggMainOnButton.PutValue(1); + if (mvControlled->Mains != true) // hunter-080812: poprawka + mvControlled->ConverterSwitch(false); + if (fMainRelayTimer > mvControlled->InitialCtrlDelay) // wlaczanie WSa z opoznieniem + if (mvControlled->MainSwitch(true)) + { + // if (mvControlled->MainCtrlPos!=0) //zabezpieczenie, by po wrzuceniu + // pozycji przed wlaczonym + // mvControlled->StLinFlag=true; //WSem nie wrzucilo na ta pozycje po + // jego zalaczeniu //yBARC - co to tutaj robi?! + if (mvControlled->EngineType == DieselEngine) + dsbDieselIgnition->Play(0, 0, 0); + } + } + else + { + if (ggConverterButton.GetValue() != + 0) // po puszczeniu przycisku od WSa odpalanie potwora + mvControlled->ConverterSwitch(true); + // hunter-091012: przeniesione z mover.pas, zeby dzwiek sie nie zapetlal, drugi warunek + // zeby nie odtwarzalo w nieskonczonosc i przeniesienie zerowania timera + if ((mvControlled->Mains != true) && (fMainRelayTimer > 0)) + { + dsbRelay->Play(0, 0, 0); + fMainRelayTimer = 0; + } + ggMainOnButton.UpdateValue(0); + } + //--- + + if (!Console::Pressed(VK_SHIFT) && Console::Pressed(Global::Keys[k_Main])) + { + ggMainOffButton.PutValue(1); + if (mvControlled->MainSwitch(false)) + dsbRelay->Play(0, 0, 0); + } + else + ggMainOffButton.UpdateValue(0); + + /* if (cKey==Global::Keys[k_Main]) //z shiftem + { + ggMainOnButton.PutValue(1); + if (mvControlled->MainSwitch(true)) { - case e_tunnel: - { - vol*=3; - dfreq*=0.95; - } - break; - case e_canyon: - { - vol*=1.1; - } - break; - case e_bridge: - { - vol*=2; - dfreq*=0.98; - } - break; + if (mvControlled->MainCtrlPos!=0) //hunter-131211: takie zabezpieczenie + mvControlled->StLinFlag=true; + + if (mvControlled->EngineType==DieselEngine) + dsbDieselIgnition->Play(0,0,0); + else + dsbNastawnikJazdy->Play(0,0,0); } - - } - else //uszkodzone kolo (podkucie) - if (fabs(mvOccupied->nrot)>0.01) - { - dfreq=rsRunningNoise.FM*mvOccupied->Vel+rsRunningNoise.FA; - vol=rsRunningNoise.AM*mvOccupied->Vel+rsRunningNoise.AA; - switch (tor->eEnvironment) - { - case e_tunnel: - { - vol*=2; - } - break; - case e_canyon: - { - vol*=1.1; - } - break; - case e_bridge: - { - vol*=1.5; - } - break; - } - } - if (fabs(mvOccupied->nrot)>0.01) - vol*=1+mvOccupied->UnitBrakeForce/(1+mvOccupied->MaxBrakeForce); //hamulce wzmagaja halas - vol=vol*(20.0+tor->iDamageFlag)/21; - rsRunningNoise.AdjFreq(dfreq,0); - rsRunningNoise.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - rsRunningNoise.Stop(); - } - - if (rsBrake.AM!=0) - { - if ((!mvOccupied->SlippingWheels) && (mvOccupied->UnitBrakeForce>10.0) && (DynamicObject->GetVelocity()>0.01)) - { -// vol=rsBrake.AA+rsBrake.AM*(DynamicObject->GetVelocity()*100+mvOccupied->UnitBrakeForce); - vol=rsBrake.AM*sqrt((DynamicObject->GetVelocity()*mvOccupied->UnitBrakeForce)); - dfreq=rsBrake.FA+rsBrake.FM*DynamicObject->GetVelocity(); - rsBrake.AdjFreq(dfreq,0); - rsBrake.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsBrake.Stop(); - } - } - - - if (rsEngageSlippery.AM!=0) - { - if /*((fabs(mvControlled->dizel_engagedeltaomega)>0.2) && */ (mvControlled->dizel_engage>0.1) - { - if (fabs(mvControlled->dizel_engagedeltaomega)>0.2) - { - dfreq=rsEngageSlippery.FA+rsEngageSlippery.FM*fabs(mvControlled->dizel_engagedeltaomega); - vol=rsEngageSlippery.AA+rsEngageSlippery.AM*(mvControlled->dizel_engage); } - else - { - dfreq=1; //rsEngageSlippery.FA+0.7*rsEngageSlippery.FM*(fabs(mvControlled->enrot)+mvControlled->nmax); - if (mvControlled->dizel_engage>0.2) - vol=rsEngageSlippery.AA+0.2*rsEngageSlippery.AM*(mvControlled->enrot/mvControlled->nmax); - else - vol=0; - } - rsEngageSlippery.AdjFreq(dfreq,0); - rsEngageSlippery.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsEngageSlippery.Stop(); - } - } + else */ - if (FreeFlyModeFlag) - rsFadeSound.Stop(); //wyłącz to cholerne cykanie! - else - rsFadeSound.Play(1,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - -// McZapkie! - to wazne - SoundFlag wystawiane jest przez moje moduly -// gdy zachodza pewne wydarzenia komentowane dzwiekiem. -// Mysle ze wystarczy sprawdzac a potem zerowac SoundFlag tutaj -// a nie w DynObject - gdyby cos poszlo zle to po co szarpac dzwiekiem co 10ms. - - if (TestFlag(mvOccupied->SoundFlag,sound_relay)) // przekaznik - gdy bezpiecznik, automatyczny rozruch itp - { - if (mvOccupied->EventFlag || TestFlag(mvOccupied->SoundFlag,sound_loud)) - { - mvOccupied->EventFlag=false; //Ra: w kabinie? - dsbRelay->SetVolume(DSBVOLUME_MAX); - } - else - { - dsbRelay->SetVolume(-40); - } - if (!TestFlag(mvOccupied->SoundFlag,sound_manyrelay)) - dsbRelay->Play(0,0,0); - else - { - if (TestFlag(mvOccupied->SoundFlag,sound_loud)) - dsbWejscie_na_bezoporow->Play(0,0,0); - else - dsbWejscie_na_drugi_uklad->Play(0,0,0); - } - } - // potem dorobic bufory, sprzegi jako RealSound. - if (TestFlag(mvOccupied->SoundFlag,sound_bufferclamp)) // zderzaki uderzaja o siebie - { - if (TestFlag(mvOccupied->SoundFlag,sound_loud)) - dsbBufferClamp->SetVolume(DSBVOLUME_MAX); - else - dsbBufferClamp->SetVolume(-20); - dsbBufferClamp->Play(0,0,0); - } - if (dsbCouplerStretch) - if (TestFlag(mvOccupied->SoundFlag,sound_couplerstretch)) // sprzegi sie rozciagaja - { - if (TestFlag(mvOccupied->SoundFlag,sound_loud)) - dsbCouplerStretch->SetVolume(DSBVOLUME_MAX); - else - dsbCouplerStretch->SetVolume(-20); - dsbCouplerStretch->Play(0,0,0); - } - - if (mvOccupied->SoundFlag==0) - if (mvOccupied->EventFlag) - if (TestFlag(mvOccupied->DamageFlag,dtrain_wheelwear)) - {//Ra: przenieść do DynObj! - if (rsRunningNoise.AM!=0) - { - rsRunningNoise.Stop(); - //float aa=rsRunningNoise.AA; - float am=rsRunningNoise.AM; - float fa=rsRunningNoise.FA; - float fm=rsRunningNoise.FM; - rsRunningNoise.Init("lomotpodkucia.wav",-1,0,0,0,true); //MC: zmiana szumu na lomot - if (rsRunningNoise.AM==1) - rsRunningNoise.AM=am; - rsRunningNoise.AA=0.7; - rsRunningNoise.FA=fa; - rsRunningNoise.FM-fm; - } - mvOccupied->EventFlag=false; - } - - mvOccupied->SoundFlag=0; -/* - for (int b=0; b<2; b++) //MC: aby zerowac stukanie przekaznikow w czlonie silnikowym - if (TestFlag(mvControlled->Couplers[b].CouplingFlag,ctrain_controll)) - if (mvControlled->Couplers[b].Connected.Power>0.01) - mvControlled->Couplers[b]->Connected->SoundFlag=0; -*/ - - // McZapkie! - koniec obslugi dzwiekow z mover.pas - -//youBy - prad w drugim czlonie: galaz lub calosc -{ - TDynamicObject *tmp; - tmp=NULL; - if (DynamicObject->NextConnected) - if ((TestFlag(mvControlled->Couplers[1].CouplingFlag,ctrain_controll)) && (mvOccupied->ActiveCab==1)) - tmp=DynamicObject->NextConnected; - if (DynamicObject->PrevConnected) - if ((TestFlag(mvControlled->Couplers[0].CouplingFlag,ctrain_controll)) && (mvOccupied->ActiveCab==-1)) - tmp=DynamicObject->PrevConnected; - if (tmp) - if (tmp->MoverParameters->Power>0) - { - if (ggI1B.SubModel) - { - ggI1B.UpdateValue(tmp->MoverParameters->ShowCurrent(1)); - ggI1B.Update(); - } - if (ggI2B.SubModel) - { - ggI2B.UpdateValue(tmp->MoverParameters->ShowCurrent(2)); - ggI2B.Update(); - } - if (ggI3B.SubModel) - { - ggI3B.UpdateValue(tmp->MoverParameters->ShowCurrent(3)); - ggI3B.Update(); - } - if (ggItotalB.SubModel) - { - ggItotalB.UpdateValue(tmp->MoverParameters->ShowCurrent(0)); - ggItotalB.Update(); - } - } -} -/* -//McZapkie-240302 ggVelocity.UpdateValue(DynamicObject->GetVelocity()); - //fHaslerTimer+=dt; - //if (fHaslerTimer>fHaslerTime) - {//Ra: ryzykowne jest to, gdyż może się nie uaktualniać prędkość - //Ra: prędkość się powinna zaokrąglać tam gdzie się liczy fTachoVelocity - if (ggVelocity.SubModel) - {//ZiomalCl: wskazanie Haslera w kabinie A ze zwloka czasowa oraz odpowiednia tolerancja - //Nalezy sie zastanowic na przyszlosc nad rozroznieniem predkosciomierzy (dokladnosc wskazan, zwloka czasowa wskazania, inne funkcje) - //ZiomalCl: W ezt typu stare EN57 wskazania haslera sa mniej dokladne (linka) - //ggVelocity.UpdateValue(fTachoVelocity>2?fTachoVelocity+0.5-random(mvControlled->TrainType==dt_EZT?5:2)/2:0); - ggVelocity.UpdateValue(Min0R(fTachoVelocity,mvControlled->Vmax*1.05)); //ograniczenie maksymalnego wskazania na analogowym - ggVelocity.Update(); - } - if (ggVelocityDgt.SubModel) - {//Ra 2014-07: prędkościomierz cyfrowy - ggVelocityDgt.UpdateValue(fTachoVelocity); - ggVelocityDgt.Update(); - } - if (ggVelocity_B.SubModel) - {//ZiomalCl: wskazanie Haslera w kabinie B ze zwloka czasowa oraz odpowiednia tolerancja - //Nalezy sie zastanowic na przyszlosc nad rozroznieniem predkosciomierzy (dokladnosc wskazan, zwloka czasowa wskazania, inne funkcje) - //Velocity_B.UpdateValue(fTachoVelocity>2?fTachoVelocity+0.5-random(mvControlled->TrainType==dt_EZT?5:2)/2:0); - ggVelocity_B.UpdateValue(fTachoVelocity); - ggVelocity_B.Update(); - } - //fHaslerTimer-=fHaslerTime; //1.2s (???) - } -*/ -//McZapkie-300302: zegarek - if (ggClockMInd.SubModel) - { - ggClockSInd.UpdateValue(int(GlobalTime->mr)); - ggClockSInd.Update(); - ggClockMInd.UpdateValue(GlobalTime->mm); - ggClockMInd.Update(); - ggClockHInd.UpdateValue(GlobalTime->hh+GlobalTime->mm/60.0); - ggClockHInd.Update(); - } - - Cabine[iCabn].Update(); //nowy sposób ustawienia animacji - if (ggZbS.SubModel) - { - ggZbS.UpdateValue(mvOccupied->Handle->GetCP()); - ggZbS.Update(); - } - -//youBy - napiecie na silnikach - if (ggEngineVoltage.SubModel) - { - if (mvControlled->DynamicBrakeFlag) - { ggEngineVoltage.UpdateValue(abs(mvControlled->Im*5)); } - else + /* if (cKey==Global::Keys[k_Main]) //bez shifta { - int x; - if ((mvControlled->TrainType==dt_ET42)&&(mvControlled->Imax==mvControlled->ImaxHi)) - x=1;else x=2; - if ((mvControlled->RList[mvControlled->MainCtrlActualPos].Mn>0) && (abs(mvControlled->Im)>0)) - { ggEngineVoltage.UpdateValue((x*(mvControlled->RunningTraction.TractionVoltage-mvControlled->RList[mvControlled->MainCtrlActualPos].R*abs(mvControlled->Im))/mvControlled->RList[mvControlled->MainCtrlActualPos].Mn)); } - else - { ggEngineVoltage.UpdateValue(0); }} - ggEngineVoltage.Update(); - } - -//Winger 140404 - woltomierz NN - if (ggLVoltage.SubModel) - { - if (mvControlled->Battery==true) - ggLVoltage.UpdateValue(mvControlled->BatteryVoltage); - else - ggLVoltage.UpdateValue(0); - ggLVoltage.Update(); - } - - if (mvControlled->EngineType==DieselElectric) - {//ustawienie zmiennych dla silnika spalinowego - fEngine[1]=mvControlled->ShowEngineRotation(1); - fEngine[2]=mvControlled->ShowEngineRotation(2); - //if (ggEnrot1m.SubModel) - //{ - // ggEnrot1m.UpdateValue(mvControlled->ShowEngineRotation(1)); - // ggEnrot1m.Update(); - //} - //if (ggEnrot2m.SubModel) - //{ - // ggEnrot2m.UpdateValue(mvControlled->ShowEngineRotation(2)); - // ggEnrot2m.Update(); - //} - } - - - - else if (mvControlled->EngineType==DieselEngine) - {//albo dla innego spalinowego - fEngine[1]=mvControlled->ShowEngineRotation(1); - fEngine[2]=mvControlled->ShowEngineRotation(2); - fEngine[3]=mvControlled->ShowEngineRotation(3); - //if (ggEnrot1m.SubModel) - //{ - // ggEnrot1m.UpdateValue(mvControlled->ShowEngineRotation(1)); - // ggEnrot1m.Update(); - //} - //if (ggEnrot2m.SubModel) - //{ - // ggEnrot2m.UpdateValue(mvControlled->ShowEngineRotation(2)); - // ggEnrot2m.Update(); - //} - //if (ggEnrot3m.SubModel) - // if (mvControlled->Couplers[1].Connected) - // { - // ggEnrot3m.UpdateValue(mvControlled->ShowEngineRotation(3)); - // ggEnrot3m.Update(); - // } - //if (ggEngageRatio.SubModel) - //{ - // ggEngageRatio.UpdateValue(mvControlled->dizel_engage); - // ggEngageRatio.Update(); - //} - if (ggMainGearStatus.SubModel) - { - if (mvControlled->Mains) - ggMainGearStatus.UpdateValue(1.1-fabs(mvControlled->dizel_automaticgearstatus)); - else - ggMainGearStatus.UpdateValue(0); - ggMainGearStatus.Update(); - } - if (ggIgnitionKey.SubModel) - { - ggIgnitionKey.UpdateValue(mvControlled->dizel_enginestart); - ggIgnitionKey.Update(); - } - } - - if (mvControlled->SlippingWheels) - {//Ra 2014-12: lokomotywy 181/182 dostają SlippingWheels po zahamowaniu powyżej 2.85 bara i buczały - double veldiff=(DynamicObject->GetVelocity()-fTachoVelocity)/mvControlled->Vmax; - if (veldiff<-0.01) //1% Vmax rezerwy, żeby 181/182 nie buczały po zahamowaniu, ale to proteza - { - if (fabs(mvControlled->Im)>10.0) - btLampkaPoslizg.TurnOn(); - rsSlippery.Play(-rsSlippery.AM*veldiff+rsSlippery.AA,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - if (mvControlled->TrainType==dt_181) //alarm przy poslizgu dla 181/182 - BOMBARDIER - if (dsbSlipAlarm) dsbSlipAlarm->Play(0,0,DSBPLAY_LOOPING); - } - else - { - if ((mvOccupied->UnitBrakeForce>100.0) && (DynamicObject->GetVelocity()>1.0)) - { - rsSlippery.Play(rsSlippery.AM*veldiff+rsSlippery.AA,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - if (mvControlled->TrainType==dt_181) - if (dsbSlipAlarm) dsbSlipAlarm->Stop(); - } - } - } - else - { - btLampkaPoslizg.TurnOff(); - rsSlippery.Stop(); - if (mvControlled->TrainType==dt_181) - if (dsbSlipAlarm) dsbSlipAlarm->Stop(); - } - - if (mvControlled->Mains) - { - btLampkaWylSzybki.TurnOn(); - btLampkaOpory.Turn(mvControlled->StLinFlag?mvControlled->ResistorsFlagCheck():false); - btLampkaBezoporowa.Turn(mvControlled->ResistorsFlagCheck()||(mvControlled->MainCtrlActualPos==0)); //do EU04 - if ( (mvControlled->Itot!=0) || (mvOccupied->BrakePress > 2) || ( mvOccupied->PipePress < 3.6 )) - btLampkaStyczn.TurnOff(); //Ra: czy to jest udawanie działania styczników liniowych? - else - if (mvOccupied->BrakePress < 1) - btLampkaStyczn.TurnOn(); //mozna prowadzic rozruch - if (((TestFlag(mvControlled->Couplers[1].CouplingFlag,ctrain_controll)) && (mvControlled->CabNo==1)) || - ((TestFlag(mvControlled->Couplers[0].CouplingFlag,ctrain_controll)) && (mvControlled->CabNo==-1))) - btLampkaUkrotnienie.TurnOn(); - else - btLampkaUkrotnienie.TurnOff(); - -// if ((TestFlag(mvControlled->BrakeStatus,+b_Rused+b_Ractive)))//Lampka drugiego stopnia hamowania - btLampkaHamPosp.Turn((TestFlag(mvOccupied->BrakeStatus,1))) ;//lampka drugiego stopnia hamowania //TODO: youBy wyciągnąć flagę wysokiego stopnia - - //hunter-111211: wylacznik cisnieniowy - Ra: tutaj? w kabinie? //yBARC - omujborzegrzesiuzniszczylesmicalydzien -// if (mvControlled->TrainType!=dt_EZT) -// if (((mvOccupied->BrakePress > 2) || ( mvOccupied->PipePress < 3.6 )) && ( mvControlled->MainCtrlPos != 0 )) -// mvControlled->StLinFlag=true; - //------- - - //hunter-121211: lampka zanikowo-pradowego wentylatorow: - btLampkaNadmWent.Turn((mvControlled->RventRot<5.0)&&mvControlled->ResistorsFlagCheck()); - //------- - - btLampkaNadmSil.Turn(mvControlled->FuseFlagCheck()); - btLampkaWysRozr.Turn(mvControlled->Imax==mvControlled->ImaxHi); - if ((( mvControlled->ScndCtrlActualPos > 0) || ( (mvControlled->RList[mvControlled->MainCtrlActualPos].ScndAct!=0)&&(mvControlled->RList[mvControlled->MainCtrlActualPos].ScndAct!=255)))&&(!mvControlled->DelayCtrlFlag)) - btLampkaBoczniki.TurnOn(); - else - btLampkaBoczniki.TurnOff(); - - - btLampkaNapNastHam.Turn(mvControlled->ActiveDir!=0); //napiecie na nastawniku hamulcowym - btLampkaSprezarka.Turn(mvControlled->CompressorFlag); //mutopsitka dziala - //boczniki - unsigned char scp; //Ra: dopisałem "unsigned" - //Ra: w SU45 boczniki wchodzą na MainCtrlPos, a nie na MainCtrlActualPos - pokićkał ktoś? - scp=mvControlled->RList[mvControlled->MainCtrlPos].ScndAct; - scp=(scp==255?0:scp); //Ra: whatta hella is this? - if ((mvControlled->ScndCtrlPos>0)||(mvControlled->ScndInMain)&&(scp>0)) - {//boczniki pojedynczo - btLampkaBocznik1.TurnOn(); - btLampkaBocznik2.Turn(mvControlled->ScndCtrlPos>1); - btLampkaBocznik3.Turn(mvControlled->ScndCtrlPos>2); - btLampkaBocznik4.Turn(mvControlled->ScndCtrlPos>3); - } - else - {//wyłączone wszystkie cztery - btLampkaBocznik1.TurnOff(); - btLampkaBocznik2.TurnOff(); - btLampkaBocznik3.TurnOff(); - btLampkaBocznik4.TurnOff(); - } -/* - { //sprezarka w drugim wozie - bool comptemp=false; - if (DynamicObject->NextConnected) - if (TestFlag(mvControlled->Couplers[1].CouplingFlag,ctrain_controll)) - comptemp=DynamicObject->NextConnected->MoverParameters->CompressorFlag; - if ((DynamicObject->PrevConnected) && (!comptemp)) - if (TestFlag(mvControlled->Couplers[0].CouplingFlag,ctrain_controll)) - comptemp=DynamicObject->PrevConnected->MoverParameters->CompressorFlag; - btLampkaSprezarkaB.Turn(comptemp); -*/ - } - else //wylaczone - { - btLampkaWylSzybki.TurnOff(); - btLampkaOpory.TurnOff(); - btLampkaStyczn.TurnOff(); - btLampkaNadmSil.TurnOff(); - btLampkaUkrotnienie.TurnOff(); - btLampkaHamPosp.TurnOff(); - btLampkaBoczniki.TurnOff(); - btLampkaNapNastHam.TurnOff(); - btLampkaSprezarka.TurnOff(); - btLampkaBezoporowa.TurnOff(); - } -if ( mvControlled->Signalling==true ) - { - - if ((mvOccupied->BrakePress>=0.145f)&&(mvControlled->Battery==true)&&(mvControlled->Signalling==true)) - { btLampkaHamowanie1zes.TurnOn(); } - if (mvControlled->BrakePress<0.075f) - { btLampkaHamowanie1zes.TurnOff(); } - } - else - { - btLampkaHamowanie1zes.TurnOff(); - } - btLampkaBlokadaDrzwi.Turn(mvControlled->DoorSignalling?mvOccupied->DoorBlockedFlag()&&mvControlled->Battery:false); - - - - -{ //yB - wskazniki drugiego czlonu - TDynamicObject *tmp; //=mvControlled->mvSecond; //Ra 2014-07: trzeba to jeszcze wyjąć z kabiny... -// Ra 2014-07: no nie ma potrzeby szukać tego w każdej klatce - tmp=NULL; - if ((TestFlag(mvControlled->Couplers[1].CouplingFlag,ctrain_controll)) && (mvOccupied->ActiveCab>0)) - tmp=DynamicObject->NextConnected; - if ((TestFlag(mvControlled->Couplers[0].CouplingFlag,ctrain_controll)) && (mvOccupied->ActiveCab<0)) - tmp=DynamicObject->PrevConnected; - - if (tmp) - if (tmp->MoverParameters->Mains) - { - btLampkaWylSzybkiB.TurnOn(); - btLampkaOporyB.Turn(tmp->MoverParameters->ResistorsFlagCheck()); - btLampkaBezoporowaB.Turn(tmp->MoverParameters->ResistorsFlagCheck()||(tmp->MoverParameters->MainCtrlActualPos==0)); //do EU04 - if ( (tmp->MoverParameters->Itot!=0) || (tmp->MoverParameters->BrakePress > 0.2) || ( tmp->MoverParameters->PipePress < 0.36 )) - btLampkaStycznB.TurnOff(); // - else - if (tmp->MoverParameters->BrakePress < 0.1) - btLampkaStycznB.TurnOn(); //mozna prowadzic rozruch - - //----------------- -// //hunter-271211: brak jazdy w drugim czlonie, gdy w pierwszym tez nie ma (i odwrotnie) - Ra: tutaj? w kabinie? -// if (tmp->MoverParameters->TrainType!=dt_EZT) -// if (((tmp->MoverParameters->BrakePress > 2) || ( tmp->MoverParameters->PipePress < 3.6 )) && ( tmp->MoverParameters->MainCtrlPos != 0 )) -// { -// tmp->MoverParameters->MainCtrlActualPos=0; //inaczej StLinFlag nie zmienia sie na false w drugim pojezdzie -// //tmp->MoverParameters->StLinFlag=true; -// mvControlled->StLinFlag=true; -// } -// if (mvControlled->StLinFlag==true) -// tmp->MoverParameters->MainCtrlActualPos=0; //tmp->MoverParameters->StLinFlag=true; - - //----------------- - //hunter-271211: sygnalizacja poslizgu w pierwszym pojezdzie, gdy wystapi w drugim - btLampkaPoslizg.Turn(tmp->MoverParameters->SlippingWheels); - //----------------- - - - btLampkaSprezarkaB.Turn(tmp->MoverParameters->CompressorFlag); //mutopsitka dziala - if (( tmp->MoverParameters->BrakePress>=0.145f*10 )&&(mvControlled->Battery==true)&&(mvControlled->Signalling==true)) - { btLampkaHamowanie2zes.TurnOn(); } - if(( tmp->MoverParameters->BrakePress<0.075f*10 )|| (mvControlled->Battery==false)||(mvControlled->Signalling==false)) - { btLampkaHamowanie2zes.TurnOff(); } - btLampkaNadmPrzetwB.Turn(tmp->MoverParameters->ConvOvldFlag); //nadmiarowy przetwornicy? - btLampkaPrzetwB.Turn(!tmp->MoverParameters->ConverterFlag); //zalaczenie przetwornicy - } - else //wylaczone - { - btLampkaWylSzybkiB.TurnOff(); - btLampkaOporyB.TurnOff(); - btLampkaStycznB.TurnOff(); - btLampkaSprezarkaB.TurnOff(); - btLampkaBezoporowaB.TurnOff(); - btLampkaHamowanie2zes.TurnOff(); - btLampkaNadmPrzetwB.TurnOn(); - btLampkaPrzetwB.TurnOff(); - } - - //hunter-261211: jakis stary kod (i niezgodny z prawda), zahaszowalem - //if (tmp) - // if (tmp->MoverParameters->ConverterFlag==true) - // btLampkaNadmPrzetwB.TurnOff(); - // else - // btLampkaNadmPrzetwB.TurnOn(); - -} //**************************************************** */ - if (mvControlled->Battery) - { - switch (mvControlled->TrainType) - {//zależnie od typu lokomotywy - case dt_EZT: - btLampkaHamienie.Turn((mvControlled->BrakePress>=0.2)&&mvControlled->Signalling); break; - case dt_ET41: //odhamowanie drugiego członu - if (mvSecond) //bo może komuś przyjść do głowy jeżdżenie jednym członem - btLampkaHamienie.Turn(mvSecond->BrakePress<0.4); - break; - default: - btLampkaHamienie.Turn((mvOccupied->BrakePress>=0.1)||mvControlled->DynamicBrakeFlag); - } - //KURS90 - btLampkaMaxSila.Turn(abs(mvControlled->Im)>=350); - btLampkaPrzekrMaxSila.Turn(abs(mvControlled->Im)>=450); - btLampkaRadio.Turn(mvControlled->Radio); - btLampkaHamulecReczny.Turn(mvOccupied->ManualBrakePos>0); - //NBMX wrzesien 2003 - drzwi oraz sygnał odjazdu - btLampkaDoorLeft.Turn(mvOccupied->DoorLeftOpened); - btLampkaDoorRight.Turn(mvOccupied->DoorRightOpened); - btLampkaNapNastHam.Turn((mvControlled->ActiveDir!=0)&&(mvOccupied->EpFuse)); //napiecie na nastawniku hamulcowym - btLampkaForward.Turn(mvControlled->ActiveDir>0); //jazda do przodu - btLampkaBackward.Turn(mvControlled->ActiveDir<0); //jazda do tyłu - } - else - {//gdy bateria wyłączona - btLampkaHamienie.TurnOff(); - btLampkaMaxSila.TurnOff(); - btLampkaPrzekrMaxSila.TurnOff(); - btLampkaRadio.TurnOff(); - btLampkaHamulecReczny.TurnOff(); - btLampkaDoorLeft.TurnOff(); - btLampkaDoorRight.TurnOff(); - btLampkaNapNastHam.TurnOff(); - btLampkaForward.TurnOff(); - btLampkaBackward.TurnOff(); - } -//McZapkie-080602: obroty (albo translacje) regulatorow - if (ggMainCtrl.SubModel) - { - if (mvControlled->CoupledCtrl) - ggMainCtrl.UpdateValue(double(mvControlled->MainCtrlPos+mvControlled->ScndCtrlPos)); - else - ggMainCtrl.UpdateValue(double(mvControlled->MainCtrlPos)); - ggMainCtrl.Update(); - } - if (ggMainCtrlAct.SubModel) - { - if (mvControlled->CoupledCtrl) - ggMainCtrlAct.UpdateValue(double(mvControlled->MainCtrlActualPos+mvControlled->ScndCtrlActualPos)); - else - ggMainCtrlAct.UpdateValue(double(mvControlled->MainCtrlActualPos)); - ggMainCtrlAct.Update(); - } - if (ggScndCtrl.SubModel) - {//Ra: od byte odejmowane boolean i konwertowane potem na double? - ggScndCtrl.UpdateValue(double(mvControlled->ScndCtrlPos-((mvControlled->TrainType==dt_ET42)&&mvControlled->DynamicBrakeFlag))); - ggScndCtrl.Update(); - } - if (ggDirKey.SubModel) - { - if (mvControlled->TrainType!=dt_EZT) - ggDirKey.UpdateValue(double(mvControlled->ActiveDir)); - else - ggDirKey.UpdateValue(double(mvControlled->ActiveDir)+ - double(mvControlled->Imin== - mvControlled->IminHi)); - ggDirKey.Update(); - } - if (ggBrakeCtrl.SubModel) - {if (DynamicObject->Mechanik?(DynamicObject->Mechanik->AIControllFlag?false:Global::iFeedbackMode==4):false) //nie blokujemy AI - {//Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba - double b=Console::AnalogGet(0); //odczyt z pulpitu i modyfikacja pozycji kranu - if ((b>=0.0)&&((mvOccupied->BrakeHandle==FV4a)||(mvOccupied->BrakeHandle==FVel6))) //może można usunąć ograniczenie do FV4a i FVel6? - {b=(((Global::fCalibrateIn[0][3]*b)+Global::fCalibrateIn[0][2])*b+Global::fCalibrateIn[0][1])*b+Global::fCalibrateIn[0][0]; - if (b<-2.0) b=-2.0; else if (b>mvOccupied->BrakeCtrlPosNo) b=mvOccupied->BrakeCtrlPosNo; - ggBrakeCtrl.UpdateValue(b); //przesów bez zaokrąglenia - mvOccupied->BrakeLevelSet(b); - } - //else //standardowa prodedura z kranem powiązanym z klawiaturą - // ggBrakeCtrl.UpdateValue(double(mvOccupied->BrakeCtrlPos)); - } - //else //standardowa prodedura z kranem powiązanym z klawiaturą - // ggBrakeCtrl.UpdateValue(double(mvOccupied->BrakeCtrlPos)); - ggBrakeCtrl.UpdateValue(mvOccupied->fBrakeCtrlPos); - ggBrakeCtrl.Update(); - } - if (ggLocalBrake.SubModel) - {if (DynamicObject->Mechanik?(DynamicObject->Mechanik->AIControllFlag?false:Global::iFeedbackMode==4):false) //nie blokujemy AI - {//Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba - double b=Console::AnalogGet(1); //odczyt z pulpitu i modyfikacja pozycji kranu - if ((b>=0.0)&&(mvOccupied->BrakeLocHandle==FD1)) - {b=(((Global::fCalibrateIn[1][3]*b)+Global::fCalibrateIn[1][2])*b+Global::fCalibrateIn[1][1])*b+Global::fCalibrateIn[1][0]; - if (b<0.0) b=0.0; else if (b>Hamulce::LocalBrakePosNo) b=Hamulce::LocalBrakePosNo; - ggLocalBrake.UpdateValue(b); //przesów bez zaokrąglenia - mvOccupied->LocalBrakePos=int(1.09*b); //sposób zaokrąglania jest do ustalenia - } - else //standardowa prodedura z kranem powiązanym z klawiaturą - ggLocalBrake.UpdateValue(double(mvOccupied->LocalBrakePos)); - } - else //standardowa prodedura z kranem powiązanym z klawiaturą - ggLocalBrake.UpdateValue(double(mvOccupied->LocalBrakePos)); - ggLocalBrake.Update(); - } - if (ggManualBrake.SubModel!=NULL) - { - ggManualBrake.UpdateValue(double(mvOccupied->ManualBrakePos)); - ggManualBrake.Update(); - } - if (ggBrakeProfileCtrl.SubModel) - { - ggBrakeProfileCtrl.UpdateValue(double(mvOccupied->BrakeDelayFlag==4?2:mvOccupied->BrakeDelayFlag-1)); - ggBrakeProfileCtrl.Update(); - } - if (ggBrakeProfileG.SubModel) - { - ggBrakeProfileG.UpdateValue(double(mvOccupied->BrakeDelayFlag==bdelay_G?1:0)); - ggBrakeProfileG.Update(); - } - if (ggBrakeProfileR.SubModel) - { - ggBrakeProfileR.UpdateValue(double(mvOccupied->BrakeDelayFlag==bdelay_R?1:0)); - ggBrakeProfileR.Update(); - } - - if (ggMaxCurrentCtrl.SubModel) - { - ggMaxCurrentCtrl.UpdateValue(double(mvControlled->Imax==mvControlled->ImaxHi)); - ggMaxCurrentCtrl.Update(); - } - -// NBMX wrzesien 2003 - drzwi - if (ggDoorLeftButton.SubModel) - { - ggDoorLeftButton.PutValue(mvOccupied->DoorLeftOpened?1:0); - ggDoorLeftButton.Update(); - } - if (ggDoorRightButton.SubModel) - { - ggDoorRightButton.PutValue(mvOccupied->DoorRightOpened?1:0); - ggDoorRightButton.Update(); - } - if (ggDepartureSignalButton.SubModel) - { -// ggDepartureSignalButton.UpdateValue(double()); - ggDepartureSignalButton.Update(); - } - -//NBMX dzwignia sprezarki - if (ggCompressorButton.SubModel) //hunter-261211: poprawka - ggCompressorButton.Update(); - if (ggMainButton.SubModel) - ggMainButton.Update(); - if (ggRadioButton.SubModel) - { - ggRadioButton.PutValue(mvControlled->Radio?1:0); - ggRadioButton.Update(); - } - if (ggConverterButton.SubModel) - ggConverterButton.Update(); - if (ggConverterOffButton.SubModel) - ggConverterOffButton.Update(); - - if (((DynamicObject->iLights[0])==0) - &&((DynamicObject->iLights[1])==0)) - { - ggRightLightButton.PutValue(0); - ggLeftLightButton.PutValue(0); - ggUpperLightButton.PutValue(0); - ggRightEndLightButton.PutValue(0); - ggLeftEndLightButton.PutValue(0); - } - - //--------- - //hunter-101211: poprawka na zle obracajace sie przelaczniki - /* - if (((DynamicObject->iLights[0]&1)==1) - ||((DynamicObject->iLights[1]&1)==1)) - ggLeftLightButton.PutValue(1); - if (((DynamicObject->iLights[0]&16)==16) - ||((DynamicObject->iLights[1]&16)==16)) - ggRightLightButton.PutValue(1); - if (((DynamicObject->iLights[0]&4)==4) - ||((DynamicObject->iLights[1]&4)==4)) - ggUpperLightButton.PutValue(1); - - if (((DynamicObject->iLights[0]&2)==2) - ||((DynamicObject->iLights[1]&2)==2)) - if (ggLeftEndLightButton.SubModel) - { - ggLeftEndLightButton.PutValue(1); - ggLeftLightButton.PutValue(0); - } - else - ggLeftLightButton.PutValue(-1); - - if (((DynamicObject->iLights[0]&32)==32) - ||((DynamicObject->iLights[1]&32)==32)) - if (ggRightEndLightButton.SubModel) - { - ggRightEndLightButton.PutValue(1); - ggRightLightButton.PutValue(0); - } - else - ggRightLightButton.PutValue(-1); - */ - - //-------------- - //hunter-230112 - - //REFLEKTOR LEWY - //glowne oswietlenie - if ((DynamicObject->iLights[0]&1)==1) - if ((mvOccupied->ActiveCab)==1) - ggLeftLightButton.PutValue(1); - else if ((mvOccupied->ActiveCab)==-1) - ggRearLeftLightButton.PutValue(1); - - if ((DynamicObject->iLights[1]&1)==1) - if ((mvOccupied->ActiveCab)==-1) - ggLeftLightButton.PutValue(1); - else if ((mvOccupied->ActiveCab)==1) - ggRearLeftLightButton.PutValue(1); - - - //końcówki - if ((DynamicObject->iLights[0]&2)==2) - if ((mvOccupied->ActiveCab)==1) - { - if (ggLeftEndLightButton.SubModel) - { - ggLeftEndLightButton.PutValue(1); - ggLeftLightButton.PutValue(0); - } - else - ggLeftLightButton.PutValue(-1); - } - else if ((mvOccupied->ActiveCab)==-1) - { - if (ggRearLeftEndLightButton.SubModel) - { - ggRearLeftEndLightButton.PutValue(1); - ggRearLeftLightButton.PutValue(0); - } - else - ggRearLeftLightButton.PutValue(-1); - } - - if ((DynamicObject->iLights[1]&2)==2) - if ((mvOccupied->ActiveCab)==-1) - { - if (ggLeftEndLightButton.SubModel) - { - ggLeftEndLightButton.PutValue(1); - ggLeftLightButton.PutValue(0); - } - else - ggLeftLightButton.PutValue(-1); - } - else if ((mvOccupied->ActiveCab)==1) - { - if (ggRearLeftEndLightButton.SubModel) - { - ggRearLeftEndLightButton.PutValue(1); - ggRearLeftLightButton.PutValue(0); - } - else - ggRearLeftLightButton.PutValue(-1); - } - //-------------- - //REFLEKTOR GORNY - if ((DynamicObject->iLights[0]&4)==4) - if ((mvOccupied->ActiveCab)==1) - ggUpperLightButton.PutValue(1); - else if ((mvOccupied->ActiveCab)==-1) - ggRearUpperLightButton.PutValue(1); - - if ((DynamicObject->iLights[1]&4)==4) - if ((mvOccupied->ActiveCab)==-1) - ggUpperLightButton.PutValue(1); - else if ((mvOccupied->ActiveCab)==1) - ggRearUpperLightButton.PutValue(1); - //-------------- - //REFLEKTOR PRAWY - //główne oświetlenie - if ((DynamicObject->iLights[0]&16)==16) - if ((mvOccupied->ActiveCab)==1) - ggRightLightButton.PutValue(1); - else if ((mvOccupied->ActiveCab)==-1) - ggRearRightLightButton.PutValue(1); - - if ((DynamicObject->iLights[1]&16)==16) - if ((mvOccupied->ActiveCab)==-1) - ggRightLightButton.PutValue(1); - else if ((mvOccupied->ActiveCab)==1) - ggRearRightLightButton.PutValue(1); - - - //końcówki - if ((DynamicObject->iLights[0]&32)==32) - if ((mvOccupied->ActiveCab)==1) - { - if (ggRightEndLightButton.SubModel) - { - ggRightEndLightButton.PutValue(1); - ggRightLightButton.PutValue(0); - } - else - ggRightLightButton.PutValue(-1); - } - else if ((mvOccupied->ActiveCab)==-1) - { - if (ggRearRightEndLightButton.SubModel) - { - ggRearRightEndLightButton.PutValue(1); - ggRearRightLightButton.PutValue(0); - } - else - ggRearRightLightButton.PutValue(-1); - } - - if ((DynamicObject->iLights[1]&32)==32) - if ((mvOccupied->ActiveCab)==-1) - { - if (ggRightEndLightButton.SubModel) - { - ggRightEndLightButton.PutValue(1); - ggRightLightButton.PutValue(0); - } - else - ggRightLightButton.PutValue(-1); - } - else if ((mvOccupied->ActiveCab)==1) - { - if (ggRearRightEndLightButton.SubModel) - { - ggRearRightEndLightButton.PutValue(1); - ggRearRightLightButton.PutValue(0); - } - else - ggRearRightLightButton.PutValue(-1); - } - - //--------- -//Winger 010304 - pantografy - if (ggPantFrontButton.SubModel) - { - if (mvControlled->PantFrontUp) - ggPantFrontButton.PutValue(1); - else - ggPantFrontButton.PutValue(0); - ggPantFrontButton.Update(); - } - if (ggPantRearButton.SubModel) - { - ggPantRearButton.PutValue(mvControlled->PantRearUp?1:0); - ggPantRearButton.Update(); - } - if (ggPantFrontButtonOff.SubModel) - { - ggPantFrontButtonOff.Update(); - } -//Winger 020304 - ogrzewanie - //---------- - //hunter-080812: poprawka na ogrzewanie w elektrykach - usuniete uzaleznienie od przetwornicy - if (ggTrainHeatingButton.SubModel) - { - if (mvControlled->Heating) - { - ggTrainHeatingButton.PutValue(1); - //if (mvControlled->ConverterFlag==true) - // btLampkaOgrzewanieSkladu.TurnOn(); - } - else - { - ggTrainHeatingButton.PutValue(0); - //btLampkaOgrzewanieSkladu.TurnOff(); - } - ggTrainHeatingButton.Update(); - } - if (ggSignallingButton.SubModel!=NULL) - { - ggSignallingButton.PutValue(mvControlled->Signalling?1:0); - ggSignallingButton.Update(); - } - if (ggDoorSignallingButton.SubModel!=NULL) - { - ggDoorSignallingButton.PutValue(mvControlled->DoorSignalling?1:0); - ggDoorSignallingButton.Update(); - } - //if (ggDistCounter.SubModel) - //{//Ra 2014-07: licznik kilometrów - // ggDistCounter.PutValue(mvControlled->DistCounter); - // ggDistCounter.Update(); - //} - if ((((mvControlled->EngineType==ElectricSeriesMotor)&&(mvControlled->Mains==true)&&(mvControlled->ConvOvldFlag==false))||(mvControlled->ConverterFlag))&&(mvControlled->Heating==true)) - btLampkaOgrzewanieSkladu.TurnOn(); - else - btLampkaOgrzewanieSkladu.TurnOff(); - - //---------- - //hunter-261211: jakis stary kod (i niezgodny z prawda), - //zahaszowalem i poprawilem - //youBy-220913: ale przyda sie do lampki samej przetwornicy - btLampkaPrzetw.Turn(!mvControlled->ConverterFlag); - btLampkaNadmPrzetw.Turn(mvControlled->ConvOvldFlag); - //---------- - - -//McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa - if (mvOccupied->SecuritySystem.Status>0) - { - if (fBlinkTimer>fCzuwakBlink) - fBlinkTimer=-fCzuwakBlink; - else - fBlinkTimer+=dt; - - //hunter-091012: dodanie testu czuwaka - if ((TestFlag(mvOccupied->SecuritySystem.Status,s_aware))||(TestFlag(mvOccupied->SecuritySystem.Status,s_CAtest))) - { - btLampkaCzuwaka.Turn(fBlinkTimer>0); - } - else btLampkaCzuwaka.TurnOff(); - btLampkaSHP.Turn(TestFlag(mvOccupied->SecuritySystem.Status,s_active)); - - //hunter-091012: rozdzielenie alarmow - //if (TestFlag(mvOccupied->SecuritySystem.Status,s_alarm)) - if (TestFlag(mvOccupied->SecuritySystem.Status,s_CAalarm)||TestFlag(mvOccupied->SecuritySystem.Status,s_SHPalarm)) - { - dsbBuzzer->GetStatus(&stat); - if (!(stat&DSBSTATUS_PLAYING)) - dsbBuzzer->Play(0,0,DSBPLAY_LOOPING); - } - else - { - dsbBuzzer->GetStatus(&stat); - if (stat&DSBSTATUS_PLAYING) - dsbBuzzer->Stop(); - } - } - else //wylaczone - { - btLampkaCzuwaka.TurnOff(); - btLampkaSHP.TurnOff(); - dsbBuzzer->GetStatus(&stat); - if (stat&DSBSTATUS_PLAYING) - dsbBuzzer->Stop(); - } - - //****************************************** - //przelaczniki - - if (Console::Pressed(Global::Keys[k_Horn])) - { - if (Console::Pressed(VK_SHIFT)) - { - SetFlag(mvOccupied->WarningSignal,2); - mvOccupied->WarningSignal&=(255-1); - if (ggHornButton.SubModel) - ggHornButton.UpdateValue(1); - } - else - { - SetFlag(mvOccupied->WarningSignal,1); - mvOccupied->WarningSignal&=(255-2); - if (ggHornButton.SubModel) - ggHornButton.UpdateValue(-1); - } - } - else - { - mvOccupied->WarningSignal=0; - if (ggHornButton.SubModel) - ggHornButton.UpdateValue(0); - } - - if ( Console::Pressed(Global::Keys[k_Horn2]) ) - if (Global::Keys[k_Horn2]!=Global::Keys[k_Horn]) - { - SetFlag(mvOccupied->WarningSignal,2); - } - - //---------------- - //hunter-141211: wyl. szybki zalaczony i wylaczony przeniesiony z OnKeyPress() - if ( Console::Pressed(VK_SHIFT)&&Console::Pressed(Global::Keys[k_Main]) ) - { - fMainRelayTimer+=dt; - ggMainOnButton.PutValue(1); - if (mvControlled->Mains!=true) //hunter-080812: poprawka - mvControlled->ConverterSwitch(false); - if (fMainRelayTimer>mvControlled->InitialCtrlDelay) //wlaczanie WSa z opoznieniem - if (mvControlled->MainSwitch(true)) - { -// if (mvControlled->MainCtrlPos!=0) //zabezpieczenie, by po wrzuceniu pozycji przed wlaczonym -// mvControlled->StLinFlag=true; //WSem nie wrzucilo na ta pozycje po jego zalaczeniu //yBARC - co to tutaj robi?! - if (mvControlled->EngineType==DieselEngine) - dsbDieselIgnition->Play(0,0,0); - } - } - else - { - if (ggConverterButton.GetValue()!=0) //po puszczeniu przycisku od WSa odpalanie potwora - mvControlled->ConverterSwitch(true); - //hunter-091012: przeniesione z mover.pas, zeby dzwiek sie nie zapetlal, drugi warunek zeby nie odtwarzalo w nieskonczonosc i przeniesienie zerowania timera - if ((mvControlled->Mains!=true)&&(fMainRelayTimer>0)) - { - dsbRelay->Play(0,0,0); - fMainRelayTimer=0; - } - ggMainOnButton.UpdateValue(0); - } - //--- - - if ( !Console::Pressed(VK_SHIFT)&&Console::Pressed(Global::Keys[k_Main]) ) - { ggMainOffButton.PutValue(1); if (mvControlled->MainSwitch(false)) - dsbRelay->Play(0,0,0); - } - else - ggMainOffButton.UpdateValue(0); + { + dsbNastawnikJazdy->Play(0,0,0); + } + } + else */ - /* if (cKey==Global::Keys[k_Main]) //z shiftem - { - ggMainOnButton.PutValue(1); - if (mvControlled->MainSwitch(true)) - { - if (mvControlled->MainCtrlPos!=0) //hunter-131211: takie zabezpieczenie - mvControlled->StLinFlag=true; - - if (mvControlled->EngineType==DieselEngine) - dsbDieselIgnition->Play(0,0,0); - else - dsbNastawnikJazdy->Play(0,0,0); - } - } - else */ - - /* if (cKey==Global::Keys[k_Main]) //bez shifta - { - ggMainOffButton.PutValue(1); - if (mvControlled->MainSwitch(false)) - { - dsbNastawnikJazdy->Play(0,0,0); - } - } - else */ - - //---------------- - //hunter-131211: czuwak przeniesiony z OnKeyPress - //hunter-091012: zrobiony test czuwaka - if ( Console::Pressed(Global::Keys[k_Czuwak]) ) - {//czuwak testuje kierunek, ale podobno w EZT nie, więc może być w rozrządczym - fCzuwakTestTimer+=dt; - ggSecurityResetButton.PutValue(1); - if (CAflag==false) - { - CAflag=true; - mvOccupied->SecuritySystemReset(); - } - else if (fCzuwakTestTimer>1.0) - SetFlag(mvOccupied->SecuritySystem.Status,s_CAtest); - } - else - { - fCzuwakTestTimer=0; - ggSecurityResetButton.UpdateValue(0); - if (TestFlag(mvOccupied->SecuritySystem.Status,s_CAtest))//&&(!TestFlag(mvControlled->SecuritySystem.Status,s_CAebrake))) - { - SetFlag(mvOccupied->SecuritySystem.Status,-s_CAtest); - mvOccupied->s_CAtestebrake=false; - mvOccupied->SecuritySystem.SystemBrakeCATestTimer=0; -// if ((!TestFlag(mvOccupied->SecuritySystem.Status,s_SHPebrake)) -// ||(!TestFlag(mvOccupied->SecuritySystem.Status,s_CAebrake))) -// mvControlled->EmergencyBrakeFlag=false; //YB-HN - } - CAflag=false; - } - /* - if ( Console::Pressed(Global::Keys[k_Czuwak]) ) - { - ggSecurityResetButton.PutValue(1); - if ((mvOccupied->SecuritySystem.Status&s_aware)&& - (mvOccupied->SecuritySystem.Status&s_active)) - { - mvOccupied->SecuritySystem.SystemTimer=0; - mvOccupied->SecuritySystem.Status-=s_aware; - mvOccupied->SecuritySystem.VelocityAllowed=-1; - CAflag=1; - } - else if (CAflag!=1) - mvOccupied->SecuritySystemReset(); - } - else - { - ggSecurityResetButton.UpdateValue(0); - CAflag=0; - } - */ - - //----------------- - //hunter-201211: piasecznica przeniesiona z OnKeyPress, wlacza sie tylko, - //gdy trzymamy przycisk, a nie tak jak wczesniej (raz nacisnelo sie 's' - //i sypala caly czas) - /* - if (cKey==Global::Keys[k_Sand]) - { - if (mvControlled->SandDoseOn()) - if (mvControlled->SandDose) + //---------------- + // hunter-131211: czuwak przeniesiony z OnKeyPress + // hunter-091012: zrobiony test czuwaka + if (Console::Pressed(Global::Keys[k_Czuwak])) + { // czuwak testuje kierunek, ale podobno w EZT nie, więc może być w rozrządczym + fCzuwakTestTimer += dt; + ggSecurityResetButton.PutValue(1); + if (CAflag == false) { - dsbPneumaticRelay->SetVolume(-30); - dsbPneumaticRelay->Play(0,0,0); + CAflag = true; + mvOccupied->SecuritySystemReset(); } - } - */ - - - if ( Console::Pressed(Global::Keys[k_Sand]) ) - { - mvControlled->SandDose=true; - //mvControlled->SandDoseOn(true); - } - else - { - mvControlled->SandDose=false; - //mvControlled->SandDoseOn(false); - //dsbPneumaticRelay->SetVolume(-30); - //dsbPneumaticRelay->Play(0,0,0); - } - - //----------------- - //hunter-221211: hamowanie przy poslizgu - if ( Console::Pressed(Global::Keys[k_AntiSlipping]) ) - { - if (mvControlled->BrakeSystem!=ElectroPneumatic) - { - ggAntiSlipButton.PutValue(1); - mvControlled->AntiSlippingBrake(); - } - } - else - ggAntiSlipButton.UpdateValue(0); - //----------------- - //hunter-261211: przetwornica i sprezarka - if ( Console::Pressed(VK_SHIFT)&&Console::Pressed(Global::Keys[k_Converter]) ) //NBMX 14-09-2003: przetwornica wl - { //(mvControlled->CompressorPower<2) - ggConverterButton.PutValue(1); - if ((mvControlled->PantFrontVolt!=0.0)||(mvControlled->PantRearVolt!=0.0)||(mvControlled->EnginePowerSource.SourceType!=CurrentCollector)/*||(!Global::bLiveTraction)*/) - mvControlled->ConverterSwitch(true); - //if ((mvControlled->EngineType!=ElectricSeriesMotor)&&(mvControlled->TrainType!=dt_EZT)) //hunter-110212: poprawka dla EZT - if (mvControlled->CompressorPower==2) //hunter-091012: tak jest poprawnie - mvControlled->CompressorSwitch(true); - } - else - { - if (mvControlled->ConvSwitchType=="impulse") - { - ggConverterButton.PutValue(0); - ggConverterOffButton.PutValue(0); - } - } - -// if ( Console::Pressed(VK_SHIFT)&&Console::Pressed(Global::Keys[k_Compressor])&&((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->TrainType==dt_EZT)) ) //NBMX 14-09-2003: sprezarka wl - if ( Console::Pressed(VK_SHIFT)&&Console::Pressed(Global::Keys[k_Compressor])&&(mvControlled->CompressorPower<2)) //hunter-091012: tak jest poprawnie - { //hunter-110212: poprawka dla EZT - ggCompressorButton.PutValue(1); - mvControlled->CompressorSwitch(true); - } - - if ( !Console::Pressed(VK_SHIFT)&&Console::Pressed(Global::Keys[k_Converter]) ) //NBMX 14-09-2003: przetwornica wl - { - ggConverterButton.PutValue(0); - ggConverterOffButton.PutValue(1); - mvControlled->ConverterSwitch(false); - } - -// if ( !Console::Pressed(VK_SHIFT)&&Console::Pressed(Global::Keys[k_Compressor])&&((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->TrainType==dt_EZT)) ) //NBMX 14-09-2003: sprezarka wl - if ( !Console::Pressed(VK_SHIFT)&&Console::Pressed(Global::Keys[k_Compressor])&&(mvControlled->CompressorPower<2)) //hunter-091012: tak jest poprawnie - { //hunter-110212: poprawka dla EZT - ggCompressorButton.PutValue(0); - mvControlled->CompressorSwitch(false); - } - - /* - bez szifta - if (cKey==Global::Keys[k_Converter]) //NBMX wyl przetwornicy - { - if (mvControlled->ConverterSwitch(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0);; - } - } - else - if (cKey==Global::Keys[k_Compressor]) //NBMX wyl sprezarka - { - if (mvControlled->CompressorSwitch(false)) - { - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0);; - } - } - else - */ - //----------------- - - if (!FreeFlyModeFlag) - { - if (Console::Pressed(Global::Keys[k_Releaser])) //yB: odluzniacz caly czas trzymany, warunki powinny byc takie same, jak przy naciskaniu. Wlasciwie stamtad mozna wyrzucic sprawdzanie nacisniecia. - { - if ((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->EngineType==DieselElectric)) - if (mvControlled->TrainType!=dt_EZT) - if ((mvOccupied->BrakeCtrlPosNo>0)&&(mvControlled->ActiveDir!=0)) - { - ggReleaserButton.PutValue(1); - mvOccupied->BrakeReleaser(1); - } - } //releaser - else mvOccupied->BrakeReleaser(0); - } //FFMF - - - - - if (Console::Pressed(Global::Keys[k_Univ1])) - { - if (!DebugModeFlag) - { - if (ggUniversal1Button.SubModel) - if (Console::Pressed(VK_SHIFT)) - ggUniversal1Button.IncValue(dt/2); - else - ggUniversal1Button.DecValue(dt/2); - } - } - if (!Console::Pressed(Global::Keys[k_SmallCompressor])) - //Ra: przecieść to na zwolnienie klawisza - if (DynamicObject->Mechanik?!DynamicObject->Mechanik->AIControllFlag:false) //nie wyłączać, gdy AI - mvControlled->PantCompFlag=false; //wyłączona, gdy nie trzymamy klawisza - if (Console::Pressed(Global::Keys[k_Univ2])) - { - if (!DebugModeFlag) - { - if (ggUniversal2Button.SubModel) - if (Console::Pressed(VK_SHIFT)) - ggUniversal2Button.IncValue(dt/2); - else - ggUniversal2Button.DecValue(dt/2); - } - } - - //hunter-091012: zrobione z uwzglednieniem przelacznika swiatla - if ( Console::Pressed(Global::Keys[k_Univ3]) ) - { - if (Console::Pressed(VK_SHIFT)) - { - if (Console::Pressed(VK_CONTROL)) - { - bCabLight=true; - if (ggCabLightButton.SubModel) - { - ggCabLightButton.PutValue(1); - btCabLight.TurnOn(); - } - } - else - { - if (ggUniversal3Button.SubModel) - { - ggUniversal3Button.PutValue(1); //hunter-131211: z UpdateValue na PutValue - by zachowywal sie jak pozostale przelaczniki - if (btLampkaUniversal3.Active()) - LampkaUniversal3_st=true; - } - } - } - else - { - if (Console::Pressed(VK_CONTROL)) - { - bCabLight=false; - if (ggCabLightButton.SubModel) - { - ggCabLightButton.PutValue(0); - btCabLight.TurnOff(); - } - } - else - { - if (ggUniversal3Button.SubModel) - { - ggUniversal3Button.PutValue(0); //hunter-131211: z UpdateValue na PutValue - by zachowywal sie jak pozostale przelaczniki - if (btLampkaUniversal3.Active()) - LampkaUniversal3_st=false; - } - } - } - } - - - //hunter-091012: to w ogole jest bez sensu i tak namodzone ze nie wiadomo o co chodzi - zakomentowalem i zrobilem po swojemu - /* - if ( Console::Pressed(Global::Keys[k_Univ3]) ) - { - if (ggUniversal3Button.SubModel) - - - if (Console::Pressed(VK_CONTROL)) - {//z [Ctrl] zapalamy albo gasimy światełko w kabinie - //tutaj jest bez sensu, trzeba reagować na wciskanie klawisza! - if (Console::Pressed(VK_SHIFT)) - {//zapalenie - if (iCabLightFlag<2) ++iCabLightFlag; - } - else - {//gaszenie - if (iCabLightFlag) --iCabLightFlag; - } - - } - else - {//bez [Ctrl] przełączamy cośtem - if (Console::Pressed(VK_SHIFT)) - { - ggUniversal3Button.PutValue(1); //hunter-131211: z UpdateValue na PutValue - by zachowywal sie jak pozostale przelaczniki - if (btLampkaUniversal3.Active()) - LampkaUniversal3_st=true; - } - else - { - ggUniversal3Button.PutValue(0); //hunter-131211: z UpdateValue na PutValue - by zachowywal sie jak pozostale przelaczniki - if (btLampkaUniversal3.Active()) - LampkaUniversal3_st=false; - } - } - } */ - - //ABu030405 obsluga lampki uniwersalnej: - if (btLampkaUniversal3.Active()) //w ogóle jest - if (LampkaUniversal3_st) //załączona - switch (LampkaUniversal3_typ) - {case 0: btLampkaUniversal3.Turn(mvControlled->Battery); break; - case 1: btLampkaUniversal3.Turn(mvControlled->Mains); break; - case 2: btLampkaUniversal3.Turn(mvControlled->ConverterFlag); break; - default: - btLampkaUniversal3.TurnOff(); - } - else - btLampkaUniversal3.TurnOff(); - - /* - if (Console::Pressed(Global::Keys[k_Univ4])) - { - if (ggUniversal4Button.SubModel) - if (Console::Pressed(VK_SHIFT)) - { - ActiveUniversal4=true; - //ggUniversal4Button.UpdateValue(1); + else if (fCzuwakTestTimer > 1.0) + SetFlag(mvOccupied->SecuritySystem.Status, s_CAtest); } else { - ActiveUniversal4=false; - //ggUniversal4Button.UpdateValue(0); + fCzuwakTestTimer = 0; + ggSecurityResetButton.UpdateValue(0); + if (TestFlag(mvOccupied->SecuritySystem.Status, + s_CAtest)) //&&(!TestFlag(mvControlled->SecuritySystem.Status,s_CAebrake))) + { + SetFlag(mvOccupied->SecuritySystem.Status, -s_CAtest); + mvOccupied->s_CAtestebrake = false; + mvOccupied->SecuritySystem.SystemBrakeCATestTimer = 0; + // if ((!TestFlag(mvOccupied->SecuritySystem.Status,s_SHPebrake)) + // ||(!TestFlag(mvOccupied->SecuritySystem.Status,s_CAebrake))) + // mvControlled->EmergencyBrakeFlag=false; //YB-HN + } + CAflag = false; } - } - */ + /* + if ( Console::Pressed(Global::Keys[k_Czuwak]) ) + { + ggSecurityResetButton.PutValue(1); + if ((mvOccupied->SecuritySystem.Status&s_aware)&& + (mvOccupied->SecuritySystem.Status&s_active)) + { + mvOccupied->SecuritySystem.SystemTimer=0; + mvOccupied->SecuritySystem.Status-=s_aware; + mvOccupied->SecuritySystem.VelocityAllowed=-1; + CAflag=1; + } + else if (CAflag!=1) + mvOccupied->SecuritySystemReset(); + } + else + { + ggSecurityResetButton.UpdateValue(0); + CAflag=0; + } + */ - //hunter-091012: przepisanie univ4 i zrobione z uwzglednieniem przelacznika swiatla - if ( Console::Pressed(Global::Keys[k_Univ4]) ) - { - if (Console::Pressed(VK_SHIFT)) - { - if (Console::Pressed(VK_CONTROL)) + //----------------- + // hunter-201211: piasecznica przeniesiona z OnKeyPress, wlacza sie tylko, + // gdy trzymamy przycisk, a nie tak jak wczesniej (raz nacisnelo sie 's' + // i sypala caly czas) + /* + if (cKey==Global::Keys[k_Sand]) + { + if (mvControlled->SandDoseOn()) + if (mvControlled->SandDose) + { + dsbPneumaticRelay->SetVolume(-30); + dsbPneumaticRelay->Play(0,0,0); + } + } + */ + + if (Console::Pressed(Global::Keys[k_Sand])) + { + mvControlled->SandDose = true; + // mvControlled->SandDoseOn(true); + } + else + { + mvControlled->SandDose = false; + // mvControlled->SandDoseOn(false); + // dsbPneumaticRelay->SetVolume(-30); + // dsbPneumaticRelay->Play(0,0,0); + } + + //----------------- + // hunter-221211: hamowanie przy poslizgu + if (Console::Pressed(Global::Keys[k_AntiSlipping])) + { + if (mvControlled->BrakeSystem != ElectroPneumatic) + { + ggAntiSlipButton.PutValue(1); + mvControlled->AntiSlippingBrake(); + } + } + else + ggAntiSlipButton.UpdateValue(0); + //----------------- + // hunter-261211: przetwornica i sprezarka + if (Console::Pressed(VK_SHIFT) && + Console::Pressed(Global::Keys[k_Converter])) // NBMX 14-09-2003: przetwornica wl + { //(mvControlled->CompressorPower<2) + ggConverterButton.PutValue(1); + if ((mvControlled->PantFrontVolt != 0.0) || (mvControlled->PantRearVolt != 0.0) || + (mvControlled->EnginePowerSource.SourceType != + CurrentCollector) /*||(!Global::bLiveTraction)*/) + mvControlled->ConverterSwitch(true); + // if + // ((mvControlled->EngineType!=ElectricSeriesMotor)&&(mvControlled->TrainType!=dt_EZT)) + // //hunter-110212: poprawka dla EZT + if (mvControlled->CompressorPower == 2) // hunter-091012: tak jest poprawnie + mvControlled->CompressorSwitch(true); + } + else + { + if (mvControlled->ConvSwitchType == "impulse") + { + ggConverterButton.PutValue(0); + ggConverterOffButton.PutValue(0); + } + } + + // if ( + // Console::Pressed(VK_SHIFT)&&Console::Pressed(Global::Keys[k_Compressor])&&((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->TrainType==dt_EZT)) + // ) //NBMX 14-09-2003: sprezarka wl + if (Console::Pressed(VK_SHIFT) && Console::Pressed(Global::Keys[k_Compressor]) && + (mvControlled->CompressorPower < 2)) // hunter-091012: tak jest poprawnie + { // hunter-110212: poprawka dla EZT + ggCompressorButton.PutValue(1); + mvControlled->CompressorSwitch(true); + } + + if (!Console::Pressed(VK_SHIFT) && + Console::Pressed(Global::Keys[k_Converter])) // NBMX 14-09-2003: przetwornica wl + { + ggConverterButton.PutValue(0); + ggConverterOffButton.PutValue(1); + mvControlled->ConverterSwitch(false); + } + + // if ( + // !Console::Pressed(VK_SHIFT)&&Console::Pressed(Global::Keys[k_Compressor])&&((mvControlled->EngineType==ElectricSeriesMotor)||(mvControlled->TrainType==dt_EZT)) + // ) //NBMX 14-09-2003: sprezarka wl + if (!Console::Pressed(VK_SHIFT) && Console::Pressed(Global::Keys[k_Compressor]) && + (mvControlled->CompressorPower < 2)) // hunter-091012: tak jest poprawnie + { // hunter-110212: poprawka dla EZT + ggCompressorButton.PutValue(0); + mvControlled->CompressorSwitch(false); + } + + /* + bez szifta + if (cKey==Global::Keys[k_Converter]) //NBMX wyl przetwornicy + { + if (mvControlled->ConverterSwitch(false)) { - bCabLightDim=true; - if (ggCabLightDimButton.SubModel) - { - ggCabLightDimButton.PutValue(1); - } + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0,0,0);; } + } + else + if (cKey==Global::Keys[k_Compressor]) //NBMX wyl sprezarka + { + if (mvControlled->CompressorSwitch(false)) + { + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0,0,0);; + } + } + else + */ + //----------------- + + if (!FreeFlyModeFlag) + { + if (Console::Pressed(Global::Keys[k_Releaser])) // yB: odluzniacz caly czas trzymany, + // warunki powinny byc takie same, jak + // przy naciskaniu. Wlasciwie stamtad + // mozna wyrzucic sprawdzanie + // nacisniecia. + { + if ((mvControlled->EngineType == ElectricSeriesMotor) || + (mvControlled->EngineType == DieselElectric)) + if (mvControlled->TrainType != dt_EZT) + if ((mvOccupied->BrakeCtrlPosNo > 0) && (mvControlled->ActiveDir != 0)) + { + ggReleaserButton.PutValue(1); + mvOccupied->BrakeReleaser(1); + } + } // releaser else - { - ActiveUniversal4=true; - //ggUniversal4Button.UpdateValue(1); - } + mvOccupied->BrakeReleaser(0); + } // FFMF + + if (Console::Pressed(Global::Keys[k_Univ1])) + { + if (!DebugModeFlag) + { + if (ggUniversal1Button.SubModel) + if (Console::Pressed(VK_SHIFT)) + ggUniversal1Button.IncValue(dt / 2); + else + ggUniversal1Button.DecValue(dt / 2); + } + } + if (!Console::Pressed(Global::Keys[k_SmallCompressor])) + // Ra: przecieść to na zwolnienie klawisza + if (DynamicObject->Mechanik ? !DynamicObject->Mechanik->AIControllFlag : + false) // nie wyłączać, gdy AI + mvControlled->PantCompFlag = false; // wyłączona, gdy nie trzymamy klawisza + if (Console::Pressed(Global::Keys[k_Univ2])) + { + if (!DebugModeFlag) + { + if (ggUniversal2Button.SubModel) + if (Console::Pressed(VK_SHIFT)) + ggUniversal2Button.IncValue(dt / 2); + else + ggUniversal2Button.DecValue(dt / 2); + } + } + + // hunter-091012: zrobione z uwzglednieniem przelacznika swiatla + if (Console::Pressed(Global::Keys[k_Univ3])) + { + if (Console::Pressed(VK_SHIFT)) + { + if (Console::Pressed(VK_CONTROL)) + { + bCabLight = true; + if (ggCabLightButton.SubModel) + { + ggCabLightButton.PutValue(1); + btCabLight.TurnOn(); + } + } + else + { + if (ggUniversal3Button.SubModel) + { + ggUniversal3Button.PutValue(1); // hunter-131211: z UpdateValue na PutValue + // - by zachowywal sie jak pozostale + // przelaczniki + if (btLampkaUniversal3.Active()) + LampkaUniversal3_st = true; + } + } + } + else + { + if (Console::Pressed(VK_CONTROL)) + { + bCabLight = false; + if (ggCabLightButton.SubModel) + { + ggCabLightButton.PutValue(0); + btCabLight.TurnOff(); + } + } + else + { + if (ggUniversal3Button.SubModel) + { + ggUniversal3Button.PutValue(0); // hunter-131211: z UpdateValue na PutValue + // - by zachowywal sie jak pozostale + // przelaczniki + if (btLampkaUniversal3.Active()) + LampkaUniversal3_st = false; + } + } + } + } + + // hunter-091012: to w ogole jest bez sensu i tak namodzone ze nie wiadomo o co chodzi - + // zakomentowalem i zrobilem po swojemu + /* + if ( Console::Pressed(Global::Keys[k_Univ3]) ) + { + if (ggUniversal3Button.SubModel) + + + if (Console::Pressed(VK_CONTROL)) + {//z [Ctrl] zapalamy albo gasimy światełko w kabinie + //tutaj jest bez sensu, trzeba reagować na wciskanie klawisza! + if (Console::Pressed(VK_SHIFT)) + {//zapalenie + if (iCabLightFlag<2) ++iCabLightFlag; + } + else + {//gaszenie + if (iCabLightFlag) --iCabLightFlag; + } + } - else - { - if (Console::Pressed(VK_CONTROL)) - { - bCabLightDim=false; - if (ggCabLightDimButton.SubModel) - { - ggCabLightDimButton.PutValue(0); //hunter-131211: z UpdateValue na PutValue - by zachowywal sie jak pozostale przelaczniki - } - } + else + {//bez [Ctrl] przełączamy cośtem + if (Console::Pressed(VK_SHIFT)) + { + ggUniversal3Button.PutValue(1); //hunter-131211: z UpdateValue na PutValue - by + zachowywal sie jak pozostale przelaczniki + if (btLampkaUniversal3.Active()) + LampkaUniversal3_st=true; + } else - { + { + ggUniversal3Button.PutValue(0); //hunter-131211: z UpdateValue na PutValue - by + zachowywal sie jak pozostale przelaczniki + if (btLampkaUniversal3.Active()) + LampkaUniversal3_st=false; + } + } + } */ + + // ABu030405 obsluga lampki uniwersalnej: + if (btLampkaUniversal3.Active()) // w ogóle jest + if (LampkaUniversal3_st) // załączona + switch (LampkaUniversal3_typ) + { + case 0: + btLampkaUniversal3.Turn(mvControlled->Battery); + break; + case 1: + btLampkaUniversal3.Turn(mvControlled->Mains); + break; + case 2: + btLampkaUniversal3.Turn(mvControlled->ConverterFlag); + break; + default: + btLampkaUniversal3.TurnOff(); + } + else + btLampkaUniversal3.TurnOff(); + + /* + if (Console::Pressed(Global::Keys[k_Univ4])) + { + if (ggUniversal4Button.SubModel) + if (Console::Pressed(VK_SHIFT)) + { + ActiveUniversal4=true; + //ggUniversal4Button.UpdateValue(1); + } + else + { ActiveUniversal4=false; //ggUniversal4Button.UpdateValue(0); - } } - } - // Odskakiwanie hamulce EP - if ((!Console::Pressed(Global::Keys[k_DecBrakeLevel]))&&(!Console::Pressed(Global::Keys[k_WaveBrake]))&&(mvOccupied->BrakeCtrlPos==-1)&&(mvOccupied->BrakeHandle==FVel6)&&(DynamicObject->Controller!=AIdriver)&&(Global::iFeedbackMode!=4)) - { - //mvOccupied->BrakeCtrlPos=(mvOccupied->BrakeCtrlPos)+1; - //mvOccupied->IncBrakeLevel(); - mvOccupied->BrakeLevelSet(mvOccupied->BrakeCtrlPos+1); - keybrakecount=0; - if ((mvOccupied->TrainType==dt_EZT)&&(mvControlled->Mains)&&(mvControlled->ActiveDir!=0)) - { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); - } - } - - //Ra: przeklejka z SPKS - płynne poruszanie hamulcem - //if ((mvOccupied->BrakeHandle==FV4a)&&(Console::Pressed(Global::Keys[k_IncBrakeLevel]))) - if ((Console::Pressed(Global::Keys[k_IncBrakeLevel]))) - { - if (Console::Pressed(VK_CONTROL)) - { - //mvOccupied->BrakeCtrlPos2-=dt/20.0; - //if (mvOccupied->BrakeCtrlPos2<-1.5) mvOccupied->BrakeCtrlPos2=-1.5; - } - else - { - //mvOccupied->BrakeCtrlPosR+=(mvOccupied->BrakeCtrlPosR>mvOccupied->BrakeCtrlPosNo?0:dt*2); - //mvOccupied->BrakeCtrlPos= floor(mvOccupied->BrakeCtrlPosR+0.499); - } - } - //if ((mvOccupied->BrakeHandle==FV4a)&&(Console::Pressed(Global::Keys[k_DecBrakeLevel]))) - if ((Console::Pressed(Global::Keys[k_DecBrakeLevel]))) - { - if (Console::Pressed(VK_CONTROL)) - { - //mvOccupied->BrakeCtrlPos2+=(mvOccupied->BrakeCtrlPos2>2?0:dt/20.0); - //if (mvOccupied->BrakeCtrlPos2<-3) mvOccupied->BrakeCtrlPos2=-3; - //mvOccupied->BrakeLevelAdd(mvOccupied->fBrakeCtrlPos<-1?0:dt*2); - } - else - { - //mvOccupied->BrakeCtrlPosR-=(mvOccupied->BrakeCtrlPosR<-1?0:dt*2); - //mvOccupied->BrakeCtrlPos= floor(mvOccupied->BrakeCtrlPosR+0.499); - //mvOccupied->BrakeLevelAdd(mvOccupied->fBrakeCtrlPos<-1?0:-dt*2); - } - } - - if ((mvOccupied->BrakeHandle==FV4a)&&(Console::Pressed(Global::Keys[k_IncBrakeLevel]))) - { - if (Console::Pressed(VK_CONTROL)) - { - mvOccupied->BrakeCtrlPos2-=dt/20.0; - if(mvOccupied->BrakeCtrlPos2<-1.5) mvOccupied->BrakeCtrlPos2=-1.5; - } - else - { -// mvOccupied->BrakeCtrlPosR+=(mvOccupied->BrakeCtrlPosR>mvOccupied->BrakeCtrlPosNo?0:dt*2); - mvOccupied->BrakeLevelAdd(dt*2); -// mvOccupied->BrakeCtrlPos= floor(mvOccupied->BrakeCtrlPosR+0.499); - } - } - - if ((mvOccupied->BrakeHandle==FV4a)&&(Console::Pressed(Global::Keys[k_DecBrakeLevel]))) - { - if (Console::Pressed(VK_CONTROL)) - { - mvOccupied->BrakeCtrlPos2+=(mvOccupied->BrakeCtrlPos2>2?0:dt/20.0); - if(mvOccupied->BrakeCtrlPos2<-3) mvOccupied->BrakeCtrlPos2=-3; - } - else - { -// mvOccupied->BrakeCtrlPosR-=(mvOccupied->BrakeCtrlPosR<-1?0:dt*2); -// mvOccupied->BrakeCtrlPos= floor(mvOccupied->BrakeCtrlPosR+0.499); - mvOccupied->BrakeLevelAdd(-dt*2); - } - } - - - -// bool kEP; -// kEP=(mvOccupied->BrakeSubsystem==Knorr)||(mvOccupied->BrakeSubsystem==Hik)||(mvOccupied->BrakeSubsystem==Kk); - if ((mvOccupied->BrakeSystem==ElectroPneumatic)&&((mvOccupied->BrakeHandle==St113))&&(mvControlled->EpFuse==true)) - if (Console::Pressed(Global::Keys[k_AntiSlipping])) //kEP - { - ggAntiSlipButton.UpdateValue(1); - if (mvOccupied->SwitchEPBrake(1)) - { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); } - } - else - { - if (mvOccupied->SwitchEPBrake(0)) + */ + + // hunter-091012: przepisanie univ4 i zrobione z uwzglednieniem przelacznika swiatla + if (Console::Pressed(Global::Keys[k_Univ4])) { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); + if (Console::Pressed(VK_SHIFT)) + { + if (Console::Pressed(VK_CONTROL)) + { + bCabLightDim = true; + if (ggCabLightDimButton.SubModel) + { + ggCabLightDimButton.PutValue(1); + } + } + else + { + ActiveUniversal4 = true; + // ggUniversal4Button.UpdateValue(1); + } + } + else + { + if (Console::Pressed(VK_CONTROL)) + { + bCabLightDim = false; + if (ggCabLightDimButton.SubModel) + { + ggCabLightDimButton.PutValue(0); // hunter-131211: z UpdateValue na PutValue + // - by zachowywal sie jak pozostale + // przelaczniki + } + } + else + { + ActiveUniversal4 = false; + // ggUniversal4Button.UpdateValue(0); + } + } + } + // Odskakiwanie hamulce EP + if ((!Console::Pressed(Global::Keys[k_DecBrakeLevel])) && + (!Console::Pressed(Global::Keys[k_WaveBrake])) && (mvOccupied->BrakeCtrlPos == -1) && + (mvOccupied->BrakeHandle == FVel6) && (DynamicObject->Controller != AIdriver) && + (Global::iFeedbackMode != 4)) + { + // mvOccupied->BrakeCtrlPos=(mvOccupied->BrakeCtrlPos)+1; + // mvOccupied->IncBrakeLevel(); + mvOccupied->BrakeLevelSet(mvOccupied->BrakeCtrlPos + 1); + keybrakecount = 0; + if ((mvOccupied->TrainType == dt_EZT) && (mvControlled->Mains) && + (mvControlled->ActiveDir != 0)) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } } - } - if ( Console::Pressed(Global::Keys[k_DepartureSignal]) ) - { - ggDepartureSignalButton.PutValue(1); - btLampkaDepartureSignal.TurnOn(); - mvControlled->DepartureSignal=true; - } - else - { - btLampkaDepartureSignal.TurnOff(); - if (DynamicObject->Mechanik) //może nie być? - if (!DynamicObject->Mechanik->AIControllFlag) //tylko jeśli nie prowadzi AI - mvControlled->DepartureSignal=false; - } + // Ra: przeklejka z SPKS - płynne poruszanie hamulcem + // if ((mvOccupied->BrakeHandle==FV4a)&&(Console::Pressed(Global::Keys[k_IncBrakeLevel]))) + if ((Console::Pressed(Global::Keys[k_IncBrakeLevel]))) + { + if (Console::Pressed(VK_CONTROL)) + { + // mvOccupied->BrakeCtrlPos2-=dt/20.0; + // if (mvOccupied->BrakeCtrlPos2<-1.5) mvOccupied->BrakeCtrlPos2=-1.5; + } + else + { + // mvOccupied->BrakeCtrlPosR+=(mvOccupied->BrakeCtrlPosR>mvOccupied->BrakeCtrlPosNo?0:dt*2); + // mvOccupied->BrakeCtrlPos= floor(mvOccupied->BrakeCtrlPosR+0.499); + } + } + // if ((mvOccupied->BrakeHandle==FV4a)&&(Console::Pressed(Global::Keys[k_DecBrakeLevel]))) + if ((Console::Pressed(Global::Keys[k_DecBrakeLevel]))) + { + if (Console::Pressed(VK_CONTROL)) + { + // mvOccupied->BrakeCtrlPos2+=(mvOccupied->BrakeCtrlPos2>2?0:dt/20.0); + // if (mvOccupied->BrakeCtrlPos2<-3) mvOccupied->BrakeCtrlPos2=-3; + // mvOccupied->BrakeLevelAdd(mvOccupied->fBrakeCtrlPos<-1?0:dt*2); + } + else + { + // mvOccupied->BrakeCtrlPosR-=(mvOccupied->BrakeCtrlPosR<-1?0:dt*2); + // mvOccupied->BrakeCtrlPos= floor(mvOccupied->BrakeCtrlPosR+0.499); + // mvOccupied->BrakeLevelAdd(mvOccupied->fBrakeCtrlPos<-1?0:-dt*2); + } + } -if ( Console::Pressed(Global::Keys[k_Main]) ) //[] - { - if (Console::Pressed(VK_SHIFT)) - ggMainButton.PutValue(1); - else - ggMainButton.PutValue(0); - } - else - ggMainButton.PutValue(0); + if ((mvOccupied->BrakeHandle == FV4a) && (Console::Pressed(Global::Keys[k_IncBrakeLevel]))) + { + if (Console::Pressed(VK_CONTROL)) + { + mvOccupied->BrakeCtrlPos2 -= dt / 20.0; + if (mvOccupied->BrakeCtrlPos2 < -1.5) + mvOccupied->BrakeCtrlPos2 = -1.5; + } + else + { + // mvOccupied->BrakeCtrlPosR+=(mvOccupied->BrakeCtrlPosR>mvOccupied->BrakeCtrlPosNo?0:dt*2); + mvOccupied->BrakeLevelAdd(dt * 2); + // mvOccupied->BrakeCtrlPos= floor(mvOccupied->BrakeCtrlPosR+0.499); + } + } -if ( Console::Pressed(Global::Keys[k_CurrentNext])) - { - if (mvControlled->TrainType!=dt_EZT) - { - if (ShowNextCurrent==false) - { - if (ggNextCurrentButton.SubModel) - { - ggNextCurrentButton.UpdateValue(1); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ShowNextCurrent=true; - } + if ((mvOccupied->BrakeHandle == FV4a) && (Console::Pressed(Global::Keys[k_DecBrakeLevel]))) + { + if (Console::Pressed(VK_CONTROL)) + { + mvOccupied->BrakeCtrlPos2 += (mvOccupied->BrakeCtrlPos2 > 2 ? 0 : dt / 20.0); + if (mvOccupied->BrakeCtrlPos2 < -3) + mvOccupied->BrakeCtrlPos2 = -3; + } + else + { + // mvOccupied->BrakeCtrlPosR-=(mvOccupied->BrakeCtrlPosR<-1?0:dt*2); + // mvOccupied->BrakeCtrlPos= floor(mvOccupied->BrakeCtrlPosR+0.499); + mvOccupied->BrakeLevelAdd(-dt * 2); + } + } + + // bool kEP; + // kEP=(mvOccupied->BrakeSubsystem==Knorr)||(mvOccupied->BrakeSubsystem==Hik)||(mvOccupied->BrakeSubsystem==Kk); + if ((mvOccupied->BrakeSystem == ElectroPneumatic) && ((mvOccupied->BrakeHandle == St113)) && + (mvControlled->EpFuse == true)) + if (Console::Pressed(Global::Keys[k_AntiSlipping])) // kEP + { + ggAntiSlipButton.UpdateValue(1); + if (mvOccupied->SwitchEPBrake(1)) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + } + else + { + if (mvOccupied->SwitchEPBrake(0)) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + } + + if (Console::Pressed(Global::Keys[k_DepartureSignal])) + { + ggDepartureSignalButton.PutValue(1); + btLampkaDepartureSignal.TurnOn(); + mvControlled->DepartureSignal = true; + } + else + { + btLampkaDepartureSignal.TurnOff(); + if (DynamicObject->Mechanik) // może nie być? + if (!DynamicObject->Mechanik->AIControllFlag) // tylko jeśli nie prowadzi AI + mvControlled->DepartureSignal = false; + } + + if (Console::Pressed(Global::Keys[k_Main])) //[] + { + if (Console::Pressed(VK_SHIFT)) + ggMainButton.PutValue(1); + else + ggMainButton.PutValue(0); + } + else + ggMainButton.PutValue(0); + + if (Console::Pressed(Global::Keys[k_CurrentNext])) + { + if (mvControlled->TrainType != dt_EZT) + { + if (ShowNextCurrent == false) + { + if (ggNextCurrentButton.SubModel) + { + ggNextCurrentButton.UpdateValue(1); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ShowNextCurrent = true; + } + } + } + else + { + if (Console::Pressed(VK_SHIFT)) + { + // if (Console::Pressed(k_CurrentNext)) + { // Ra: było pod VK_F3 + if ((mvOccupied->EpFuseSwitch(true))) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + } + } + else + { + // if (Console::Pressed(k_CurrentNext)) + { // Ra: było pod VK_F3 + if (Console::Pressed(VK_CONTROL)) + { + if ((mvOccupied->EpFuseSwitch(false))) + { + dsbPneumaticSwitch->SetVolume(-10); + dsbPneumaticSwitch->Play(0, 0, 0); + } + } + } + } + } + } + else + { + if (ShowNextCurrent == true) + { + if (ggNextCurrentButton.SubModel) + { + ggNextCurrentButton.UpdateValue(0); + dsbSwitch->SetVolume(DSBVOLUME_MAX); + dsbSwitch->Play(0, 0, 0); + ShowNextCurrent = false; + } + } + } + + // Winger 010304 PantAllDownButton + if (Console::Pressed(Global::Keys[k_PantFrontUp])) + { + if (Console::Pressed(VK_SHIFT)) + ggPantFrontButton.PutValue(1); + else + ggPantAllDownButton.PutValue(1); + } + else if (mvControlled->PantSwitchType == "impulse") + { + ggPantFrontButton.PutValue(0); + ggPantAllDownButton.PutValue(0); + } + + if (Console::Pressed(Global::Keys[k_PantRearUp])) + { + if (Console::Pressed(VK_SHIFT)) + ggPantRearButton.PutValue(1); + else + ggPantFrontButtonOff.PutValue(1); + } + else if (mvControlled->PantSwitchType == "impulse") + { + ggPantRearButton.PutValue(0); + ggPantFrontButtonOff.PutValue(0); + } + + /* if ((mvControlled->Mains) && (mvControlled->EngineType==ElectricSeriesMotor)) + { + //tu dac w przyszlosci zaleznosc od wlaczenia przetwornicy + if (mvControlled->ConverterFlag) //NBMX -obsluga przetwornicy + { + //glosnosc zalezna od nap. sieci + //-2000 do 0 + long tmpVol; + int trackVol; + trackVol=3550-2000; + if (mvControlled->RunningTraction.TractionVoltage<2000) + { + tmpVol=0; + } + else + { + tmpVol=mvControlled->RunningTraction.TractionVoltage-2000; + } + sConverter.Volume(-2000*(trackVol-tmpVol)/trackVol); + + if (!sConverter.Playing()) + sConverter.TurnOn(); + } + else //wyl przetwornicy + sConverter.TurnOff(); + } + else + { + if (sConverter.Playing()) + sConverter.TurnOff(); + } + sConverter.Update(); + */ + + // if (fabs(DynamicObject->GetVelocity())>0.5) + if (FreeFlyModeFlag ? false : fTachoCount > maxtacho) + { + dsbHasler->GetStatus(&stat); + if (!(stat & DSBSTATUS_PLAYING)) + dsbHasler->Play(0, 0, DSBPLAY_LOOPING); + } + else + { + if (FreeFlyModeFlag ? true : fTachoCount < 1) + { + dsbHasler->GetStatus(&stat); + if (stat & DSBSTATUS_PLAYING) + dsbHasler->Stop(); + } + } + + // koniec mieszania z dzwiekami + + // guziki: + ggMainOffButton.Update(); + ggMainOnButton.Update(); + ggMainButton.Update(); + ggSecurityResetButton.Update(); + ggReleaserButton.Update(); + ggAntiSlipButton.Update(); + ggFuseButton.Update(); + ggConverterFuseButton.Update(); + ggStLinOffButton.Update(); + ggRadioButton.Update(); + ggDepartureSignalButton.Update(); + ggPantFrontButton.Update(); + ggPantRearButton.Update(); + ggPantFrontButtonOff.Update(); + ggUpperLightButton.Update(); + ggLeftLightButton.Update(); + ggRightLightButton.Update(); + ggLeftEndLightButton.Update(); + ggRightEndLightButton.Update(); + // hunter-230112 + ggRearUpperLightButton.Update(); + ggRearLeftLightButton.Update(); + ggRearRightLightButton.Update(); + ggRearLeftEndLightButton.Update(); + ggRearRightEndLightButton.Update(); + //------------ + ggPantAllDownButton.Update(); + ggConverterButton.Update(); + ggConverterOffButton.Update(); + ggTrainHeatingButton.Update(); + ggSignallingButton.Update(); + ggNextCurrentButton.Update(); + ggHornButton.Update(); + ggUniversal1Button.Update(); + ggUniversal2Button.Update(); + ggUniversal3Button.Update(); + // hunter-091012 + ggCabLightButton.Update(); + ggCabLightDimButton.Update(); + //------ + if (ActiveUniversal4) + ggUniversal4Button.PermIncValue(dt); + + ggUniversal4Button.Update(); + ggMainOffButton.UpdateValue(0); + ggMainOnButton.UpdateValue(0); + ggSecurityResetButton.UpdateValue(0); + ggReleaserButton.UpdateValue(0); + ggAntiSlipButton.UpdateValue(0); + ggDepartureSignalButton.UpdateValue(0); + ggFuseButton.UpdateValue(0); + ggConverterFuseButton.UpdateValue(0); } - } - else - { - if (Console::Pressed(VK_SHIFT)) - { -// if (Console::Pressed(k_CurrentNext)) - {//Ra: było pod VK_F3 - if ((mvOccupied->EpFuseSwitch(true))) - { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); - } - } - } - else - { -// if (Console::Pressed(k_CurrentNext)) - {//Ra: było pod VK_F3 - if (Console::Pressed(VK_CONTROL)) - { - if ((mvOccupied->EpFuseSwitch(false))) - { - dsbPneumaticSwitch->SetVolume(-10); - dsbPneumaticSwitch->Play(0,0,0); - } - } - } - } - } - } -else - { - if (ShowNextCurrent==true) - { - if (ggNextCurrentButton.SubModel) - { - ggNextCurrentButton.UpdateValue(0); - dsbSwitch->SetVolume(DSBVOLUME_MAX); - dsbSwitch->Play(0,0,0); - ShowNextCurrent=false; - } - } - } - -//Winger 010304 PantAllDownButton - if ( Console::Pressed(Global::Keys[k_PantFrontUp]) ) - { - if (Console::Pressed(VK_SHIFT)) - ggPantFrontButton.PutValue(1); - else - ggPantAllDownButton.PutValue(1); - } - else - if (mvControlled->PantSwitchType=="impulse") - { - ggPantFrontButton.PutValue(0); - ggPantAllDownButton.PutValue(0); - } - - if ( Console::Pressed(Global::Keys[k_PantRearUp]) ) - { - if (Console::Pressed(VK_SHIFT)) - ggPantRearButton.PutValue(1); - else - ggPantFrontButtonOff.PutValue(1); - } - else - if (mvControlled->PantSwitchType=="impulse") - { - ggPantRearButton.PutValue(0); - ggPantFrontButtonOff.PutValue(0); - } - -/* if ((mvControlled->Mains) && (mvControlled->EngineType==ElectricSeriesMotor)) - { -//tu dac w przyszlosci zaleznosc od wlaczenia przetwornicy - if (mvControlled->ConverterFlag) //NBMX -obsluga przetwornicy - { - //glosnosc zalezna od nap. sieci - //-2000 do 0 - long tmpVol; - int trackVol; - trackVol=3550-2000; - if (mvControlled->RunningTraction.TractionVoltage<2000) - { - tmpVol=0; - } - else - { - tmpVol=mvControlled->RunningTraction.TractionVoltage-2000; - } - sConverter.Volume(-2000*(trackVol-tmpVol)/trackVol); - - if (!sConverter.Playing()) - sConverter.TurnOn(); - } - else //wyl przetwornicy - sConverter.TurnOff(); - } - else - { - if (sConverter.Playing()) - sConverter.TurnOff(); - } - sConverter.Update(); -*/ - -// if (fabs(DynamicObject->GetVelocity())>0.5) - if (FreeFlyModeFlag?false:fTachoCount>maxtacho) - { - dsbHasler->GetStatus(&stat); - if (!(stat&DSBSTATUS_PLAYING)) - dsbHasler->Play(0,0,DSBPLAY_LOOPING ); - } - else - { - if (FreeFlyModeFlag?true:fTachoCount<1) - { - dsbHasler->GetStatus(&stat); - if (stat&DSBSTATUS_PLAYING) - dsbHasler->Stop(); - } - } - -// koniec mieszania z dzwiekami - -// guziki: - ggMainOffButton.Update(); - ggMainOnButton.Update(); - ggMainButton.Update(); - ggSecurityResetButton.Update(); - ggReleaserButton.Update(); - ggAntiSlipButton.Update(); - ggFuseButton.Update(); - ggConverterFuseButton.Update(); - ggStLinOffButton.Update(); - ggRadioButton.Update(); - ggDepartureSignalButton.Update(); - ggPantFrontButton.Update(); - ggPantRearButton.Update(); - ggPantFrontButtonOff.Update(); - ggUpperLightButton.Update(); - ggLeftLightButton.Update(); - ggRightLightButton.Update(); - ggLeftEndLightButton.Update(); - ggRightEndLightButton.Update(); - //hunter-230112 - ggRearUpperLightButton.Update(); - ggRearLeftLightButton.Update(); - ggRearRightLightButton.Update(); - ggRearLeftEndLightButton.Update(); - ggRearRightEndLightButton.Update(); - //------------ - ggPantAllDownButton.Update(); - ggConverterButton.Update(); - ggConverterOffButton.Update(); - ggTrainHeatingButton.Update(); - ggSignallingButton.Update(); - ggNextCurrentButton.Update(); - ggHornButton.Update(); - ggUniversal1Button.Update(); - ggUniversal2Button.Update(); - ggUniversal3Button.Update(); - //hunter-091012 - ggCabLightButton.Update(); - ggCabLightDimButton.Update(); - //------ - if (ActiveUniversal4) - ggUniversal4Button.PermIncValue(dt); - - ggUniversal4Button.Update(); - ggMainOffButton.UpdateValue(0); - ggMainOnButton.UpdateValue(0); - ggSecurityResetButton.UpdateValue(0); - ggReleaserButton.UpdateValue(0); - ggAntiSlipButton.UpdateValue(0); - ggDepartureSignalButton.UpdateValue(0); - ggFuseButton.UpdateValue(0); - ggConverterFuseButton.UpdateValue(0); - } - //wyprowadzenie sygnałów dla haslera na PoKeys (zaznaczanie na taśmie) - btHaslerBrakes.Turn(DynamicObject->MoverParameters->BrakePress>0.4); //ciśnienie w cylindrach - btHaslerCurrent.Turn(DynamicObject->MoverParameters->Im!=0.0); //prąd na silnikach - return true; //(DynamicObject->Update(dt)); -} //koniec update - + // wyprowadzenie sygnałów dla haslera na PoKeys (zaznaczanie na taśmie) + btHaslerBrakes.Turn(DynamicObject->MoverParameters->BrakePress > 0.4); // ciśnienie w cylindrach + btHaslerCurrent.Turn(DynamicObject->MoverParameters->Im != 0.0); // prąd na silnikach + return true; //(DynamicObject->Update(dt)); +} // koniec update bool TTrain::CabChange(int iDirection) -{//McZapkie-090902: zmiana kabiny 1->0->2 i z powrotem - if (DynamicObject->Mechanik?DynamicObject->Mechanik->AIControllFlag:true) //jeśli prowadzi AI albo jest w innym członie - {//jak AI prowadzi, to nie można mu mieszać - if (abs(DynamicObject->MoverParameters->ActiveCab+iDirection)>1) - return false; //ewentualna zmiana pojazdu - DynamicObject->MoverParameters->ActiveCab=DynamicObject->MoverParameters->ActiveCab+iDirection; - } - else - {//jeśli pojazd prowadzony ręcznie albo wcale (wagon) - DynamicObject->MoverParameters->CabDeactivisation(); - if (DynamicObject->MoverParameters->ChangeCab(iDirection)) - if (InitializeCab(DynamicObject->MoverParameters->ActiveCab,DynamicObject->asBaseDir+DynamicObject->MoverParameters->TypeName+".mmd")) - {//zmiana kabiny w ramach tego samego pojazdu - DynamicObject->MoverParameters->CabActivisation(); //załączenie rozrządu (wirtualne kabiny) - return true; //udało się zmienić kabinę - } - DynamicObject->MoverParameters->CabActivisation(); //aktywizacja poprzedniej, bo jeszcze nie wiadomo, czy jakiś pojazd jest - } - return false; //ewentualna zmiana pojazdu +{ // McZapkie-090902: zmiana kabiny 1->0->2 i z powrotem + if (DynamicObject->Mechanik ? DynamicObject->Mechanik->AIControllFlag : + true) // jeśli prowadzi AI albo jest w innym członie + { // jak AI prowadzi, to nie można mu mieszać + if (abs(DynamicObject->MoverParameters->ActiveCab + iDirection) > 1) + return false; // ewentualna zmiana pojazdu + DynamicObject->MoverParameters->ActiveCab = + DynamicObject->MoverParameters->ActiveCab + iDirection; + } + else + { // jeśli pojazd prowadzony ręcznie albo wcale (wagon) + DynamicObject->MoverParameters->CabDeactivisation(); + if (DynamicObject->MoverParameters->ChangeCab(iDirection)) + if (InitializeCab(DynamicObject->MoverParameters->ActiveCab, + DynamicObject->asBaseDir + DynamicObject->MoverParameters->TypeName + + ".mmd")) + { // zmiana kabiny w ramach tego samego pojazdu + DynamicObject->MoverParameters + ->CabActivisation(); // załączenie rozrządu (wirtualne kabiny) + return true; // udało się zmienić kabinę + } + DynamicObject->MoverParameters->CabActivisation(); // aktywizacja poprzedniej, bo jeszcze + // nie wiadomo, czy jakiś pojazd jest + } + return false; // ewentualna zmiana pojazdu } -//McZapkie-310302 -//wczytywanie pliku z danymi multimedialnymi (dzwieki, kontrolki, kabiny) +// McZapkie-310302 +// wczytywanie pliku z danymi multimedialnymi (dzwieki, kontrolki, kabiny) bool __fastcall TTrain::LoadMMediaFile(AnsiString asFileName) { double dSDist; TFileStream *fs; - fs=new TFileStream(asFileName , fmOpenRead | fmShareCompat ); - AnsiString str=""; -// DecimalSeparator='.'; - int size=fs->Size; + fs = new TFileStream(asFileName, fmOpenRead | fmShareCompat); + AnsiString str = ""; + // DecimalSeparator='.'; + int size = fs->Size; str.SetLength(size); - fs->Read(str.c_str(),size); - str+=""; + fs->Read(str.c_str(), size); + str += ""; delete fs; TQueryParserComp *Parser; - Parser=new TQueryParserComp(NULL); - Parser->TextToParse=str; -// Parser->LoadStringToParse(asFile); + Parser = new TQueryParserComp(NULL); + Parser->TextToParse = str; + // Parser->LoadStringToParse(asFile); Parser->First(); - str=""; - dsbPneumaticSwitch=TSoundsManager::GetFromName("silence1.wav",true); - while ((!Parser->EndOfFile) && (str!=AnsiString("internaldata:"))) + str = ""; + dsbPneumaticSwitch = TSoundsManager::GetFromName("silence1.wav", true); + while ((!Parser->EndOfFile) && (str != AnsiString("internaldata:"))) { - str=Parser->GetNextSymbol().LowerCase(); + str = Parser->GetNextSymbol().LowerCase(); } - if (str==AnsiString("internaldata:")) + if (str == AnsiString("internaldata:")) { - while (!Parser->EndOfFile) - { - str=Parser->GetNextSymbol().LowerCase(); -//SEKCJA DZWIEKOW - if (str==AnsiString("ctrl:")) //nastawnik: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbNastawnikJazdy=TSoundsManager::GetFromName(str.c_str(),true); - } - else - //--------------- - //hunter-081211: nastawnik bocznikowania - if (str==AnsiString("ctrlscnd:")) //nastawnik bocznikowania: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbNastawnikBocz=TSoundsManager::GetFromName(str.c_str(),true); - } - else - //--------------- - //hunter-131211: dzwiek kierunkowego - if (str==AnsiString("reverserkey:")) //nastawnik kierunkowy - { - str=Parser->GetNextSymbol().LowerCase(); - dsbReverserKey=TSoundsManager::GetFromName(str.c_str(),true); - } - else - //--------------- - if (str==AnsiString("buzzer:")) //bzyczek shp: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbBuzzer=TSoundsManager::GetFromName(str.c_str(),true); - } - else - if (str==AnsiString("slipalarm:")) //Bombardier 011010: alarm przy poslizgu: + while (!Parser->EndOfFile) { - str=Parser->GetNextSymbol().LowerCase(); - dsbSlipAlarm=TSoundsManager::GetFromName(str.c_str(),true); + str = Parser->GetNextSymbol().LowerCase(); + // SEKCJA DZWIEKOW + if (str == AnsiString("ctrl:")) // nastawnik: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbNastawnikJazdy = TSoundsManager::GetFromName(str.c_str(), true); + } + else + //--------------- + // hunter-081211: nastawnik bocznikowania + if (str == AnsiString("ctrlscnd:")) // nastawnik bocznikowania: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbNastawnikBocz = TSoundsManager::GetFromName(str.c_str(), true); + } + else + //--------------- + // hunter-131211: dzwiek kierunkowego + if (str == AnsiString("reverserkey:")) // nastawnik kierunkowy + { + str = Parser->GetNextSymbol().LowerCase(); + dsbReverserKey = TSoundsManager::GetFromName(str.c_str(), true); + } + else + //--------------- + if (str == AnsiString("buzzer:")) // bzyczek shp: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbBuzzer = TSoundsManager::GetFromName(str.c_str(), true); + } + else if (str == AnsiString("slipalarm:")) // Bombardier 011010: alarm przy poslizgu: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbSlipAlarm = TSoundsManager::GetFromName(str.c_str(), true); + } + else if (str == AnsiString("tachoclock:")) // cykanie rejestratora: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbHasler = TSoundsManager::GetFromName(str.c_str(), true); + } + else if (str == AnsiString("switch:")) // przelaczniki: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbSwitch = TSoundsManager::GetFromName(str.c_str(), true); + } + else if (str == AnsiString("pneumaticswitch:")) // stycznik EP: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbPneumaticSwitch = TSoundsManager::GetFromName(str.c_str(), true); + } + else + //--------------- + // hunter-111211: wydzielenie wejscia na bezoporowa i na drugi uklad do pliku + if (str == AnsiString("wejscie_na_bezoporow:")) + { + str = Parser->GetNextSymbol().LowerCase(); + dsbWejscie_na_bezoporow = TSoundsManager::GetFromName(str.c_str(), true); + } + else if (str == AnsiString("wejscie_na_drugi_uklad:")) + { + str = Parser->GetNextSymbol().LowerCase(); + dsbWejscie_na_drugi_uklad = TSoundsManager::GetFromName(str.c_str(), true); + } + else + //--------------- + if (str == AnsiString("relay:")) // styczniki itp: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbRelay = TSoundsManager::GetFromName(str.c_str(), true); + if (!dsbWejscie_na_bezoporow) // hunter-111211: domyslne, gdy brak + dsbWejscie_na_bezoporow = + TSoundsManager::GetFromName("wejscie_na_bezoporow.wav", true); + if (!dsbWejscie_na_drugi_uklad) + dsbWejscie_na_drugi_uklad = + TSoundsManager::GetFromName("wescie_na_drugi_uklad.wav", true); + } + else if (str == AnsiString("pneumaticrelay:")) // wylaczniki pneumatyczne: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbPneumaticRelay = TSoundsManager::GetFromName(str.c_str(), true); + } + else if (str == AnsiString("couplerattach:")) // laczenie: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbCouplerAttach = TSoundsManager::GetFromName(str.c_str(), true); + dsbCouplerStretch = TSoundsManager::GetFromName( + "en57_couplerstretch.wav", true); // McZapkie-090503: PROWIZORKA!!! + } + else if (str == AnsiString("couplerdetach:")) // rozlaczanie: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbCouplerDetach = TSoundsManager::GetFromName(str.c_str(), true); + dsbBufferClamp = TSoundsManager::GetFromName( + "en57_bufferclamp.wav", true); // McZapkie-090503: PROWIZORKA!!! + } + else if (str == AnsiString("ignition:")) + { // odpalanie silnika + str = Parser->GetNextSymbol().LowerCase(); + dsbDieselIgnition = TSoundsManager::GetFromName(str.c_str(), true); + } + else if (str == AnsiString("brakesound:")) // hamowanie zwykle: + { + str = Parser->GetNextSymbol(); + rsBrake.Init(str.c_str(), -1, 0, 0, 0, true, true); + rsBrake.AM = + Parser->GetNextSymbol().ToDouble() / (1 + mvOccupied->MaxBrakeForce * 1000); + rsBrake.AA = Parser->GetNextSymbol().ToDouble(); + rsBrake.FM = Parser->GetNextSymbol().ToDouble() / (1 + mvOccupied->Vmax); + rsBrake.FA = Parser->GetNextSymbol().ToDouble(); + } + else if (str == AnsiString("slipperysound:")) // sanie: + { + str = Parser->GetNextSymbol(); + rsSlippery.Init(str.c_str(), -1, 0, 0, 0, true); + rsSlippery.AM = Parser->GetNextSymbol().ToDouble() / (1 + mvOccupied->Vmax); + rsSlippery.AA = Parser->GetNextSymbol().ToDouble(); + rsSlippery.FM = 0.0; + rsSlippery.FA = 1.0; + } + else if (str == AnsiString("airsound:")) // syk: + { + str = Parser->GetNextSymbol(); + rsHiss.Init(str.c_str(), -1, 0, 0, 0, true); + rsHiss.AM = Parser->GetNextSymbol().ToDouble(); + rsHiss.AA = Parser->GetNextSymbol().ToDouble(); + rsHiss.FM = 0.0; + rsHiss.FA = 1.0; + } + else if (str == AnsiString("airsound2:")) // syk: + { + str = Parser->GetNextSymbol(); + rsHissU.Init(str.c_str(), -1, 0, 0, 0, true); + rsHissU.AM = Parser->GetNextSymbol().ToDouble(); + rsHissU.AA = Parser->GetNextSymbol().ToDouble(); + rsHissU.FM = 0.0; + rsHissU.FA = 1.0; + } + else if (str == AnsiString("airsound3:")) // syk: + { + str = Parser->GetNextSymbol(); + rsHissE.Init(str.c_str(), -1, 0, 0, 0, true); + rsHissE.AM = Parser->GetNextSymbol().ToDouble(); + rsHissE.AA = Parser->GetNextSymbol().ToDouble(); + rsHissE.FM = 0.0; + rsHissE.FA = 1.0; + } + else if (str == AnsiString("airsound4:")) // syk: + { + str = Parser->GetNextSymbol(); + rsHissX.Init(str.c_str(), -1, 0, 0, 0, true); + rsHissX.AM = Parser->GetNextSymbol().ToDouble(); + rsHissX.AA = Parser->GetNextSymbol().ToDouble(); + rsHissX.FM = 0.0; + rsHissX.FA = 1.0; + } + else if (str == AnsiString("airsound5:")) // syk: + { + str = Parser->GetNextSymbol(); + rsHissT.Init(str.c_str(), -1, 0, 0, 0, true); + rsHissT.AM = Parser->GetNextSymbol().ToDouble(); + rsHissT.AA = Parser->GetNextSymbol().ToDouble(); + rsHissT.FM = 0.0; + rsHissT.FA = 1.0; + } + else if (str == AnsiString("fadesound:")) // syk: + { + str = Parser->GetNextSymbol(); + rsFadeSound.Init(str.c_str(), -1, 0, 0, 0, true); + rsFadeSound.AM = 1.0; + rsFadeSound.AA = 1.0; + rsFadeSound.FM = 1.0; + rsFadeSound.FA = 1.0; + } + else if (str == AnsiString("localbrakesound:")) // syk: + { + str = Parser->GetNextSymbol(); + rsSBHiss.Init(str.c_str(), -1, 0, 0, 0, true); + rsSBHiss.AM = Parser->GetNextSymbol().ToDouble(); + rsSBHiss.AA = Parser->GetNextSymbol().ToDouble(); + rsSBHiss.FM = 0.0; + rsSBHiss.FA = 1.0; + } + else if (str == AnsiString("runningnoise:")) // szum podczas jazdy: + { + str = Parser->GetNextSymbol(); + rsRunningNoise.Init(str.c_str(), -1, 0, 0, 0, true, true); + rsRunningNoise.AM = Parser->GetNextSymbol().ToDouble() / (1 + mvOccupied->Vmax); + rsRunningNoise.AA = Parser->GetNextSymbol().ToDouble(); + rsRunningNoise.FM = Parser->GetNextSymbol().ToDouble() / (1 + mvOccupied->Vmax); + rsRunningNoise.FA = Parser->GetNextSymbol().ToDouble(); + } + else if (str == AnsiString("engageslippery:")) // tarcie tarcz sprzegla: + { + str = Parser->GetNextSymbol(); + rsEngageSlippery.Init(str.c_str(), -1, 0, 0, 0, true, true); + rsEngageSlippery.AM = Parser->GetNextSymbol().ToDouble(); + rsEngageSlippery.AA = Parser->GetNextSymbol().ToDouble(); + rsEngageSlippery.FM = Parser->GetNextSymbol().ToDouble() / (1 + mvOccupied->nmax); + rsEngageSlippery.FA = Parser->GetNextSymbol().ToDouble(); + } + else if (str == AnsiString("mechspring:")) // parametry bujania kamery: + { + str = Parser->GetNextSymbol(); + MechSpring.Init(0, str.ToDouble(), Parser->GetNextSymbol().ToDouble()); + fMechSpringX = Parser->GetNextSymbol().ToDouble(); + fMechSpringY = Parser->GetNextSymbol().ToDouble(); + fMechSpringZ = Parser->GetNextSymbol().ToDouble(); + fMechMaxSpring = Parser->GetNextSymbol().ToDouble(); + fMechRoll = Parser->GetNextSymbol().ToDouble(); + fMechPitch = Parser->GetNextSymbol().ToDouble(); + } + else if (str == AnsiString("pantographup:")) // podniesienie patyka: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbPantUp = TSoundsManager::GetFromName(str.c_str(), true); + } + else if (str == AnsiString("pantographdown:")) // podniesienie patyka: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbPantDown = TSoundsManager::GetFromName(str.c_str(), true); + } + else if (str == AnsiString("doorclose:")) // zamkniecie drzwi: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbDoorClose = TSoundsManager::GetFromName(str.c_str(), true); + } + else if (str == AnsiString("dooropen:")) // wotwarcie drzwi: + { + str = Parser->GetNextSymbol().LowerCase(); + dsbDoorOpen = TSoundsManager::GetFromName(str.c_str(), true); + } } - else - if (str==AnsiString("tachoclock:")) //cykanie rejestratora: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbHasler=TSoundsManager::GetFromName(str.c_str(),true); - } - else - if (str==AnsiString("switch:")) //przelaczniki: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbSwitch=TSoundsManager::GetFromName(str.c_str(),true); - } - else - if (str==AnsiString("pneumaticswitch:")) //stycznik EP: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbPneumaticSwitch=TSoundsManager::GetFromName(str.c_str(),true); - } - else - //--------------- - //hunter-111211: wydzielenie wejscia na bezoporowa i na drugi uklad do pliku - if (str==AnsiString("wejscie_na_bezoporow:")) - { - str=Parser->GetNextSymbol().LowerCase(); - dsbWejscie_na_bezoporow=TSoundsManager::GetFromName(str.c_str(),true); - } - else - if (str==AnsiString("wejscie_na_drugi_uklad:")) - { - str=Parser->GetNextSymbol().LowerCase(); - dsbWejscie_na_drugi_uklad=TSoundsManager::GetFromName(str.c_str(),true); - } - else - //--------------- - if (str==AnsiString("relay:")) //styczniki itp: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbRelay=TSoundsManager::GetFromName(str.c_str(),true); - if (!dsbWejscie_na_bezoporow) //hunter-111211: domyslne, gdy brak - dsbWejscie_na_bezoporow=TSoundsManager::GetFromName("wejscie_na_bezoporow.wav",true); - if (!dsbWejscie_na_drugi_uklad) - dsbWejscie_na_drugi_uklad=TSoundsManager::GetFromName("wescie_na_drugi_uklad.wav",true); - } - else - if (str==AnsiString("pneumaticrelay:")) //wylaczniki pneumatyczne: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbPneumaticRelay=TSoundsManager::GetFromName(str.c_str(),true); - } - else - if (str==AnsiString("couplerattach:")) //laczenie: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbCouplerAttach=TSoundsManager::GetFromName(str.c_str(),true); - dsbCouplerStretch=TSoundsManager::GetFromName("en57_couplerstretch.wav",true); //McZapkie-090503: PROWIZORKA!!! - } - else - if (str==AnsiString("couplerdetach:")) //rozlaczanie: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbCouplerDetach=TSoundsManager::GetFromName(str.c_str(),true); - dsbBufferClamp=TSoundsManager::GetFromName("en57_bufferclamp.wav",true); //McZapkie-090503: PROWIZORKA!!! - } - else - if (str==AnsiString("ignition:")) - {//odpalanie silnika - str=Parser->GetNextSymbol().LowerCase(); - dsbDieselIgnition=TSoundsManager::GetFromName(str.c_str(),true); - } - else - if (str==AnsiString("brakesound:")) //hamowanie zwykle: - { - str=Parser->GetNextSymbol(); - rsBrake.Init(str.c_str(),-1,0,0,0,true,true); - rsBrake.AM=Parser->GetNextSymbol().ToDouble()/(1+mvOccupied->MaxBrakeForce*1000); - rsBrake.AA=Parser->GetNextSymbol().ToDouble(); - rsBrake.FM=Parser->GetNextSymbol().ToDouble()/(1+mvOccupied->Vmax); - rsBrake.FA=Parser->GetNextSymbol().ToDouble(); - } - else - if (str==AnsiString("slipperysound:")) //sanie: - { - str=Parser->GetNextSymbol(); - rsSlippery.Init(str.c_str(),-1,0,0,0,true); - rsSlippery.AM=Parser->GetNextSymbol().ToDouble()/(1+mvOccupied->Vmax); - rsSlippery.AA=Parser->GetNextSymbol().ToDouble(); - rsSlippery.FM=0.0; - rsSlippery.FA=1.0; - } - else - if (str==AnsiString("airsound:")) //syk: - { - str=Parser->GetNextSymbol(); - rsHiss.Init(str.c_str(),-1,0,0,0,true); - rsHiss.AM=Parser->GetNextSymbol().ToDouble(); - rsHiss.AA=Parser->GetNextSymbol().ToDouble(); - rsHiss.FM=0.0; - rsHiss.FA=1.0; - } - else - if (str==AnsiString("airsound2:")) //syk: - { - str=Parser->GetNextSymbol(); - rsHissU.Init(str.c_str(),-1,0,0,0,true); - rsHissU.AM=Parser->GetNextSymbol().ToDouble(); - rsHissU.AA=Parser->GetNextSymbol().ToDouble(); - rsHissU.FM=0.0; - rsHissU.FA=1.0; - } - else - if (str==AnsiString("airsound3:")) //syk: - { - str=Parser->GetNextSymbol(); - rsHissE.Init(str.c_str(),-1,0,0,0,true); - rsHissE.AM=Parser->GetNextSymbol().ToDouble(); - rsHissE.AA=Parser->GetNextSymbol().ToDouble(); - rsHissE.FM=0.0; - rsHissE.FA=1.0; - } - else - if (str==AnsiString("airsound4:")) //syk: - { - str=Parser->GetNextSymbol(); - rsHissX.Init(str.c_str(),-1,0,0,0,true); - rsHissX.AM=Parser->GetNextSymbol().ToDouble(); - rsHissX.AA=Parser->GetNextSymbol().ToDouble(); - rsHissX.FM=0.0; - rsHissX.FA=1.0; - } - else - if (str==AnsiString("airsound5:")) //syk: - { - str=Parser->GetNextSymbol(); - rsHissT.Init(str.c_str(),-1,0,0,0,true); - rsHissT.AM=Parser->GetNextSymbol().ToDouble(); - rsHissT.AA=Parser->GetNextSymbol().ToDouble(); - rsHissT.FM=0.0; - rsHissT.FA=1.0; - } - else - if (str==AnsiString("fadesound:")) //syk: - { - str=Parser->GetNextSymbol(); - rsFadeSound.Init(str.c_str(),-1,0,0,0,true); - rsFadeSound.AM=1.0; - rsFadeSound.AA=1.0; - rsFadeSound.FM=1.0; - rsFadeSound.FA=1.0; - } - else - if (str==AnsiString("localbrakesound:")) //syk: - { - str=Parser->GetNextSymbol(); - rsSBHiss.Init(str.c_str(),-1,0,0,0,true); - rsSBHiss.AM=Parser->GetNextSymbol().ToDouble(); - rsSBHiss.AA=Parser->GetNextSymbol().ToDouble(); - rsSBHiss.FM=0.0; - rsSBHiss.FA=1.0; - } - else - if (str==AnsiString("runningnoise:")) //szum podczas jazdy: - { - str=Parser->GetNextSymbol(); - rsRunningNoise.Init(str.c_str(),-1,0,0,0,true,true); - rsRunningNoise.AM=Parser->GetNextSymbol().ToDouble()/(1+mvOccupied->Vmax); - rsRunningNoise.AA=Parser->GetNextSymbol().ToDouble(); - rsRunningNoise.FM=Parser->GetNextSymbol().ToDouble()/(1+mvOccupied->Vmax); - rsRunningNoise.FA=Parser->GetNextSymbol().ToDouble(); - } - else - if (str==AnsiString("engageslippery:")) //tarcie tarcz sprzegla: - { - str=Parser->GetNextSymbol(); - rsEngageSlippery.Init(str.c_str(),-1,0,0,0,true,true); - rsEngageSlippery.AM=Parser->GetNextSymbol().ToDouble(); - rsEngageSlippery.AA=Parser->GetNextSymbol().ToDouble(); - rsEngageSlippery.FM=Parser->GetNextSymbol().ToDouble()/(1+mvOccupied->nmax); - rsEngageSlippery.FA=Parser->GetNextSymbol().ToDouble(); - } - else - if (str==AnsiString("mechspring:")) //parametry bujania kamery: - { - str=Parser->GetNextSymbol(); - MechSpring.Init(0,str.ToDouble(),Parser->GetNextSymbol().ToDouble()); - fMechSpringX=Parser->GetNextSymbol().ToDouble(); - fMechSpringY=Parser->GetNextSymbol().ToDouble(); - fMechSpringZ=Parser->GetNextSymbol().ToDouble(); - fMechMaxSpring=Parser->GetNextSymbol().ToDouble(); - fMechRoll=Parser->GetNextSymbol().ToDouble(); - fMechPitch=Parser->GetNextSymbol().ToDouble(); - } - else - if (str==AnsiString("pantographup:")) //podniesienie patyka: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbPantUp=TSoundsManager::GetFromName(str.c_str(),true); - } - else - if (str==AnsiString("pantographdown:")) //podniesienie patyka: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbPantDown=TSoundsManager::GetFromName(str.c_str(),true); - } - else - if (str==AnsiString("doorclose:")) //zamkniecie drzwi: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbDoorClose=TSoundsManager::GetFromName(str.c_str(),true); - } - else - if (str==AnsiString("dooropen:")) //wotwarcie drzwi: - { - str=Parser->GetNextSymbol().LowerCase(); - dsbDoorOpen=TSoundsManager::GetFromName(str.c_str(),true); - } - } } - else return false; //nie znalazl sekcji internal - delete Parser; //Ra: jak się coś newuje, to trzeba zdeletować, inaczej syf się robi - if (!InitializeCab(mvOccupied->ActiveCab,asFileName)) //zle zainicjowana kabina - return false; - else - { - if (DynamicObject->Controller==Humandriver) - DynamicObject->bDisplayCab=true; //McZapkie-030303: mozliwosc wyswietlania kabiny, w przyszlosci dac opcje w mmd - return true; - } + else + return false; // nie znalazl sekcji internal + delete Parser; // Ra: jak się coś newuje, to trzeba zdeletować, inaczej syf się robi + if (!InitializeCab(mvOccupied->ActiveCab, asFileName)) // zle zainicjowana kabina + return false; + else + { + if (DynamicObject->Controller == Humandriver) + DynamicObject->bDisplayCab = true; // McZapkie-030303: mozliwosc wyswietlania kabiny, w + // przyszlosci dac opcje w mmd + return true; + } } - bool TTrain::InitializeCab(int NewCabNo, AnsiString asFileName) { - bool parse=false; - double dSDist; - TFileStream *fs; - fs=new TFileStream(asFileName,fmOpenRead|fmShareCompat); - AnsiString str=""; - //DecimalSeparator='.'; - int size=fs->Size; - str.SetLength(size); - fs->Read(str.c_str(),size); - str+=""; - delete fs; - TQueryParserComp *Parser; - Parser=new TQueryParserComp(NULL); - Parser->TextToParse=str; - //Parser->LoadStringToParse(asFile); - Parser->First(); - str=""; - int cabindex=0; - TGauge *gg; //roboczy wsaźnik na obiekt animujący gałkę - DynamicObject->mdKabina=NULL; //likwidacja wskaźnika na dotychczasową kabinę - switch (NewCabNo) - {//ustalenie numeru kabiny do wczytania - case -1: cabindex=2; break; - case 1: cabindex=1; break; - case 0: cabindex=0; - } - AnsiString cabstr=AnsiString("cab")+cabindex+AnsiString("definition:"); - while ((!Parser->EndOfFile) && (AnsiCompareStr(str,cabstr)!=0)) - str=Parser->GetNextSymbol().LowerCase(); //szukanie kabiny - if (cabindex!=1) - if (AnsiCompareStr(str,cabstr)!=0) //jeśli nie znaleziony wpis kabiny - {//próba szukania kabiny 1 - cabstr=AnsiString("cab1definition:"); - Parser->First(); - while ((!Parser->EndOfFile) && (AnsiCompareStr(str,cabstr)!=0)) - str=Parser->GetNextSymbol().LowerCase(); //szukanie kabiny - } - if (AnsiCompareStr(str,cabstr)==0) //jeśli znaleziony wpis kabiny - { - Cabine[cabindex].Load(Parser); - str=Parser->GetNextSymbol().LowerCase(); - if (AnsiCompareStr(AnsiString("driver")+cabindex+AnsiString("pos:"),str)==0) //pozycja poczatkowa maszynisty - { - pMechOffset.x=Parser->GetNextSymbol().ToDouble(); - pMechOffset.y=Parser->GetNextSymbol().ToDouble(); - pMechOffset.z=Parser->GetNextSymbol().ToDouble(); - pMechSittingPosition.x=pMechOffset.x; - pMechSittingPosition.y=pMechOffset.y; - pMechSittingPosition.z=pMechOffset.z; - } - //ABu: pozycja siedzaca mechanika - str=Parser->GetNextSymbol().LowerCase(); - if (AnsiCompareStr(AnsiString("driver")+cabindex+AnsiString("sitpos:"),str)==0) //ABu 180404 pozycja siedzaca maszynisty - { - pMechSittingPosition.x=Parser->GetNextSymbol().ToDouble(); - pMechSittingPosition.y=Parser->GetNextSymbol().ToDouble(); - pMechSittingPosition.z=Parser->GetNextSymbol().ToDouble(); - parse=true; - } - //else parse=false; - while (!Parser->EndOfFile) - {//ABu: wstawione warunki, wczesniej tylko to: - // str=Parser->GetNextSymbol().LowerCase(); - if (parse) - str=Parser->GetNextSymbol().LowerCase(); - else - parse=true; - //inicjacja kabiny - //Ra 2014-08: zmieniamy zasady - zamiast przypisywać submodel do istniejących obiektów animujących - //będziemy teraz uaktywniać obiekty animujące z tablicy i podawać im submodel oraz wskaźnik na parametr - if (AnsiCompareStr(AnsiString("cab")+cabindex+AnsiString("model:"),str)==0) //model kabiny - { - str=Parser->GetNextSymbol().LowerCase(); - if (str!=AnsiString("none")) - { - str=DynamicObject->asBaseDir+str; - Global::asCurrentTexturePath=DynamicObject->asBaseDir; //bieżąca sciezka do tekstur to dynamic/... - TModel3d *k=TModelsManager::GetModel(str.c_str(),true); //szukaj kabinę jako oddzielny model - Global::asCurrentTexturePath=AnsiString(szTexturePath); //z powrotem defaultowa sciezka do tekstur - //if (DynamicObject->mdKabina!=k) - if (k) - DynamicObject->mdKabina=k; //nowa kabina - //(mdKabina) może zostać to samo po przejściu do innego członu bez zmiany kabiny, przy powrocie musi być wiązanie ponowne - //else - // break; //wyjście z pętli, bo model zostaje bez zmian + bool parse = false; + double dSDist; + TFileStream *fs; + fs = new TFileStream(asFileName, fmOpenRead | fmShareCompat); + AnsiString str = ""; + // DecimalSeparator='.'; + int size = fs->Size; + str.SetLength(size); + fs->Read(str.c_str(), size); + str += ""; + delete fs; + TQueryParserComp *Parser; + Parser = new TQueryParserComp(NULL); + Parser->TextToParse = str; + // Parser->LoadStringToParse(asFile); + Parser->First(); + str = ""; + int cabindex = 0; + TGauge *gg; // roboczy wsaźnik na obiekt animujący gałkę + DynamicObject->mdKabina = NULL; // likwidacja wskaźnika na dotychczasową kabinę + switch (NewCabNo) + { // ustalenie numeru kabiny do wczytania + case -1: + cabindex = 2; + break; + case 1: + cabindex = 1; + break; + case 0: + cabindex = 0; } - else if (cabindex==1) //model tylko, gdy nie ma kabiny 1 - DynamicObject->mdKabina=DynamicObject->mdModel; //McZapkie-170103: szukaj elementy kabiny w glownym modelu - ActiveUniversal4=false; - ggMainCtrl.Clear(); - ggMainCtrlAct.Clear(); - ggScndCtrl.Clear(); - ggDirKey.Clear(); - ggBrakeCtrl.Clear(); - ggLocalBrake.Clear(); - ggManualBrake.Clear(); - ggBrakeProfileCtrl.Clear(); - ggBrakeProfileG.Clear(); - ggBrakeProfileR.Clear(); - ggMaxCurrentCtrl.Clear(); - ggMainOffButton.Clear(); - ggMainOnButton.Clear(); - ggSecurityResetButton.Clear(); - ggReleaserButton.Clear(); - ggAntiSlipButton.Clear(); - ggHornButton.Clear(); - ggNextCurrentButton.Clear(); - ggUniversal1Button.Clear(); - ggUniversal2Button.Clear(); - ggUniversal3Button.Clear(); - //hunter-091012 - ggCabLightButton.Clear(); - ggCabLightDimButton.Clear(); - //------- - ggUniversal4Button.Clear(); - ggFuseButton.Clear(); - ggConverterFuseButton.Clear(); - ggStLinOffButton.Clear(); - ggDoorLeftButton.Clear(); - ggDoorRightButton.Clear(); - ggDepartureSignalButton.Clear(); - ggCompressorButton.Clear(); - ggConverterButton.Clear(); - ggPantFrontButton.Clear(); - ggPantRearButton.Clear(); - ggPantFrontButtonOff.Clear(); - ggPantAllDownButton.Clear(); - ggZbS.Clear(); - ggI1B.Clear(); - ggI2B.Clear(); - ggI3B.Clear(); - ggItotalB.Clear(); - - ggClockSInd.Clear(); - ggClockMInd.Clear(); - ggClockHInd.Clear(); - ggEngineVoltage.Clear(); - ggLVoltage.Clear(); - //ggLVoltage.Output(0); //Ra: sterowanie miernikiem: niskie napięcie - //ggEnrot1m.Clear(); - //ggEnrot2m.Clear(); - //ggEnrot3m.Clear(); - //ggEngageRatio.Clear(); - ggMainGearStatus.Clear(); - ggIgnitionKey.Clear(); - btLampkaPoslizg.Clear(6); - btLampkaStyczn.Clear(5); - btLampkaNadmPrzetw.Clear((mvControlled->TrainType&(dt_EZT))?-1:7); //EN57 nie ma tej lampki - btLampkaPrzetw.Clear((mvControlled->TrainType&(dt_EZT))?7:-1); //za to ma tę - btLampkaPrzekRozn.Clear(); - btLampkaPrzekRoznPom.Clear(); - btLampkaNadmSil.Clear(4); - btLampkaUkrotnienie.Clear(); - btLampkaHamPosp.Clear(); - btLampkaWylSzybki.Clear(3); - btLampkaNadmWent.Clear(9); - btLampkaNadmSpr.Clear(8); - btLampkaOpory.Clear(2); - btLampkaWysRozr.Clear((mvControlled->TrainType&(dt_ET22))?-1:10); //ET22 nie ma tej lampki - btLampkaBezoporowa.Clear(); - btLampkaBezoporowaB.Clear(); - btLampkaMaxSila.Clear(); - btLampkaPrzekrMaxSila.Clear(); - btLampkaRadio.Clear(); - btLampkaHamulecReczny.Clear(); - btLampkaBlokadaDrzwi.Clear(); - btLampkaUniversal3.Clear(); - btLampkaWentZaluzje.Clear(); - btLampkaOgrzewanieSkladu.Clear(11); - btLampkaSHP.Clear(0); - btLampkaCzuwaka.Clear(1); - btLampkaDoorLeft.Clear(); - btLampkaDoorRight.Clear(); - btLampkaDepartureSignal.Clear(); - btLampkaRezerwa.Clear(); - btLampkaBoczniki.Clear(); - btLampkaBocznik1.Clear(); - btLampkaBocznik2.Clear(); - btLampkaBocznik3.Clear(); - btLampkaBocznik4.Clear(); - btLampkaRadiotelefon.Clear(); - btLampkaHamienie.Clear(); - btLampkaSprezarka.Clear(); - btLampkaSprezarkaB.Clear(); - btLampkaNapNastHam.Clear(); - btLampkaJazda.Clear(); - btLampkaStycznB.Clear(); - btLampkaHamowanie1zes.Clear(); - btLampkaHamowanie2zes.Clear(); - btLampkaNadmPrzetwB.Clear(); - btLampkaPrzetwB.Clear(); - btLampkaWylSzybkiB.Clear(); - btLampkaForward.Clear(); - btLampkaBackward.Clear(); - btCabLight.Clear(); //hunter-171012 - ggLeftLightButton.Clear(); - ggRightLightButton.Clear(); - ggUpperLightButton.Clear(); - ggLeftEndLightButton.Clear(); - ggRightEndLightButton.Clear(); - //hunter-230112 - ggRearLeftLightButton.Clear(); - ggRearRightLightButton.Clear(); - ggRearUpperLightButton.Clear(); - ggRearLeftEndLightButton.Clear(); - ggRearRightEndLightButton.Clear(); - btHaslerBrakes.Clear(12); //ciśnienie w cylindrach do odbijania na haslerze - btHaslerCurrent.Clear(13); //prąd na silnikach do odbijania na haslerze - } - //SEKCJA REGULATOROW - else if (str==AnsiString("mainctrl:")) //nastawnik - { - if (!DynamicObject->mdKabina) + AnsiString cabstr = AnsiString("cab") + cabindex + AnsiString("definition:"); + while ((!Parser->EndOfFile) && (AnsiCompareStr(str, cabstr) != 0)) + str = Parser->GetNextSymbol().LowerCase(); // szukanie kabiny + if (cabindex != 1) + if (AnsiCompareStr(str, cabstr) != 0) // jeśli nie znaleziony wpis kabiny + { // próba szukania kabiny 1 + cabstr = AnsiString("cab1definition:"); + Parser->First(); + while ((!Parser->EndOfFile) && (AnsiCompareStr(str, cabstr) != 0)) + str = Parser->GetNextSymbol().LowerCase(); // szukanie kabiny + } + if (AnsiCompareStr(str, cabstr) == 0) // jeśli znaleziony wpis kabiny { - delete Parser; - WriteLog("Cab not initialised!"); - return false; + Cabine[cabindex].Load(Parser); + str = Parser->GetNextSymbol().LowerCase(); + if (AnsiCompareStr(AnsiString("driver") + cabindex + AnsiString("pos:"), str) == + 0) // pozycja poczatkowa maszynisty + { + pMechOffset.x = Parser->GetNextSymbol().ToDouble(); + pMechOffset.y = Parser->GetNextSymbol().ToDouble(); + pMechOffset.z = Parser->GetNextSymbol().ToDouble(); + pMechSittingPosition.x = pMechOffset.x; + pMechSittingPosition.y = pMechOffset.y; + pMechSittingPosition.z = pMechOffset.z; + } + // ABu: pozycja siedzaca mechanika + str = Parser->GetNextSymbol().LowerCase(); + if (AnsiCompareStr(AnsiString("driver") + cabindex + AnsiString("sitpos:"), str) == + 0) // ABu 180404 pozycja siedzaca maszynisty + { + pMechSittingPosition.x = Parser->GetNextSymbol().ToDouble(); + pMechSittingPosition.y = Parser->GetNextSymbol().ToDouble(); + pMechSittingPosition.z = Parser->GetNextSymbol().ToDouble(); + parse = true; + } + // else parse=false; + while (!Parser->EndOfFile) + { // ABu: wstawione warunki, wczesniej tylko to: + // str=Parser->GetNextSymbol().LowerCase(); + if (parse) + str = Parser->GetNextSymbol().LowerCase(); + else + parse = true; + // inicjacja kabiny + // Ra 2014-08: zmieniamy zasady - zamiast przypisywać submodel do istniejących obiektów + // animujących + // będziemy teraz uaktywniać obiekty animujące z tablicy i podawać im submodel oraz + // wskaźnik na parametr + if (AnsiCompareStr(AnsiString("cab") + cabindex + AnsiString("model:"), str) == + 0) // model kabiny + { + str = Parser->GetNextSymbol().LowerCase(); + if (str != AnsiString("none")) + { + str = DynamicObject->asBaseDir + str; + Global::asCurrentTexturePath = + DynamicObject->asBaseDir; // bieżąca sciezka do tekstur to dynamic/... + TModel3d *k = TModelsManager::GetModel( + str.c_str(), true); // szukaj kabinę jako oddzielny model + Global::asCurrentTexturePath = + AnsiString(szTexturePath); // z powrotem defaultowa sciezka do tekstur + // if (DynamicObject->mdKabina!=k) + if (k) + DynamicObject->mdKabina = k; // nowa kabina + //(mdKabina) może zostać to samo po przejściu do innego członu bez zmiany + //kabiny, przy powrocie musi być wiązanie ponowne + // else + // break; //wyjście z pętli, bo model zostaje bez zmian + } + else if (cabindex == 1) // model tylko, gdy nie ma kabiny 1 + DynamicObject->mdKabina = + DynamicObject + ->mdModel; // McZapkie-170103: szukaj elementy kabiny w glownym modelu + ActiveUniversal4 = false; + ggMainCtrl.Clear(); + ggMainCtrlAct.Clear(); + ggScndCtrl.Clear(); + ggDirKey.Clear(); + ggBrakeCtrl.Clear(); + ggLocalBrake.Clear(); + ggManualBrake.Clear(); + ggBrakeProfileCtrl.Clear(); + ggBrakeProfileG.Clear(); + ggBrakeProfileR.Clear(); + ggMaxCurrentCtrl.Clear(); + ggMainOffButton.Clear(); + ggMainOnButton.Clear(); + ggSecurityResetButton.Clear(); + ggReleaserButton.Clear(); + ggAntiSlipButton.Clear(); + ggHornButton.Clear(); + ggNextCurrentButton.Clear(); + ggUniversal1Button.Clear(); + ggUniversal2Button.Clear(); + ggUniversal3Button.Clear(); + // hunter-091012 + ggCabLightButton.Clear(); + ggCabLightDimButton.Clear(); + //------- + ggUniversal4Button.Clear(); + ggFuseButton.Clear(); + ggConverterFuseButton.Clear(); + ggStLinOffButton.Clear(); + ggDoorLeftButton.Clear(); + ggDoorRightButton.Clear(); + ggDepartureSignalButton.Clear(); + ggCompressorButton.Clear(); + ggConverterButton.Clear(); + ggPantFrontButton.Clear(); + ggPantRearButton.Clear(); + ggPantFrontButtonOff.Clear(); + ggPantAllDownButton.Clear(); + ggZbS.Clear(); + ggI1B.Clear(); + ggI2B.Clear(); + ggI3B.Clear(); + ggItotalB.Clear(); + + ggClockSInd.Clear(); + ggClockMInd.Clear(); + ggClockHInd.Clear(); + ggEngineVoltage.Clear(); + ggLVoltage.Clear(); + // ggLVoltage.Output(0); //Ra: sterowanie miernikiem: niskie napięcie + // ggEnrot1m.Clear(); + // ggEnrot2m.Clear(); + // ggEnrot3m.Clear(); + // ggEngageRatio.Clear(); + ggMainGearStatus.Clear(); + ggIgnitionKey.Clear(); + btLampkaPoslizg.Clear(6); + btLampkaStyczn.Clear(5); + btLampkaNadmPrzetw.Clear( + (mvControlled->TrainType & (dt_EZT)) ? -1 : 7); // EN57 nie ma tej lampki + btLampkaPrzetw.Clear((mvControlled->TrainType & (dt_EZT)) ? 7 : -1); // za to ma tę + btLampkaPrzekRozn.Clear(); + btLampkaPrzekRoznPom.Clear(); + btLampkaNadmSil.Clear(4); + btLampkaUkrotnienie.Clear(); + btLampkaHamPosp.Clear(); + btLampkaWylSzybki.Clear(3); + btLampkaNadmWent.Clear(9); + btLampkaNadmSpr.Clear(8); + btLampkaOpory.Clear(2); + btLampkaWysRozr.Clear( + (mvControlled->TrainType & (dt_ET22)) ? -1 : 10); // ET22 nie ma tej lampki + btLampkaBezoporowa.Clear(); + btLampkaBezoporowaB.Clear(); + btLampkaMaxSila.Clear(); + btLampkaPrzekrMaxSila.Clear(); + btLampkaRadio.Clear(); + btLampkaHamulecReczny.Clear(); + btLampkaBlokadaDrzwi.Clear(); + btLampkaUniversal3.Clear(); + btLampkaWentZaluzje.Clear(); + btLampkaOgrzewanieSkladu.Clear(11); + btLampkaSHP.Clear(0); + btLampkaCzuwaka.Clear(1); + btLampkaDoorLeft.Clear(); + btLampkaDoorRight.Clear(); + btLampkaDepartureSignal.Clear(); + btLampkaRezerwa.Clear(); + btLampkaBoczniki.Clear(); + btLampkaBocznik1.Clear(); + btLampkaBocznik2.Clear(); + btLampkaBocznik3.Clear(); + btLampkaBocznik4.Clear(); + btLampkaRadiotelefon.Clear(); + btLampkaHamienie.Clear(); + btLampkaSprezarka.Clear(); + btLampkaSprezarkaB.Clear(); + btLampkaNapNastHam.Clear(); + btLampkaJazda.Clear(); + btLampkaStycznB.Clear(); + btLampkaHamowanie1zes.Clear(); + btLampkaHamowanie2zes.Clear(); + btLampkaNadmPrzetwB.Clear(); + btLampkaPrzetwB.Clear(); + btLampkaWylSzybkiB.Clear(); + btLampkaForward.Clear(); + btLampkaBackward.Clear(); + btCabLight.Clear(); // hunter-171012 + ggLeftLightButton.Clear(); + ggRightLightButton.Clear(); + ggUpperLightButton.Clear(); + ggLeftEndLightButton.Clear(); + ggRightEndLightButton.Clear(); + // hunter-230112 + ggRearLeftLightButton.Clear(); + ggRearRightLightButton.Clear(); + ggRearUpperLightButton.Clear(); + ggRearLeftEndLightButton.Clear(); + ggRearRightEndLightButton.Clear(); + btHaslerBrakes.Clear(12); // ciśnienie w cylindrach do odbijania na haslerze + btHaslerCurrent.Clear(13); // prąd na silnikach do odbijania na haslerze + } + // SEKCJA REGULATOROW + else if (str == AnsiString("mainctrl:")) // nastawnik + { + if (!DynamicObject->mdKabina) + { + delete Parser; + WriteLog("Cab not initialised!"); + return false; + } + else + ggMainCtrl.Load(Parser, DynamicObject->mdKabina); + } + else if (str == AnsiString("mainctrlact:")) // zabek pozycji aktualnej + ggMainCtrlAct.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("scndctrl:")) // bocznik + ggScndCtrl.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("dirkey:")) // klucz kierunku + ggDirKey.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("brakectrl:")) // hamulec zasadniczy + ggBrakeCtrl.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("localbrake:")) // hamulec pomocniczy + ggLocalBrake.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("manualbrake:")) // hamulec reczny + ggManualBrake.Load(Parser, DynamicObject->mdKabina); + // sekcja przelacznikow obrotowych + else if (str == AnsiString("brakeprofile_sw:")) // przelacznik tow/osob/posp + ggBrakeProfileCtrl.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("brakeprofileg_sw:")) // przelacznik tow/osob + ggBrakeProfileG.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("brakeprofiler_sw:")) // przelacznik osob/posp + ggBrakeProfileR.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("maxcurrent_sw:")) // przelacznik rozruchu + ggMaxCurrentCtrl.Load(Parser, DynamicObject->mdKabina); + // SEKCJA przyciskow sprezynujacych + else if (str == + AnsiString( + "main_off_bt:")) // przycisk wylaczajacy (w EU07 wyl szybki czerwony) + ggMainOffButton.Load(Parser, DynamicObject->mdKabina); + else if (str == + AnsiString("main_on_bt:")) // przycisk wlaczajacy (w EU07 wyl szybki zielony) + ggMainOnButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("security_reset_bt:")) // przycisk zbijajacy SHP/czuwak + ggSecurityResetButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("releaser_bt:")) // przycisk odluzniacza + ggReleaserButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("releaser_bt:")) // przycisk odluzniacza + ggReleaserButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("antislip_bt:")) // przycisk antyposlizgowy + ggAntiSlipButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("horn_bt:")) // dzwignia syreny + ggHornButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("fuse_bt:")) // bezp. nadmiarowy + ggFuseButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("converterfuse_bt:")) // hunter-261211: odblokowanie + // przekaznika nadm. przetw. i ogrz. + ggConverterFuseButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("stlinoff_bt:")) // st. liniowe + ggStLinOffButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("door_left_sw:")) // drzwi lewe + ggDoorLeftButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("door_right_sw:")) // drzwi prawe + ggDoorRightButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("departure_signal_bt:")) // sygnal odjazdu + ggDepartureSignalButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("upperlight_sw:")) // swiatlo + ggUpperLightButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("leftlight_sw:")) // swiatlo + ggLeftLightButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("rightlight_sw:")) // swiatlo + ggRightLightButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("leftend_sw:")) // swiatlo + ggLeftEndLightButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("rightend_sw:")) // swiatlo + ggRightEndLightButton.Load(Parser, DynamicObject->mdKabina); + //--------------------- + // hunter-230112: przelaczniki swiatel tylnich + else if (str == AnsiString("rearupperlight_sw:")) // swiatlo + ggRearUpperLightButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("rearleftlight_sw:")) // swiatlo + ggRearLeftLightButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("rearrightlight_sw:")) // swiatlo + ggRearRightLightButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("rearleftend_sw:")) // swiatlo + ggRearLeftEndLightButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("rearrightend_sw:")) // swiatlo + ggRearRightEndLightButton.Load(Parser, DynamicObject->mdKabina); + //------------------ + else if (str == AnsiString("compressor_sw:")) // sprezarka + ggCompressorButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("converter_sw:")) // przetwornica + ggConverterButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("converteroff_sw:")) // przetwornica wyl + ggConverterOffButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("main_sw:")) // wyl szybki (ezt) + ggMainButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("radio_sw:")) // radio + ggRadioButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("pantfront_sw:")) // patyk przedni + ggPantFrontButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("pantrear_sw:")) // patyk tylny + ggPantRearButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("pantfrontoff_sw:")) // patyk przedni w dol + ggPantFrontButtonOff.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("pantalloff_sw:")) // patyk przedni w dol + ggPantAllDownButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("trainheating_sw:")) // grzanie skladu + ggTrainHeatingButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("signalling_sw:")) // Sygnalizacja hamowania + ggSignallingButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("door_signalling_sw:")) // Sygnalizacja blokady drzwi + ggDoorSignallingButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("nextcurrent_sw:")) // grzanie skladu + ggNextCurrentButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("cablight_sw:")) // hunter-091012: swiatlo w kabinie + ggCabLightButton.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("cablightdim_sw:")) + ggCabLightDimButton.Load( + Parser, + DynamicObject->mdKabina); // hunter-091012: przyciemnienie swiatla w kabinie + // ABu 090305: uniwersalne przyciski lub inne rzeczy + else if (str == AnsiString("universal1:")) + ggUniversal1Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + else if (str == AnsiString("universal2:")) + ggUniversal2Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + else if (str == AnsiString("universal3:")) + ggUniversal3Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + else if (str == AnsiString("universal4:")) + ggUniversal4Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + // SEKCJA WSKAZNIKOW + else if ((str == AnsiString("tachometer:")) || (str == AnsiString("tachometerb:"))) + { // predkosciomierz wskazówkowy z szarpaniem + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(&fTachoVelocityJump); + } + else if (str == AnsiString("tachometern:")) + { // predkosciomierz wskazówkowy bez szarpania + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(&fTachoVelocity); + } + else if (str == AnsiString("tachometerd:")) + { // predkosciomierz cyfrowy + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(&fTachoVelocity); + } + else if ((str == AnsiString("hvcurrent1:")) || (str == AnsiString("hvcurrent1b:"))) + { // 1szy amperomierz + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(fHCurrent + 1); + } + else if ((str == AnsiString("hvcurrent2:")) || (str == AnsiString("hvcurrent2b:"))) + { // 2gi amperomierz + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(fHCurrent + 2); + } + else if ((str == AnsiString("hvcurrent3:")) || (str == AnsiString("hvcurrent3b:"))) + { // 3ci amperomierz + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(fHCurrent + 3); + } + else if ((str == AnsiString("hvcurrent:")) || (str == AnsiString("hvcurrentb:"))) + { // amperomierz calkowitego pradu + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(fHCurrent); + } + else if ((str == AnsiString("brakepress:")) || (str == AnsiString("brakepressb:"))) + { // manometr cylindrow hamulcowych //Ra 2014-08: przeniesione do TCab + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina, NULL, 0.1); + gg->AssignDouble(&mvOccupied->BrakePress); + } + else if ((str == AnsiString("pipepress:")) || (str == AnsiString("pipepressb:"))) + { // manometr przewodu hamulcowego + TGauge *gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina, NULL, 0.1); + gg->AssignDouble(&mvOccupied->PipePress); + } + else if (str == + AnsiString( + "limpipepress:")) // manometr zbiornika sterujacego zaworu maszynisty + ggZbS.Load(Parser, DynamicObject->mdKabina, NULL, 0.1); + else if (str == AnsiString("cntrlpress:")) + { // manometr zbiornika kontrolnego/rorządu + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina, NULL, 0.1); + gg->AssignDouble(&mvControlled->PantPress); + } + else if ((str == AnsiString("compressor:")) || (str == AnsiString("compressorb:"))) + { // manometr sprezarki/zbiornika glownego + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina, NULL, 0.1); + gg->AssignDouble(&mvOccupied->Compressor); + } + // yB - dla drugiej sekcji + else if (str == AnsiString("hvbcurrent1:")) // 1szy amperomierz + ggI1B.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("hvbcurrent2:")) // 2gi amperomierz + ggI2B.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("hvbcurrent3:")) // 3ci amperomierz + ggI3B.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("hvbcurrent:")) // amperomierz calkowitego pradu + ggItotalB.Load(Parser, DynamicObject->mdKabina); + //************************************************************* + else if (str == AnsiString("clock:")) // zegar analogowy + { + if (Parser->GetNextSymbol() == AnsiString("analog")) + { + // McZapkie-300302: zegarek + ggClockSInd.Init(DynamicObject->mdKabina->GetFromName("ClockShand"), gt_Rotate, + 0.016666667, 0, 0); + ggClockMInd.Init(DynamicObject->mdKabina->GetFromName("ClockMhand"), gt_Rotate, + 0.016666667, 0, 0); + ggClockHInd.Init(DynamicObject->mdKabina->GetFromName("ClockHhand"), gt_Rotate, + 0.083333333, 0, 0); + } + } + else if (str == AnsiString("evoltage:")) // woltomierz napiecia silnikow + ggEngineVoltage.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("hvoltage:")) + { // woltomierz wysokiego napiecia + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(&fHVoltage); + } + else if (str == AnsiString("lvoltage:")) // woltomierz niskiego napiecia + ggLVoltage.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("enrot1m:")) + { // obrotomierz + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(fEngine + 1); + } // ggEnrot1m.Load(Parser,DynamicObject->mdKabina); + else if (str == AnsiString("enrot2m:")) + { // obrotomierz + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(fEngine + 2); + } // ggEnrot2m.Load(Parser,DynamicObject->mdKabina); + else if (str == AnsiString("enrot3m:")) + { // obrotomierz + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignFloat(fEngine + 3); + } // ggEnrot3m.Load(Parser,DynamicObject->mdKabina); + else if (str == AnsiString("engageratio:")) + { // np. ciśnienie sterownika sprzęgła + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignDouble(&mvControlled->dizel_engage); + } // ggEngageRatio.Load(Parser,DynamicObject->mdKabina); + else if (str == AnsiString("maingearstatus:")) // np. ciśnienie sterownika skrzyni + // biegów + ggMainGearStatus.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("ignitionkey:")) // + ggIgnitionKey.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("distcounter:")) + { // Ra 2014-07: licznik kilometrów + gg = Cabine[cabindex].Gauge(-1); // pierwsza wolna gałka + gg->Load(Parser, DynamicObject->mdKabina); + gg->AssignDouble(&mvControlled->DistCounter); + } + // SEKCJA LAMPEK + else if (str == AnsiString("i-maxft:")) + btLampkaMaxSila.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-maxftt:")) + btLampkaPrzekrMaxSila.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-radio:")) + btLampkaRadio.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-manual_brake:")) + btLampkaHamulecReczny.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-door_blocked:")) + btLampkaBlokadaDrzwi.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-slippery:")) + btLampkaPoslizg.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-contactors:")) + btLampkaStyczn.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-conv_ovld:")) + btLampkaNadmPrzetw.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-converter:")) + btLampkaPrzetw.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-diff_relay:")) + btLampkaPrzekRozn.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-diff_relay2:")) + btLampkaPrzekRoznPom.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-motor_ovld:")) + btLampkaNadmSil.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-train_controll:")) + btLampkaUkrotnienie.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-brake_delay_r:")) + btLampkaHamPosp.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-mainbreaker:")) + btLampkaWylSzybki.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-vent_ovld:")) + btLampkaNadmWent.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-comp_ovld:")) + btLampkaNadmSpr.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-resistors:")) + btLampkaOpory.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-no_resistors:")) + btLampkaBezoporowa.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-no_resistors_b:")) + btLampkaBezoporowaB.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-highcurrent:")) + btLampkaWysRozr.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-universal3:")) + { + btLampkaUniversal3.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + LampkaUniversal3_typ = 0; + } + else if (str == AnsiString("i-universal3_M:")) + { + btLampkaUniversal3.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + LampkaUniversal3_typ = 1; + } + else if (str == AnsiString("i-universal3_C:")) + { + btLampkaUniversal3.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + LampkaUniversal3_typ = 2; + } + else if (str == AnsiString("i-vent_trim:")) + btLampkaWentZaluzje.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-trainheating:")) + btLampkaOgrzewanieSkladu.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-security_aware:")) + btLampkaCzuwaka.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-security_cabsignal:")) + btLampkaSHP.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-door_left:")) + btLampkaDoorLeft.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-door_right:")) + btLampkaDoorRight.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-departure_signal:")) + btLampkaDepartureSignal.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-reserve:")) + btLampkaRezerwa.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-scnd:")) + btLampkaBoczniki.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-scnd1:")) + btLampkaBocznik1.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-scnd2:")) + btLampkaBocznik2.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-scnd3:")) + btLampkaBocznik3.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-scnd4:")) + btLampkaBocznik4.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-braking:")) + btLampkaHamienie.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-braking-ezt:")) + btLampkaHamowanie1zes.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-braking-ezt2:")) + btLampkaHamowanie2zes.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-compressor:")) + btLampkaSprezarka.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-compressorb:")) + btLampkaSprezarkaB.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-voltbrake:")) + btLampkaNapNastHam.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-mainbreakerb:")) + btLampkaWylSzybkiB.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-resistorsb:")) + btLampkaOporyB.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-contactorsb:")) + btLampkaStycznB.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-conv_ovldb:")) + btLampkaNadmPrzetwB.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-converterb:")) + btLampkaPrzetwB.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-forward:")) + btLampkaForward.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-backward:")) + btLampkaBackward.Load(Parser, DynamicObject->mdKabina); + else if (str == AnsiString("i-cablight:")) // hunter-171012 + btCabLight.Load(Parser, DynamicObject->mdKabina); + // btLampkaUnknown.Init("unknown",mdKabina,false); + } } else - ggMainCtrl.Load(Parser,DynamicObject->mdKabina); - } - else if (str==AnsiString("mainctrlact:")) //zabek pozycji aktualnej - ggMainCtrlAct.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("scndctrl:")) //bocznik - ggScndCtrl.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("dirkey:")) //klucz kierunku - ggDirKey.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("brakectrl:")) //hamulec zasadniczy - ggBrakeCtrl.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("localbrake:")) //hamulec pomocniczy - ggLocalBrake.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("manualbrake:")) //hamulec reczny - ggManualBrake.Load(Parser,DynamicObject->mdKabina); - //sekcja przelacznikow obrotowych - else if (str==AnsiString("brakeprofile_sw:")) //przelacznik tow/osob/posp - ggBrakeProfileCtrl.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("brakeprofileg_sw:")) //przelacznik tow/osob - ggBrakeProfileG.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("brakeprofiler_sw:")) //przelacznik osob/posp - ggBrakeProfileR.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("maxcurrent_sw:")) //przelacznik rozruchu - ggMaxCurrentCtrl.Load(Parser,DynamicObject->mdKabina); - //SEKCJA przyciskow sprezynujacych - else if (str==AnsiString("main_off_bt:")) //przycisk wylaczajacy (w EU07 wyl szybki czerwony) - ggMainOffButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("main_on_bt:")) //przycisk wlaczajacy (w EU07 wyl szybki zielony) - ggMainOnButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("security_reset_bt:")) //przycisk zbijajacy SHP/czuwak - ggSecurityResetButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("releaser_bt:")) //przycisk odluzniacza - ggReleaserButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("releaser_bt:")) //przycisk odluzniacza - ggReleaserButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("antislip_bt:")) //przycisk antyposlizgowy - ggAntiSlipButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("horn_bt:")) //dzwignia syreny - ggHornButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("fuse_bt:")) //bezp. nadmiarowy - ggFuseButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("converterfuse_bt:")) //hunter-261211: odblokowanie przekaznika nadm. przetw. i ogrz. - ggConverterFuseButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("stlinoff_bt:")) //st. liniowe - ggStLinOffButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("door_left_sw:")) //drzwi lewe - ggDoorLeftButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("door_right_sw:")) //drzwi prawe - ggDoorRightButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("departure_signal_bt:")) //sygnal odjazdu - ggDepartureSignalButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("upperlight_sw:")) //swiatlo - ggUpperLightButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("leftlight_sw:")) //swiatlo - ggLeftLightButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("rightlight_sw:")) //swiatlo - ggRightLightButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("leftend_sw:")) //swiatlo - ggLeftEndLightButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("rightend_sw:")) //swiatlo - ggRightEndLightButton.Load(Parser,DynamicObject->mdKabina); - //--------------------- - //hunter-230112: przelaczniki swiatel tylnich - else if (str==AnsiString("rearupperlight_sw:")) //swiatlo - ggRearUpperLightButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("rearleftlight_sw:")) //swiatlo - ggRearLeftLightButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("rearrightlight_sw:")) //swiatlo - ggRearRightLightButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("rearleftend_sw:")) //swiatlo - ggRearLeftEndLightButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("rearrightend_sw:")) //swiatlo - ggRearRightEndLightButton.Load(Parser,DynamicObject->mdKabina); - //------------------ - else if (str==AnsiString("compressor_sw:")) //sprezarka - ggCompressorButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("converter_sw:")) //przetwornica - ggConverterButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("converteroff_sw:")) //przetwornica wyl - ggConverterOffButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("main_sw:")) //wyl szybki (ezt) - ggMainButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("radio_sw:")) //radio - ggRadioButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("pantfront_sw:")) //patyk przedni - ggPantFrontButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("pantrear_sw:")) //patyk tylny - ggPantRearButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("pantfrontoff_sw:")) //patyk przedni w dol - ggPantFrontButtonOff.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("pantalloff_sw:")) //patyk przedni w dol - ggPantAllDownButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("trainheating_sw:")) //grzanie skladu - ggTrainHeatingButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("signalling_sw:")) //Sygnalizacja hamowania - ggSignallingButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("door_signalling_sw:")) //Sygnalizacja blokady drzwi - ggDoorSignallingButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("nextcurrent_sw:")) //grzanie skladu - ggNextCurrentButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("cablight_sw:")) //hunter-091012: swiatlo w kabinie - ggCabLightButton.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("cablightdim_sw:")) - ggCabLightDimButton.Load(Parser,DynamicObject->mdKabina); //hunter-091012: przyciemnienie swiatla w kabinie - //ABu 090305: uniwersalne przyciski lub inne rzeczy - else if (str==AnsiString("universal1:")) - ggUniversal1Button.Load(Parser,DynamicObject->mdKabina,DynamicObject->mdModel); - else if (str==AnsiString("universal2:")) - ggUniversal2Button.Load(Parser,DynamicObject->mdKabina,DynamicObject->mdModel); - else if (str==AnsiString("universal3:")) - ggUniversal3Button.Load(Parser,DynamicObject->mdKabina,DynamicObject->mdModel); - else if (str==AnsiString("universal4:")) - ggUniversal4Button.Load(Parser,DynamicObject->mdKabina,DynamicObject->mdModel); - //SEKCJA WSKAZNIKOW - else if ((str==AnsiString("tachometer:"))||(str==AnsiString("tachometerb:"))) - {//predkosciomierz wskazówkowy z szarpaniem - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(&fTachoVelocityJump); - } - else if (str==AnsiString("tachometern:")) - {//predkosciomierz wskazówkowy bez szarpania - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(&fTachoVelocity); - } - else if (str==AnsiString("tachometerd:")) - {//predkosciomierz cyfrowy - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(&fTachoVelocity); - } - else if ((str==AnsiString("hvcurrent1:"))||(str==AnsiString("hvcurrent1b:"))) - {//1szy amperomierz - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(fHCurrent+1); - } - else if ((str==AnsiString("hvcurrent2:"))||(str==AnsiString("hvcurrent2b:"))) - {//2gi amperomierz - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(fHCurrent+2); - } - else if ((str==AnsiString("hvcurrent3:"))||(str==AnsiString("hvcurrent3b:"))) - {//3ci amperomierz - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(fHCurrent+3); - } - else if ((str==AnsiString("hvcurrent:"))||(str==AnsiString("hvcurrentb:"))) - {//amperomierz calkowitego pradu - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(fHCurrent); - } - else if ((str==AnsiString("brakepress:"))||(str==AnsiString("brakepressb:"))) - {//manometr cylindrow hamulcowych //Ra 2014-08: przeniesione do TCab - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina,NULL,0.1); - gg->AssignDouble(&mvOccupied->BrakePress); - } - else if ((str==AnsiString("pipepress:"))||(str==AnsiString("pipepressb:"))) - {//manometr przewodu hamulcowego - TGauge *gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina,NULL,0.1); - gg->AssignDouble(&mvOccupied->PipePress); - } - else if (str==AnsiString("limpipepress:")) //manometr zbiornika sterujacego zaworu maszynisty - ggZbS.Load(Parser,DynamicObject->mdKabina,NULL,0.1); - else if (str==AnsiString("cntrlpress:")) - {//manometr zbiornika kontrolnego/rorządu - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina,NULL,0.1); - gg->AssignDouble(&mvControlled->PantPress); - } - else if ((str==AnsiString("compressor:"))||(str==AnsiString("compressorb:"))) - {//manometr sprezarki/zbiornika glownego - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina,NULL,0.1); - gg->AssignDouble(&mvOccupied->Compressor); - } - //yB - dla drugiej sekcji - else if (str==AnsiString("hvbcurrent1:")) //1szy amperomierz - ggI1B.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("hvbcurrent2:")) //2gi amperomierz - ggI2B.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("hvbcurrent3:")) //3ci amperomierz - ggI3B.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("hvbcurrent:")) //amperomierz calkowitego pradu - ggItotalB.Load(Parser,DynamicObject->mdKabina); - //************************************************************* - else if (str==AnsiString("clock:")) //zegar analogowy - { - if (Parser->GetNextSymbol()==AnsiString("analog")) - { - //McZapkie-300302: zegarek - ggClockSInd.Init(DynamicObject->mdKabina->GetFromName("ClockShand"),gt_Rotate,0.016666667,0,0); - ggClockMInd.Init(DynamicObject->mdKabina->GetFromName("ClockMhand"),gt_Rotate,0.016666667,0,0); - ggClockHInd.Init(DynamicObject->mdKabina->GetFromName("ClockHhand"),gt_Rotate,0.083333333,0,0); - } - } - else if (str==AnsiString("evoltage:")) //woltomierz napiecia silnikow - ggEngineVoltage.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("hvoltage:")) - {//woltomierz wysokiego napiecia - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(&fHVoltage); - } - else if (str==AnsiString("lvoltage:")) //woltomierz niskiego napiecia - ggLVoltage.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("enrot1m:")) - {//obrotomierz - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(fEngine+1); - } //ggEnrot1m.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("enrot2m:")) - {//obrotomierz - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(fEngine+2); - } //ggEnrot2m.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("enrot3m:")) - {//obrotomierz - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignFloat(fEngine+3); - } //ggEnrot3m.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("engageratio:")) - {//np. ciśnienie sterownika sprzęgła - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignDouble(&mvControlled->dizel_engage); - } //ggEngageRatio.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("maingearstatus:")) //np. ciśnienie sterownika skrzyni biegów - ggMainGearStatus.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("ignitionkey:")) // - ggIgnitionKey.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("distcounter:")) - {//Ra 2014-07: licznik kilometrów - gg=Cabine[cabindex].Gauge(-1); //pierwsza wolna gałka - gg->Load(Parser,DynamicObject->mdKabina); - gg->AssignDouble(&mvControlled->DistCounter); - } - //SEKCJA LAMPEK - else if (str==AnsiString("i-maxft:")) - btLampkaMaxSila.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-maxftt:")) - btLampkaPrzekrMaxSila.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-radio:")) - btLampkaRadio.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-manual_brake:")) - btLampkaHamulecReczny.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-door_blocked:")) - btLampkaBlokadaDrzwi.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-slippery:")) - btLampkaPoslizg.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-contactors:")) - btLampkaStyczn.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-conv_ovld:")) - btLampkaNadmPrzetw.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-converter:")) - btLampkaPrzetw.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-diff_relay:")) - btLampkaPrzekRozn.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-diff_relay2:")) - btLampkaPrzekRoznPom.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-motor_ovld:")) - btLampkaNadmSil.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-train_controll:")) - btLampkaUkrotnienie.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-brake_delay_r:")) - btLampkaHamPosp.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-mainbreaker:")) - btLampkaWylSzybki.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-vent_ovld:")) - btLampkaNadmWent.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-comp_ovld:")) - btLampkaNadmSpr.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-resistors:")) - btLampkaOpory.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-no_resistors:")) - btLampkaBezoporowa.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-no_resistors_b:")) - btLampkaBezoporowaB.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-highcurrent:")) - btLampkaWysRozr.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-universal3:")) - { - btLampkaUniversal3.Load(Parser,DynamicObject->mdKabina,DynamicObject->mdModel); - LampkaUniversal3_typ=0; - } - else if (str==AnsiString("i-universal3_M:")) - { - btLampkaUniversal3.Load(Parser,DynamicObject->mdKabina,DynamicObject->mdModel); - LampkaUniversal3_typ=1; - } - else if (str==AnsiString("i-universal3_C:")) - { - btLampkaUniversal3.Load(Parser,DynamicObject->mdKabina,DynamicObject->mdModel); - LampkaUniversal3_typ=2; - } - else if (str==AnsiString("i-vent_trim:")) - btLampkaWentZaluzje.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-trainheating:")) - btLampkaOgrzewanieSkladu.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-security_aware:")) - btLampkaCzuwaka.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-security_cabsignal:")) - btLampkaSHP.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-door_left:")) - btLampkaDoorLeft.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-door_right:")) - btLampkaDoorRight.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-departure_signal:")) - btLampkaDepartureSignal.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-reserve:")) - btLampkaRezerwa.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-scnd:")) - btLampkaBoczniki.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-scnd1:")) - btLampkaBocznik1.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-scnd2:")) - btLampkaBocznik2.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-scnd3:")) - btLampkaBocznik3.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-scnd4:")) - btLampkaBocznik4.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-braking:")) - btLampkaHamienie.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-braking-ezt:")) - btLampkaHamowanie1zes.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-braking-ezt2:")) - btLampkaHamowanie2zes.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-compressor:")) - btLampkaSprezarka.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-compressorb:")) - btLampkaSprezarkaB.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-voltbrake:")) - btLampkaNapNastHam.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-mainbreakerb:")) - btLampkaWylSzybkiB.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-resistorsb:")) - btLampkaOporyB.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-contactorsb:")) - btLampkaStycznB.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-conv_ovldb:")) - btLampkaNadmPrzetwB.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-converterb:")) - btLampkaPrzetwB.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-forward:")) - btLampkaForward.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-backward:")) - btLampkaBackward.Load(Parser,DynamicObject->mdKabina); - else if (str==AnsiString("i-cablight:")) //hunter-171012 - btCabLight.Load(Parser,DynamicObject->mdKabina); - //btLampkaUnknown.Init("unknown",mdKabina,false); - } - } - else - {delete Parser; - return false; - } - //ABu 050205: tego wczesniej nie bylo: - delete Parser; - if (DynamicObject->mdKabina) - { - DynamicObject->mdKabina->Init(); //obrócenie modelu oraz optymalizacja, również zapisanie binarnego - return true; - } - return AnsiCompareStr(str,AnsiString("none")); + { + delete Parser; + return false; + } + // ABu 050205: tego wczesniej nie bylo: + delete Parser; + if (DynamicObject->mdKabina) + { + DynamicObject->mdKabina + ->Init(); // obrócenie modelu oraz optymalizacja, również zapisanie binarnego + return true; + } + return AnsiCompareStr(str, AnsiString("none")); } void __fastcall TTrain::MechStop() -{//likwidacja ruchu kamery w kabinie (po powrocie przez [F4]) - pMechPosition=vector3(0,0,0); - pMechShake=vector3(0,0,0); - vMechMovement=vector3(0,0,0); - vMechVelocity=vector3(0,0,0); //tu zostawały jakieś ułamki, powodujące uciekanie kamery +{ // likwidacja ruchu kamery w kabinie (po powrocie przez [F4]) + pMechPosition = vector3(0, 0, 0); + pMechShake = vector3(0, 0, 0); + vMechMovement = vector3(0, 0, 0); + vMechVelocity = vector3(0, 0, 0); // tu zostawały jakieś ułamki, powodujące uciekanie kamery }; vector3 __fastcall TTrain::MirrorPosition(bool lewe) -{//zwraca współrzędne widoku kamery z lusterka - switch (iCabn) - { - case 1: //przednia (1) - return DynamicObject->mMatrix*vector3(lewe?Cabine[iCabn].CabPos2.x:Cabine[iCabn].CabPos1.x,1.5+Cabine[iCabn].CabPos1.y,Cabine[iCabn].CabPos2.z); - case 2: //tylna (-1) - return DynamicObject->mMatrix*vector3(lewe?Cabine[iCabn].CabPos1.x:Cabine[iCabn].CabPos2.x,1.5+Cabine[iCabn].CabPos1.y,Cabine[iCabn].CabPos1.z); - } - return DynamicObject->GetPosition(); //współrzędne środka pojazdu +{ // zwraca współrzędne widoku kamery z lusterka + switch (iCabn) + { + case 1: // przednia (1) + return DynamicObject->mMatrix * + vector3(lewe ? Cabine[iCabn].CabPos2.x : Cabine[iCabn].CabPos1.x, + 1.5 + Cabine[iCabn].CabPos1.y, Cabine[iCabn].CabPos2.z); + case 2: // tylna (-1) + return DynamicObject->mMatrix * + vector3(lewe ? Cabine[iCabn].CabPos1.x : Cabine[iCabn].CabPos2.x, + 1.5 + Cabine[iCabn].CabPos1.y, Cabine[iCabn].CabPos1.z); + } + return DynamicObject->GetPosition(); // współrzędne środka pojazdu }; void __fastcall TTrain::DynamicSet(TDynamicObject *d) -{//taka proteza: chcę podłączyć kabinę EN57 bezpośrednio z silnikowym, aby nie robić tego przez ukrotnienie - //drugi silnikowy i tak musi być ukrotniony, podobnie jak kolejna jednostka - //problem się robi ze światłami, które będą zapalane w silnikowym, ale muszą świecić się w rozrządczych - //dla EZT światła czołowe będą "zapalane w silnikowym", ale widziane z rozrządczych - //również wczytywanie MMD powinno dotyczyć aktualnego członu - //problematyczna może być kwestia wybranej kabiny (w silnikowym...) - //jeśli silnikowy będzie zapięty odwrotnie (tzn. -1), to i tak powinno jeździć dobrze - //również hamowanie wykonuje się zaworem w członie, a nie w silnikowym... - DynamicObject=d; //jedyne miejsce zmiany - mvOccupied=mvControlled=d?DynamicObject->MoverParameters:NULL; //albo silnikowy w EZT - if (!DynamicObject) return; - if (mvControlled->TrainType&dt_EZT) //na razie dotyczy to EZT - if (DynamicObject->NextConnected?mvControlled->Couplers[1].AllowedFlag&ctrain_depot:false) - {//gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy) - if ((mvControlled->Power<1.0)&&(mvControlled->Couplers[1].Connected->Power>1.0)) //my nie mamy mocy, ale ten drugi ma - mvControlled=DynamicObject->NextConnected->MoverParameters; //będziemy sterować tym z mocą - } - else if (DynamicObject->PrevConnected?mvControlled->Couplers[0].AllowedFlag&ctrain_depot:false) - {//gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy) - if ((mvControlled->Power<1.0)&&(mvControlled->Couplers[0].Connected->Power>1.0)) //my nie mamy mocy, ale ten drugi ma - mvControlled=DynamicObject->PrevConnected->MoverParameters; //będziemy sterować tym z mocą - } - mvSecond=NULL; //gdyby się nic nie znalazło - if (mvOccupied->Power>1.0) //dwuczłonowe lub ukrotnienia, żeby nie szukać każdorazowo - if (mvOccupied->Couplers[1].Connected?mvOccupied->Couplers[1].AllowedFlag&ctrain_controll:false) - {//gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy) - if (mvOccupied->Couplers[1].Connected->Power>1.0) //ten drugi ma moc - mvSecond=(TMoverParameters*)mvOccupied->Couplers[1].Connected; //wskaźnik na drugiego - } - else if (mvOccupied->Couplers[0].Connected?mvOccupied->Couplers[0].AllowedFlag&ctrain_controll:false) - {//gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy) - if (mvOccupied->Couplers[0].Connected->Power>1.0) //ale ten drugi ma moc - mvSecond=(TMoverParameters*)mvOccupied->Couplers[0].Connected; //wskaźnik na drugiego - } +{ // taka proteza: chcę podłączyć kabinę EN57 bezpośrednio z silnikowym, aby nie robić tego przez + // ukrotnienie + // drugi silnikowy i tak musi być ukrotniony, podobnie jak kolejna jednostka + // problem się robi ze światłami, które będą zapalane w silnikowym, ale muszą świecić się w + // rozrządczych + // dla EZT światła czołowe będą "zapalane w silnikowym", ale widziane z rozrządczych + // również wczytywanie MMD powinno dotyczyć aktualnego członu + // problematyczna może być kwestia wybranej kabiny (w silnikowym...) + // jeśli silnikowy będzie zapięty odwrotnie (tzn. -1), to i tak powinno jeździć dobrze + // również hamowanie wykonuje się zaworem w członie, a nie w silnikowym... + DynamicObject = d; // jedyne miejsce zmiany + mvOccupied = mvControlled = d ? DynamicObject->MoverParameters : NULL; // albo silnikowy w EZT + if (!DynamicObject) + return; + if (mvControlled->TrainType & dt_EZT) // na razie dotyczy to EZT + if (DynamicObject->NextConnected ? mvControlled->Couplers[1].AllowedFlag & ctrain_depot : + false) + { // gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy) + if ((mvControlled->Power < 1.0) && (mvControlled->Couplers[1].Connected->Power > + 1.0)) // my nie mamy mocy, ale ten drugi ma + mvControlled = + DynamicObject->NextConnected->MoverParameters; // będziemy sterować tym z mocą + } + else if (DynamicObject->PrevConnected ? + mvControlled->Couplers[0].AllowedFlag & ctrain_depot : + false) + { // gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy) + if ((mvControlled->Power < 1.0) && (mvControlled->Couplers[0].Connected->Power > + 1.0)) // my nie mamy mocy, ale ten drugi ma + mvControlled = + DynamicObject->PrevConnected->MoverParameters; // będziemy sterować tym z mocą + } + mvSecond = NULL; // gdyby się nic nie znalazło + if (mvOccupied->Power > 1.0) // dwuczłonowe lub ukrotnienia, żeby nie szukać każdorazowo + if (mvOccupied->Couplers[1].Connected ? + mvOccupied->Couplers[1].AllowedFlag & ctrain_controll : + false) + { // gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy) + if (mvOccupied->Couplers[1].Connected->Power > 1.0) // ten drugi ma moc + mvSecond = + (TMoverParameters *)mvOccupied->Couplers[1].Connected; // wskaźnik na drugiego + } + else if (mvOccupied->Couplers[0].Connected ? + mvOccupied->Couplers[0].AllowedFlag & ctrain_controll : + false) + { // gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy) + if (mvOccupied->Couplers[0].Connected->Power > 1.0) // ale ten drugi ma moc + mvSecond = + (TMoverParameters *)mvOccupied->Couplers[0].Connected; // wskaźnik na drugiego + } }; void __fastcall TTrain::Silence() -{//wyciszenie dźwięków przy wychodzeniu - if (dsbNastawnikJazdy) dsbNastawnikJazdy->Stop(); - if (dsbNastawnikBocz) dsbNastawnikBocz->Stop(); - if (dsbRelay) dsbRelay->Stop(); - if (dsbPneumaticRelay) dsbPneumaticRelay->Stop(); - if (dsbSwitch) dsbSwitch->Stop(); - if (dsbPneumaticSwitch) dsbPneumaticSwitch->Stop(); - if (dsbReverserKey) dsbReverserKey->Stop(); - if (dsbCouplerAttach) dsbCouplerAttach->Stop(); - if (dsbCouplerDetach) dsbCouplerDetach->Stop(); - if (dsbDieselIgnition) dsbDieselIgnition->Stop(); - if (dsbDoorClose) dsbDoorClose->Stop(); - if (dsbDoorOpen) dsbDoorOpen->Stop(); - if (dsbPantUp) dsbPantUp->Stop(); - if (dsbPantDown) dsbPantDown->Stop(); - if (dsbWejscie_na_bezoporow) dsbWejscie_na_bezoporow->Stop(); - if (dsbWejscie_na_drugi_uklad) dsbWejscie_na_drugi_uklad->Stop(); - rsBrake.Stop(); - rsSlippery.Stop(); - rsHiss.Stop(); - rsHissU.Stop(); - rsHissE.Stop(); - rsHissX.Stop(); - rsHissT.Stop(); - rsSBHiss.Stop(); - rsRunningNoise.Stop(); - rsEngageSlippery.Stop(); - rsFadeSound.Stop(); - if (dsbHasler) dsbHasler->Stop(); //wyłączenie dźwięków opuszczanej kabiny - if (dsbBuzzer) dsbBuzzer->Stop(); - if (dsbSlipAlarm) dsbSlipAlarm->Stop(); //dźwięk alarmu przy poślizgu - //sConverter.Stop(); - //sSmallCompressor->Stop(); - if (dsbCouplerStretch) dsbCouplerStretch->Stop(); - if (dsbEN57_CouplerStretch) dsbEN57_CouplerStretch->Stop(); - if (dsbBufferClamp) dsbBufferClamp->Stop(); +{ // wyciszenie dźwięków przy wychodzeniu + if (dsbNastawnikJazdy) + dsbNastawnikJazdy->Stop(); + if (dsbNastawnikBocz) + dsbNastawnikBocz->Stop(); + if (dsbRelay) + dsbRelay->Stop(); + if (dsbPneumaticRelay) + dsbPneumaticRelay->Stop(); + if (dsbSwitch) + dsbSwitch->Stop(); + if (dsbPneumaticSwitch) + dsbPneumaticSwitch->Stop(); + if (dsbReverserKey) + dsbReverserKey->Stop(); + if (dsbCouplerAttach) + dsbCouplerAttach->Stop(); + if (dsbCouplerDetach) + dsbCouplerDetach->Stop(); + if (dsbDieselIgnition) + dsbDieselIgnition->Stop(); + if (dsbDoorClose) + dsbDoorClose->Stop(); + if (dsbDoorOpen) + dsbDoorOpen->Stop(); + if (dsbPantUp) + dsbPantUp->Stop(); + if (dsbPantDown) + dsbPantDown->Stop(); + if (dsbWejscie_na_bezoporow) + dsbWejscie_na_bezoporow->Stop(); + if (dsbWejscie_na_drugi_uklad) + dsbWejscie_na_drugi_uklad->Stop(); + rsBrake.Stop(); + rsSlippery.Stop(); + rsHiss.Stop(); + rsHissU.Stop(); + rsHissE.Stop(); + rsHissX.Stop(); + rsHissT.Stop(); + rsSBHiss.Stop(); + rsRunningNoise.Stop(); + rsEngageSlippery.Stop(); + rsFadeSound.Stop(); + if (dsbHasler) + dsbHasler->Stop(); // wyłączenie dźwięków opuszczanej kabiny + if (dsbBuzzer) + dsbBuzzer->Stop(); + if (dsbSlipAlarm) + dsbSlipAlarm->Stop(); // dźwięk alarmu przy poślizgu + // sConverter.Stop(); + // sSmallCompressor->Stop(); + if (dsbCouplerStretch) + dsbCouplerStretch->Stop(); + if (dsbEN57_CouplerStretch) + dsbEN57_CouplerStretch->Stop(); + if (dsbBufferClamp) + dsbBufferClamp->Stop(); }; - diff --git a/Train.h b/Train.h index b718e359..5b9878f7 100644 --- a/Train.h +++ b/Train.h @@ -17,106 +17,105 @@ #include "RealSound.h" #include "FadeSound.h" - // typedef enum {st_Off, st_Starting, st_On, st_ShuttingDown} T4State; -const int maxcab=2; +const int maxcab = 2; // const double fCzuwakTime= 90.0f; -const double fCzuwakBlink=0.15; -const float fConverterPrzekaznik=1.5; //hunter-261211: do przekaznika nadmiarowego przetwornicy - //0.33f +const double fCzuwakBlink = 0.15; +const float fConverterPrzekaznik = 1.5; // hunter-261211: do przekaznika nadmiarowego przetwornicy +// 0.33f // const double fBuzzerTime= 5.0f; -const float fHaslerTime=1.2; +const float fHaslerTime = 1.2; // const double fStycznTime= 0.5f; // const double fDblClickTime= 0.2f; class TCab { -public: - __fastcall TCab(); - __fastcall ~TCab(); - void __fastcall Init(double Initx1,double Inity1,double Initz1,double Initx2,double Inity2,double Initz2,bool InitEnabled,bool InitOccupied); - void __fastcall Load(TQueryParserComp *Parser); - vector3 CabPos1; - vector3 CabPos2; - bool bEnabled; - bool bOccupied; - double dimm_r, dimm_g, dimm_b; //McZapkie-120503: tlumienie swiatla - double intlit_r, intlit_g, intlit_b; //McZapkie-120503: oswietlenie kabiny - double intlitlow_r, intlitlow_g, intlitlow_b; //McZapkie-120503: przyciemnione oswietlenie kabiny -private: - //bool bChangePossible; - TGauge *ggList; //Ra 2014-08: lista animacji macierzowych (gałek) w kabinie - int iGaugesMax,iGauges; //ile miejsca w tablicy i ile jest w użyciu - TButton *btList; //Ra 2014-08: lista animacji dwustanowych (lampek) w kabinie - int iButtonsMax,iButtons; //ile miejsca w tablicy i ile jest w użyciu -public: - TGauge* __fastcall Gauge(int n=-1); //pobranie adresu obiektu - TButton* __fastcall Button(int n=-1); //pobranie adresu obiektu - void __fastcall Update(); + public: + __fastcall TCab(); + __fastcall ~TCab(); + void __fastcall Init(double Initx1, double Inity1, double Initz1, double Initx2, double Inity2, + double Initz2, bool InitEnabled, bool InitOccupied); + void __fastcall Load(TQueryParserComp *Parser); + vector3 CabPos1; + vector3 CabPos2; + bool bEnabled; + bool bOccupied; + double dimm_r, dimm_g, dimm_b; // McZapkie-120503: tlumienie swiatla + double intlit_r, intlit_g, intlit_b; // McZapkie-120503: oswietlenie kabiny + double intlitlow_r, intlitlow_g, + intlitlow_b; // McZapkie-120503: przyciemnione oswietlenie kabiny + private: + // bool bChangePossible; + TGauge *ggList; // Ra 2014-08: lista animacji macierzowych (gałek) w kabinie + int iGaugesMax, iGauges; // ile miejsca w tablicy i ile jest w użyciu + TButton *btList; // Ra 2014-08: lista animacji dwustanowych (lampek) w kabinie + int iButtonsMax, iButtons; // ile miejsca w tablicy i ile jest w użyciu + public: + TGauge *__fastcall Gauge(int n = -1); // pobranie adresu obiektu + TButton *__fastcall Button(int n = -1); // pobranie adresu obiektu + void __fastcall Update(); }; - class TTrain { -public: + public: bool CabChange(int iDirection); bool ActiveUniversal4; - bool ShowNextCurrent; //pokaz przd w podlaczonej lokomotywie (ET41) + bool ShowNextCurrent; // pokaz przd w podlaczonej lokomotywie (ET41) bool InitializeCab(int NewCabNo, AnsiString asFileName); __fastcall TTrain(); __fastcall ~TTrain(); -// bool __fastcall Init(TTrack *Track); -//McZapkie-010302 - bool __fastcall Init(TDynamicObject *NewDynamicObject,bool e3d=false); + // bool __fastcall Init(TTrack *Track); + // McZapkie-010302 + bool __fastcall Init(TDynamicObject *NewDynamicObject, bool e3d = false); void __fastcall OnKeyDown(int cKey); void __fastcall OnKeyUp(int cKey); -// bool __fastcall SHP() { fShpTimer= 0; }; + // bool __fastcall SHP() { fShpTimer= 0; }; inline vector3 __fastcall GetDirection() { return DynamicObject->VectorFront(); }; inline vector3 __fastcall GetUp() { return DynamicObject->VectorUp(); }; void __fastcall UpdateMechPosition(double dt); bool __fastcall Update(); void __fastcall MechStop(); -// virtual bool __fastcall RenderAlpha(); -//McZapkie-310302: ladowanie parametrow z pliku + // virtual bool __fastcall RenderAlpha(); + // McZapkie-310302: ladowanie parametrow z pliku bool __fastcall LoadMMediaFile(AnsiString asFileName); -private: //żeby go nic z zewnątrz nie przestawiało - TDynamicObject *DynamicObject; //przestawia zmiana pojazdu [F5] -private: //żeby go nic z zewnątrz nie przestawiało - TMoverParameters *mvControlled; //człon, w którym sterujemy silnikiem - TMoverParameters *mvOccupied; //człon, w którym sterujemy hamulcem - TMoverParameters *mvSecond; //drugi człon (ET40, ET41, ET42, ukrotnienia) - TMoverParameters *mvThird; //trzeci człon (SN61) -public: //reszta może być publiczna + private: //żeby go nic z zewnątrz nie przestawiało + TDynamicObject *DynamicObject; // przestawia zmiana pojazdu [F5] + private: //żeby go nic z zewnątrz nie przestawiało + TMoverParameters *mvControlled; // człon, w którym sterujemy silnikiem + TMoverParameters *mvOccupied; // człon, w którym sterujemy hamulcem + TMoverParameters *mvSecond; // drugi człon (ET40, ET41, ET42, ukrotnienia) + TMoverParameters *mvThird; // trzeci człon (SN61) + public: // reszta może być publiczna + // AnsiString asMessage; - //AnsiString asMessage; - -//McZapkie: definicje wskaźników -//Ra 2014-08: częsciowo przeniesione do tablicy w TCab + // McZapkie: definicje wskaźników + // Ra 2014-08: częsciowo przeniesione do tablicy w TCab TGauge ggZbS; TGauge ggClockSInd; TGauge ggClockMInd; TGauge ggClockHInd; - //TGauge ggHVoltage; + // TGauge ggHVoltage; TGauge ggLVoltage; - //TGauge ggEnrot1m; - //TGauge ggEnrot2m; - //TGauge ggEnrot3m; - //TGauge ggEngageRatio; + // TGauge ggEnrot1m; + // TGauge ggEnrot2m; + // TGauge ggEnrot3m; + // TGauge ggEngageRatio; TGauge ggMainGearStatus; TGauge ggEngineVoltage; - TGauge ggI1B; //drugi człon w postaci jawnej + TGauge ggI1B; // drugi człon w postaci jawnej TGauge ggI2B; TGauge ggI3B; TGauge ggItotalB; -//McZapkie: definicje regulatorow + // McZapkie: definicje regulatorow TGauge ggMainCtrl; TGauge ggMainCtrlAct; TGauge ggScndCtrl; @@ -125,20 +124,21 @@ public: //reszta mo TGauge ggBrakeCtrl; TGauge ggLocalBrake; TGauge ggManualBrake; - TGauge ggBrakeProfileCtrl; //nastawiacz GPR - przelacznik obrotowy - TGauge ggBrakeProfileG; //nastawiacz GP - hebelek towarowy - TGauge ggBrakeProfileR; //nastawiacz PR - hamowanie dwustopniowe + TGauge ggBrakeProfileCtrl; // nastawiacz GPR - przelacznik obrotowy + TGauge ggBrakeProfileG; // nastawiacz GP - hebelek towarowy + TGauge ggBrakeProfileR; // nastawiacz PR - hamowanie dwustopniowe TGauge ggMaxCurrentCtrl; TGauge ggMainOffButton; TGauge ggMainOnButton; - TGauge ggMainButton; //EZT + TGauge ggMainButton; // EZT TGauge ggSecurityResetButton; TGauge ggReleaserButton; TGauge ggAntiSlipButton; TGauge ggFuseButton; - TGauge ggConverterFuseButton; //hunter-261211: przycisk odblokowania nadmiarowego przetwornic i ogrzewania + TGauge ggConverterFuseButton; // hunter-261211: przycisk odblokowania nadmiarowego przetwornic i + // ogrzewania TGauge ggStLinOffButton; TGauge ggRadioButton; TGauge ggUpperLightButton; @@ -147,7 +147,7 @@ public: //reszta mo TGauge ggLeftEndLightButton; TGauge ggRightEndLightButton; - //hunter-230112: przelacznik swiatel tylnich + // hunter-230112: przelacznik swiatel tylnich TGauge ggRearUpperLightButton; TGauge ggRearLeftLightButton; TGauge ggRearRightLightButton; @@ -160,35 +160,35 @@ public: //reszta mo TGauge ggConverterButton; TGauge ggConverterOffButton; -//ABu 090305 - syrena i prad nastepnego czlonu + // ABu 090305 - syrena i prad nastepnego czlonu TGauge ggHornButton; TGauge ggNextCurrentButton; -//ABu 090305 - uniwersalne przyciski + // ABu 090305 - uniwersalne przyciski TGauge ggUniversal1Button; TGauge ggUniversal2Button; TGauge ggUniversal3Button; TGauge ggUniversal4Button; - TGauge ggCabLightButton; //hunter-091012: przelacznik oswietlania kabiny - TGauge ggCabLightDimButton; //hunter-091012: przelacznik przyciemnienia oswietlenia kabiny + TGauge ggCabLightButton; // hunter-091012: przelacznik oswietlania kabiny + TGauge ggCabLightDimButton; // hunter-091012: przelacznik przyciemnienia oswietlenia kabiny -//NBMX wrzesien 2003 - obsluga drzwi + // NBMX wrzesien 2003 - obsluga drzwi TGauge ggDoorLeftButton; TGauge ggDoorRightButton; TGauge ggDepartureSignalButton; -//Winger 160204 - obsluga pantografow - ZROBIC + // Winger 160204 - obsluga pantografow - ZROBIC TGauge ggPantFrontButton; TGauge ggPantRearButton; - TGauge ggPantFrontButtonOff; //EZT + TGauge ggPantFrontButtonOff; // EZT TGauge ggPantAllDownButton; -//Winger 020304 - wlacznik ogrzewania + // Winger 020304 - wlacznik ogrzewania TGauge ggTrainHeatingButton; TGauge ggSignallingButton; TGauge ggDoorSignallingButton; -// TModel3d *mdKabina; McZapkie-030303: to do dynobj - //TGauge ggDistCounter; //Ra 2014-07: licznik kilometrów - //TGauge ggVelocityDgt; //i od razu prędkościomierz + // TModel3d *mdKabina; McZapkie-030303: to do dynobj + // TGauge ggDistCounter; //Ra 2014-07: licznik kilometrów + // TGauge ggVelocityDgt; //i od razu prędkościomierz TButton btLampkaPoslizg; TButton btLampkaStyczn; @@ -200,32 +200,32 @@ public: //reszta mo TButton btLampkaWylSzybki; TButton btLampkaNadmWent; TButton btLampkaNadmSpr; -//yB: drugie lampki dla EP05 i ET42 - TButton btLampkaOporyB; - TButton btLampkaStycznB; - TButton btLampkaWylSzybkiB; - TButton btLampkaNadmPrzetwB; - TButton btLampkaPrzetwB; - //KURS90 lampki jazdy bezoporowej dla EU04 - TButton btLampkaBezoporowaB; - TButton btLampkaBezoporowa; - TButton btLampkaUkrotnienie; - TButton btLampkaHamPosp; - TButton btLampkaRadio; - TButton btLampkaHamowanie1zes; - TButton btLampkaHamowanie2zes; -// TButton btLampkaUnknown; + // yB: drugie lampki dla EP05 i ET42 + TButton btLampkaOporyB; + TButton btLampkaStycznB; + TButton btLampkaWylSzybkiB; + TButton btLampkaNadmPrzetwB; + TButton btLampkaPrzetwB; + // KURS90 lampki jazdy bezoporowej dla EU04 + TButton btLampkaBezoporowaB; + TButton btLampkaBezoporowa; + TButton btLampkaUkrotnienie; + TButton btLampkaHamPosp; + TButton btLampkaRadio; + TButton btLampkaHamowanie1zes; + TButton btLampkaHamowanie2zes; + // TButton btLampkaUnknown; TButton btLampkaOpory; TButton btLampkaWysRozr; TButton btLampkaUniversal3; - int LampkaUniversal3_typ; //ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw. + int LampkaUniversal3_typ; // ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw. bool LampkaUniversal3_st; - TButton btLampkaWentZaluzje; //ET22 + TButton btLampkaWentZaluzje; // ET22 TButton btLampkaOgrzewanieSkladu; TButton btLampkaSHP; - TButton btLampkaCzuwaka; //McZapkie-141102 + TButton btLampkaCzuwaka; // McZapkie-141102 TButton btLampkaRezerwa; -//youBy - jakies dodatkowe lampki + // youBy - jakies dodatkowe lampki TButton btLampkaNapNastHam; TButton btLampkaSprezarka; TButton btLampkaSprezarkaB; @@ -235,39 +235,39 @@ public: //reszta mo TButton btLampkaBocznik4; TButton btLampkaRadiotelefon; TButton btLampkaHamienie; - TButton btLampkaJazda; //Ra: nie używane -//KURS90 - TButton btLampkaBoczniki; - TButton btLampkaMaxSila; - TButton btLampkaPrzekrMaxSila; -// TButton bt; -// + TButton btLampkaJazda; // Ra: nie używane + // KURS90 + TButton btLampkaBoczniki; + TButton btLampkaMaxSila; + TButton btLampkaPrzekrMaxSila; + // TButton bt; + // TButton btLampkaDoorLeft; TButton btLampkaDoorRight; TButton btLampkaDepartureSignal; TButton btLampkaBlokadaDrzwi; TButton btLampkaHamulecReczny; - TButton btLampkaForward; //Ra: lampki w przód i w tył dla komputerowych kabin + TButton btLampkaForward; // Ra: lampki w przód i w tył dla komputerowych kabin TButton btLampkaBackward; - TButton btCabLight; //hunter-171012: lampa oswietlajaca kabine - //Ra 2013-12: wirtualne "lampki" do odbijania na haslerze w PoKeys - TButton btHaslerBrakes; //ciśnienie w cylindrach - TButton btHaslerCurrent; //prąd na silnikach + TButton btCabLight; // hunter-171012: lampa oswietlajaca kabine + // Ra 2013-12: wirtualne "lampki" do odbijania na haslerze w PoKeys + TButton btHaslerBrakes; // ciśnienie w cylindrach + TButton btHaslerCurrent; // prąd na silnikach vector3 pPosition; - vector3 pMechOffset; //driverNpos + vector3 pMechOffset; // driverNpos vector3 vMechMovement; vector3 pMechPosition; vector3 pMechShake; vector3 vMechVelocity; -//McZapkie: do poruszania sie po kabinie + // McZapkie: do poruszania sie po kabinie double fMechCroach; -//McZapkie: opis kabiny - obszar poruszania sie mechanika oraz zajetosc - TCab Cabine[maxcab+1]; //przedzial maszynowy, kabina 1 (A), kabina 2 (B) + // McZapkie: opis kabiny - obszar poruszania sie mechanika oraz zajetosc + TCab Cabine[maxcab + 1]; // przedzial maszynowy, kabina 1 (A), kabina 2 (B) int iCabn; TSpring MechSpring; - double fMechSpringX; //McZapkie-250303: parametry bujania + double fMechSpringX; // McZapkie-250303: parametry bujania double fMechSpringY; double fMechSpringZ; double fMechMaxSpring; @@ -275,40 +275,39 @@ public: //reszta mo double fMechPitch; PSound dsbNastawnikJazdy; - PSound dsbNastawnikBocz; //hunter-081211 + PSound dsbNastawnikBocz; // hunter-081211 PSound dsbRelay; PSound dsbPneumaticRelay; PSound dsbSwitch; PSound dsbPneumaticSwitch; - PSound dsbReverserKey; //hunter-121211 + PSound dsbReverserKey; // hunter-121211 - PSound dsbCouplerAttach; //Ra: w kabinie???? - PSound dsbCouplerDetach; //Ra: w kabinie??? + PSound dsbCouplerAttach; // Ra: w kabinie???? + PSound dsbCouplerDetach; // Ra: w kabinie??? - PSound dsbDieselIgnition; //Ra: w kabinie??? + PSound dsbDieselIgnition; // Ra: w kabinie??? - PSound dsbDoorClose; //Ra: w kabinie??? - PSound dsbDoorOpen; //Ra: w kabinie??? + PSound dsbDoorClose; // Ra: w kabinie??? + PSound dsbDoorOpen; // Ra: w kabinie??? -//Winger 010304 + // Winger 010304 PSound dsbPantUp; PSound dsbPantDown; PSound dsbWejscie_na_bezoporow; - PSound dsbWejscie_na_drugi_uklad; //hunter-081211: poprawka literowki + PSound dsbWejscie_na_drugi_uklad; // hunter-081211: poprawka literowki + // PSound dsbHiss1; + // PSound dsbHiss2; -// PSound dsbHiss1; - // PSound dsbHiss2; - -//McZapkie-280302 + // McZapkie-280302 TRealSound rsBrake; TRealSound rsSlippery; - TRealSound rsHiss; //upuszczanie - TRealSound rsHissU; //napelnianie - TRealSound rsHissE; //nagle - TRealSound rsHissX; //fala - TRealSound rsHissT; //czasowy + TRealSound rsHiss; // upuszczanie + TRealSound rsHissU; // napelnianie + TRealSound rsHissE; // nagle + TRealSound rsHissX; // fala + TRealSound rsHissT; // czasowy TRealSound rsSBHiss; TRealSound rsRunningNoise; TRealSound rsEngageSlippery; @@ -316,61 +315,62 @@ public: //reszta mo PSound dsbHasler; PSound dsbBuzzer; - PSound dsbSlipAlarm; //Bombardier 011010: alarm przy poslizgu dla 181/182 - //TFadeSound sConverter; //przetwornica - //TFadeSound sSmallCompressor; //przetwornica + PSound dsbSlipAlarm; // Bombardier 011010: alarm przy poslizgu dla 181/182 + // TFadeSound sConverter; //przetwornica + // TFadeSound sSmallCompressor; //przetwornica - int iCabLightFlag; //McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne) - bool bCabLight; //hunter-091012: czy swiatlo jest zapalone? - bool bCabLightDim; //hunter-091012: czy przyciemnienie kabiny jest zapalone? + int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne) + bool bCabLight; // hunter-091012: czy swiatlo jest zapalone? + bool bCabLightDim; // hunter-091012: czy przyciemnienie kabiny jest zapalone? - vector3 pMechSittingPosition; //ABu 180404 - vector3 __fastcall MirrorPosition(bool lewe); -private: - //PSound dsbBuzzer; - PSound dsbCouplerStretch; - PSound dsbEN57_CouplerStretch; - PSound dsbBufferClamp; -// TSubModel *smCzuwakShpOn; -// TSubModel *smCzuwakOn; -// TSubModel *smShpOn; -// TSubModel *smCzuwakShpOff; -// double fCzuwakTimer; - double fBlinkTimer; - float fHaslerTimer; - float fConverterTimer; //hunter-261211: dla przekaznika - float fMainRelayTimer; //hunter-141211: zalaczanie WSa z opoznieniem - float fCzuwakTestTimer; //hunter-091012: do testu czuwaka + vector3 pMechSittingPosition; // ABu 180404 + vector3 __fastcall MirrorPosition(bool lewe); - int CAflag; //hunter-131211: dla osobnego zbijania CA i SHP + private: + // PSound dsbBuzzer; + PSound dsbCouplerStretch; + PSound dsbEN57_CouplerStretch; + PSound dsbBufferClamp; + // TSubModel *smCzuwakShpOn; + // TSubModel *smCzuwakOn; + // TSubModel *smShpOn; + // TSubModel *smCzuwakShpOff; + // double fCzuwakTimer; + double fBlinkTimer; + float fHaslerTimer; + float fConverterTimer; // hunter-261211: dla przekaznika + float fMainRelayTimer; // hunter-141211: zalaczanie WSa z opoznieniem + float fCzuwakTestTimer; // hunter-091012: do testu czuwaka + + int CAflag; // hunter-131211: dla osobnego zbijania CA i SHP double fPoslizgTimer; -// double fShpTimer; -// double fDblClickTimer; - //ABu: Przeniesione do public. - Wiem, ze to nieladnie... - //bool CabChange(int iDirection); - //bool InitializeCab(int NewCabNo, AnsiString asFileName); + // double fShpTimer; + // double fDblClickTimer; + // ABu: Przeniesione do public. - Wiem, ze to nieladnie... + // bool CabChange(int iDirection); + // bool InitializeCab(int NewCabNo, AnsiString asFileName); TTrack *tor; int keybrakecount; -//McZapkie-240302 - przyda sie do tachometru + // McZapkie-240302 - przyda sie do tachometru float fTachoVelocity; - float fTachoVelocityJump; //ze skakaniem + float fTachoVelocityJump; // ze skakaniem float fTachoTimer; float fTachoCount; - float fHVoltage; //napięcie dla dynamicznych gałek - float fHCurrent[4]; //prądy: suma i amperomierze 1,2,3 - float fEngine[4]; //obroty też trzeba pobrać -//McZapkie: do syczenia - float fPPress,fNPress; - float fSPPress,fSNPress; - int iSekunda; //Ra: sekunda aktualizacji prędkości - int iRadioChannel; //numer aktualnego kanału radiowego -public: - int __fastcall RadioChannel() {return iRadioChannel;}; - inline TDynamicObject* __fastcall Dynamic() {return DynamicObject;}; - inline TMoverParameters* __fastcall Controlled() {return mvControlled;}; - void __fastcall DynamicSet(TDynamicObject *d); - void __fastcall Silence(); + float fHVoltage; // napięcie dla dynamicznych gałek + float fHCurrent[4]; // prądy: suma i amperomierze 1,2,3 + float fEngine[4]; // obroty też trzeba pobrać + // McZapkie: do syczenia + float fPPress, fNPress; + float fSPPress, fSNPress; + int iSekunda; // Ra: sekunda aktualizacji prędkości + int iRadioChannel; // numer aktualnego kanału radiowego + public: + int __fastcall RadioChannel() { return iRadioChannel; }; + inline TDynamicObject *__fastcall Dynamic() { return DynamicObject; }; + inline TMoverParameters *__fastcall Controlled() { return mvControlled; }; + void __fastcall DynamicSet(TDynamicObject *d); + void __fastcall Silence(); }; //--------------------------------------------------------------------------- #endif diff --git a/TrkFoll.cpp b/TrkFoll.cpp index da958057..1dcc9138 100644 --- a/TrkFoll.cpp +++ b/TrkFoll.cpp @@ -22,272 +22,308 @@ __fastcall TTrackFollower::TTrackFollower() { - pCurrentTrack=NULL; - pCurrentSegment=NULL; - fCurrentDistance=0; - pPosition=vAngles=vector3(0,0,0); - fDirection=1; //jest przodem do Point2 - fOffsetH=0.0; //na starcie stoi na środku + pCurrentTrack = NULL; + pCurrentSegment = NULL; + fCurrentDistance = 0; + pPosition = vAngles = vector3(0, 0, 0); + fDirection = 1; // jest przodem do Point2 + fOffsetH = 0.0; // na starcie stoi na środku } -__fastcall TTrackFollower::~TTrackFollower() +__fastcall TTrackFollower::~TTrackFollower() {} + +bool __fastcall TTrackFollower::Init(TTrack *pTrack, TDynamicObject *NewOwner, double fDir) { + fDirection = fDir; + Owner = NewOwner; + SetCurrentTrack(pTrack, 0); + iEventFlag = 3; // na torze startowym również wykonać eventy 1/2 + iEventallFlag = 3; + if ((pCurrentSegment)) // && (pCurrentSegment->GetLength()GetLength()eType) - {case tt_Switch: //jeśli zwrotnica, to przekładamy ją, aby uzyskać dobry segment - {int i=(end?pCurrentTrack->iNextDirection:pCurrentTrack->iPrevDirection); - if (i>0) //jeżeli wjazd z ostrza - pTrack->SwitchForced(i>>1,Owner); //to przełożenie zwrotnicy - rozprucie! - } - break; - case tt_Cross: //skrzyżowanie trzeba tymczasowo przełączyć, aby wjechać na właściwy tor - {iSegment=Owner->RouteWish(pTrack); //nr segmentu został ustalony podczas skanowania - //Ra 2014-08: aby ustalić dalszą trasę, należy zapytać AI - trasa jest ustalana podczas skanowania - //Ra 15-01: zapytanie AI nie wybiera segmentu - kolejny skanujący może przestawić - //pTrack->CrossSegment(end?pCurrentTrack->iNextDirection:pCurrentTrack->iPrevDirection,i); //ustawienie właściwego wskaźnika - //powinno zwracać kierunek do zapamiętania, bo segmenty mogą mieć różny kierunek - //if fDirection=(iSegment>0)?1.0:-1.0; //kierunek na tym segmencie jest ustalany bezpośrednio - if (iSegment==0) - {//to jest błędna sytuacja - generuje pętle zawracające za skrzyżowaniem - ustalić, kiedy powstaje! - iSegment=1; //doraźna poprawka +TTrack *__fastcall TTrackFollower::SetCurrentTrack(TTrack *pTrack, int end) +{ // przejechanie na inny odcinkek toru, z ewentualnym rozpruciem + if (pTrack) + switch (pTrack->eType) + { + case tt_Switch: // jeśli zwrotnica, to przekładamy ją, aby uzyskać dobry segment + { + int i = (end ? pCurrentTrack->iNextDirection : pCurrentTrack->iPrevDirection); + if (i > 0) // jeżeli wjazd z ostrza + pTrack->SwitchForced(i >> 1, Owner); // to przełożenie zwrotnicy - rozprucie! + } + break; + case tt_Cross: // skrzyżowanie trzeba tymczasowo przełączyć, aby wjechać na właściwy tor + { + iSegment = Owner->RouteWish(pTrack); // nr segmentu został ustalony podczas skanowania + // Ra 2014-08: aby ustalić dalszą trasę, należy zapytać AI - trasa jest ustalana podczas + // skanowania + // Ra 15-01: zapytanie AI nie wybiera segmentu - kolejny skanujący może przestawić + // pTrack->CrossSegment(end?pCurrentTrack->iNextDirection:pCurrentTrack->iPrevDirection,i); + // //ustawienie właściwego wskaźnika + // powinno zwracać kierunek do zapamiętania, bo segmenty mogą mieć różny kierunek + // if fDirection=(iSegment>0)?1.0:-1.0; //kierunek na tym segmencie jest ustalany + // bezpośrednio + if (iSegment == 0) + { // to jest błędna sytuacja - generuje pętle zawracające za skrzyżowaniem - ustalić, + // kiedy powstaje! + iSegment = 1; // doraźna poprawka + } + if ((end ? iSegment : -iSegment) < 0) + fDirection = -fDirection; // wtórna zmiana + pTrack->SwitchForced(abs(iSegment) - 1, NULL); // wybór zapamiętanego segmentu + } + break; + } + if (!pTrack) + { // gdy nie ma toru w kierunku jazdy + pTrack = pCurrentTrack->NullCreate( + end); // tworzenie toru wykolejącego na przedłużeniu pCurrentTrack + if (!end) // jeśli dodana od strony zero, to zmiana kierunku + fDirection = -fDirection; // wtórna zmiana + // if (pTrack->iCategoryFlag&2) + //{//jeśli samochód, zepsuć na miejscu + // Owner->MoverParameters->V=0; //zatrzymać + // Owner->MoverParameters->Power=0; //ukraść silnik + // Owner->MoverParameters->AccS=0; //wchłonąć moc + // Global::iPause|=1; //zapauzowanie symulacji + //} } - if ((end?iSegment:-iSegment)<0) - fDirection=-fDirection; //wtórna zmiana - pTrack->SwitchForced(abs(iSegment)-1,NULL); //wybór zapamiętanego segmentu - } - break; - } - if (!pTrack) - {//gdy nie ma toru w kierunku jazdy - pTrack=pCurrentTrack->NullCreate(end); //tworzenie toru wykolejącego na przedłużeniu pCurrentTrack - if (!end) //jeśli dodana od strony zero, to zmiana kierunku - fDirection=-fDirection; //wtórna zmiana - //if (pTrack->iCategoryFlag&2) - //{//jeśli samochód, zepsuć na miejscu - // Owner->MoverParameters->V=0; //zatrzymać - // Owner->MoverParameters->Power=0; //ukraść silnik - // Owner->MoverParameters->AccS=0; //wchłonąć moc - // Global::iPause|=1; //zapauzowanie symulacji - //} - } - else - {//najpierw +1, później -1, aby odcinek izolowany wspólny dla tych torów nie wykrył zera - pTrack->AxleCounter(+1,Owner); //zajęcie nowego toru - if (pCurrentTrack) pCurrentTrack->AxleCounter(-1,Owner); //opuszczenie tamtego toru - } - pCurrentTrack=pTrack; - pCurrentSegment=(pCurrentTrack?pCurrentTrack->CurrentSegment():NULL); - if (!pCurrentTrack) - Error(Owner->MoverParameters->Name+" at NULL track"); - return pCurrentTrack; + else + { // najpierw +1, później -1, aby odcinek izolowany wspólny dla tych torów nie wykrył zera + pTrack->AxleCounter(+1, Owner); // zajęcie nowego toru + if (pCurrentTrack) + pCurrentTrack->AxleCounter(-1, Owner); // opuszczenie tamtego toru + } + pCurrentTrack = pTrack; + pCurrentSegment = (pCurrentTrack ? pCurrentTrack->CurrentSegment() : NULL); + if (!pCurrentTrack) + Error(Owner->MoverParameters->Name + " at NULL track"); + return pCurrentTrack; }; -bool __fastcall TTrackFollower::Move(double fDistance,bool bPrimary) -{//przesuwanie wózka po torach o odległość (fDistance), z wyzwoleniem eventów - //bPrimary=true - jest pierwszą osią w pojeździe, czyli generuje eventy i przepisuje pojazd - //Ra: zwraca false, jeśli pojazd ma być usunięty - fDistance*=fDirection; //dystans mnożnony przez kierunek - double s; //roboczy dystans - double dir; //zapamiętany kierunek do sprawdzenia, czy się zmienił - bool bCanSkip; //czy przemieścić pojazd na inny tor - while (true) //pętla wychodzi, gdy przesunięcie wyjdzie zerowe - {//pętla przesuwająca wózek przez kolejne tory, aż do trafienia w jakiś - if (!pCurrentTrack) return false; //nie ma toru, to nie ma przesuwania - if (pCurrentTrack->iEvents) //sumaryczna informacja o eventach - {//omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma) - if (fDistance<0) - { - if (iSetFlag(iEventFlag,-1)) //zawsze zeruje flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona - if (Owner->Mechanik) //tylko dla jednego członu - //if (TestFlag(iEventFlag,1)) //McZapkie-280503: wyzwalanie event tylko dla pojazdow z obsada - if (bPrimary && pCurrentTrack->evEvent1 && (!pCurrentTrack->evEvent1->iQueued)) - Global::AddToQuery(pCurrentTrack->evEvent1,Owner); //dodanie do kolejki - //Owner->RaAxleEvent(pCurrentTrack->Event1); //Ra: dynamic zdecyduje, czy dodać do kolejki - //if (TestFlag(iEventallFlag,1)) - if (iSetFlag(iEventallFlag,-1)) //McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow - if (bPrimary && pCurrentTrack->evEventall1 && (!pCurrentTrack->evEventall1->iQueued)) - Global::AddToQuery(pCurrentTrack->evEventall1,Owner); //dodanie do kolejki - //Owner->RaAxleEvent(pCurrentTrack->Eventall1); //Ra: dynamic zdecyduje, czy dodać do kolejki - } - else if (fDistance>0) - { - if (iSetFlag(iEventFlag,-2)) //zawsze ustawia flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona - if (Owner->Mechanik) //tylko dla jednego członu - //if (TestFlag(iEventFlag,2)) //sprawdzanie jest od razu w pierwszym warunku - if (bPrimary && pCurrentTrack->evEvent2 && (!pCurrentTrack->evEvent2->iQueued)) - Global::AddToQuery(pCurrentTrack->evEvent2,Owner); - //Owner->RaAxleEvent(pCurrentTrack->Event2); //Ra: dynamic zdecyduje, czy dodać do kolejki - //if (TestFlag(iEventallFlag,2)) - if (iSetFlag(iEventallFlag,-2)) //sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0 - if (bPrimary && pCurrentTrack->evEventall2 && (!pCurrentTrack->evEventall2->iQueued)) - Global::AddToQuery(pCurrentTrack->evEventall2,Owner); - //Owner->RaAxleEvent(pCurrentTrack->Eventall2); //Ra: dynamic zdecyduje, czy dodać do kolejki - } - else //if (fDistance==0) //McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi - { - if (Owner->Mechanik) //tylko dla jednego członu - if (pCurrentTrack->evEvent0) - if (!pCurrentTrack->evEvent0->iQueued) - Global::AddToQuery(pCurrentTrack->evEvent0,Owner); - //Owner->RaAxleEvent(pCurrentTrack->Event0); //Ra: dynamic zdecyduje, czy dodać do kolejki - if (pCurrentTrack->evEventall0) - if (!pCurrentTrack->evEventall0->iQueued) - Global::AddToQuery(pCurrentTrack->evEventall0,Owner); - //Owner->RaAxleEvent(pCurrentTrack->Eventall0); //Ra: dynamic zdecyduje, czy dodać do kolejki - } - } - if (!pCurrentSegment) //jeżeli nie ma powiązanego segmentu toru? - return false; - //if (fDistance==0.0) return true; //Ra: jak stoi, to chyba dalej nie ma co kombinować? - s=fCurrentDistance+fDistance; //doliczenie przesunięcia - //Ra: W Point2 toru może znajdować się "dziura", która zamieni energię kinetyczną - // ruchu wzdłużnego na energię potencjalną, zamieniającą się potem na energię - // sprężystości na amortyzatorach. Należałoby we wpisie toru umieścić współczynnik - // podziału energii kinetycznej. - // Współczynnik normalnie 1, z dziurą np. 0.99, a -1 będzie oznaczało 100% odbicia (kozioł). - // Albo w postaci kąta: normalnie 0°, a 180° oznacza 100% odbicia (cosinus powyższego). -/* - if (pCurrentTrack->eType==tt_Cross) - {//zjazdu ze skrzyżowania nie da się określić przez (iPrevDirection) i (iNextDirection) - //int segment=Owner->RouteWish(pCurrentTrack); //numer segmentu dla skrzyżowań - //pCurrentTrack->SwitchForced(abs(segment)-1,NULL); //tymczasowo ustawienie tego segmentu - //pCurrentSegment=pCurrentTrack->CurrentSegment(); //odświeżyć sobie wskaźnik segmentu (?) - } -*/ - if (s<0) - {//jeśli przekroczenie toru od strony Point1 - bCanSkip=bPrimary?pCurrentTrack->CheckDynamicObject(Owner):false; - if (bCanSkip) //tylko główna oś przenosi pojazd do innego toru - Owner->MyTrack->RemoveDynamicObject(Owner); //zdejmujemy pojazd z dotychczasowego toru - dir=fDirection; - if (pCurrentTrack->eType==tt_Cross) - {if (!SetCurrentTrack(pCurrentTrack->Neightbour(iSegment,fDirection),0)) - return false; //wyjście z błędem - } - else if (!SetCurrentTrack(pCurrentTrack->Neightbour(-1,fDirection),0)) //ustawia fDirection - return false; //wyjście z błędem - if (dir==fDirection) //(pCurrentTrack->iPrevDirection) - {//gdy kierunek bez zmiany (Point1->Point2) - fCurrentDistance=pCurrentSegment->GetLength(); - fDistance=s; - } - else - {//gdy zmiana kierunku toru (Point1->Point1) - fCurrentDistance=0; - fDistance=-s; - } - if (bCanSkip) - {//jak główna oś, to dodanie pojazdu do nowego toru - pCurrentTrack->AddDynamicObject(Owner); - iEventFlag=3; //McZapkie-020602: umozliwienie uruchamiania event1,2 po zmianie toru - iEventallFlag=3; //McZapkie-280503: jw, dla eventall1,2 - if (!Owner->MyTrack) return false; - } - continue; - } - else if (s>pCurrentSegment->GetLength()) - {//jeśli przekroczenie toru od strony Point2 - bCanSkip=bPrimary?pCurrentTrack->CheckDynamicObject(Owner):false; - if (bCanSkip) //tylko główna oś przenosi pojazd do innego toru - Owner->MyTrack->RemoveDynamicObject(Owner); //zdejmujemy pojazd z dotychczasowego toru - fDistance=s-pCurrentSegment->GetLength(); - dir=fDirection; - if (pCurrentTrack->eType==tt_Cross) - {if (!SetCurrentTrack(pCurrentTrack->Neightbour(iSegment,fDirection),1)) - return false; //wyjście z błędem - } - else if (!SetCurrentTrack(pCurrentTrack->Neightbour(1,fDirection),1)) //ustawia fDirection - return false; //wyjście z błędem - if (dir!=fDirection) //(pCurrentTrack->iNextDirection) - {//gdy zmiana kierunku toru (Point2->Point2) - fDistance=-fDistance; //(s-pCurrentSegment->GetLength()); - fCurrentDistance=pCurrentSegment->GetLength(); - } - else //gdy kierunek bez zmiany (Point2->Point1) - fCurrentDistance=0; - if (bCanSkip) - {//jak główna oś, to dodanie pojazdu do nowego toru - pCurrentTrack->AddDynamicObject(Owner); - iEventFlag=3; //McZapkie-020602: umozliwienie uruchamiania event1,2 po zmianie toru - iEventallFlag=3; - if (!Owner->MyTrack) return false; - } - continue; - } - else - {//gdy zostaje na tym samym torze (przesuwanie już nie zmienia toru) - if (bPrimary) - {//tylko gdy początkowe ustawienie, dodajemy eventy stania do kolejki - if (Owner->MoverParameters->ActiveCab!=0) - //if (Owner->MoverParameters->CabNo!=0) - { - if (pCurrentTrack->evEvent1 && pCurrentTrack->evEvent1->fDelay<=-1.0f) - Global::AddToQuery(pCurrentTrack->evEvent1,Owner); - if (pCurrentTrack->evEvent2 && pCurrentTrack->evEvent2->fDelay<=-1.0f) - Global::AddToQuery(pCurrentTrack->evEvent2,Owner); +bool __fastcall TTrackFollower::Move(double fDistance, bool bPrimary) +{ // przesuwanie wózka po torach o odległość (fDistance), z wyzwoleniem eventów + // bPrimary=true - jest pierwszą osią w pojeździe, czyli generuje eventy i przepisuje pojazd + // Ra: zwraca false, jeśli pojazd ma być usunięty + fDistance *= fDirection; // dystans mnożnony przez kierunek + double s; // roboczy dystans + double dir; // zapamiętany kierunek do sprawdzenia, czy się zmienił + bool bCanSkip; // czy przemieścić pojazd na inny tor + while (true) // pętla wychodzi, gdy przesunięcie wyjdzie zerowe + { // pętla przesuwająca wózek przez kolejne tory, aż do trafienia w jakiś + if (!pCurrentTrack) + return false; // nie ma toru, to nie ma przesuwania + if (pCurrentTrack->iEvents) // sumaryczna informacja o eventach + { // omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma) + if (fDistance < 0) + { + if (iSetFlag(iEventFlag, -1)) // zawsze zeruje flagę sprawdzenia, jak mechanik + // dosiądzie, to się nie wykona + if (Owner->Mechanik) // tylko dla jednego członu + // if (TestFlag(iEventFlag,1)) //McZapkie-280503: wyzwalanie event tylko dla + // pojazdow z obsada + if (bPrimary && pCurrentTrack->evEvent1 && + (!pCurrentTrack->evEvent1->iQueued)) + Global::AddToQuery(pCurrentTrack->evEvent1, Owner); // dodanie do + // kolejki + // Owner->RaAxleEvent(pCurrentTrack->Event1); //Ra: dynamic zdecyduje, czy dodać do + // kolejki + // if (TestFlag(iEventallFlag,1)) + if (iSetFlag(iEventallFlag, + -1)) // McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow + if (bPrimary && pCurrentTrack->evEventall1 && + (!pCurrentTrack->evEventall1->iQueued)) + Global::AddToQuery(pCurrentTrack->evEventall1, Owner); // dodanie do kolejki + // Owner->RaAxleEvent(pCurrentTrack->Eventall1); //Ra: dynamic zdecyduje, czy dodać + // do kolejki + } + else if (fDistance > 0) + { + if (iSetFlag(iEventFlag, -2)) // zawsze ustawia flagę sprawdzenia, jak mechanik + // dosiądzie, to się nie wykona + if (Owner->Mechanik) // tylko dla jednego członu + // if (TestFlag(iEventFlag,2)) //sprawdzanie jest od razu w pierwszym + // warunku + if (bPrimary && pCurrentTrack->evEvent2 && + (!pCurrentTrack->evEvent2->iQueued)) + Global::AddToQuery(pCurrentTrack->evEvent2, Owner); + // Owner->RaAxleEvent(pCurrentTrack->Event2); //Ra: dynamic zdecyduje, czy dodać do + // kolejki + // if (TestFlag(iEventallFlag,2)) + if (iSetFlag(iEventallFlag, + -2)) // sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0 + if (bPrimary && pCurrentTrack->evEventall2 && + (!pCurrentTrack->evEventall2->iQueued)) + Global::AddToQuery(pCurrentTrack->evEventall2, Owner); + // Owner->RaAxleEvent(pCurrentTrack->Eventall2); //Ra: dynamic zdecyduje, czy dodać + // do kolejki + } + else // if (fDistance==0) //McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi + { + if (Owner->Mechanik) // tylko dla jednego członu + if (pCurrentTrack->evEvent0) + if (!pCurrentTrack->evEvent0->iQueued) + Global::AddToQuery(pCurrentTrack->evEvent0, Owner); + // Owner->RaAxleEvent(pCurrentTrack->Event0); //Ra: dynamic zdecyduje, czy dodać do + // kolejki + if (pCurrentTrack->evEventall0) + if (!pCurrentTrack->evEventall0->iQueued) + Global::AddToQuery(pCurrentTrack->evEventall0, Owner); + // Owner->RaAxleEvent(pCurrentTrack->Eventall0); //Ra: dynamic zdecyduje, czy dodać + // do kolejki + } + } + if (!pCurrentSegment) // jeżeli nie ma powiązanego segmentu toru? + return false; + // if (fDistance==0.0) return true; //Ra: jak stoi, to chyba dalej nie ma co kombinować? + s = fCurrentDistance + fDistance; // doliczenie przesunięcia + // Ra: W Point2 toru może znajdować się "dziura", która zamieni energię kinetyczną + // ruchu wzdłużnego na energię potencjalną, zamieniającą się potem na energię + // sprężystości na amortyzatorach. Należałoby we wpisie toru umieścić współczynnik + // podziału energii kinetycznej. + // Współczynnik normalnie 1, z dziurą np. 0.99, a -1 będzie oznaczało 100% odbicia (kozioł). + // Albo w postaci kąta: normalnie 0°, a 180° oznacza 100% odbicia (cosinus powyższego). + /* + if (pCurrentTrack->eType==tt_Cross) + {//zjazdu ze skrzyżowania nie da się określić przez (iPrevDirection) i (iNextDirection) + //int segment=Owner->RouteWish(pCurrentTrack); //numer segmentu dla skrzyżowań + //pCurrentTrack->SwitchForced(abs(segment)-1,NULL); //tymczasowo ustawienie tego segmentu + //pCurrentSegment=pCurrentTrack->CurrentSegment(); //odświeżyć sobie wskaźnik segmentu + (?) + } + */ + if (s < 0) + { // jeśli przekroczenie toru od strony Point1 + bCanSkip = bPrimary ? pCurrentTrack->CheckDynamicObject(Owner) : false; + if (bCanSkip) // tylko główna oś przenosi pojazd do innego toru + Owner->MyTrack->RemoveDynamicObject( + Owner); // zdejmujemy pojazd z dotychczasowego toru + dir = fDirection; + if (pCurrentTrack->eType == tt_Cross) + { + if (!SetCurrentTrack(pCurrentTrack->Neightbour(iSegment, fDirection), 0)) + return false; // wyjście z błędem + } + else if (!SetCurrentTrack(pCurrentTrack->Neightbour(-1, fDirection), + 0)) // ustawia fDirection + return false; // wyjście z błędem + if (dir == fDirection) //(pCurrentTrack->iPrevDirection) + { // gdy kierunek bez zmiany (Point1->Point2) + fCurrentDistance = pCurrentSegment->GetLength(); + fDistance = s; + } + else + { // gdy zmiana kierunku toru (Point1->Point1) + fCurrentDistance = 0; + fDistance = -s; + } + if (bCanSkip) + { // jak główna oś, to dodanie pojazdu do nowego toru + pCurrentTrack->AddDynamicObject(Owner); + iEventFlag = + 3; // McZapkie-020602: umozliwienie uruchamiania event1,2 po zmianie toru + iEventallFlag = 3; // McZapkie-280503: jw, dla eventall1,2 + if (!Owner->MyTrack) + return false; + } + continue; + } + else if (s > pCurrentSegment->GetLength()) + { // jeśli przekroczenie toru od strony Point2 + bCanSkip = bPrimary ? pCurrentTrack->CheckDynamicObject(Owner) : false; + if (bCanSkip) // tylko główna oś przenosi pojazd do innego toru + Owner->MyTrack->RemoveDynamicObject( + Owner); // zdejmujemy pojazd z dotychczasowego toru + fDistance = s - pCurrentSegment->GetLength(); + dir = fDirection; + if (pCurrentTrack->eType == tt_Cross) + { + if (!SetCurrentTrack(pCurrentTrack->Neightbour(iSegment, fDirection), 1)) + return false; // wyjście z błędem + } + else if (!SetCurrentTrack(pCurrentTrack->Neightbour(1, fDirection), + 1)) // ustawia fDirection + return false; // wyjście z błędem + if (dir != fDirection) //(pCurrentTrack->iNextDirection) + { // gdy zmiana kierunku toru (Point2->Point2) + fDistance = -fDistance; //(s-pCurrentSegment->GetLength()); + fCurrentDistance = pCurrentSegment->GetLength(); + } + else // gdy kierunek bez zmiany (Point2->Point1) + fCurrentDistance = 0; + if (bCanSkip) + { // jak główna oś, to dodanie pojazdu do nowego toru + pCurrentTrack->AddDynamicObject(Owner); + iEventFlag = + 3; // McZapkie-020602: umozliwienie uruchamiania event1,2 po zmianie toru + iEventallFlag = 3; + if (!Owner->MyTrack) + return false; + } + continue; + } + else + { // gdy zostaje na tym samym torze (przesuwanie już nie zmienia toru) + if (bPrimary) + { // tylko gdy początkowe ustawienie, dodajemy eventy stania do kolejki + if (Owner->MoverParameters->ActiveCab != 0) + // if (Owner->MoverParameters->CabNo!=0) + { + if (pCurrentTrack->evEvent1 && pCurrentTrack->evEvent1->fDelay <= -1.0f) + Global::AddToQuery(pCurrentTrack->evEvent1, Owner); + if (pCurrentTrack->evEvent2 && pCurrentTrack->evEvent2->fDelay <= -1.0f) + Global::AddToQuery(pCurrentTrack->evEvent2, Owner); + } + if (pCurrentTrack->evEventall1 && pCurrentTrack->evEventall1->fDelay <= -1.0f) + Global::AddToQuery(pCurrentTrack->evEventall1, Owner); + if (pCurrentTrack->evEventall2 && pCurrentTrack->evEventall2->fDelay <= -1.0f) + Global::AddToQuery(pCurrentTrack->evEventall2, Owner); + } + fCurrentDistance = s; + // fDistance=0; + return ComputatePosition(); // przeliczenie XYZ, true o ile nie wyjechał na NULL + } } - if (pCurrentTrack->evEventall1 && pCurrentTrack->evEventall1->fDelay<=-1.0f) - Global::AddToQuery(pCurrentTrack->evEventall1,Owner); - if (pCurrentTrack->evEventall2 && pCurrentTrack->evEventall2->fDelay<=-1.0f) - Global::AddToQuery(pCurrentTrack->evEventall2,Owner); - } - fCurrentDistance=s; - //fDistance=0; - return ComputatePosition(); //przeliczenie XYZ, true o ile nie wyjechał na NULL - } - } }; bool __fastcall TTrackFollower::ComputatePosition() -{//ustalenie współrzędnych XYZ - if (pCurrentSegment) //o ile jest tor - { - pCurrentSegment->RaPositionGet(fCurrentDistance,pPosition,vAngles); - if (fDirection<0) //kąty zależą jeszcze od zwrotu na torze - {//kąty są w przedziale <-M_PI;M_PI> - vAngles.x=-vAngles.x; //przechyłka jest w przecinwą stronę - vAngles.y=-vAngles.y; //pochylenie jest w przecinwą stronę - vAngles.z+=(vAngles.z>=M_PI)?-M_PI:M_PI; //ale kierunek w planie jest obrócony o 180° - } - if (fOffsetH!=0.0) - {//jeśli przesunięcie względem osi toru, to je doliczyć - - } - return true; - } - return false; +{ // ustalenie współrzędnych XYZ + if (pCurrentSegment) // o ile jest tor + { + pCurrentSegment->RaPositionGet(fCurrentDistance, pPosition, vAngles); + if (fDirection < 0) // kąty zależą jeszcze od zwrotu na torze + { // kąty są w przedziale <-M_PI;M_PI> + vAngles.x = -vAngles.x; // przechyłka jest w przecinwą stronę + vAngles.y = -vAngles.y; // pochylenie jest w przecinwą stronę + vAngles.z += + (vAngles.z >= M_PI) ? -M_PI : M_PI; // ale kierunek w planie jest obrócony o 180° + } + if (fOffsetH != 0.0) + { // jeśli przesunięcie względem osi toru, to je doliczyć + } + return true; + } + return false; } #if RENDER_CONE #include "opengl/glew.h" #include "opengl/glut.h" void __fastcall TTrackFollower::Render(float fNr) -{//funkcja rysująca stożek w miejscu osi - glPushMatrix(); //matryca kamery - glTranslatef(pPosition.x,pPosition.y+6,pPosition.z); //6m ponad - glRotated(RadToDeg(-vAngles.z),0,1,0); //obrót względem osi OY - //glRotated(RadToDeg(vAngles.z),0,1,0); //obrót względem osi OY - glDisable(GL_LIGHTING); - glColor3f(1.0,1.0-fNr,1.0-fNr); //biały dla 0, czerwony dla 1 - //glutWireCone(promień podstawy,wysokość,kątność podstawy,ilość segmentów na wysokość) - glutWireCone(0.5,2,4,1); //rysowanie stożka (ostrosłupa o podstawie wieloboka) - glEnable(GL_LIGHTING); - glPopMatrix(); +{ // funkcja rysująca stożek w miejscu osi + glPushMatrix(); // matryca kamery + glTranslatef(pPosition.x, pPosition.y + 6, pPosition.z); // 6m ponad + glRotated(RadToDeg(-vAngles.z), 0, 1, 0); // obrót względem osi OY + // glRotated(RadToDeg(vAngles.z),0,1,0); //obrót względem osi OY + glDisable(GL_LIGHTING); + glColor3f(1.0, 1.0 - fNr, 1.0 - fNr); // biały dla 0, czerwony dla 1 + // glutWireCone(promień podstawy,wysokość,kątność podstawy,ilość segmentów na wysokość) + glutWireCone(0.5, 2, 4, 1); // rysowanie stożka (ostrosłupa o podstawie wieloboka) + glEnable(GL_LIGHTING); + glPopMatrix(); } #endif //--------------------------------------------------------------------------- diff --git a/TrkFoll.h b/TrkFoll.h index 67b56b8b..3c90b276 100644 --- a/TrkFoll.h +++ b/TrkFoll.h @@ -8,35 +8,39 @@ class TDynamicObject; class TTrackFollower -{//oś poruszająca się po torze -private: - TTrack *pCurrentTrack; //na którym torze się znajduje - TSegment *pCurrentSegment; //zwrotnice mogą mieć dwa segmenty - double fCurrentDistance; //przesunięcie względem Point1 w stronę Point2 - double fDirection; //ustawienie względem toru: -1.0 albo 1.0, mnożone przez dystans - bool __fastcall ComputatePosition(); //przeliczenie pozycji na torze - TDynamicObject *Owner; //pojazd posiadający - int iEventFlag; //McZapkie-020602: informacja o tym czy wyzwalac zdarzenie: 0,1,2,3 - int iEventallFlag; - int iSegment; //który segment toru jest używany (żeby nie przeskakiwało po przestawieniu zwrotnicy pod taborem) -public: - double fOffsetH; //Ra: odległość środka osi od osi toru (dla samochodów) - użyć do wężykowania - vector3 pPosition; //współrzędne XYZ w układzie scenerii - vector3 vAngles; //x:przechyłka, y:pochylenie, z:kierunek w planie (w radianach) - __fastcall TTrackFollower(); - __fastcall ~TTrackFollower(); - TTrack* __fastcall SetCurrentTrack(TTrack *pTrack,int end); - bool __fastcall Move(double fDistance,bool bPrimary); - inline TTrack* __fastcall GetTrack() {return pCurrentTrack;}; - inline double __fastcall GetRoll() {return vAngles.x;}; //przechyłka policzona przy ustalaniu pozycji - //{return pCurrentSegment->GetRoll(fCurrentDistance)*fDirection;}; //zamiast liczyć można pobrać - inline double __fastcall GetDirection() {return fDirection;}; //zwrot na torze - inline double __fastcall GetTranslation() {return fCurrentDistance;}; //ABu-030403 - //inline double __fastcall GetLength(vector3 p1, vector3 cp1, vector3 cp2, vector3 p2) - //{ return pCurrentSegment->ComputeLength(p1,cp1,cp2,p2); }; - //inline double __fastcall GetRadius(double L, double d); //McZapkie-150503 - bool __fastcall Init(TTrack *pTrack,TDynamicObject *NewOwner,double fDir); - void __fastcall Render(float fNr); +{ // oś poruszająca się po torze + private: + TTrack *pCurrentTrack; // na którym torze się znajduje + TSegment *pCurrentSegment; // zwrotnice mogą mieć dwa segmenty + double fCurrentDistance; // przesunięcie względem Point1 w stronę Point2 + double fDirection; // ustawienie względem toru: -1.0 albo 1.0, mnożone przez dystans + bool __fastcall ComputatePosition(); // przeliczenie pozycji na torze + TDynamicObject *Owner; // pojazd posiadający + int iEventFlag; // McZapkie-020602: informacja o tym czy wyzwalac zdarzenie: 0,1,2,3 + int iEventallFlag; + int iSegment; // który segment toru jest używany (żeby nie przeskakiwało po przestawieniu + // zwrotnicy pod taborem) + public: + double fOffsetH; // Ra: odległość środka osi od osi toru (dla samochodów) - użyć do wężykowania + vector3 pPosition; // współrzędne XYZ w układzie scenerii + vector3 vAngles; // x:przechyłka, y:pochylenie, z:kierunek w planie (w radianach) + __fastcall TTrackFollower(); + __fastcall ~TTrackFollower(); + TTrack *__fastcall SetCurrentTrack(TTrack *pTrack, int end); + bool __fastcall Move(double fDistance, bool bPrimary); + inline TTrack *__fastcall GetTrack() { return pCurrentTrack; }; + inline double __fastcall GetRoll() + { + return vAngles.x; + }; // przechyłka policzona przy ustalaniu pozycji + //{return pCurrentSegment->GetRoll(fCurrentDistance)*fDirection;}; //zamiast liczyć można pobrać + inline double __fastcall GetDirection() { return fDirection; }; // zwrot na torze + inline double __fastcall GetTranslation() { return fCurrentDistance; }; // ABu-030403 + // inline double __fastcall GetLength(vector3 p1, vector3 cp1, vector3 cp2, vector3 p2) + //{ return pCurrentSegment->ComputeLength(p1,cp1,cp2,p2); }; + // inline double __fastcall GetRadius(double L, double d); //McZapkie-150503 + bool __fastcall Init(TTrack *pTrack, TDynamicObject *NewOwner, double fDir); + void __fastcall Render(float fNr); }; //--------------------------------------------------------------------------- #endif diff --git a/VBO.cpp b/VBO.cpp index 4ea89f62..361d2f6e 100644 --- a/VBO.cpp +++ b/VBO.cpp @@ -11,85 +11,89 @@ #pragma package(smart_init) __fastcall CMesh::CMesh() -{//utworzenie pustego obiektu - m_pVNT=NULL; - m_nVertexCount=-1; - m_nVBOVertices=0; //nie zarezerwowane +{ // utworzenie pustego obiektu + m_pVNT = NULL; + m_nVertexCount = -1; + m_nVBOVertices = 0; // nie zarezerwowane }; __fastcall CMesh::~CMesh() -{//usuwanie obiektu - Clear(); //zwolnienie zasobów +{ // usuwanie obiektu + Clear(); // zwolnienie zasobów }; void __fastcall CMesh::MakeArray(int n) -{//tworzenie tablic - m_nVertexCount=n; - m_pVNT=new CVertNormTex[m_nVertexCount]; // przydzielenie pamięci dla tablicy +{ // tworzenie tablic + m_nVertexCount = n; + m_pVNT = new CVertNormTex[m_nVertexCount]; // przydzielenie pamięci dla tablicy }; void __fastcall CMesh::BuildVBOs(bool del) -{//tworzenie VBO i kasowanie już niepotrzebnych tablic - //pobierz numer VBO oraz ustaw go jako aktywny - glGenBuffersARB(1,&m_nVBOVertices); //pobierz numer - glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_nVBOVertices); //ustaw bufor jako aktualny - glBufferDataARB(GL_ARRAY_BUFFER_ARB,m_nVertexCount*sizeof(CVertNormTex),m_pVNT,GL_STATIC_DRAW_ARB); - //WriteLog("Assigned VBO number "+AnsiString(m_nVBOVertices)+", vertices: "+AnsiString(m_nVertexCount)); - if (del) SafeDeleteArray(m_pVNT); //wierzchołki już się nie przydadzą +{ // tworzenie VBO i kasowanie już niepotrzebnych tablic + // pobierz numer VBO oraz ustaw go jako aktywny + glGenBuffersARB(1, &m_nVBOVertices); // pobierz numer + glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_nVBOVertices); // ustaw bufor jako aktualny + glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_nVertexCount * sizeof(CVertNormTex), m_pVNT, + GL_STATIC_DRAW_ARB); + // WriteLog("Assigned VBO number "+AnsiString(m_nVBOVertices)+", vertices: + // "+AnsiString(m_nVertexCount)); + if (del) + SafeDeleteArray(m_pVNT); // wierzchołki już się nie przydadzą }; void __fastcall CMesh::Clear() -{//niewirtualne zwolnienie zasobów przez sprzątacz albo destruktor - //inna nazwa, żeby nie mieszało się z funkcją wirtualną sprzątacza - if (m_nVBOVertices) //jeśli było coś rezerwowane - { - glDeleteBuffersARB(1,&m_nVBOVertices); // Free The Memory - //WriteLog("Released VBO number "+AnsiString(m_nVBOVertices)); - } - m_nVBOVertices=0; - m_nVertexCount=-1; //do ponownego zliczenia - SafeDeleteArray(m_pVNT); //usuwanie tablic, gdy były użyte do Vertex Array +{ // niewirtualne zwolnienie zasobów przez sprzątacz albo destruktor + // inna nazwa, żeby nie mieszało się z funkcją wirtualną sprzątacza + if (m_nVBOVertices) // jeśli było coś rezerwowane + { + glDeleteBuffersARB(1, &m_nVBOVertices); // Free The Memory + // WriteLog("Released VBO number "+AnsiString(m_nVBOVertices)); + } + m_nVBOVertices = 0; + m_nVertexCount = -1; // do ponownego zliczenia + SafeDeleteArray(m_pVNT); // usuwanie tablic, gdy były użyte do Vertex Array }; bool __fastcall CMesh::StartVBO() -{//początek rysowania elementów z VBO - if (m_nVertexCount<=0) return false; //nie ma nic do rysowania w ten sposób - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (m_nVBOVertices) - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_nVBOVertices); - glVertexPointer(3,GL_FLOAT,sizeof(CVertNormTex),((char*)NULL)); //pozycje - glNormalPointer(GL_FLOAT,sizeof(CVertNormTex),((char*)NULL)+12); //normalne - glTexCoordPointer(2,GL_FLOAT,sizeof(CVertNormTex),((char*)NULL)+24); //wierzchołki - } - return true; //można rysować z VBO +{ // początek rysowania elementów z VBO + if (m_nVertexCount <= 0) + return false; // nie ma nic do rysowania w ten sposób + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (m_nVBOVertices) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_nVBOVertices); + glVertexPointer(3, GL_FLOAT, sizeof(CVertNormTex), ((char *)NULL)); // pozycje + glNormalPointer(GL_FLOAT, sizeof(CVertNormTex), ((char *)NULL) + 12); // normalne + glTexCoordPointer(2, GL_FLOAT, sizeof(CVertNormTex), ((char *)NULL) + 24); // wierzchołki + } + return true; // można rysować z VBO }; bool __fastcall CMesh::StartColorVBO() -{//początek rysowania punktów świecących z VBO - if (m_nVertexCount<=0) return false; //nie ma nic do rysowania w ten sposób - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - if (m_nVBOVertices) - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_nVBOVertices); - glVertexPointer(3,GL_FLOAT,sizeof(CVertNormTex),((char*)NULL)); //pozycje - //glColorPointer(3,GL_UNSIGNED_BYTE,sizeof(CVertNormTex),((char*)NULL)+12); //kolory - glColorPointer(3,GL_FLOAT,sizeof(CVertNormTex),((char*)NULL)+12); //kolory - } - return true; //można rysować z VBO +{ // początek rysowania punktów świecących z VBO + if (m_nVertexCount <= 0) + return false; // nie ma nic do rysowania w ten sposób + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + if (m_nVBOVertices) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_nVBOVertices); + glVertexPointer(3, GL_FLOAT, sizeof(CVertNormTex), ((char *)NULL)); // pozycje + // glColorPointer(3,GL_UNSIGNED_BYTE,sizeof(CVertNormTex),((char*)NULL)+12); //kolory + glColorPointer(3, GL_FLOAT, sizeof(CVertNormTex), ((char *)NULL) + 12); // kolory + } + return true; // można rysować z VBO }; void __fastcall CMesh::EndVBO() -{//koniec użycia VBO - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - //glBindBuffer(GL_ARRAY_BUFFER,0); //takie coś psuje, mimo iż polecali użyć - glBindBufferARB(GL_ARRAY_BUFFER_ARB,0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,0); //Ra: to na przyszłość +{ // koniec użycia VBO + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + // glBindBuffer(GL_ARRAY_BUFFER,0); //takie coś psuje, mimo iż polecali użyć + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); // Ra: to na przyszłość }; - diff --git a/VBO.h b/VBO.h index 99ace3fb..03c7266e 100644 --- a/VBO.h +++ b/VBO.h @@ -5,32 +5,31 @@ //--------------------------------------------------------------------------- class CVertNormTex { -public: - float x; //X wierzchołka - float y; //Y wierzchołka - float z; //Z wierzchołka - float nx; //X wektora normalnego - float ny; //Y wektora normalnego - float nz; //Z wektora normalnego - float u; //U mapowania - float v; //V mapowania + public: + float x; // X wierzchołka + float y; // Y wierzchołka + float z; // Z wierzchołka + float nx; // X wektora normalnego + float ny; // Y wektora normalnego + float nz; // Z wektora normalnego + float u; // U mapowania + float v; // V mapowania }; class CMesh -{//wsparcie dla VBO -public: - int m_nVertexCount; //liczba wierzchołków - CVertNormTex *m_pVNT; - unsigned int m_nVBOVertices; //numer VBO z wierzchołkami - __fastcall CMesh(); - __fastcall ~CMesh(); - void __fastcall MakeArray(int n); //tworzenie tablicy z elementami VNT - void __fastcall BuildVBOs(bool del=true); //zamiana tablic na VBO - void __fastcall Clear(); //zwolnienie zasobów - bool __fastcall StartVBO(); - void __fastcall EndVBO(); - bool __fastcall StartColorVBO(); +{ // wsparcie dla VBO + public: + int m_nVertexCount; // liczba wierzchołków + CVertNormTex *m_pVNT; + unsigned int m_nVBOVertices; // numer VBO z wierzchołkami + __fastcall CMesh(); + __fastcall ~CMesh(); + void __fastcall MakeArray(int n); // tworzenie tablicy z elementami VNT + void __fastcall BuildVBOs(bool del = true); // zamiana tablic na VBO + void __fastcall Clear(); // zwolnienie zasobów + bool __fastcall StartVBO(); + void __fastcall EndVBO(); + bool __fastcall StartColorVBO(); }; #endif - diff --git a/World.cpp b/World.cpp index a57fc715..9f86e31b 100644 --- a/World.cpp +++ b/World.cpp @@ -25,83 +25,84 @@ #include "Driver.h" #include "Console.h" -#define TEXTURE_FILTER_CONTROL_EXT 0x8500 -#define TEXTURE_LOD_BIAS_EXT 0x8501 +#define TEXTURE_FILTER_CONTROL_EXT 0x8500 +#define TEXTURE_LOD_BIAS_EXT 0x8501 //--------------------------------------------------------------------------- #pragma package(smart_init) -typedef void (APIENTRY *FglutBitmapCharacter)(void *font,int character); //typ funkcji -FglutBitmapCharacter glutBitmapCharacterDLL=NULL; //deklaracja zmiennej -HINSTANCE hinstGLUT32=NULL; //wskaźnik do GLUT32.DLL -//GLUTAPI void APIENTRY glutBitmapCharacterDLL(void *font, int character); -TDynamicObject *Controlled=NULL; //pojazd, który prowadzimy +typedef void(APIENTRY *FglutBitmapCharacter)(void *font, int character); // typ funkcji +FglutBitmapCharacter glutBitmapCharacterDLL = NULL; // deklaracja zmiennej +HINSTANCE hinstGLUT32 = NULL; // wskaźnik do GLUT32.DLL +// GLUTAPI void APIENTRY glutBitmapCharacterDLL(void *font, int character); +TDynamicObject *Controlled = NULL; // pojazd, który prowadzimy using namespace Timer; -const double fTimeMax=1.00; //[s] maksymalny czas aktualizacji w jednek klatce +const double fTimeMax = 1.00; //[s] maksymalny czas aktualizacji w jednek klatce __fastcall TWorld::TWorld() { - //randomize(); - //Randomize(); - Train=NULL; - //Aspect=1; - for (int i=0;i<10;++i) - KeyEvents[i]=NULL; //eventy wyzwalane klawiszami cyfrowymi - Global::iSlowMotion=0; - //Global::changeDynObj=NULL; - OutText1=""; //teksty wyświetlane na ekranie - OutText2=""; - OutText3=""; - iCheckFPS=0; //kiedy znów sprawdzić FPS, żeby wyłączać optymalizacji od razu do zera - pDynamicNearest=NULL; - fTimeBuffer=0.0; //bufor czasu aktualizacji dla stałego kroku fizyki - fMaxDt=0.01; //[s] początkowy krok czasowy fizyki - fTime50Hz=0.0; //bufor czasu dla komunikacji z PoKeys + // randomize(); + // Randomize(); + Train = NULL; + // Aspect=1; + for (int i = 0; i < 10; ++i) + KeyEvents[i] = NULL; // eventy wyzwalane klawiszami cyfrowymi + Global::iSlowMotion = 0; + // Global::changeDynObj=NULL; + OutText1 = ""; // teksty wyświetlane na ekranie + OutText2 = ""; + OutText3 = ""; + iCheckFPS = 0; // kiedy znów sprawdzić FPS, żeby wyłączać optymalizacji od razu do zera + pDynamicNearest = NULL; + fTimeBuffer = 0.0; // bufor czasu aktualizacji dla stałego kroku fizyki + fMaxDt = 0.01; //[s] początkowy krok czasowy fizyki + fTime50Hz = 0.0; // bufor czasu dla komunikacji z PoKeys } __fastcall TWorld::~TWorld() { - Global::bManageNodes=false; //Ra: wyłączenie wyrejestrowania, bo się sypie - TrainDelete(); - //Ground.Free(); //Ra: usunięcie obiektów przed usunięciem dźwięków - sypie się - TSoundsManager::Free(); - TModelsManager::Free(); - TTexturesManager::Free(); - glDeleteLists(base,96); - if (hinstGLUT32) - FreeLibrary(hinstGLUT32); + Global::bManageNodes = false; // Ra: wyłączenie wyrejestrowania, bo się sypie + TrainDelete(); + // Ground.Free(); //Ra: usunięcie obiektów przed usunięciem dźwięków - sypie się + TSoundsManager::Free(); + TModelsManager::Free(); + TTexturesManager::Free(); + glDeleteLists(base, 96); + if (hinstGLUT32) + FreeLibrary(hinstGLUT32); } void __fastcall TWorld::TrainDelete(TDynamicObject *d) -{//usunięcie pojazdu prowadzonego przez użytkownika - if (d) - if (Train) - if (Train->Dynamic()!=d) - return; //nie tego usuwać - delete Train; //i nie ma czym sterować - Train=NULL; - Controlled=NULL; //tego też już nie ma - mvControlled=NULL; - Global::pUserDynamic=NULL; //tego też nie ma +{ // usunięcie pojazdu prowadzonego przez użytkownika + if (d) + if (Train) + if (Train->Dynamic() != d) + return; // nie tego usuwać + delete Train; // i nie ma czym sterować + Train = NULL; + Controlled = NULL; // tego też już nie ma + mvControlled = NULL; + Global::pUserDynamic = NULL; // tego też nie ma }; -GLvoid __fastcall TWorld::glPrint(const char *txt) //custom GL "Print" routine -{//wypisywanie tekstu 2D na ekranie - if (!txt) return; - if (Global::bGlutFont) - {//tekst generowany przez GLUT - int i,len=strlen(txt); - for (i=0;iglver.Pos(".")) - glver=glver.SubString(1,glver.LastDelimiter(".")-1); //obcięcie od drugiej kropki - double ogl; - try {ogl=glver.ToDouble();} catch (...) {ogl=0.0;} - if (Global::fOpenGL>0.0) //jeśli była wpisane maksymalna wersja w EU07.INI - {if (ogl>0.0) //zakładając, że się odczytało dobrze - if (ogl=1.5); //są fragmentaryczne animacje VBO + WriteLog("Online documentation and additional files on http://eu07.pl"); + WriteLog("Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx_EU, OLO_EU, Bart, Quark-t, " + "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter and others"); + WriteLog("Renderer:"); + WriteLog((char *)glGetString(GL_RENDERER)); + WriteLog("Vendor:"); + // Winger030405: sprawdzanie sterownikow + WriteLog((char *)glGetString(GL_VENDOR)); + AnsiString glver = ((char *)glGetString(GL_VERSION)); + WriteLog("OpenGL Version:"); + WriteLog(glver); + if ((glver == "1.5.1") || (glver == "1.5.2")) + { + Error("Niekompatybilna wersja openGL - dwuwymiarowy tekst nie bedzie wyswietlany!"); + WriteLog("WARNING! This OpenGL version is not fully compatible with simulator!"); + WriteLog("UWAGA! Ta wersja OpenGL nie jest w pelni kompatybilna z symulatorem!"); + Global::detonatoryOK = false; + } + else + Global::detonatoryOK = true; + // Ra: umieszczone w EU07.cpp jakoś nie chce działać + while (glver.LastDelimiter(".") > glver.Pos(".")) + glver = glver.SubString(1, glver.LastDelimiter(".") - 1); // obcięcie od drugiej kropki + double ogl; + try + { + ogl = glver.ToDouble(); + } + catch (...) + { + ogl = 0.0; + } + if (Global::fOpenGL > 0.0) // jeśli była wpisane maksymalna wersja w EU07.INI + { + if (ogl > 0.0) // zakładając, że się odczytało dobrze + if (ogl < Global::fOpenGL) // a karta oferuje niższą wersję niż wpisana + Global::fOpenGL = ogl; // to przyjąc to z karty + } + else if (ogl < 1.3) // sprzętowa deompresja DDS zwykle wymaga 1.3 + Error("Missed OpenGL 1.3+ drivers!"); // błąd np. gdy wersja 1.1, a nie ma wpisu w EU07.INI + Global::bOpenGL_1_5 = (Global::fOpenGL >= 1.5); // są fragmentaryczne animacje VBO - WriteLog("Supported extensions:"); - WriteLog((char*)glGetString(GL_EXTENSIONS)); - if (glewGetExtension("GL_ARB_vertex_buffer_object")) //czy jest VBO w karcie graficznej - { - if (AnsiString((char*)glGetString(GL_VENDOR)).Pos("Intel")) //wymuszenie tylko dla kart Intel - {//karty Intel nie nadają się do grafiki 3D, ale robimy wyjątek, bo to w końcu symulator - Global::iMultisampling=0; //to robi problemy na "Intel(R) HD Graphics Family" - czarny ekran - if (Global::fOpenGL>=1.4) //1.4 miało obsługę VBO, ale bez opcji modyfikacji fragmentu bufora - Global::bUseVBO=true; //VBO włączane tylko, jeśli jest obsługa oraz nie ustawiono niższego numeru - } - if (Global::bUseVBO) - WriteLog("Ra: The VBO is found and will be used."); - else - WriteLog("Ra: The VBO is found, but Display Lists are selected."); - } - else - {WriteLog("Ra: No VBO found - Display Lists used. Graphics card too old?"); - Global::bUseVBO=false; //może być włączone parametrem w INI - } - if (Global::bDecompressDDS) //jeśli sprzętowa (domyślnie jest false) - WriteLog("DDS textures support at OpenGL level is disabled in INI file."); - else - {Global::bDecompressDDS=!glewGetExtension("GL_EXT_texture_compression_s3tc"); //czy obsługiwane? - if (Global::bDecompressDDS) //czy jest obsługa DDS w karcie graficznej - WriteLog("DDS textures are not supported."); - else //brak obsługi DDS - trzeba włączyć programową dekompresję - WriteLog("DDS textures are supported."); - } - if (Global::iMultisampling) - WriteLog("Used multisampling of "+AnsiString(Global::iMultisampling)+" samples."); - {//ograniczenie maksymalnego rozmiaru tekstur - parametr dla skalowania tekstur - GLint i; - glGetIntegerv(GL_MAX_TEXTURE_SIZE,&i); - if (i=1.2) //poniższe nie działa w 1.1 - glTexEnvf(TEXTURE_FILTER_CONTROL_EXT,TEXTURE_LOD_BIAS_EXT,-1); - GLfloat FogColor[]={1.0f,1.0f,1.0f,1.0f}; - glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear screen and depth buffer - glLoadIdentity(); - //WriteLog("glClearColor (FogColor[0], FogColor[1], FogColor[2], 0.0); "); - //glClearColor (1.0, 0.0, 0.0, 0.0); // Background Color - //glClearColor (FogColor[0], FogColor[1], FogColor[2], 0.0); // Background Color - glClearColor (0.2, 0.4, 0.33, 1.0); // Background Color + WriteLog("Supported extensions:"); + WriteLog((char *)glGetString(GL_EXTENSIONS)); + if (glewGetExtension("GL_ARB_vertex_buffer_object")) // czy jest VBO w karcie graficznej + { + if (AnsiString((char *)glGetString(GL_VENDOR)) + .Pos("Intel")) // wymuszenie tylko dla kart Intel + { // karty Intel nie nadają się do grafiki 3D, ale robimy wyjątek, bo to w końcu symulator + Global::iMultisampling = + 0; // to robi problemy na "Intel(R) HD Graphics Family" - czarny ekran + if (Global::fOpenGL >= + 1.4) // 1.4 miało obsługę VBO, ale bez opcji modyfikacji fragmentu bufora + Global::bUseVBO = true; // VBO włączane tylko, jeśli jest obsługa oraz nie ustawiono + // niższego numeru + } + if (Global::bUseVBO) + WriteLog("Ra: The VBO is found and will be used."); + else + WriteLog("Ra: The VBO is found, but Display Lists are selected."); + } + else + { + WriteLog("Ra: No VBO found - Display Lists used. Graphics card too old?"); + Global::bUseVBO = false; // może być włączone parametrem w INI + } + if (Global::bDecompressDDS) // jeśli sprzętowa (domyślnie jest false) + WriteLog("DDS textures support at OpenGL level is disabled in INI file."); + else + { + Global::bDecompressDDS = + !glewGetExtension("GL_EXT_texture_compression_s3tc"); // czy obsługiwane? + if (Global::bDecompressDDS) // czy jest obsługa DDS w karcie graficznej + WriteLog("DDS textures are not supported."); + else // brak obsługi DDS - trzeba włączyć programową dekompresję + WriteLog("DDS textures are supported."); + } + if (Global::iMultisampling) + WriteLog("Used multisampling of " + AnsiString(Global::iMultisampling) + " samples."); + { // ograniczenie maksymalnego rozmiaru tekstur - parametr dla skalowania tekstur + GLint i; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &i); + if (i < Global::iMaxTextureSize) + Global::iMaxTextureSize = i; + WriteLog("Max texture size: " + AnsiString(Global::iMaxTextureSize)); + } + /*-----------------------Render Initialization----------------------*/ + if (Global::fOpenGL >= 1.2) // poniższe nie działa w 1.1 + glTexEnvf(TEXTURE_FILTER_CONTROL_EXT, TEXTURE_LOD_BIAS_EXT, -1); + GLfloat FogColor[] = {1.0f, 1.0f, 1.0f, 1.0f}; + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear screen and depth buffer + glLoadIdentity(); + // WriteLog("glClearColor (FogColor[0], FogColor[1], FogColor[2], 0.0); "); + // glClearColor (1.0, 0.0, 0.0, 0.0); // Background Color + // glClearColor (FogColor[0], FogColor[1], FogColor[2], 0.0); // Background + // Color + glClearColor(0.2, 0.4, 0.33, 1.0); // Background Color - WriteLog("glFogfv(GL_FOG_COLOR, FogColor);"); - glFogfv(GL_FOG_COLOR, FogColor); // Set Fog Color + WriteLog("glFogfv(GL_FOG_COLOR, FogColor);"); + glFogfv(GL_FOG_COLOR, FogColor); // Set Fog Color WriteLog("glClearDepth(1.0f); "); - glClearDepth(1.0f); // ZBuffer Value + glClearDepth(1.0f); // ZBuffer Value + // glEnable(GL_NORMALIZE); + // glEnable(GL_RESCALE_NORMAL); - // glEnable(GL_NORMALIZE); -// glEnable(GL_RESCALE_NORMAL); - -// glEnable(GL_CULL_FACE); + // glEnable(GL_CULL_FACE); WriteLog("glEnable(GL_TEXTURE_2D);"); - glEnable(GL_TEXTURE_2D); // Enable Texture Mapping + glEnable(GL_TEXTURE_2D); // Enable Texture Mapping WriteLog("glShadeModel(GL_SMOOTH);"); - glShadeModel(GL_SMOOTH); // Enable Smooth Shading + glShadeModel(GL_SMOOTH); // Enable Smooth Shading WriteLog("glEnable(GL_DEPTH_TEST);"); glEnable(GL_DEPTH_TEST); -//McZapkie:261102-uruchomienie polprzezroczystosci (na razie linie) pod kierunkiem Marcina - //if (Global::bRenderAlpha) //Ra: wywalam tę flagę + // McZapkie:261102-uruchomienie polprzezroczystosci (na razie linie) pod kierunkiem Marcina + // if (Global::bRenderAlpha) //Ra: wywalam tę flagę { - WriteLog("glEnable(GL_BLEND);"); - glEnable(GL_BLEND); - WriteLog("glEnable(GL_ALPHA_TEST);"); - glEnable(GL_ALPHA_TEST); - WriteLog("glAlphaFunc(GL_GREATER,0.04);"); - glAlphaFunc(GL_GREATER,0.04); - WriteLog("glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);"); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - WriteLog("glDepthFunc(GL_LEQUAL);"); - glDepthFunc(GL_LEQUAL); + WriteLog("glEnable(GL_BLEND);"); + glEnable(GL_BLEND); + WriteLog("glEnable(GL_ALPHA_TEST);"); + glEnable(GL_ALPHA_TEST); + WriteLog("glAlphaFunc(GL_GREATER,0.04);"); + glAlphaFunc(GL_GREATER, 0.04); + WriteLog("glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);"); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + WriteLog("glDepthFunc(GL_LEQUAL);"); + glDepthFunc(GL_LEQUAL); } -/* - else - { - WriteLog("glEnable(GL_ALPHA_TEST);"); - glEnable(GL_ALPHA_TEST); - WriteLog("glAlphaFunc(GL_GREATER,0.5);"); - glAlphaFunc(GL_GREATER,0.5); - WriteLog("glDepthFunc(GL_LEQUAL);"); - glDepthFunc(GL_LEQUAL); - WriteLog("glDisable(GL_BLEND);"); - glDisable(GL_BLEND); - } -*/ -/* zakomentowanie to co bylo kiedys mieszane - WriteLog("glEnable(GL_ALPHA_TEST);"); - glEnable(GL_ALPHA_TEST);//glGetIntegerv() - WriteLog("glAlphaFunc(GL_GREATER,0.5);"); -// glAlphaFunc(GL_LESS,0.5); - glAlphaFunc(GL_GREATER,0.5); -// glBlendFunc(GL_SRC_ALPHA,GL_ONE); - WriteLog("glDepthFunc(GL_LEQUAL);"); - glDepthFunc(GL_LEQUAL);//EQUAL); // The Type Of Depth Testing To Do - // glEnable(GL_BLEND); -// glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); -*/ + /* + else + { + WriteLog("glEnable(GL_ALPHA_TEST);"); + glEnable(GL_ALPHA_TEST); + WriteLog("glAlphaFunc(GL_GREATER,0.5);"); + glAlphaFunc(GL_GREATER,0.5); + WriteLog("glDepthFunc(GL_LEQUAL);"); + glDepthFunc(GL_LEQUAL); + WriteLog("glDisable(GL_BLEND);"); + glDisable(GL_BLEND); + } + */ + /* zakomentowanie to co bylo kiedys mieszane + WriteLog("glEnable(GL_ALPHA_TEST);"); + glEnable(GL_ALPHA_TEST);//glGetIntegerv() + WriteLog("glAlphaFunc(GL_GREATER,0.5);"); + // glAlphaFunc(GL_LESS,0.5); + glAlphaFunc(GL_GREATER,0.5); + // glBlendFunc(GL_SRC_ALPHA,GL_ONE); + WriteLog("glDepthFunc(GL_LEQUAL);"); + glDepthFunc(GL_LEQUAL);//EQUAL); + // The Type Of Depth Testing To Do + // glEnable(GL_BLEND); + // glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + */ WriteLog("glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);"); - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations - + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations WriteLog("glPolygonMode(GL_FRONT, GL_FILL);"); glPolygonMode(GL_FRONT, GL_FILL); WriteLog("glFrontFace(GL_CCW);"); - glFrontFace(GL_CCW); // Counter clock-wise polygons face out + glFrontFace(GL_CCW); // Counter clock-wise polygons face out WriteLog("glEnable(GL_CULL_FACE); "); - glEnable(GL_CULL_FACE); // Cull back-facing triangles + glEnable(GL_CULL_FACE); // Cull back-facing triangles WriteLog("glLineWidth(1.0f);"); - glLineWidth(1.0f); -// glLineWidth(2.0f); + glLineWidth(1.0f); + // glLineWidth(2.0f); WriteLog("glPointSize(2.0f);"); - glPointSize(2.0f); + glPointSize(2.0f); -// ----------- LIGHTING SETUP ----------- - // Light values and coordinates + // ----------- LIGHTING SETUP ----------- + // Light values and coordinates - vector3 lp= Normalize(vector3(-500,500,200)); + vector3 lp = Normalize(vector3(-500, 500, 200)); - Global::lightPos[0]=lp.x; - Global::lightPos[1]=lp.y; - Global::lightPos[2]=lp.z; - Global::lightPos[3]=0.0f; + Global::lightPos[0] = lp.x; + Global::lightPos[1] = lp.y; + Global::lightPos[2] = lp.z; + Global::lightPos[3] = 0.0f; - //Ra: światła by sensowniej było ustawiać po wczytaniu scenerii + // Ra: światła by sensowniej było ustawiać po wczytaniu scenerii - //Ra: szczątkowe światło rozproszone - żeby było cokolwiek widać w ciemności + // Ra: szczątkowe światło rozproszone - żeby było cokolwiek widać w ciemności WriteLog("glLightModelfv(GL_LIGHT_MODEL_AMBIENT,darkLight);"); - glLightModelfv(GL_LIGHT_MODEL_AMBIENT,Global::darkLight); + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Global::darkLight); - //Ra: światło 0 - główne światło zewnętrzne (Słońce, Księżyc) + // Ra: światło 0 - główne światło zewnętrzne (Słońce, Księżyc) WriteLog("glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);"); - glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); + glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); WriteLog("glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);"); - glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); WriteLog("glLightfv(GL_LIGHT0,GL_SPECULAR,specularLight);"); - glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); WriteLog("glLightfv(GL_LIGHT0,GL_POSITION,lightPos);"); - glLightfv(GL_LIGHT0,GL_POSITION,Global::lightPos); + glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos); WriteLog("glEnable(GL_LIGHT0);"); glEnable(GL_LIGHT0); - - //glColor() ma zmieniać kolor wybrany w glColorMaterial() + // glColor() ma zmieniać kolor wybrany w glColorMaterial() WriteLog("glEnable(GL_COLOR_MATERIAL);"); glEnable(GL_COLOR_MATERIAL); WriteLog("glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);"); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); -// WriteLog("glMaterialfv( GL_FRONT, GL_AMBIENT, whiteLight );"); -// glMaterialfv( GL_FRONT, GL_AMBIENT, Global::whiteLight ); + // WriteLog("glMaterialfv( GL_FRONT, GL_AMBIENT, whiteLight );"); + // glMaterialfv( GL_FRONT, GL_AMBIENT, Global::whiteLight ); WriteLog("glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, whiteLight );"); - glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, Global::whiteLight ); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, Global::whiteLight); -/* - WriteLog("glMaterialfv( GL_FRONT, GL_SPECULAR, noLight );"); - glMaterialfv( GL_FRONT, GL_SPECULAR, Global::noLight ); -*/ + /* + WriteLog("glMaterialfv( GL_FRONT, GL_SPECULAR, noLight );"); + glMaterialfv( GL_FRONT, GL_SPECULAR, Global::noLight ); + */ WriteLog("glEnable(GL_LIGHTING);"); - glEnable(GL_LIGHTING); - + glEnable(GL_LIGHTING); WriteLog("glFogi(GL_FOG_MODE, GL_LINEAR);"); - glFogi(GL_FOG_MODE, GL_LINEAR); // Fog Mode + glFogi(GL_FOG_MODE, GL_LINEAR); // Fog Mode WriteLog("glFogfv(GL_FOG_COLOR, FogColor);"); - glFogfv(GL_FOG_COLOR, FogColor); // Set Fog Color -// glFogf(GL_FOG_DENSITY, 0.594f); // How Dense Will The Fog Be -// glHint(GL_FOG_HINT, GL_NICEST); // Fog Hint Value + glFogfv(GL_FOG_COLOR, FogColor); // Set Fog Color + // glFogf(GL_FOG_DENSITY, 0.594f); // How Dense Will The Fog + //Be + // glHint(GL_FOG_HINT, GL_NICEST); // Fog Hint Value WriteLog("glFogf(GL_FOG_START, 1000.0f);"); - glFogf(GL_FOG_START, 10.0f); // Fog Start Depth + glFogf(GL_FOG_START, 10.0f); // Fog Start Depth WriteLog("glFogf(GL_FOG_END, 2000.0f);"); - glFogf(GL_FOG_END, 200.0f); // Fog End Depth + glFogf(GL_FOG_END, 200.0f); // Fog End Depth WriteLog("glEnable(GL_FOG);"); - glEnable(GL_FOG); // Enables GL_FOG + glEnable(GL_FOG); // Enables GL_FOG - //Ra: ustawienia testowe - glHint(GL_LINE_SMOOTH_HINT,GL_NICEST); - glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST); + // Ra: ustawienia testowe + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); -/*--------------------Render Initialization End---------------------*/ + /*--------------------Render Initialization End---------------------*/ - WriteLog("Font init"); //początek inicjacji fontów 2D - if (Global::bGlutFont) //jeśli wybrano GLUT font, próbujemy zlinkować GLUT32.DLL - { - UINT mode=SetErrorMode(SEM_NOOPENFILEERRORBOX); //aby nie wrzeszczał, że znaleźć nie może - hinstGLUT32=LoadLibrary(TEXT("GLUT32.DLL")); //get a handle to the DLL module - SetErrorMode(mode); - // If the handle is valid, try to get the function address. - if (hinstGLUT32) - glutBitmapCharacterDLL=(FglutBitmapCharacter)GetProcAddress(hinstGLUT32,"glutBitmapCharacter"); - else - WriteLog("Missed GLUT32.DLL."); - if (glutBitmapCharacterDLL) - WriteLog("Used font from GLUT32.DLL."); - else - Global::bGlutFont=false; //nie udało się, trzeba spróbować na Display List - } - if (!Global::bGlutFont) - {//jeśli bezGLUTowy font - HFONT font; // Windows Font ID - base=glGenLists(96); //storage for 96 characters - font=CreateFont( -15, //height of font - 0, //width of font - 0, //angle of escapement - 0, //orientation angle - FW_BOLD, //font weight - FALSE, //italic - FALSE, //underline - FALSE, //strikeout - ANSI_CHARSET, //character set identifier - OUT_TT_PRECIS, //output precision - CLIP_DEFAULT_PRECIS, //clipping precision - ANTIALIASED_QUALITY, //output quality - FF_DONTCARE|DEFAULT_PITCH, //family and pitch - "Courier New"); //font name - SelectObject(hDC,font); //selects the font we want - wglUseFontBitmapsA(hDC,32,96,base); //builds 96 characters starting at character 32 - WriteLog("Display Lists font used."); //+AnsiString(glGetError()) - } - WriteLog("Font init OK"); //+AnsiString(glGetError()) + WriteLog("Font init"); // początek inicjacji fontów 2D + if (Global::bGlutFont) // jeśli wybrano GLUT font, próbujemy zlinkować GLUT32.DLL + { + UINT mode = SetErrorMode(SEM_NOOPENFILEERRORBOX); // aby nie wrzeszczał, że znaleźć nie może + hinstGLUT32 = LoadLibrary(TEXT("GLUT32.DLL")); // get a handle to the DLL module + SetErrorMode(mode); + // If the handle is valid, try to get the function address. + if (hinstGLUT32) + glutBitmapCharacterDLL = + (FglutBitmapCharacter)GetProcAddress(hinstGLUT32, "glutBitmapCharacter"); + else + WriteLog("Missed GLUT32.DLL."); + if (glutBitmapCharacterDLL) + WriteLog("Used font from GLUT32.DLL."); + else + Global::bGlutFont = false; // nie udało się, trzeba spróbować na Display List + } + if (!Global::bGlutFont) + { // jeśli bezGLUTowy font + HFONT font; // Windows Font ID + base = glGenLists(96); // storage for 96 characters + font = CreateFont(-15, // height of font + 0, // width of font + 0, // angle of escapement + 0, // orientation angle + FW_BOLD, // font weight + FALSE, // italic + FALSE, // underline + FALSE, // strikeout + ANSI_CHARSET, // character set identifier + OUT_TT_PRECIS, // output precision + CLIP_DEFAULT_PRECIS, // clipping precision + ANTIALIASED_QUALITY, // output quality + FF_DONTCARE | DEFAULT_PITCH, // family and pitch + "Courier New"); // font name + SelectObject(hDC, font); // selects the font we want + wglUseFontBitmapsA(hDC, 32, 96, base); // builds 96 characters starting at character 32 + WriteLog("Display Lists font used."); //+AnsiString(glGetError()) + } + WriteLog("Font init OK"); //+AnsiString(glGetError()) - Timer::ResetTimers(); + Timer::ResetTimers(); - hWnd= NhWnd; - glColor4f(1.0f,3.0f,3.0f,0.0f); -// SwapBuffers(hDC); // Swap Buffers (Double Buffering) -// glClear(GL_COLOR_BUFFER_BIT); -// glFlush(); + hWnd = NhWnd; + glColor4f(1.0f, 3.0f, 3.0f, 0.0f); + // SwapBuffers(hDC); // Swap Buffers (Double Buffering) + // glClear(GL_COLOR_BUFFER_BIT); + // glFlush(); SetForegroundWindow(hWnd); WriteLog("Sound Init"); - glLoadIdentity(); -// glColor4f(0.3f,0.0f,0.0f,0.0f); + // glColor4f(0.3f,0.0f,0.0f,0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glTranslatef(0.0f,0.0f,-0.50f); -// glRasterPos2f(-0.25f, -0.10f); - glDisable(GL_DEPTH_TEST); // Disables depth testing - glColor3f(3.0f,3.0f,3.0f); + glTranslatef(0.0f, 0.0f, -0.50f); + // glRasterPos2f(-0.25f, -0.10f); + glDisable(GL_DEPTH_TEST); // Disables depth testing + glColor3f(3.0f, 3.0f, 3.0f); - GLuint logo; - logo=TTexturesManager::GetTextureID(szTexturePath,szSceneryPath,"logo",6); - glBindTexture(GL_TEXTURE_2D,logo); // Select our texture + GLuint logo; + logo = TTexturesManager::GetTextureID(szTexturePath, szSceneryPath, "logo", 6); + glBindTexture(GL_TEXTURE_2D, logo); // Select our texture - glBegin(GL_QUADS); // Drawing using triangles - glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.28f, -0.22f, 0.0f); //bottom left of the texture and quad - glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.28f, -0.22f, 0.0f); //bottom right of the texture and quad - glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.28f, 0.22f, 0.0f); //top right of the texture and quad - glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.28f, 0.22f, 0.0f); //top left of the texture and quad - glEnd(); - //~logo; Ra: to jest bez sensu zapis - glColor3f(0.0f,0.0f,100.0f); + glBegin(GL_QUADS); // Drawing using triangles + glTexCoord2f(0.0f, 0.0f); + glVertex3f(-0.28f, -0.22f, 0.0f); // bottom left of the texture and quad + glTexCoord2f(1.0f, 0.0f); + glVertex3f(0.28f, -0.22f, 0.0f); // bottom right of the texture and quad + glTexCoord2f(1.0f, 1.0f); + glVertex3f(0.28f, 0.22f, 0.0f); // top right of the texture and quad + glTexCoord2f(0.0f, 1.0f); + glVertex3f(-0.28f, 0.22f, 0.0f); // top left of the texture and quad + glEnd(); + //~logo; Ra: to jest bez sensu zapis + glColor3f(0.0f, 0.0f, 100.0f); if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.09f); - glPrint("Uruchamianie / Initializing..."); - glRasterPos2f(-0.25f, -0.10f); - glPrint("Dzwiek / Sound..."); + glRasterPos2f(-0.25f, -0.09f); + glPrint("Uruchamianie / Initializing..."); + glRasterPos2f(-0.25f, -0.10f); + glPrint("Dzwiek / Sound..."); } - SwapBuffers(hDC); // Swap Buffers (Double Buffering) + SwapBuffers(hDC); // Swap Buffers (Double Buffering) - glEnable(GL_LIGHTING); -/*-----------------------Sound Initialization-----------------------*/ + glEnable(GL_LIGHTING); + /*-----------------------Sound Initialization-----------------------*/ TSoundsManager::Init(hWnd); - //TSoundsManager::LoadSounds( "" ); -/*---------------------Sound Initialization End---------------------*/ + // TSoundsManager::LoadSounds( "" ); + /*---------------------Sound Initialization End---------------------*/ WriteLog("Sound Init OK"); if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.11f); - glPrint("OK."); + glRasterPos2f(-0.25f, -0.11f); + glPrint("OK."); } - SwapBuffers(hDC); // Swap Buffers (Double Buffering) + SwapBuffers(hDC); // Swap Buffers (Double Buffering) int i; - Paused= true; + Paused = true; WriteLog("Textures init"); - if(Global::detonatoryOK) + if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.12f); - glPrint("Tekstury / Textures..."); + glRasterPos2f(-0.25f, -0.12f); + glPrint("Tekstury / Textures..."); } - SwapBuffers(hDC); // Swap Buffers (Double Buffering) + SwapBuffers(hDC); // Swap Buffers (Double Buffering) TTexturesManager::Init(); WriteLog("Textures init OK"); - if(Global::detonatoryOK) + if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.13f); - glPrint("OK."); + glRasterPos2f(-0.25f, -0.13f); + glPrint("OK."); } - SwapBuffers(hDC); // Swap Buffers (Double Buffering) + SwapBuffers(hDC); // Swap Buffers (Double Buffering) WriteLog("Models init"); - if(Global::detonatoryOK) + if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.14f); - glPrint("Modele / Models..."); + glRasterPos2f(-0.25f, -0.14f); + glPrint("Modele / Models..."); } - SwapBuffers(hDC); // Swap Buffers (Double Buffering) -//McZapkie: dodalem sciezke zeby mozna bylo definiowac skad brac modele ale to malo eleganckie -// TModelsManager::LoadModels(asModelsPatch); + SwapBuffers(hDC); // Swap Buffers (Double Buffering) + // McZapkie: dodalem sciezke zeby mozna bylo definiowac skad brac modele ale to malo eleganckie + // TModelsManager::LoadModels(asModelsPatch); TModelsManager::Init(); WriteLog("Models init OK"); if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.15f); - glPrint("OK."); + glRasterPos2f(-0.25f, -0.15f); + glPrint("OK."); } - SwapBuffers(hDC); // Swap Buffers (Double Buffering) + SwapBuffers(hDC); // Swap Buffers (Double Buffering) WriteLog("Ground init"); if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.16f); - glPrint("Sceneria / Scenery (please wait)..."); + glRasterPos2f(-0.25f, -0.16f); + glPrint("Sceneria / Scenery (please wait)..."); } - SwapBuffers(hDC); // Swap Buffers (Double Buffering) + SwapBuffers(hDC); // Swap Buffers (Double Buffering) - Ground.Init(Global::szSceneryFile,hDC); -// Global::tSinceStart= 0; + Ground.Init(Global::szSceneryFile, hDC); + // Global::tSinceStart= 0; Clouds.Init(); WriteLog("Ground init OK"); if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.17f); - glPrint("OK."); + glRasterPos2f(-0.25f, -0.17f); + glPrint("OK."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) -// TTrack *Track=Ground.FindGroundNode("train_start",TP_TRACK)->pTrack; + // TTrack *Track=Ground.FindGroundNode("train_start",TP_TRACK)->pTrack; -// Camera.Init(vector3(2700,10,6500),0,M_PI,0); -// Camera.Init(vector3(00,40,000),0,M_PI,0); -// Camera.Init(vector3(1500,5,-4000),0,M_PI,0); -//McZapkie-130302 - coby nie przekompilowywac: -// Camera.Init(Global::pFreeCameraInit,0,M_PI,0); - Camera.Init(Global::pFreeCameraInit[0],Global::pFreeCameraInitAngle[0]); + // Camera.Init(vector3(2700,10,6500),0,M_PI,0); + // Camera.Init(vector3(00,40,000),0,M_PI,0); + // Camera.Init(vector3(1500,5,-4000),0,M_PI,0); + // McZapkie-130302 - coby nie przekompilowywac: + // Camera.Init(Global::pFreeCameraInit,0,M_PI,0); + Camera.Init(Global::pFreeCameraInit[0], Global::pFreeCameraInitAngle[0]); - char buff[255]="Player train init: "; + char buff[255] = "Player train init: "; if (Global::detonatoryOK) { - glRasterPos2f(-0.25f,-0.18f); - glPrint("Przygotowanie kabiny do sterowania..."); + glRasterPos2f(-0.25f, -0.18f); + glPrint("Przygotowanie kabiny do sterowania..."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) - strcat(buff,Global::asHumanCtrlVehicle.c_str()); + strcat(buff, Global::asHumanCtrlVehicle.c_str()); WriteLog(buff); - TGroundNode *nPlayerTrain=NULL; - if (Global::asHumanCtrlVehicle!="ghostview") - nPlayerTrain=Ground.DynamicFind(Global::asHumanCtrlVehicle); //szukanie w tych z obsadą + TGroundNode *nPlayerTrain = NULL; + if (Global::asHumanCtrlVehicle != "ghostview") + nPlayerTrain = Ground.DynamicFind(Global::asHumanCtrlVehicle); // szukanie w tych z obsadą if (nPlayerTrain) { - Train=new TTrain(); - if (Train->Init(nPlayerTrain->DynamicObject)) - { - Controlled=Train->Dynamic(); - mvControlled=Controlled->ControlledFind()->MoverParameters; - Global::pUserDynamic=Controlled; //renerowanie pojazdu względem kabiny - WriteLog("Player train init OK"); - if (Global::detonatoryOK) - { - glRasterPos2f(-0.25f, -0.19f); - glPrint("OK."); - } - FollowView(); - SwapBuffers(hDC); // Swap Buffers (Double Buffering) - } - else - { - Error("Player train init failed!"); - FreeFlyModeFlag=true; //Ra: automatycznie włączone latanie - if (Global::detonatoryOK) - { - glRasterPos2f(-0.25f, -0.20f); - glPrint("Blad inicjalizacji sterowanego pojazdu!"); - } - SwapBuffers(hDC); // Swap Buffers (Double Buffering) - Controlled=NULL; - mvControlled=NULL; - Camera.Type=tp_Free; - } + Train = new TTrain(); + if (Train->Init(nPlayerTrain->DynamicObject)) + { + Controlled = Train->Dynamic(); + mvControlled = Controlled->ControlledFind()->MoverParameters; + Global::pUserDynamic = Controlled; // renerowanie pojazdu względem kabiny + WriteLog("Player train init OK"); + if (Global::detonatoryOK) + { + glRasterPos2f(-0.25f, -0.19f); + glPrint("OK."); + } + FollowView(); + SwapBuffers(hDC); // Swap Buffers (Double Buffering) + } + else + { + Error("Player train init failed!"); + FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie + if (Global::detonatoryOK) + { + glRasterPos2f(-0.25f, -0.20f); + glPrint("Blad inicjalizacji sterowanego pojazdu!"); + } + SwapBuffers(hDC); // Swap Buffers (Double Buffering) + Controlled = NULL; + mvControlled = NULL; + Camera.Type = tp_Free; + } } else { - if (Global::asHumanCtrlVehicle!="ghostview") - {Error("Player train not exist!"); - if (Global::detonatoryOK) - { - glRasterPos2f(-0.25f, -0.20f); - glPrint("Wybrany pojazd nie istnieje w scenerii!"); - } - } - FreeFlyModeFlag=true; //Ra: automatycznie włączone latanie - SwapBuffers(hDC); //swap buffers (double buffering) - Controlled=NULL; - mvControlled=NULL; - Camera.Type=tp_Free; + if (Global::asHumanCtrlVehicle != "ghostview") + { + Error("Player train not exist!"); + if (Global::detonatoryOK) + { + glRasterPos2f(-0.25f, -0.20f); + glPrint("Wybrany pojazd nie istnieje w scenerii!"); + } + } + FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie + SwapBuffers(hDC); // swap buffers (double buffering) + Controlled = NULL; + mvControlled = NULL; + Camera.Type = tp_Free; } glEnable(GL_DEPTH_TEST); - //Ground.pTrain=Train; - //if (!Global::bMultiplayer) //na razie włączone - {//eventy aktywowane z klawiatury tylko dla jednego użytkownika - KeyEvents[0]=Ground.FindEvent("keyctrl00"); - KeyEvents[1]=Ground.FindEvent("keyctrl01"); - KeyEvents[2]=Ground.FindEvent("keyctrl02"); - KeyEvents[3]=Ground.FindEvent("keyctrl03"); - KeyEvents[4]=Ground.FindEvent("keyctrl04"); - KeyEvents[5]=Ground.FindEvent("keyctrl05"); - KeyEvents[6]=Ground.FindEvent("keyctrl06"); - KeyEvents[7]=Ground.FindEvent("keyctrl07"); - KeyEvents[8]=Ground.FindEvent("keyctrl08"); - KeyEvents[9]=Ground.FindEvent("keyctrl09"); + // Ground.pTrain=Train; + // if (!Global::bMultiplayer) //na razie włączone + { // eventy aktywowane z klawiatury tylko dla jednego użytkownika + KeyEvents[0] = Ground.FindEvent("keyctrl00"); + KeyEvents[1] = Ground.FindEvent("keyctrl01"); + KeyEvents[2] = Ground.FindEvent("keyctrl02"); + KeyEvents[3] = Ground.FindEvent("keyctrl03"); + KeyEvents[4] = Ground.FindEvent("keyctrl04"); + KeyEvents[5] = Ground.FindEvent("keyctrl05"); + KeyEvents[6] = Ground.FindEvent("keyctrl06"); + KeyEvents[7] = Ground.FindEvent("keyctrl07"); + KeyEvents[8] = Ground.FindEvent("keyctrl08"); + KeyEvents[9] = Ground.FindEvent("keyctrl09"); } - //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //{Texture blends with object background} - light=TTexturesManager::GetTextureID(szTexturePath,szSceneryPath,"smuga.tga"); - //Camera.Reset(); - ResetTimers(); - WriteLog("Load time: "+FloatToStrF((86400.0*((double)Now()-time)),ffFixed,7,1)+" seconds"); - if (DebugModeFlag) //w Debugmode automatyczne włączenie AI - if (Train) - if (Train->Dynamic()->Mechanik) - Train->Dynamic()->Mechanik->TakeControl(true); - return true; + // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //{Texture blends with object + // background} + light = TTexturesManager::GetTextureID(szTexturePath, szSceneryPath, "smuga.tga"); + // Camera.Reset(); + ResetTimers(); + WriteLog("Load time: " + FloatToStrF((86400.0 * ((double)Now() - time)), ffFixed, 7, 1) + + " seconds"); + if (DebugModeFlag) // w Debugmode automatyczne włączenie AI + if (Train) + if (Train->Dynamic()->Mechanik) + Train->Dynamic()->Mechanik->TakeControl(true); + return true; }; void __fastcall TWorld::OnKeyDown(int cKey) -{//(cKey) to kod klawisza, cyfrowe i literowe się zgadzają - //Ra 2014-09: tu by można dodać tabelę konwersji: 256 wirtualnych kodów w kontekście dwóch przełączników [Shift] i [Ctrl] - //na każdy kod wirtualny niech przypadają 4 bajty: 2 dla naciśnięcia i 2 dla zwolnienia - //powtórzone 256 razy da 1kB na każdy stan przełączników, łącznie będzie 4kB pierwszej tabeli przekodowania - if (!Global::iPause) - {//podczas pauzy klawisze nie działają - AnsiString info="Key pressed: ["; - if (Console::Pressed(VK_SHIFT)) info+="Shift]+["; - if (Console::Pressed(VK_CONTROL)) info+="Ctrl]+["; - if (cKey>192) //coś tam jeszcze ciekawego jest? - { - if (cKey<255) //255 to [Fn] w laptopach - WriteLog(info+AnsiString(char(cKey-128))+"]"); - } - else if (cKey>=186) - WriteLog(info+AnsiString(";=,-./~").SubString(cKey-185,1)+"]"); - else if (cKey>123) //coś tam jeszcze ciekawego jest? - WriteLog(info+AnsiString(cKey)+"]"); //numer klawisza - else if (cKey>=112) //funkcyjne - WriteLog(info+"F"+AnsiString(cKey-111)+"]"); - else if (cKey>=96) - WriteLog(info+"Num"+AnsiString("0123456789*+?-./").SubString(cKey-95,1)+"]"); - else if (((cKey>='0')&&(cKey<='9'))||((cKey>='A')&&(cKey<='Z'))||(cKey==' ')) - WriteLog(info+AnsiString(char(cKey))+"]"); - else if (cKey=='-') - WriteLog(info+"Insert]"); - else if (cKey=='.') - WriteLog(info+"Delete]"); - else if (cKey=='$') - WriteLog(info+"Home]"); - else if (cKey=='#') - WriteLog(info+"End]"); - else if (cKey>'Z') //żeby nie logować kursorów - WriteLog(info+AnsiString(cKey)+"]"); //numer klawisza - } - if ((cKey<='9')?(cKey>='0'):false) //klawisze cyfrowe - {int i=cKey-'0'; //numer klawisza - if (Console::Pressed(VK_SHIFT)) - {//z [Shift] uruchomienie eventu - if (!Global::iPause) //podczas pauzy klawisze nie działają - if (KeyEvents[i]) - Ground.AddToQuery(KeyEvents[i],NULL); - } - else //zapamiętywanie kamery może działać podczas pauzy - if (FreeFlyModeFlag) //w trybie latania można przeskakiwać do ustawionych kamer - if ((Global::iTextMode!=VK_F12)&&(Global::iTextMode!=VK_F3)) //ograniczamy użycie kamer - {if ((!Global::pFreeCameraInit[i].x&&!Global::pFreeCameraInit[i].y&&!Global::pFreeCameraInit[i].z)) - {//jeśli kamera jest w punkcie zerowym, zapamiętanie współrzędnych i kątów - Global::pFreeCameraInit[i]=Camera.Pos; - Global::pFreeCameraInitAngle[i].x=Camera.Pitch; - Global::pFreeCameraInitAngle[i].y=Camera.Yaw; - Global::pFreeCameraInitAngle[i].z=Camera.Roll; - //logowanie, żeby można było do scenerii przepisać - WriteLog("camera " - +FloatToStrF(Global::pFreeCameraInit[i].x,ffFixed,7,3)+" " - +FloatToStrF(Global::pFreeCameraInit[i].y,ffFixed,7,3)+" " - +FloatToStrF(Global::pFreeCameraInit[i].z,ffFixed,7,3)+" " - +FloatToStrF(RadToDeg(Global::pFreeCameraInitAngle[i].x),ffFixed,7,3)+" " - +FloatToStrF(RadToDeg(Global::pFreeCameraInitAngle[i].y),ffFixed,7,3)+" " - +FloatToStrF(RadToDeg(Global::pFreeCameraInitAngle[i].z),ffFixed,7,3)+" " - +AnsiString(i)+" endcamera"); +{ //(cKey) to kod klawisza, cyfrowe i literowe się zgadzają + // Ra 2014-09: tu by można dodać tabelę konwersji: 256 wirtualnych kodów w kontekście dwóch + // przełączników [Shift] i [Ctrl] + // na każdy kod wirtualny niech przypadają 4 bajty: 2 dla naciśnięcia i 2 dla zwolnienia + // powtórzone 256 razy da 1kB na każdy stan przełączników, łącznie będzie 4kB pierwszej tabeli + // przekodowania + if (!Global::iPause) + { // podczas pauzy klawisze nie działają + AnsiString info = "Key pressed: ["; + if (Console::Pressed(VK_SHIFT)) + info += "Shift]+["; + if (Console::Pressed(VK_CONTROL)) + info += "Ctrl]+["; + if (cKey > 192) // coś tam jeszcze ciekawego jest? + { + if (cKey < 255) // 255 to [Fn] w laptopach + WriteLog(info + AnsiString(char(cKey - 128)) + "]"); + } + else if (cKey >= 186) + WriteLog(info + AnsiString(";=,-./~").SubString(cKey - 185, 1) + "]"); + else if (cKey > 123) // coś tam jeszcze ciekawego jest? + WriteLog(info + AnsiString(cKey) + "]"); // numer klawisza + else if (cKey >= 112) // funkcyjne + WriteLog(info + "F" + AnsiString(cKey - 111) + "]"); + else if (cKey >= 96) + WriteLog(info + "Num" + AnsiString("0123456789*+?-./").SubString(cKey - 95, 1) + "]"); + else if (((cKey >= '0') && (cKey <= '9')) || ((cKey >= 'A') && (cKey <= 'Z')) || + (cKey == ' ')) + WriteLog(info + AnsiString(char(cKey)) + "]"); + else if (cKey == '-') + WriteLog(info + "Insert]"); + else if (cKey == '.') + WriteLog(info + "Delete]"); + else if (cKey == '$') + WriteLog(info + "Home]"); + else if (cKey == '#') + WriteLog(info + "End]"); + else if (cKey > 'Z') //żeby nie logować kursorów + WriteLog(info + AnsiString(cKey) + "]"); // numer klawisza } - else //również przeskakiwanie - {//Ra: to z tą kamerą (Camera.Pos i Global::pCameraPosition) jest trochę bez sensu - Global::SetCameraPosition(Global::pFreeCameraInit[i]); //nowa pozycja dla generowania obiektów - Ground.Silence(Camera.Pos); //wyciszenie wszystkiego z poprzedniej pozycji - Camera.Init(Global::pFreeCameraInit[i],Global::pFreeCameraInitAngle[i]); //przestawienie - } - } - //będzie jeszcze załączanie sprzęgów z [Ctrl] - } - else if ((cKey>=VK_F1)?(cKey<=VK_F12):false) - { - switch (cKey) - {case VK_F1: //czas i relacja - case VK_F3: - case VK_F5: //przesiadka do innego pojazdu - case VK_F8: //FPS - case VK_F9: //wersja, typ wyświetlania, błędy OpenGL - case VK_F10: - if (Global::iTextMode==cKey) - Global::iTextMode=(Global::iPause&&(cKey!=VK_F1)?VK_F1:0); //wyłączenie napisów, chyba że pauza - else - Global::iTextMode=cKey; - break; - case VK_F2: //parametry pojazdu - if (Global::iTextMode==cKey) //jeśli kolejne naciśnięcie - ++Global::iScreenMode[cKey-VK_F1]; //kolejny ekran - else - {//pierwsze naciśnięcie daje pierwszy (tzn. zerowy) ekran - Global::iTextMode=cKey; - Global::iScreenMode[cKey-VK_F1]=0; - } - break; - case VK_F12: //coś tam jeszcze - if (Console::Pressed(VK_CONTROL)&&Console::Pressed(VK_SHIFT)) - DebugModeFlag=!DebugModeFlag; //taka opcjonalna funkcja, może się czasem przydać -/* //Ra 2F1P: teraz włączanie i wyłączanie klawiszami cyfrowymi po użyciu [F12] - else if (Console::Pressed(VK_SHIFT)) - {//odpalenie logu w razie "W" - if ((Global::iWriteLogEnabled&2)==0) //nie było okienka - {//otwarcie okna - AllocConsole(); - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN); - } - Global::iWriteLogEnabled|=3; - } */ - else - Global::iTextMode=cKey; - break; - case VK_F4: - InOutKey(); - break; - case VK_F6: - if (DebugModeFlag) - {//przyspieszenie symulacji do testowania scenerii... uwaga na FPS! - //Global::iViewMode=VK_F6; - if (Console::Pressed(VK_CONTROL)) - Global::fTimeSpeed=(Console::Pressed(VK_SHIFT)?10.0:5.0); - else - Global::fTimeSpeed=(Console::Pressed(VK_SHIFT)?2.0:1.0); - } - break; - } - //if (cKey!=VK_F4) - return; //nie są przekazywane do pojazdu wcale - } - if (Global::iTextMode==VK_F10) //wyświetlone napisy klawiszem F10 - {//i potwierdzenie - Global::iTextMode=(cKey=='Y')?-1:0; //flaga wyjścia z programu - return; //nie przekazujemy do pociągu - } - else if ((Global::iTextMode==VK_F12)?(cKey>='0')&&(cKey<='9'):false) - {//tryb konfiguracji debugmode (przestawianie kamery już wyłączone - if (!Console::Pressed(VK_SHIFT)) //bez [Shift] - {if (cKey=='1') - Global::iWriteLogEnabled^=1; //włącz/wyłącz logowanie do pliku - else if (cKey=='2') - {//włącz/wyłącz okno konsoli - Global::iWriteLogEnabled^=2; - if ((Global::iWriteLogEnabled&2)==0) //nie było okienka - {//otwarcie okna - AllocConsole(); //jeśli konsola już jest, to zwróci błąd; uwalniać nie ma po co, bo się odłączy - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN); - } - } - //else if (cKey=='3') Global::iWriteLogEnabled^=4; //wypisywanie nazw torów - } - } - else if (cKey==3) //[Ctrl]+[Break] - {//hamowanie wszystkich pojazdów w okolicy - Ground.RadioStop(Camera.Pos); - } - else if (!Global::iPause) //||(cKey==VK_F4)) //podczas pauzy sterownaie nie działa, F4 tak - if (Train) - if (Controlled) - if ((Controlled->Controller==Humandriver)?true:DebugModeFlag||(cKey=='Q')) - Train->OnKeyDown(cKey); //przekazanie klawisza do kabiny - if (FreeFlyModeFlag) //aby nie odluźniało wagonu za lokomotywą - {//operacje wykonywane na dowolnym pojeździe, przeniesione tu z kabiny - if (cKey==Global::Keys[k_Releaser]) //odluźniacz - {//działa globalnie, sprawdzić zasięg - TDynamicObject *temp=Global::DynamicNearest(); - if (temp) - { - if (GetAsyncKeyState(VK_CONTROL)<0) //z ctrl odcinanie + if ((cKey <= '9') ? (cKey >= '0') : false) // klawisze cyfrowe { - temp->MoverParameters->BrakeStatus^=128; + int i = cKey - '0'; // numer klawisza + if (Console::Pressed(VK_SHIFT)) + { // z [Shift] uruchomienie eventu + if (!Global::iPause) // podczas pauzy klawisze nie działają + if (KeyEvents[i]) + Ground.AddToQuery(KeyEvents[i], NULL); + } + else // zapamiętywanie kamery może działać podczas pauzy + if (FreeFlyModeFlag) // w trybie latania można przeskakiwać do ustawionych kamer + if ((Global::iTextMode != VK_F12) && + (Global::iTextMode != VK_F3)) // ograniczamy użycie kamer + { + if ((!Global::pFreeCameraInit[i].x && !Global::pFreeCameraInit[i].y && + !Global::pFreeCameraInit[i].z)) + { // jeśli kamera jest w punkcie zerowym, zapamiętanie współrzędnych i kątów + Global::pFreeCameraInit[i] = Camera.Pos; + Global::pFreeCameraInitAngle[i].x = Camera.Pitch; + Global::pFreeCameraInitAngle[i].y = Camera.Yaw; + Global::pFreeCameraInitAngle[i].z = Camera.Roll; + // logowanie, żeby można było do scenerii przepisać + WriteLog( + "camera " + FloatToStrF(Global::pFreeCameraInit[i].x, ffFixed, 7, 3) + " " + + FloatToStrF(Global::pFreeCameraInit[i].y, ffFixed, 7, 3) + " " + + FloatToStrF(Global::pFreeCameraInit[i].z, ffFixed, 7, 3) + " " + + FloatToStrF(RadToDeg(Global::pFreeCameraInitAngle[i].x), ffFixed, 7, 3) + + " " + + FloatToStrF(RadToDeg(Global::pFreeCameraInitAngle[i].y), ffFixed, 7, 3) + + " " + + FloatToStrF(RadToDeg(Global::pFreeCameraInitAngle[i].z), ffFixed, 7, 3) + + " " + AnsiString(i) + " endcamera"); + } + else // również przeskakiwanie + { // Ra: to z tą kamerą (Camera.Pos i Global::pCameraPosition) jest trochę bez sensu + Global::SetCameraPosition( + Global::pFreeCameraInit[i]); // nowa pozycja dla generowania obiektów + Ground.Silence(Camera.Pos); // wyciszenie wszystkiego z poprzedniej pozycji + Camera.Init(Global::pFreeCameraInit[i], + Global::pFreeCameraInitAngle[i]); // przestawienie + } + } + // będzie jeszcze załączanie sprzęgów z [Ctrl] } - else - if (temp->MoverParameters->BrakeReleaser(1)) + else if ((cKey >= VK_F1) ? (cKey <= VK_F12) : false) { - //temp->sBrakeAcc-> - //dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); - //dsbPneumaticRelay->Play(0,0,0); //temp->Position()-Camera.Pos //??? + switch (cKey) + { + case VK_F1: // czas i relacja + case VK_F3: + case VK_F5: // przesiadka do innego pojazdu + case VK_F8: // FPS + case VK_F9: // wersja, typ wyświetlania, błędy OpenGL + case VK_F10: + if (Global::iTextMode == cKey) + Global::iTextMode = + (Global::iPause && (cKey != VK_F1) ? VK_F1 : + 0); // wyłączenie napisów, chyba że pauza + else + Global::iTextMode = cKey; + break; + case VK_F2: // parametry pojazdu + if (Global::iTextMode == cKey) // jeśli kolejne naciśnięcie + ++Global::iScreenMode[cKey - VK_F1]; // kolejny ekran + else + { // pierwsze naciśnięcie daje pierwszy (tzn. zerowy) ekran + Global::iTextMode = cKey; + Global::iScreenMode[cKey - VK_F1] = 0; + } + break; + case VK_F12: // coś tam jeszcze + if (Console::Pressed(VK_CONTROL) && Console::Pressed(VK_SHIFT)) + DebugModeFlag = !DebugModeFlag; // taka opcjonalna funkcja, może się czasem przydać + /* //Ra 2F1P: teraz włączanie i wyłączanie klawiszami cyfrowymi po użyciu [F12] + else if (Console::Pressed(VK_SHIFT)) + {//odpalenie logu w razie "W" + if ((Global::iWriteLogEnabled&2)==0) //nie było okienka + {//otwarcie okna + AllocConsole(); + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN); + } + Global::iWriteLogEnabled|=3; + } */ + else + Global::iTextMode = cKey; + break; + case VK_F4: + InOutKey(); + break; + case VK_F6: + if (DebugModeFlag) + { // przyspieszenie symulacji do testowania scenerii... uwaga na FPS! + // Global::iViewMode=VK_F6; + if (Console::Pressed(VK_CONTROL)) + Global::fTimeSpeed = (Console::Pressed(VK_SHIFT) ? 10.0 : 5.0); + else + Global::fTimeSpeed = (Console::Pressed(VK_SHIFT) ? 2.0 : 1.0); + } + break; + } + // if (cKey!=VK_F4) + return; // nie są przekazywane do pojazdu wcale } - } - } - else if (cKey==Global::Keys[k_Heating]) //Ra: klawisz nie jest najszczęśliwszy - {//zmiana próżny/ładowny; Ra: zabrane z kabiny - TDynamicObject *temp=Global::DynamicNearest(); - if (temp) - { - if (Console::Pressed(VK_SHIFT)?temp->MoverParameters->IncBrakeMult():temp->MoverParameters->DecBrakeMult()) - if (Train) - {//dźwięk oczywiście jest w kabinie - Train->dsbSwitch->SetVolume(DSBVOLUME_MAX); - Train->dsbSwitch->Play(0,0,0); - } - } - } - else if (cKey==Global::Keys[k_EndSign]) - {//Ra 2014-07: zabrane z kabiny - TDynamicObject *tmp=Global::CouplerNearest(); //domyślnie wyszukuje do 20m - if (tmp) - { - int CouplNr=(LengthSquared3(tmp->HeadPosition()-Camera.Pos)>LengthSquared3(tmp->RearPosition()-Camera.Pos)?1:-1)*tmp->DirectionGet(); - if (CouplNr<0) CouplNr=0; //z [-1,1] zrobić [0,1] - int mask,set=0; //Ra: [Shift]+[Ctrl]+[T] odpala mi jakąś idiotyczną zmianę tapety pulpitu :/ - if (GetAsyncKeyState(VK_SHIFT)<0) //z [Shift] zapalanie - set=mask=64; //bez [Ctrl] założyć tabliczki - else if (GetAsyncKeyState(VK_CONTROL)<0) - set=mask=2+32; //z [Ctrl] zapalić światła czerwone - else - mask=2+32+64; //wyłączanie ściąga wszystko - if (((tmp->iLights[CouplNr])&mask)!=set) - { - tmp->iLights[CouplNr]=(tmp->iLights[CouplNr]&~mask)|set; - if (Train) - {//Ra: ten dźwięk z kabiny to przegięcie, ale na razie zostawiam - Train->dsbSwitch->SetVolume(DSBVOLUME_MAX); - Train->dsbSwitch->Play(0,0,0); - } + if (Global::iTextMode == VK_F10) // wyświetlone napisy klawiszem F10 + { // i potwierdzenie + Global::iTextMode = (cKey == 'Y') ? -1 : 0; // flaga wyjścia z programu + return; // nie przekazujemy do pociągu } - } - } - else if (cKey==Global::Keys[k_IncLocalBrakeLevel]) - {//zahamowanie dowolnego pojazdu - TDynamicObject *temp=Global::DynamicNearest(); - if (temp) - { - if (GetAsyncKeyState(VK_CONTROL)<0) - if ((temp->MoverParameters->LocalBrake==ManualBrake)||(temp->MoverParameters->MBrake==true)) - temp->MoverParameters->IncManualBrakeLevel(1); - else; - else - if (temp->MoverParameters->LocalBrake!=ManualBrake) - if (temp->MoverParameters->IncLocalBrakeLevelFAST()) - if (Train) - {//dźwięk oczywiście jest w kabinie - Train->dsbPneumaticRelay->SetVolume(-80); - Train->dsbPneumaticRelay->Play(0,0,0); - } - } - } - else if (cKey==Global::Keys[k_DecLocalBrakeLevel]) - {//odhamowanie dowolnego pojazdu - TDynamicObject *temp=Global::DynamicNearest(); - if (temp) - { - if (GetAsyncKeyState(VK_CONTROL)<0) - if ((temp->MoverParameters->LocalBrake==ManualBrake)||(temp->MoverParameters->MBrake==true)) - temp->MoverParameters->DecManualBrakeLevel(1); - else; - else - if (temp->MoverParameters->LocalBrake!=ManualBrake) - if (temp->MoverParameters->DecLocalBrakeLevelFAST()) - if (Train) - {//dźwięk oczywiście jest w kabinie - Train->dsbPneumaticRelay->SetVolume(-80); - Train->dsbPneumaticRelay->Play(0,0,0); - } - } - } - } - //switch (cKey) - //{case 'a': //ignorowanie repetycji - // case 'A': Global::iKeyLast=cKey; break; - // default: Global::iKeyLast=0; - //} + else if ((Global::iTextMode == VK_F12) ? (cKey >= '0') && (cKey <= '9') : false) + { // tryb konfiguracji debugmode (przestawianie kamery już wyłączone + if (!Console::Pressed(VK_SHIFT)) // bez [Shift] + { + if (cKey == '1') + Global::iWriteLogEnabled ^= 1; // włącz/wyłącz logowanie do pliku + else if (cKey == '2') + { // włącz/wyłącz okno konsoli + Global::iWriteLogEnabled ^= 2; + if ((Global::iWriteLogEnabled & 2) == 0) // nie było okienka + { // otwarcie okna + AllocConsole(); // jeśli konsola już jest, to zwróci błąd; uwalniać nie ma po + // co, bo się odłączy + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN); + } + } + // else if (cKey=='3') Global::iWriteLogEnabled^=4; //wypisywanie nazw torów + } + } + else if (cKey == 3) //[Ctrl]+[Break] + { // hamowanie wszystkich pojazdów w okolicy + Ground.RadioStop(Camera.Pos); + } + else if (!Global::iPause) //||(cKey==VK_F4)) //podczas pauzy sterownaie nie działa, F4 tak + if (Train) + if (Controlled) + if ((Controlled->Controller == Humandriver) ? true : DebugModeFlag || (cKey == 'Q')) + Train->OnKeyDown(cKey); // przekazanie klawisza do kabiny + if (FreeFlyModeFlag) // aby nie odluźniało wagonu za lokomotywą + { // operacje wykonywane na dowolnym pojeździe, przeniesione tu z kabiny + if (cKey == Global::Keys[k_Releaser]) // odluźniacz + { // działa globalnie, sprawdzić zasięg + TDynamicObject *temp = Global::DynamicNearest(); + if (temp) + { + if (GetAsyncKeyState(VK_CONTROL) < 0) // z ctrl odcinanie + { + temp->MoverParameters->BrakeStatus ^= 128; + } + else if (temp->MoverParameters->BrakeReleaser(1)) + { + // temp->sBrakeAcc-> + // dsbPneumaticRelay->SetVolume(DSBVOLUME_MAX); + // dsbPneumaticRelay->Play(0,0,0); //temp->Position()-Camera.Pos //??? + } + } + } + else if (cKey == Global::Keys[k_Heating]) // Ra: klawisz nie jest najszczęśliwszy + { // zmiana próżny/ładowny; Ra: zabrane z kabiny + TDynamicObject *temp = Global::DynamicNearest(); + if (temp) + { + if (Console::Pressed(VK_SHIFT) ? temp->MoverParameters->IncBrakeMult() : + temp->MoverParameters->DecBrakeMult()) + if (Train) + { // dźwięk oczywiście jest w kabinie + Train->dsbSwitch->SetVolume(DSBVOLUME_MAX); + Train->dsbSwitch->Play(0, 0, 0); + } + } + } + else if (cKey == Global::Keys[k_EndSign]) + { // Ra 2014-07: zabrane z kabiny + TDynamicObject *tmp = Global::CouplerNearest(); // domyślnie wyszukuje do 20m + if (tmp) + { + int CouplNr = (LengthSquared3(tmp->HeadPosition() - Camera.Pos) > + LengthSquared3(tmp->RearPosition() - Camera.Pos) ? + 1 : + -1) * + tmp->DirectionGet(); + if (CouplNr < 0) + CouplNr = 0; // z [-1,1] zrobić [0,1] + int mask, set = 0; // Ra: [Shift]+[Ctrl]+[T] odpala mi jakąś idiotyczną zmianę + // tapety pulpitu :/ + if (GetAsyncKeyState(VK_SHIFT) < 0) // z [Shift] zapalanie + set = mask = 64; // bez [Ctrl] założyć tabliczki + else if (GetAsyncKeyState(VK_CONTROL) < 0) + set = mask = 2 + 32; // z [Ctrl] zapalić światła czerwone + else + mask = 2 + 32 + 64; // wyłączanie ściąga wszystko + if (((tmp->iLights[CouplNr]) & mask) != set) + { + tmp->iLights[CouplNr] = (tmp->iLights[CouplNr] & ~mask) | set; + if (Train) + { // Ra: ten dźwięk z kabiny to przegięcie, ale na razie zostawiam + Train->dsbSwitch->SetVolume(DSBVOLUME_MAX); + Train->dsbSwitch->Play(0, 0, 0); + } + } + } + } + else if (cKey == Global::Keys[k_IncLocalBrakeLevel]) + { // zahamowanie dowolnego pojazdu + TDynamicObject *temp = Global::DynamicNearest(); + if (temp) + { + if (GetAsyncKeyState(VK_CONTROL) < 0) + if ((temp->MoverParameters->LocalBrake == ManualBrake) || + (temp->MoverParameters->MBrake == true)) + temp->MoverParameters->IncManualBrakeLevel(1); + else + ; + else if (temp->MoverParameters->LocalBrake != ManualBrake) + if (temp->MoverParameters->IncLocalBrakeLevelFAST()) + if (Train) + { // dźwięk oczywiście jest w kabinie + Train->dsbPneumaticRelay->SetVolume(-80); + Train->dsbPneumaticRelay->Play(0, 0, 0); + } + } + } + else if (cKey == Global::Keys[k_DecLocalBrakeLevel]) + { // odhamowanie dowolnego pojazdu + TDynamicObject *temp = Global::DynamicNearest(); + if (temp) + { + if (GetAsyncKeyState(VK_CONTROL) < 0) + if ((temp->MoverParameters->LocalBrake == ManualBrake) || + (temp->MoverParameters->MBrake == true)) + temp->MoverParameters->DecManualBrakeLevel(1); + else + ; + else if (temp->MoverParameters->LocalBrake != ManualBrake) + if (temp->MoverParameters->DecLocalBrakeLevelFAST()) + if (Train) + { // dźwięk oczywiście jest w kabinie + Train->dsbPneumaticRelay->SetVolume(-80); + Train->dsbPneumaticRelay->Play(0, 0, 0); + } + } + } + } + // switch (cKey) + //{case 'a': //ignorowanie repetycji + // case 'A': Global::iKeyLast=cKey; break; + // default: Global::iKeyLast=0; + //} } void __fastcall TWorld::OnKeyUp(int cKey) -{//zwolnienie klawisza; (cKey) to kod klawisza, cyfrowe i literowe się zgadzają - if (!Global::iPause) //podczas pauzy sterownaie nie działa - if (Train) - if (Controlled) - if ((Controlled->Controller==Humandriver)?true:DebugModeFlag||(cKey=='Q')) - Train->OnKeyUp(cKey); //przekazanie zwolnienia klawisza do kabiny +{ // zwolnienie klawisza; (cKey) to kod klawisza, cyfrowe i literowe się zgadzają + if (!Global::iPause) // podczas pauzy sterownaie nie działa + if (Train) + if (Controlled) + if ((Controlled->Controller == Humandriver) ? true : DebugModeFlag || (cKey == 'Q')) + Train->OnKeyUp(cKey); // przekazanie zwolnienia klawisza do kabiny }; void __fastcall TWorld::OnMouseMove(double x, double y) -{//McZapkie:060503-definicja obracania myszy - Camera.OnCursorMove(x*Global::fMouseXScale,-y*Global::fMouseYScale); +{ // McZapkie:060503-definicja obracania myszy + Camera.OnCursorMove(x * Global::fMouseXScale, -y * Global::fMouseYScale); } void __fastcall TWorld::InOutKey() -{//przełączenie widoku z kabiny na zewnętrzny i odwrotnie - FreeFlyModeFlag=!FreeFlyModeFlag; //zmiana widoku - if (FreeFlyModeFlag) - {//jeżeli poza kabiną, przestawiamy w jej okolicę - OK - Global::pUserDynamic=NULL; //bez renderowania względem kamery - if (Train) - {//Train->Dynamic()->ABuSetModelShake(vector3(0,0,0)); - Train->Silence(); //wyłączenie dźwięków kabiny - Train->Dynamic()->bDisplayCab=false; - DistantView(); - } - } - else - {//jazda w kabinie - if (Train) - {Global::pUserDynamic=Controlled; //renerowanie względem kamery - Train->Dynamic()->bDisplayCab=true; - Train->Dynamic()->ABuSetModelShake(vector3(0,0,0)); //zerowanie przesunięcia przed powrotem? - //Camera.Stop(); //zatrzymanie ruchu - Train->MechStop(); - FollowView(); //na pozycję mecha - } - else - FreeFlyModeFlag=true; //nadal poza kabiną - } +{ // przełączenie widoku z kabiny na zewnętrzny i odwrotnie + FreeFlyModeFlag = !FreeFlyModeFlag; // zmiana widoku + if (FreeFlyModeFlag) + { // jeżeli poza kabiną, przestawiamy w jej okolicę - OK + Global::pUserDynamic = NULL; // bez renderowania względem kamery + if (Train) + { // Train->Dynamic()->ABuSetModelShake(vector3(0,0,0)); + Train->Silence(); // wyłączenie dźwięków kabiny + Train->Dynamic()->bDisplayCab = false; + DistantView(); + } + } + else + { // jazda w kabinie + if (Train) + { + Global::pUserDynamic = Controlled; // renerowanie względem kamery + Train->Dynamic()->bDisplayCab = true; + Train->Dynamic()->ABuSetModelShake( + vector3(0, 0, 0)); // zerowanie przesunięcia przed powrotem? + // Camera.Stop(); //zatrzymanie ruchu + Train->MechStop(); + FollowView(); // na pozycję mecha + } + else + FreeFlyModeFlag = true; // nadal poza kabiną + } }; void __fastcall TWorld::DistantView() -{//ustawienie widoku pojazdu z zewnątrz - if (Controlled) //jest pojazd do prowadzenia? - {//na prowadzony - Camera.Pos=Controlled->GetPosition()+(Controlled->MoverParameters->ActiveCab>=0?30:-30)*Controlled->VectorFront()+vector3(0,5,0); - Camera.LookAt=Controlled->GetPosition(); - Camera.RaLook(); //jednorazowe przestawienie kamery - } - else if (pDynamicNearest) //jeśli jest pojazd wykryty blisko - {//patrzenie na najbliższy pojazd - Camera.Pos=pDynamicNearest->GetPosition()+(pDynamicNearest->MoverParameters->ActiveCab>=0?30:-30)*pDynamicNearest->VectorFront()+vector3(0,5,0); - Camera.LookAt=pDynamicNearest->GetPosition(); - Camera.RaLook(); //jednorazowe przestawienie kamery - } +{ // ustawienie widoku pojazdu z zewnątrz + if (Controlled) // jest pojazd do prowadzenia? + { // na prowadzony + Camera.Pos = + Controlled->GetPosition() + + (Controlled->MoverParameters->ActiveCab >= 0 ? 30 : -30) * Controlled->VectorFront() + + vector3(0, 5, 0); + Camera.LookAt = Controlled->GetPosition(); + Camera.RaLook(); // jednorazowe przestawienie kamery + } + else if (pDynamicNearest) // jeśli jest pojazd wykryty blisko + { // patrzenie na najbliższy pojazd + Camera.Pos = pDynamicNearest->GetPosition() + + (pDynamicNearest->MoverParameters->ActiveCab >= 0 ? 30 : -30) * + pDynamicNearest->VectorFront() + + vector3(0, 5, 0); + Camera.LookAt = pDynamicNearest->GetPosition(); + Camera.RaLook(); // jednorazowe przestawienie kamery + } }; void __fastcall TWorld::FollowView(bool wycisz) -{//ustawienie śledzenia pojazdu - //ABu 180404 powrot mechanika na siedzenie albo w okolicę pojazdu - //if (Console::Pressed(VK_F4)) Global::iViewMode=VK_F4; - //Ra: na zewnątrz wychodzimy w Train.cpp - Camera.Reset(); //likwidacja obrotów - patrzy horyzontalnie na południe - if (Controlled) //jest pojazd do prowadzenia? - { - vector3 camStara=Camera.Pos; //przestawianie kamery jest bez sensu: do przerobienia na potem - //Controlled->ABuSetModelShake(vector3(0,0,0)); - if (FreeFlyModeFlag) - {//jeżeli poza kabiną, przestawiamy w jej okolicę - OK - if (Train) - Train->Dynamic()->ABuSetModelShake(vector3(0,0,0)); //wyłączenie trzęsienia na siłę? - //Camera.Pos=Train->pMechPosition+Normalize(Train->GetDirection())*20; - DistantView(); //przestawienie kamery - //żeby nie bylo numerów z 'fruwajacym' lokiem - konsekwencja bujania pudła - Global::SetCameraPosition(Camera.Pos); //tu ustawić nową, bo od niej liczą się odległości - Ground.Silence(camStara); //wyciszenie dźwięków z poprzedniej pozycji - } - else if (Train) - {//korekcja ustawienia w kabinie - OK - vector3 camStara=Camera.Pos; //przestawianie kamery jest bez sensu: do przerobienia na potem - //Ra: czy to tu jest potrzebne, bo przelicza się kawałek dalej? - Camera.Pos=Train->pMechPosition;//Train.GetPosition1(); - Camera.Roll=atan(Train->pMechShake.x*Train->fMechRoll); //hustanie kamery na boki - Camera.Pitch-=atan(Train->vMechVelocity.z*Train->fMechPitch); //hustanie kamery przod tyl - if (Train->Dynamic()->MoverParameters->ActiveCab==0) - Camera.LookAt=Train->pMechPosition+Train->GetDirection(); - else //patrz w strone wlasciwej kabiny - Camera.LookAt=Train->pMechPosition+Train->GetDirection()*Train->Dynamic()->MoverParameters->ActiveCab; - Train->pMechOffset.x=Train->pMechSittingPosition.x; - Train->pMechOffset.y=Train->pMechSittingPosition.y; - Train->pMechOffset.z=Train->pMechSittingPosition.z; - Global::SetCameraPosition(Train->Dynamic()->GetPosition()); //tu ustawić nową, bo od niej liczą się odległości - if (wycisz) //trzymanie prawego w kabinie daje marny efekt - Ground.Silence(camStara); //wyciszenie dźwięków z poprzedniej pozycji - } - } - else DistantView(); +{ // ustawienie śledzenia pojazdu + // ABu 180404 powrot mechanika na siedzenie albo w okolicę pojazdu + // if (Console::Pressed(VK_F4)) Global::iViewMode=VK_F4; + // Ra: na zewnątrz wychodzimy w Train.cpp + Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na południe + if (Controlled) // jest pojazd do prowadzenia? + { + vector3 camStara = + Camera.Pos; // przestawianie kamery jest bez sensu: do przerobienia na potem + // Controlled->ABuSetModelShake(vector3(0,0,0)); + if (FreeFlyModeFlag) + { // jeżeli poza kabiną, przestawiamy w jej okolicę - OK + if (Train) + Train->Dynamic()->ABuSetModelShake( + vector3(0, 0, 0)); // wyłączenie trzęsienia na siłę? + // Camera.Pos=Train->pMechPosition+Normalize(Train->GetDirection())*20; + DistantView(); // przestawienie kamery + //żeby nie bylo numerów z 'fruwajacym' lokiem - konsekwencja bujania pudła + Global::SetCameraPosition( + Camera.Pos); // tu ustawić nową, bo od niej liczą się odległości + Ground.Silence(camStara); // wyciszenie dźwięków z poprzedniej pozycji + } + else if (Train) + { // korekcja ustawienia w kabinie - OK + vector3 camStara = + Camera.Pos; // przestawianie kamery jest bez sensu: do przerobienia na potem + // Ra: czy to tu jest potrzebne, bo przelicza się kawałek dalej? + Camera.Pos = Train->pMechPosition; // Train.GetPosition1(); + Camera.Roll = atan(Train->pMechShake.x * Train->fMechRoll); // hustanie kamery na boki + Camera.Pitch -= + atan(Train->vMechVelocity.z * Train->fMechPitch); // hustanie kamery przod tyl + if (Train->Dynamic()->MoverParameters->ActiveCab == 0) + Camera.LookAt = Train->pMechPosition + Train->GetDirection(); + else // patrz w strone wlasciwej kabiny + Camera.LookAt = + Train->pMechPosition + + Train->GetDirection() * Train->Dynamic()->MoverParameters->ActiveCab; + Train->pMechOffset.x = Train->pMechSittingPosition.x; + Train->pMechOffset.y = Train->pMechSittingPosition.y; + Train->pMechOffset.z = Train->pMechSittingPosition.z; + Global::SetCameraPosition( + Train->Dynamic() + ->GetPosition()); // tu ustawić nową, bo od niej liczą się odległości + if (wycisz) // trzymanie prawego w kabinie daje marny efekt + Ground.Silence(camStara); // wyciszenie dźwięków z poprzedniej pozycji + } + } + else + DistantView(); }; bool __fastcall 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"); - }; + 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 - if (iCheckFPS) - --iCheckFPS; - else - {//jak doszło do zera, to sprawdzamy wydajność - if (GetFPS()Global::fFpsMax) //jeśli jest dużo FPS - if (Global::iSegmentsRenderedGlobal::iFpsRadiusMax) //5.6km (22*22*M_PI) - Global::iSegmentsRendered=Global::iFpsRadiusMax; - } - if ((GetFPS()<12)&&(Global::iSlowMotion<7)) - {Global::iSlowMotion=(Global::iSlowMotion<<1)+1; //zapalenie kolejnego bitu - if (Global::iSlowMotionMask&1) - if (Global::iMultisampling) //a multisampling jest włączony - glDisable(GL_MULTISAMPLE); //wyłączenie multisamplingu powinno poprawić FPS - } - else if ((GetFPS()>20)&&Global::iSlowMotion) - {//FPS się zwiększył, można włączyć bajery - Global::iSlowMotion=(Global::iSlowMotion>>1); //zgaszenie bitu - if (Global::iSlowMotion==0) //jeśli jest pełna prędkość - if (Global::iMultisampling) //a multisampling jest włączony - glEnable(GL_MULTISAMPLE); - } -/* - if (!Global::bPause) - if (GetFPS()<=5) - {//zwiększenie kroku fizyki przy słabym FPS - if (fMaxDt<0.05) - {fMaxDt=0.05; //Ra: tak nie może być, bo są problemy na sprzęgach - WriteLog("Phisics step switched to 0.05s!"); - } - } - else if (GetFPS()>12) - if (fMaxDt>0.01) - {//powrót do podstawowego kroku fizyki - fMaxDt=0.01; - WriteLog("Phisics step switched to 0.01s!"); - } -*/ - iCheckFPS=0.25*GetFPS(); //tak za 0.25 sekundy sprawdzić ponownie (jeszcze przycina?) - } - UpdateTimers(Global::iPause); - if (!Global::iPause) - {//jak pauza, to nie ma po co tego przeliczać - GlobalTime->UpdateMTableTime(GetDeltaTime()); //McZapkie-300302: czas rozkladowy - //Ra 2014-07: przeliczenie kąta czasu (do animacji zależnych od czasu) - Global::fTimeAngleDeg=GlobalTime->hh*15.0+GlobalTime->mm*0.25+GlobalTime->mr/240.0; - Global::fClockAngleDeg[0]=36.0*(int(GlobalTime->mr)%10); //jednostki sekund - Global::fClockAngleDeg[1]=36.0*(int(GlobalTime->mr)/10); //dziesiątki sekund - Global::fClockAngleDeg[2]=36.0*(GlobalTime->mm%10); //jednostki minut - Global::fClockAngleDeg[3]=36.0*(GlobalTime->mm/10); //dziesiątki minut - Global::fClockAngleDeg[4]=36.0*(GlobalTime->hh%10); //jednostki godzin - Global::fClockAngleDeg[5]=36.0*(GlobalTime->hh/10); //dziesiątki godzin - if (Global::fMoveLight>=0.0) - {//testowo ruch światła - //double a=Global::fTimeAngleDeg/180.0*M_PI-M_PI; //kąt godzinny w radianach - double a=fmod(Global::fTimeAngleDeg,360.0)/180.0*M_PI-M_PI; //kąt godzinny w radianach - //(a) jest traktowane jako czas miejscowy, nie uwzględniający stref czasowych ani czasu letniego - //aby wyznaczyć strefę czasową, trzeba uwzględnić południk miejscowy - //aby uwzględnić czas letni, trzeba sprawdzić dzień roku - double L=Global::fLatitudeDeg/180.0*M_PI; //szerokość geograficzna - double H=asin(cos(L)*cos(Global::fSunDeclination)*cos(a)+sin(L)*sin(Global::fSunDeclination)); //kąt ponad horyzontem - //double A=asin(cos(d)*sin(M_PI-a)/cos(H)); - //Declination=((0.322003-22.971*cos(t)-0.357898*cos(2*t)-0.14398*cos(3*t)+3.94638*sin(t)+0.019334*sin(2*t)+0.05928*sin(3*t)))*Pi/180 - //Altitude=asin(sin(Declination)*sin(latitude)+cos(Declination)*cos(latitude)*cos((15*(time-12))*(Pi/180))); - //Azimuth=(acos((cos(latitude)*sin(Declination)-cos(Declination)*sin(latitude)*cos((15*(time-12))*(Pi/180)))/cos(Altitude))); - //double A=acos(cos(L)*sin(d)-cos(d)*sin(L)*cos(M_PI-a)/cos(H)); - //dAzimuth = atan2(-sin( dHourAngle ),tan( dDeclination )*dCos_Latitude - dSin_Latitude*dCos_HourAngle ); - double A=atan2(sin(a),tan(Global::fSunDeclination)*cos(L)-sin(L)*cos(a)); - vector3 lp=vector3(sin(A),tan(H),cos(A)); - lp=Normalize(lp); //przeliczenie na wektor długości 1.0 - Global::lightPos[0]=(float)lp.x; - Global::lightPos[1]=(float)lp.y; - Global::lightPos[2]=(float)lp.z; - glLightfv(GL_LIGHT0,GL_POSITION,Global::lightPos); //daylight position - if (H>0) - {//słońce ponad horyzontem - Global::ambientDayLight[0]=Global::ambientLight[0]; - Global::ambientDayLight[1]=Global::ambientLight[1]; - Global::ambientDayLight[2]=Global::ambientLight[2]; - if (H>0.02) //ponad 1.146° zaczynają się cienie - {Global::diffuseDayLight[0]=Global::diffuseLight[0]; //od wschodu do zachodu maksimum ??? - Global::diffuseDayLight[1]=Global::diffuseLight[1]; - Global::diffuseDayLight[2]=Global::diffuseLight[2]; - Global::specularDayLight[0]=Global::specularLight[0]; //podobnie specular - Global::specularDayLight[1]=Global::specularLight[1]; - Global::specularDayLight[2]=Global::specularLight[2]; - } + if (iCheckFPS) + --iCheckFPS; else - {Global::diffuseDayLight[0]=50*H*Global::diffuseLight[0]; //wschód albo zachód - Global::diffuseDayLight[1]=50*H*Global::diffuseLight[1]; - Global::diffuseDayLight[2]=50*H*Global::diffuseLight[2]; - Global::specularDayLight[0]=50*H*Global::specularLight[0]; //podobnie specular - Global::specularDayLight[1]=50*H*Global::specularLight[1]; - Global::specularDayLight[2]=50*H*Global::specularLight[2]; + { // jak doszło do zera, to sprawdzamy wydajność + if (GetFPS() < Global::fFpsMin) + { + Global::iSegmentsRendered -= + random(10); // floor(0.5+Global::iSegmentsRendered/Global::fRadiusFactor); + if (Global::iSegmentsRendered < 10) // jeśli jest co zmniejszać + Global::iSegmentsRendered = 10; // 10=minimalny promień to 600m + } + else if (GetFPS() > Global::fFpsMax) // jeśli jest dużo FPS + if (Global::iSegmentsRendered < Global::iFpsRadiusMax) // jeśli jest co zwiększać + { + Global::iSegmentsRendered += + random(5); // floor(0.5+Global::iSegmentsRendered*Global::fRadiusFactor); + if (Global::iSegmentsRendered > Global::iFpsRadiusMax) // 5.6km (22*22*M_PI) + Global::iSegmentsRendered = Global::iFpsRadiusMax; + } + if ((GetFPS() < 12) && (Global::iSlowMotion < 7)) + { + Global::iSlowMotion = (Global::iSlowMotion << 1) + 1; // zapalenie kolejnego bitu + if (Global::iSlowMotionMask & 1) + if (Global::iMultisampling) // a multisampling jest włączony + glDisable(GL_MULTISAMPLE); // wyłączenie multisamplingu powinno poprawić FPS + } + else if ((GetFPS() > 20) && Global::iSlowMotion) + { // FPS się zwiększył, można włączyć bajery + Global::iSlowMotion = (Global::iSlowMotion >> 1); // zgaszenie bitu + if (Global::iSlowMotion == 0) // jeśli jest pełna prędkość + if (Global::iMultisampling) // a multisampling jest włączony + glEnable(GL_MULTISAMPLE); + } + /* + if (!Global::bPause) + if (GetFPS()<=5) + {//zwiększenie kroku fizyki przy słabym FPS + if (fMaxDt<0.05) + {fMaxDt=0.05; //Ra: tak nie może być, bo są problemy na sprzęgach + WriteLog("Phisics step switched to 0.05s!"); + } + } + else if (GetFPS()>12) + if (fMaxDt>0.01) + {//powrót do podstawowego kroku fizyki + fMaxDt=0.01; + WriteLog("Phisics step switched to 0.01s!"); + } + */ + iCheckFPS = 0.25 * GetFPS(); // tak za 0.25 sekundy sprawdzić ponownie (jeszcze przycina?) } - } - else - {//słońce pod horyzontem - GLfloat lum=3.1831*(H>-0.314159?0.314159+H:0.0); //po zachodzie ambient się ściemnia - Global::ambientDayLight[0]=lum*Global::ambientLight[0]; - Global::ambientDayLight[1]=lum*Global::ambientLight[1]; - Global::ambientDayLight[2]=lum*Global::ambientLight[2]; - Global::diffuseDayLight[0]=Global::noLight[0]; //od zachodu do wschodu nie ma diffuse - Global::diffuseDayLight[1]=Global::noLight[1]; - Global::diffuseDayLight[2]=Global::noLight[2]; - Global::specularDayLight[0]=Global::noLight[0]; //ani specular - Global::specularDayLight[1]=Global::noLight[1]; - Global::specularDayLight[2]=Global::noLight[2]; - } - // Calculate sky colour according to time of day. - //GLfloat sin_t = sin(PI * time_of_day / 12.0); - //back_red = 0.3 * (1.0 - sin_t); - //back_green = 0.9 * sin_t; - //back_blue = sin_t + 0.4, 1.0; - //aktualizacja świateł - glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); - } - Global::fLuminance= //to posłuży również do zapalania latarń - +0.150*(Global::diffuseDayLight[0]+Global::ambientDayLight[0]) //R - +0.295*(Global::diffuseDayLight[1]+Global::ambientDayLight[1]) //G - +0.055*(Global::diffuseDayLight[2]+Global::ambientDayLight[2]); //B - if (Global::fMoveLight>=0.0) - {//przeliczenie koloru nieba - vector3 sky=vector3(Global::AtmoColor[0],Global::AtmoColor[1],Global::AtmoColor[2]); - if (Global::fLuminance<0.25) - {//przyspieszenie zachodu/wschodu - sky*=4.0*Global::fLuminance; //nocny kolor nieba - GLfloat fog[3]; - fog[0]=Global::FogColor[0]*4.0*Global::fLuminance; - fog[1]=Global::FogColor[1]*4.0*Global::fLuminance; - fog[2]=Global::FogColor[2]*4.0*Global::fLuminance; - glFogfv(GL_FOG_COLOR,fog); //nocny kolor mgły - } - else - glFogfv(GL_FOG_COLOR,Global::FogColor); //kolor mgły - glClearColor(sky.x,sky.y,sky.z,0.0); //kolor nieba - } - } //koniec działań niewykonywanych podczas pauzy - //Console::Update(); //tu jest zależne od FPS, co nie jest korzystne - if (Global::bActive) - {//obsługa ruchu kamery tylko gdy okno jest aktywne - if (Console::Pressed(VK_LBUTTON)) - { - Camera.Reset(); //likwidacja obrotów - patrzy horyzontalnie na południe - //if (!FreeFlyModeFlag) //jeśli wewnątrz - patrzymy do tyłu - // Camera.LookAt=Train->pMechPosition-Normalize(Train->GetDirection())*10; - if (Controlled?LengthSquared3(Controlled->GetPosition()-Camera.Pos)<2250000:false) //gdy bliżej niż 1.5km - Camera.LookAt=Controlled->GetPosition(); - else - {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 - if (d&&pDynamicNearest) //jeśli jakiś jest znaleziony wcześniej - if (100.0*LengthSquared3(d->GetPosition()-Camera.Pos)>LengthSquared3(pDynamicNearest->GetPosition()-Camera.Pos)) - d=pDynamicNearest; //jeśli najbliższy nie jest 10 razy bliżej niż poprzedni najbliższy, zostaje poprzedni - if (d) pDynamicNearest=d; //zmiana na nowy, jeśli coś znaleziony niepusty - if (pDynamicNearest) Camera.LookAt=pDynamicNearest->GetPosition(); - } - if (FreeFlyModeFlag) - Camera.RaLook(); //jednorazowe przestawienie kamery - } - else if (Console::Pressed(VK_RBUTTON))//||Console::Pressed(VK_F4)) - FollowView(false); //bez wyciszania dźwięków - else if (Global::iTextMode==-1) - {//tu mozna dodac dopisywanie do logu przebiegu lokomotywy - WriteLog("Number of textures used: "+AnsiString(Global::iTextures)); - return false; - } - Camera.Update(); //uwzględnienie ruchu wywołanego klawiszami - } //koniec bloku pomijanego przy nieaktywnym oknie - //poprzednie jakoś tam działało - double dt=GetDeltaRenderTime(); //nie uwzględnia pauzowania ani mnożenia czasu - fTime50Hz+=dt; //w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek - if (fTime50Hz>=0.2) - Console::Update(); //to i tak trzeba wywoływać - dt=GetDeltaTime(); //0.0 gdy pauza - fTimeBuffer+=dt; //[s] dodanie czasu od poprzedniej ramki - if (fTimeBuffer>=fMaxDt) //jest co najmniej jeden krok; normalnie 0.01s - {//Ra: czas dla fizyki jest skwantowany - fizykę lepiej przeliczać stałym krokiem - //tak można np. moc silników itp., ale ruch musi być przeliczany w każdej klatce, bo inaczej skacze - Global::tranTexts.Update(); //obiekt obsługujący stenogramy dźwięków na ekranie - Console::Update(); //obsługa cykli PoKeys (np. aktualizacja wyjść analogowych) - double iter=ceil(fTimeBuffer/fMaxDt); //ile kroków się zmieściło od ostatniego sprawdzania? - int n=int(iter); //ile kroków jako int - fTimeBuffer-=iter*fMaxDt; //reszta czasu na potem (do bufora) - if (n>20) n=20; //Ra: jeżeli FPS jest zatrważająco niski, to fizyka nie może zająć całkowicie procesora + UpdateTimers(Global::iPause); + if (!Global::iPause) + { // jak pauza, to nie ma po co tego przeliczać + GlobalTime->UpdateMTableTime(GetDeltaTime()); // McZapkie-300302: czas rozkladowy + // Ra 2014-07: przeliczenie kąta czasu (do animacji zależnych od czasu) + Global::fTimeAngleDeg = + GlobalTime->hh * 15.0 + GlobalTime->mm * 0.25 + GlobalTime->mr / 240.0; + Global::fClockAngleDeg[0] = 36.0 * (int(GlobalTime->mr) % 10); // jednostki sekund + Global::fClockAngleDeg[1] = 36.0 * (int(GlobalTime->mr) / 10); // dziesiątki sekund + Global::fClockAngleDeg[2] = 36.0 * (GlobalTime->mm % 10); // jednostki minut + Global::fClockAngleDeg[3] = 36.0 * (GlobalTime->mm / 10); // dziesiątki minut + Global::fClockAngleDeg[4] = 36.0 * (GlobalTime->hh % 10); // jednostki godzin + Global::fClockAngleDeg[5] = 36.0 * (GlobalTime->hh / 10); // dziesiątki godzin + if (Global::fMoveLight >= 0.0) + { // testowo ruch światła + // double a=Global::fTimeAngleDeg/180.0*M_PI-M_PI; //kąt godzinny w radianach + double a = fmod(Global::fTimeAngleDeg, 360.0) / 180.0 * M_PI - + M_PI; // kąt godzinny w radianach + //(a) jest traktowane jako czas miejscowy, nie uwzględniający stref czasowych ani czasu + //letniego + // aby wyznaczyć strefę czasową, trzeba uwzględnić południk miejscowy + // aby uwzględnić czas letni, trzeba sprawdzić dzień roku + double L = Global::fLatitudeDeg / 180.0 * M_PI; // szerokość geograficzna + double H = asin(cos(L) * cos(Global::fSunDeclination) * cos(a) + + sin(L) * sin(Global::fSunDeclination)); // kąt ponad horyzontem + // double A=asin(cos(d)*sin(M_PI-a)/cos(H)); + // Declination=((0.322003-22.971*cos(t)-0.357898*cos(2*t)-0.14398*cos(3*t)+3.94638*sin(t)+0.019334*sin(2*t)+0.05928*sin(3*t)))*Pi/180 + // Altitude=asin(sin(Declination)*sin(latitude)+cos(Declination)*cos(latitude)*cos((15*(time-12))*(Pi/180))); + // Azimuth=(acos((cos(latitude)*sin(Declination)-cos(Declination)*sin(latitude)*cos((15*(time-12))*(Pi/180)))/cos(Altitude))); + // double A=acos(cos(L)*sin(d)-cos(d)*sin(L)*cos(M_PI-a)/cos(H)); + // dAzimuth = atan2(-sin( dHourAngle ),tan( dDeclination )*dCos_Latitude - + // dSin_Latitude*dCos_HourAngle ); + double A = atan2(sin(a), tan(Global::fSunDeclination) * cos(L) - sin(L) * cos(a)); + vector3 lp = vector3(sin(A), tan(H), cos(A)); + lp = Normalize(lp); // przeliczenie na wektor długości 1.0 + Global::lightPos[0] = (float)lp.x; + Global::lightPos[1] = (float)lp.y; + Global::lightPos[2] = (float)lp.z; + glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos); // daylight position + if (H > 0) + { // słońce ponad horyzontem + Global::ambientDayLight[0] = Global::ambientLight[0]; + Global::ambientDayLight[1] = Global::ambientLight[1]; + Global::ambientDayLight[2] = Global::ambientLight[2]; + if (H > 0.02) // ponad 1.146° zaczynają się cienie + { + Global::diffuseDayLight[0] = + Global::diffuseLight[0]; // od wschodu do zachodu maksimum ??? + Global::diffuseDayLight[1] = Global::diffuseLight[1]; + Global::diffuseDayLight[2] = Global::diffuseLight[2]; + Global::specularDayLight[0] = Global::specularLight[0]; // podobnie specular + Global::specularDayLight[1] = Global::specularLight[1]; + Global::specularDayLight[2] = Global::specularLight[2]; + } + else + { + Global::diffuseDayLight[0] = + 50 * H * Global::diffuseLight[0]; // wschód albo zachód + Global::diffuseDayLight[1] = 50 * H * Global::diffuseLight[1]; + Global::diffuseDayLight[2] = 50 * H * Global::diffuseLight[2]; + Global::specularDayLight[0] = + 50 * H * Global::specularLight[0]; // podobnie specular + Global::specularDayLight[1] = 50 * H * Global::specularLight[1]; + Global::specularDayLight[2] = 50 * H * Global::specularLight[2]; + } + } + else + { // słońce pod horyzontem + GLfloat lum = 3.1831 * (H > -0.314159 ? 0.314159 + H : + 0.0); // po zachodzie ambient się ściemnia + Global::ambientDayLight[0] = lum * Global::ambientLight[0]; + Global::ambientDayLight[1] = lum * Global::ambientLight[1]; + Global::ambientDayLight[2] = lum * Global::ambientLight[2]; + Global::diffuseDayLight[0] = + Global::noLight[0]; // od zachodu do wschodu nie ma diffuse + Global::diffuseDayLight[1] = Global::noLight[1]; + Global::diffuseDayLight[2] = Global::noLight[2]; + Global::specularDayLight[0] = Global::noLight[0]; // ani specular + Global::specularDayLight[1] = Global::noLight[1]; + Global::specularDayLight[2] = Global::noLight[2]; + } + // Calculate sky colour according to time of day. + // GLfloat sin_t = sin(PI * time_of_day / 12.0); + // back_red = 0.3 * (1.0 - sin_t); + // back_green = 0.9 * sin_t; + // back_blue = sin_t + 0.4, 1.0; + // aktualizacja świateł + glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); + } + Global::fLuminance = // to posłuży również do zapalania latarń + +0.150 * (Global::diffuseDayLight[0] + Global::ambientDayLight[0]) // R + + 0.295 * (Global::diffuseDayLight[1] + Global::ambientDayLight[1]) // G + + 0.055 * (Global::diffuseDayLight[2] + Global::ambientDayLight[2]); // B + if (Global::fMoveLight >= 0.0) + { // przeliczenie koloru nieba + vector3 sky = vector3(Global::AtmoColor[0], Global::AtmoColor[1], Global::AtmoColor[2]); + if (Global::fLuminance < 0.25) + { // przyspieszenie zachodu/wschodu + sky *= 4.0 * Global::fLuminance; // nocny kolor nieba + GLfloat fog[3]; + fog[0] = Global::FogColor[0] * 4.0 * Global::fLuminance; + fog[1] = Global::FogColor[1] * 4.0 * Global::fLuminance; + fog[2] = Global::FogColor[2] * 4.0 * Global::fLuminance; + glFogfv(GL_FOG_COLOR, fog); // nocny kolor mgły + } + else + glFogfv(GL_FOG_COLOR, Global::FogColor); // kolor mgły + glClearColor(sky.x, sky.y, sky.z, 0.0); // kolor nieba + } + } // koniec działań niewykonywanych podczas pauzy + // Console::Update(); //tu jest zależne od FPS, co nie jest korzystne + if (Global::bActive) + { // obsługa ruchu kamery tylko gdy okno jest aktywne + if (Console::Pressed(VK_LBUTTON)) + { + Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na południe + // if (!FreeFlyModeFlag) //jeśli wewnątrz - patrzymy do tyłu + // Camera.LookAt=Train->pMechPosition-Normalize(Train->GetDirection())*10; + if (Controlled ? LengthSquared3(Controlled->GetPosition() - Camera.Pos) < 2250000 : + false) // gdy bliżej niż 1.5km + Camera.LookAt = Controlled->GetPosition(); + else + { + 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 + if (d && pDynamicNearest) // jeśli jakiś jest znaleziony wcześniej + if (100.0 * LengthSquared3(d->GetPosition() - Camera.Pos) > + LengthSquared3(pDynamicNearest->GetPosition() - Camera.Pos)) + d = pDynamicNearest; // jeśli najbliższy nie jest 10 razy bliżej niż + // poprzedni najbliższy, zostaje poprzedni + if (d) + pDynamicNearest = d; // zmiana na nowy, jeśli coś znaleziony niepusty + if (pDynamicNearest) + Camera.LookAt = pDynamicNearest->GetPosition(); + } + if (FreeFlyModeFlag) + Camera.RaLook(); // jednorazowe przestawienie kamery + } + else if (Console::Pressed(VK_RBUTTON)) //||Console::Pressed(VK_F4)) + FollowView(false); // bez wyciszania dźwięków + else if (Global::iTextMode == -1) + { // tu mozna dodac dopisywanie do logu przebiegu lokomotywy + WriteLog("Number of textures used: " + AnsiString(Global::iTextures)); + return false; + } + Camera.Update(); // uwzględnienie ruchu wywołanego klawiszami + } // koniec bloku pomijanego przy nieaktywnym oknie + // poprzednie jakoś tam działało + double dt = GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu + fTime50Hz += + dt; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek + if (fTime50Hz >= 0.2) + Console::Update(); // to i tak trzeba wywoływać + dt = GetDeltaTime(); // 0.0 gdy pauza + fTimeBuffer += dt; //[s] dodanie czasu od poprzedniej ramki + if (fTimeBuffer >= fMaxDt) // jest co najmniej jeden krok; normalnie 0.01s + { // Ra: czas dla fizyki jest skwantowany - fizykę lepiej przeliczać stałym krokiem + // tak można np. moc silników itp., ale ruch musi być przeliczany w każdej klatce, bo + // inaczej skacze + Global::tranTexts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie + Console::Update(); // obsługa cykli PoKeys (np. aktualizacja wyjść analogowych) + double iter = + ceil(fTimeBuffer / fMaxDt); // ile kroków się zmieściło od ostatniego sprawdzania? + int n = int(iter); // ile kroków jako int + fTimeBuffer -= iter * fMaxDt; // reszta czasu na potem (do bufora) + if (n > 20) + n = 20; // Ra: jeżeli FPS jest zatrważająco niski, to fizyka nie może zająć całkowicie + // procesora #if 0 Ground.UpdatePhys(fMaxDt,n); //Ra: teraz czas kroku jest (względnie) stały if (DebugModeFlag) @@ -1228,48 +1325,54 @@ bool __fastcall TWorld::Update() Ground.UpdatePhys(fMaxDt,n); //w sumie 5 razy } #endif - } - //awaria PoKeys mogła włączyć pauzę - przekazać informację - if (Global::iMultiplayer) //dajemy znać do serwera o wykonaniu - if (iPause!=Global::iPause) - {//przesłanie informacji o pauzie do programu nadzorującego - Ground.WyslijParam(5,3); //ramka 5 z czasem i stanem zapauzowania - iPause=Global::iPause; - } - double iter; - int n=1; - if (dt>fMaxDt) //normalnie 0.01s - { - iter=ceil(dt/fMaxDt); - n=iter; - dt=dt/iter; //Ra: fizykę lepiej by było przeliczać ze stałym krokiem - if (n>20) n=20; //McZapkie-081103: przesuniecie granicy FPS z 10 na 5 - } - //else n=1; - //blablabla - //Ground.UpdatePhys(dt,n); //na razie tu //2014-12: yB przeniósł do Ground.Update() :( - Ground.Update(dt,n); //tu zrobić tylko coklatkową aktualizację przesunięć - if (DebugModeFlag) - if (Global::bActive) //nie przyspieszać, gdy jedzie w tle :) - if (GetAsyncKeyState(VK_ESCAPE)<0) - {//yB dodał przyspieszacz fizyki - Ground.Update(dt,n); - Ground.Update(dt,n); - Ground.Update(dt,n); - Ground.Update(dt,n); //5 razy - } - dt=GetDeltaTime(); //czas niekwantowany - if (Camera.Type==tp_Follow) - {if (Train) - {//jeśli jazda w kabinie, przeliczyć trzeba parametry kamery - Train->UpdateMechPosition(dt/Global::fTimeSpeed); //ograniczyć telepanie po przyspieszeniu - vector3 tempangle; - double modelrotate; - tempangle=Controlled->VectorFront()*(Controlled->MoverParameters->ActiveCab==-1 ? -1 : 1); - modelrotate=atan2(-tempangle.x,tempangle.z); - if (Console::Pressed(VK_CONTROL)?(Console::Pressed(Global::Keys[k_MechLeft])||Console::Pressed(Global::Keys[k_MechRight])):false) - {//jeśli lusterko lewe albo prawe (bez rzucania na razie) - bool lr=Console::Pressed(Global::Keys[k_MechLeft]); + } + // awaria PoKeys mogła włączyć pauzę - przekazać informację + if (Global::iMultiplayer) // dajemy znać do serwera o wykonaniu + if (iPause != Global::iPause) + { // przesłanie informacji o pauzie do programu nadzorującego + Ground.WyslijParam(5, 3); // ramka 5 z czasem i stanem zapauzowania + iPause = Global::iPause; + } + double iter; + int n = 1; + if (dt > fMaxDt) // normalnie 0.01s + { + iter = ceil(dt / fMaxDt); + n = iter; + dt = dt / iter; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem + if (n > 20) + n = 20; // McZapkie-081103: przesuniecie granicy FPS z 10 na 5 + } + // else n=1; + // blablabla + // Ground.UpdatePhys(dt,n); //na razie tu //2014-12: yB przeniósł do Ground.Update() :( + Ground.Update(dt, n); // tu zrobić tylko coklatkową aktualizację przesunięć + if (DebugModeFlag) + if (Global::bActive) // nie przyspieszać, gdy jedzie w tle :) + if (GetAsyncKeyState(VK_ESCAPE) < 0) + { // yB dodał przyspieszacz fizyki + Ground.Update(dt, n); + Ground.Update(dt, n); + Ground.Update(dt, n); + Ground.Update(dt, n); // 5 razy + } + dt = GetDeltaTime(); // czas niekwantowany + if (Camera.Type == tp_Follow) + { + if (Train) + { // jeśli jazda w kabinie, przeliczyć trzeba parametry kamery + Train->UpdateMechPosition(dt / + Global::fTimeSpeed); // ograniczyć telepanie po przyspieszeniu + vector3 tempangle; + double modelrotate; + tempangle = + Controlled->VectorFront() * (Controlled->MoverParameters->ActiveCab == -1 ? -1 : 1); + modelrotate = atan2(-tempangle.x, tempangle.z); + if (Console::Pressed(VK_CONTROL) ? (Console::Pressed(Global::Keys[k_MechLeft]) || + Console::Pressed(Global::Keys[k_MechRight])) : + false) + { // jeśli lusterko lewe albo prawe (bez rzucania na razie) + bool lr = Console::Pressed(Global::Keys[k_MechLeft]); #if 0 Camera.Pos=Train->MirrorPosition(lr); //robocza wartość if (Controlled->MoverParameters->ActiveCab<0) lr=!lr; //w drugiej kabinie odwrotnie jest środek @@ -1279,270 +1382,306 @@ bool __fastcall TWorld::Update() //Camera.RaLook(); //jednorazowe przestawienie kamery Camera.Yaw=0; //odchylenie na bok od Camera.LookAt #else - //Camera.Yaw powinno być wyzerowane, aby po powrocie patrzeć do przodu - Camera.Pos=Controlled->GetPosition()+Train->MirrorPosition(lr); //pozycja lusterka - Camera.Yaw=0; //odchylenie na bok od Camera.LookAt - if (Train->Dynamic()->MoverParameters->ActiveCab==0) - Camera.LookAt=Camera.Pos-Train->GetDirection(); //gdy w korytarzu - else - if (Console::Pressed(VK_SHIFT)) - {//patrzenie w bok przez szybę - Camera.LookAt=Camera.Pos-(lr?-1:1)*Train->Dynamic()->VectorLeft()*Train->Dynamic()->MoverParameters->ActiveCab; - Global::SetCameraRotation(-modelrotate); - } - else - {//patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny - jakby z lusterka, ale bez odbicia - Camera.LookAt=Camera.Pos-Train->GetDirection()*Train->Dynamic()->MoverParameters->ActiveCab; //-1 albo 1 - Global::SetCameraRotation(M_PI-modelrotate); //tu już trzeba uwzględnić lusterka - } + // Camera.Yaw powinno być wyzerowane, aby po powrocie patrzeć do przodu + Camera.Pos = + Controlled->GetPosition() + Train->MirrorPosition(lr); // pozycja lusterka + Camera.Yaw = 0; // odchylenie na bok od Camera.LookAt + if (Train->Dynamic()->MoverParameters->ActiveCab == 0) + Camera.LookAt = Camera.Pos - Train->GetDirection(); // gdy w korytarzu + else if (Console::Pressed(VK_SHIFT)) + { // patrzenie w bok przez szybę + Camera.LookAt = Camera.Pos - + (lr ? -1 : 1) * Train->Dynamic()->VectorLeft() * + Train->Dynamic()->MoverParameters->ActiveCab; + Global::SetCameraRotation(-modelrotate); + } + else + { // patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny - jakby z lusterka, + // ale bez odbicia + Camera.LookAt = Camera.Pos - + Train->GetDirection() * + Train->Dynamic()->MoverParameters->ActiveCab; //-1 albo 1 + Global::SetCameraRotation(M_PI - + modelrotate); // tu już trzeba uwzględnić lusterka + } #endif - Camera.Roll=atan(Train->pMechShake.x*Train->fMechRoll); //hustanie kamery na boki - Camera.Pitch=atan(Train->vMechVelocity.z*Train->fMechPitch); //hustanie kamery przod tyl - Camera.vUp=Controlled->VectorUp(); - } - else - {//patrzenie standardowe - Camera.Pos=Train->pMechPosition;//Train.GetPosition1(); - if (!Global::iPause) - {//podczas pauzy nie przeliczać kątów przypadkowymi wartościami - Camera.Roll=atan(Train->pMechShake.x*Train->fMechRoll); //hustanie kamery na boki - Camera.Pitch-=atan(Train->vMechVelocity.z*Train->fMechPitch); //hustanie kamery przod tyl //Ra: tu jest uciekanie kamery w górę!!! + Camera.Roll = + atan(Train->pMechShake.x * Train->fMechRoll); // hustanie kamery na boki + Camera.Pitch = + atan(Train->vMechVelocity.z * Train->fMechPitch); // hustanie kamery przod tyl + Camera.vUp = Controlled->VectorUp(); + } + else + { // patrzenie standardowe + Camera.Pos = Train->pMechPosition; // Train.GetPosition1(); + if (!Global::iPause) + { // podczas pauzy nie przeliczać kątów przypadkowymi wartościami + Camera.Roll = + atan(Train->pMechShake.x * Train->fMechRoll); // hustanie kamery na boki + Camera.Pitch -= atan(Train->vMechVelocity.z * + Train->fMechPitch); // hustanie kamery przod tyl //Ra: tu + // jest uciekanie kamery w górę!!! + } + // ABu011104: rzucanie pudlem + vector3 temp; + if (abs(Train->pMechShake.y) < 0.25) + temp = vector3(0, 0, 6 * Train->pMechShake.y); + else if ((Train->pMechShake.y) > 0) + temp = vector3(0, 0, 6 * 0.25); + else + temp = vector3(0, 0, -6 * 0.25); + if (Controlled) + Controlled->ABuSetModelShake(temp); + // ABu: koniec rzucania + + if (Train->Dynamic()->MoverParameters->ActiveCab == 0) + Camera.LookAt = Train->pMechPosition + Train->GetDirection(); // gdy w korytarzu + else // patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny + Camera.LookAt = Train->pMechPosition + + Train->GetDirection() * + Train->Dynamic()->MoverParameters->ActiveCab; //-1 albo 1 + Camera.vUp = Train->GetUp(); + Global::SetCameraRotation(Camera.Yaw - + modelrotate); // tu już trzeba uwzględnić lusterka + } + } } - //ABu011104: rzucanie pudlem - vector3 temp; - if (abs(Train->pMechShake.y)<0.25) - temp=vector3(0,0,6*Train->pMechShake.y); else - if ((Train->pMechShake.y)>0) - temp=vector3(0,0,6*0.25); - else - temp=vector3(0,0,-6*0.25); - if (Controlled) Controlled->ABuSetModelShake(temp); - //ABu: koniec rzucania - - if (Train->Dynamic()->MoverParameters->ActiveCab==0) - Camera.LookAt=Train->pMechPosition+Train->GetDirection(); //gdy w korytarzu - else //patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny - Camera.LookAt=Train->pMechPosition+Train->GetDirection()*Train->Dynamic()->MoverParameters->ActiveCab; //-1 albo 1 - Camera.vUp=Train->GetUp(); - Global::SetCameraRotation(Camera.Yaw-modelrotate); //tu już trzeba uwzględnić lusterka - } - } - } - else - {//kamera nieruchoma - Global::SetCameraRotation(Camera.Yaw-M_PI); - } - Ground.CheckQuery(); - //przy 0.25 smuga gaśnie o 6:37 w Quarku, a mogłaby już 5:40 - //Ra 2014-12: przy 0.15 się skarżyli, że nie widać smug => zmieniłem na 0.25 - if (Train) //jeśli nie usunięty - Global::bSmudge=FreeFlyModeFlag?false:((Train->Dynamic()->fShade<=0.0)?(Global::fLuminance<=0.25):(Train->Dynamic()->fShade*Global::fLuminance<=0.25)); - - if (!Render()) return false; - -//********************************************************************************************************** - - if (Train) - {//rendering kabiny gdy jest oddzielnym modelem i ma byc wyswietlana - glPushMatrix(); - //ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka - if ((Train->Dynamic()->mdKabina!=Train->Dynamic()->mdModel) && Train->Dynamic()->bDisplayCab && !FreeFlyModeFlag) - { - vector3 pos=Train->Dynamic()->GetPosition(); //wszpółrzędne pojazdu z kabiną - //glTranslatef(pos.x,pos.y,pos.z); //przesunięcie o wektor (tak było i trzęsło) - //aby pozbyć się choć trochę trzęsienia, trzeba by nie przeliczać kabiny do punktu zerowego scenerii - glLoadIdentity(); //zacząć od macierzy jedynkowej - Camera.SetCabMatrix(pos); //widok z kamery po przesunięciu - glMultMatrixd(Train->Dynamic()->mMatrix.getArray()); //ta macierz nie ma przesunięcia - -//*yB: moje smuuugi 1 - if (Global::bSmudge) - {//Ra: uwzględniłem zacienienie pojazdu przy zapalaniu smug - //1. warunek na smugę wyznaczyc wcześniej - //2. jeśli smuga włączona, nie renderować pojazdu użytkownika w DynObj - //3. jeśli smuga właczona, wyrenderować pojazd użytkownia po dodaniu smugi do sceny - if (Train->Controlled()->Battery) - {//trochę na skróty z tą baterią - glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE); -// glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_DST_COLOR); -// glBlendFunc(GL_SRC_ALPHA_SATURATE,GL_ONE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glDisable(GL_FOG); - glColor4f(1.0f,1.0f,1.0f,1.0f); - glBindTexture(GL_TEXTURE_2D,light); // Select our texture - glBegin(GL_QUADS); - float fSmudge=Train->Dynamic()->MoverParameters->DimHalf.y+7; //gdzie zaczynać smugę - if (Train->Controlled()->iLights[0]&21) - {//wystarczy jeden zapalony z przodu - glTexCoord2f(0,0); glVertex3f( 15.0,0.0,+fSmudge); //rysowanie względem położenia modelu - glTexCoord2f(1,0); glVertex3f(-15.0,0.0,+fSmudge); - glTexCoord2f(1,1); glVertex3f(-15.0,2.5, 250.0); - glTexCoord2f(0,1); glVertex3f( 15.0,2.5, 250.0); - } - if (Train->Controlled()->iLights[1]&21) - {//wystarczy jeden zapalony z tyłu - glTexCoord2f(0,0); glVertex3f(-15.0,0.0,-fSmudge); - glTexCoord2f(1,0); glVertex3f( 15.0,0.0,-fSmudge); - glTexCoord2f(1,1); glVertex3f( 15.0,2.5,-250.0); - glTexCoord2f(0,1); glVertex3f(-15.0,2.5,-250.0); - } - glEnd(); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_DEPTH_TEST); - //glEnable(GL_LIGHTING); //i tak się włączy potem - glEnable(GL_FOG); + { // kamera nieruchoma + Global::SetCameraRotation(Camera.Yaw - M_PI); } - glEnable(GL_LIGHTING); //po renderowaniu smugi jest to wyłączone - //Ra: pojazd użytkownika należało by renderować po smudze, aby go nie rozświetlała - Global::bSmudge=false; //aby model użytkownika się teraz wyrenderował - Train->Dynamic()->Render(); - Train->Dynamic()->RenderAlpha(); //przezroczyste fragmenty pojazdów na torach - } //yB: moje smuuugi 1 - koniec*/ - else - glEnable(GL_LIGHTING); //po renderowaniu drutów może być to wyłączone + Ground.CheckQuery(); + // przy 0.25 smuga gaśnie o 6:37 w Quarku, a mogłaby już 5:40 + // Ra 2014-12: przy 0.15 się skarżyli, że nie widać smug => zmieniłem na 0.25 + if (Train) // jeśli nie usunięty + Global::bSmudge = + FreeFlyModeFlag ? false : ((Train->Dynamic()->fShade <= 0.0) ? + (Global::fLuminance <= 0.25) : + (Train->Dynamic()->fShade * Global::fLuminance <= 0.25)); - if (Train->Dynamic()->mdKabina) //bo mogła zniknąć przy przechodzeniu do innego pojazdu - {//oswietlenie kabiny - GLfloat ambientCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; - GLfloat diffuseCabLight[4]= { 0.5f, 0.5f, 0.5f, 1.0f }; - GLfloat specularCabLight[4]={ 0.5f, 0.5f, 0.5f, 1.0f }; - for (int li=0; li<3; li++) - {//przyciemnienie standardowe - ambientCabLight[li]= Global::ambientDayLight[li]*0.9; - diffuseCabLight[li]= Global::diffuseDayLight[li]*0.5; - specularCabLight[li]=Global::specularDayLight[li]*0.5; - } - switch (Train->Dynamic()->MyTrack->eEnvironment) - {//wpływ świetła zewnętrznego - case e_canyon: + if (!Render()) + return false; + + //********************************************************************************************************** + + if (Train) + { // rendering kabiny gdy jest oddzielnym modelem i ma byc wyswietlana + glPushMatrix(); + // ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze + // srodka + if ((Train->Dynamic()->mdKabina != Train->Dynamic()->mdModel) && + Train->Dynamic()->bDisplayCab && !FreeFlyModeFlag) + { + vector3 pos = Train->Dynamic()->GetPosition(); // wszpółrzędne pojazdu z kabiną + // glTranslatef(pos.x,pos.y,pos.z); //przesunięcie o wektor (tak było i trzęsło) + // aby pozbyć się choć trochę trzęsienia, trzeba by nie przeliczać kabiny do punktu + // zerowego scenerii + glLoadIdentity(); // zacząć od macierzy jedynkowej + Camera.SetCabMatrix(pos); // widok z kamery po przesunięciu + glMultMatrixd(Train->Dynamic()->mMatrix.getArray()); // ta macierz nie ma przesunięcia + + //*yB: moje smuuugi 1 + if (Global::bSmudge) + { // Ra: uwzględniłem zacienienie pojazdu przy zapalaniu smug + // 1. warunek na smugę wyznaczyc wcześniej + // 2. jeśli smuga włączona, nie renderować pojazdu użytkownika w DynObj + // 3. jeśli smuga właczona, wyrenderować pojazd użytkownia po dodaniu smugi do sceny + if (Train->Controlled()->Battery) + { // trochę na skróty z tą baterią + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE); + // glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_DST_COLOR); + // glBlendFunc(GL_SRC_ALPHA_SATURATE,GL_ONE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBindTexture(GL_TEXTURE_2D, light); // Select our texture + glBegin(GL_QUADS); + float fSmudge = + Train->Dynamic()->MoverParameters->DimHalf.y + 7; // gdzie zaczynać smugę + if (Train->Controlled()->iLights[0] & 21) + { // wystarczy jeden zapalony z przodu + glTexCoord2f(0, 0); + glVertex3f(15.0, 0.0, +fSmudge); // rysowanie względem położenia modelu + glTexCoord2f(1, 0); + glVertex3f(-15.0, 0.0, +fSmudge); + glTexCoord2f(1, 1); + glVertex3f(-15.0, 2.5, 250.0); + glTexCoord2f(0, 1); + glVertex3f(15.0, 2.5, 250.0); + } + if (Train->Controlled()->iLights[1] & 21) + { // wystarczy jeden zapalony z tyłu + glTexCoord2f(0, 0); + glVertex3f(-15.0, 0.0, -fSmudge); + glTexCoord2f(1, 0); + glVertex3f(15.0, 0.0, -fSmudge); + glTexCoord2f(1, 1); + glVertex3f(15.0, 2.5, -250.0); + glTexCoord2f(0, 1); + glVertex3f(-15.0, 2.5, -250.0); + } + glEnd(); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_DEPTH_TEST); + // glEnable(GL_LIGHTING); //i tak się włączy potem + glEnable(GL_FOG); + } + glEnable(GL_LIGHTING); // po renderowaniu smugi jest to wyłączone + // Ra: pojazd użytkownika należało by renderować po smudze, aby go nie rozświetlała + Global::bSmudge = false; // aby model użytkownika się teraz wyrenderował + Train->Dynamic()->Render(); + Train->Dynamic()->RenderAlpha(); // przezroczyste fragmenty pojazdów na torach + } // yB: moje smuuugi 1 - koniec*/ + else + glEnable(GL_LIGHTING); // po renderowaniu drutów może być to wyłączone + + if (Train->Dynamic()->mdKabina) // bo mogła zniknąć przy przechodzeniu do innego pojazdu + { // oswietlenie kabiny + GLfloat ambientCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + GLfloat diffuseCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + GLfloat specularCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + for (int li = 0; li < 3; li++) + { // przyciemnienie standardowe + ambientCabLight[li] = Global::ambientDayLight[li] * 0.9; + diffuseCabLight[li] = Global::diffuseDayLight[li] * 0.5; + specularCabLight[li] = Global::specularDayLight[li] * 0.5; + } + switch (Train->Dynamic()->MyTrack->eEnvironment) + { // wpływ świetła zewnętrznego + case e_canyon: + { + for (int li = 0; li < 3; li++) + { + diffuseCabLight[li] *= 0.6; + specularCabLight[li] *= 0.7; + } + } + break; + case e_tunnel: + { + for (int li = 0; li < 3; li++) + { + ambientCabLight[li] *= 0.3; + diffuseCabLight[li] *= 0.1; + specularCabLight[li] *= 0.2; + } + } + break; + } + switch (Train->iCabLightFlag) // Ra: uzeleżnic od napięcia w obwodzie sterowania + { // hunter-091012: uzaleznienie jasnosci od przetwornicy + case 0: //światło wewnętrzne zgaszone + break; + case 1: //światło wewnętrzne przygaszone (255 216 176) + if (Train->Dynamic()->MoverParameters->ConverterFlag == + true) // jasnosc dla zalaczonej przetwornicy + { + ambientCabLight[0] = Max0R(0.700, ambientCabLight[0]) * 0.75; // R + ambientCabLight[1] = Max0R(0.593, ambientCabLight[1]) * 0.75; // G + ambientCabLight[2] = Max0R(0.483, ambientCabLight[2]) * 0.75; // B + + for (int i = 0; i < 3; i++) + if (ambientCabLight[i] <= (Global::ambientDayLight[i] * 0.9)) + ambientCabLight[i] = Global::ambientDayLight[i] * 0.9; + } + else + { + ambientCabLight[0] = Max0R(0.700, ambientCabLight[0]) * 0.375; // R + ambientCabLight[1] = Max0R(0.593, ambientCabLight[1]) * 0.375; // G + ambientCabLight[2] = Max0R(0.483, ambientCabLight[2]) * 0.375; // B + + for (int i = 0; i < 3; i++) + if (ambientCabLight[i] <= (Global::ambientDayLight[i] * 0.9)) + ambientCabLight[i] = Global::ambientDayLight[i] * 0.9; + } + break; + case 2: //światło wewnętrzne zapalone (255 216 176) + if (Train->Dynamic()->MoverParameters->ConverterFlag == + true) // jasnosc dla zalaczonej przetwornicy + { + ambientCabLight[0] = Max0R(1.000, ambientCabLight[0]); // R + ambientCabLight[1] = Max0R(0.847, ambientCabLight[1]); // G + ambientCabLight[2] = Max0R(0.690, ambientCabLight[2]); // B + + for (int i = 0; i < 3; i++) + if (ambientCabLight[i] <= (Global::ambientDayLight[i] * 0.9)) + ambientCabLight[i] = Global::ambientDayLight[i] * 0.9; + } + else + { + ambientCabLight[0] = Max0R(1.000, ambientCabLight[0]) * 0.5; // R + ambientCabLight[1] = Max0R(0.847, ambientCabLight[1]) * 0.5; // G + ambientCabLight[2] = Max0R(0.690, ambientCabLight[2]) * 0.5; // B + + for (int i = 0; i < 3; i++) + if (ambientCabLight[i] <= (Global::ambientDayLight[i] * 0.9)) + ambientCabLight[i] = Global::ambientDayLight[i] * 0.9; + } + break; + } + glLightfv(GL_LIGHT0, GL_AMBIENT, ambientCabLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseCabLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, specularCabLight); + if (Global::bUseVBO) + { // renderowanie z użyciem VBO + Train->Dynamic()->mdKabina->RaRender(0.0, Train->Dynamic()->ReplacableSkinID, + Train->Dynamic()->iAlpha); + Train->Dynamic()->mdKabina->RaRenderAlpha( + 0.0, Train->Dynamic()->ReplacableSkinID, Train->Dynamic()->iAlpha); + } + else + { // renderowanie z Display List + Train->Dynamic()->mdKabina->Render(0.0, Train->Dynamic()->ReplacableSkinID, + Train->Dynamic()->iAlpha); + Train->Dynamic()->mdKabina->RenderAlpha(0.0, Train->Dynamic()->ReplacableSkinID, + Train->Dynamic()->iAlpha); + } + // przywrócenie standardowych, bo zawsze są zmieniane + glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); + } + } // koniec: if (Train->Dynamic()->mdKabina) + glPopMatrix(); + //********************************************************************************************************** + } // koniec: if (Train) + if (DebugModeFlag && !Global::iTextMode) { - for (int li=0; li<3; li++) - { - diffuseCabLight[li] *=0.6; - specularCabLight[li]*=0.7; - } + OutText1 = " FPS: "; + OutText1 += FloatToStrF(GetFPS(), ffFixed, 6, 2); + OutText1 += Global::iSlowMotion ? "s" : "n"; + + OutText1 += (GetDeltaTime() >= 0.2) ? "!" : " "; + // if (GetDeltaTime()>=0.2) //Ra: to za bardzo miota tekstem! + // { + // OutText1+= " Slowing Down !!! "; + // } } - break; - case e_tunnel: - { - for (int li=0; li<3; li++) - { - ambientCabLight[li] *=0.3; - diffuseCabLight[li] *=0.1; - specularCabLight[li]*=0.2; - } - } - break; - } - switch (Train->iCabLightFlag) //Ra: uzeleżnic od napięcia w obwodzie sterowania - { //hunter-091012: uzaleznienie jasnosci od przetwornicy - case 0: //światło wewnętrzne zgaszone - break; - case 1: //światło wewnętrzne przygaszone (255 216 176) - if (Train->Dynamic()->MoverParameters->ConverterFlag==true) //jasnosc dla zalaczonej przetwornicy - { - ambientCabLight[0]=Max0R(0.700,ambientCabLight[0])*0.75; //R - ambientCabLight[1]=Max0R(0.593,ambientCabLight[1])*0.75; //G - ambientCabLight[2]=Max0R(0.483,ambientCabLight[2])*0.75; //B - - for (int i=0;i<3;i++) - if (ambientCabLight[i]<=(Global::ambientDayLight[i]*0.9)) - ambientCabLight[i]=Global::ambientDayLight[i]*0.9; - } - else - { - ambientCabLight[0]=Max0R(0.700,ambientCabLight[0])*0.375; //R - ambientCabLight[1]=Max0R(0.593,ambientCabLight[1])*0.375; //G - ambientCabLight[2]=Max0R(0.483,ambientCabLight[2])*0.375; //B - - for (int i=0;i<3;i++) - if (ambientCabLight[i]<=(Global::ambientDayLight[i]*0.9)) - ambientCabLight[i]=Global::ambientDayLight[i]*0.9; - } - break; - case 2: //światło wewnętrzne zapalone (255 216 176) - if (Train->Dynamic()->MoverParameters->ConverterFlag==true) //jasnosc dla zalaczonej przetwornicy - { - ambientCabLight[0]=Max0R(1.000,ambientCabLight[0]); //R - ambientCabLight[1]=Max0R(0.847,ambientCabLight[1]); //G - ambientCabLight[2]=Max0R(0.690,ambientCabLight[2]); //B - - for (int i=0;i<3;i++) - if (ambientCabLight[i]<=(Global::ambientDayLight[i]*0.9)) - ambientCabLight[i]=Global::ambientDayLight[i]*0.9; - } - else - { - ambientCabLight[0]=Max0R(1.000,ambientCabLight[0])*0.5; //R - ambientCabLight[1]=Max0R(0.847,ambientCabLight[1])*0.5; //G - ambientCabLight[2]=Max0R(0.690,ambientCabLight[2])*0.5; //B - - for (int i=0;i<3;i++) - if (ambientCabLight[i]<=(Global::ambientDayLight[i]*0.9)) - ambientCabLight[i]=Global::ambientDayLight[i]*0.9; - } - break; - } - glLightfv(GL_LIGHT0,GL_AMBIENT,ambientCabLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseCabLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,specularCabLight); - if (Global::bUseVBO) - {//renderowanie z użyciem VBO - Train->Dynamic()->mdKabina->RaRender(0.0,Train->Dynamic()->ReplacableSkinID,Train->Dynamic()->iAlpha); - Train->Dynamic()->mdKabina->RaRenderAlpha(0.0,Train->Dynamic()->ReplacableSkinID,Train->Dynamic()->iAlpha); - } - else - {//renderowanie z Display List - Train->Dynamic()->mdKabina->Render(0.0,Train->Dynamic()->ReplacableSkinID,Train->Dynamic()->iAlpha); - Train->Dynamic()->mdKabina->RenderAlpha(0.0,Train->Dynamic()->ReplacableSkinID,Train->Dynamic()->iAlpha); - } - //przywrócenie standardowych, bo zawsze są zmieniane - glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); - glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); - glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); - } - } //koniec: if (Train->Dynamic()->mdKabina) - glPopMatrix(); -//********************************************************************************************************** - } //koniec: if (Train) - if (DebugModeFlag&&!Global::iTextMode) - { - OutText1=" FPS: "; - OutText1+=FloatToStrF(GetFPS(),ffFixed,6,2); - OutText1+=Global::iSlowMotion?"s":"n"; - - OutText1+=(GetDeltaTime()>=0.2)?"!":" "; - //if (GetDeltaTime()>=0.2) //Ra: to za bardzo miota tekstem! - // { - // OutText1+= " Slowing Down !!! "; - // } - } /*if (Console::Pressed(VK_F5)) {Global::slowmotion=true;}; if (Console::Pressed(VK_F6)) {Global::slowmotion=false;};*/ - if (Global::iTextMode==VK_F8) + if (Global::iTextMode == VK_F8) { - Global::iViewMode=VK_F8; - OutText1=" FPS: "; - OutText1+=FloatToStrF(GetFPS(),ffFixed,6,2); - if (Global::iSlowMotion) - OutText1+=" (slowmotion "+AnsiString(Global::iSlowMotion)+")"; - OutText1+=", sectors: "; - OutText1+=AnsiString(Ground.iRendered); + Global::iViewMode = VK_F8; + OutText1 = " FPS: "; + OutText1 += FloatToStrF(GetFPS(), ffFixed, 6, 2); + if (Global::iSlowMotion) + OutText1 += " (slowmotion " + AnsiString(Global::iSlowMotion) + ")"; + OutText1 += ", sectors: "; + OutText1 += AnsiString(Ground.iRendered); } - //if (Console::Pressed(VK_F7)) + // if (Console::Pressed(VK_F7)) //{ - // OutText1=FloatToStrF(Controlled->MoverParameters->Couplers[0].CouplingFlag,ffFixed,2,0)+", "; + // OutText1=FloatToStrF(Controlled->MoverParameters->Couplers[0].CouplingFlag,ffFixed,2,0)+", + // "; // OutText1+=FloatToStrF(Controlled->MoverParameters->Couplers[1].CouplingFlag,ffFixed,2,0); //} - /* if (Console::Pressed(VK_F5)) { @@ -1582,966 +1721,1181 @@ bool __fastcall TWorld::Update() }; */ if (Global::changeDynObj) - {//ABu zmiana pojazdu - przejście do innego - //Ra: to nie może być tak robione, to zbytnia proteza jest - Train->Silence(); //wyłączenie dźwięków opuszczanej kabiny - if (Train->Dynamic()->Mechanik) //AI może sobie samo pójść - if (!Train->Dynamic()->Mechanik->AIControllFlag) //tylko jeśli ręcznie prowadzony - {//jeśli prowadzi AI, to mu nie robimy dywersji! - Train->Dynamic()->MoverParameters->CabDeactivisation(); - Train->Dynamic()->Controller=AIdriver; - //Train->Dynamic()->MoverParameters->SecuritySystem.Status=0; //rozwala CA w EZT - Train->Dynamic()->MoverParameters->ActiveCab=0; - Train->Dynamic()->MoverParameters->BrakeLevelSet(-2); - Train->Dynamic()->MechInside=false; - } - //int CabNr; - TDynamicObject *temp=Global::changeDynObj; - //CabNr=temp->MoverParameters->ActiveCab; -/* - if (Train->Dynamic()->MoverParameters->ActiveCab==-1) - { - temp=Train->Dynamic()->NextConnected; //pojazd od strony sprzęgu 1 - CabNr=(Train->Dynamic()->NextConnectedNo==0)?1:-1; - } - else - { - temp=Train->Dynamic()->PrevConnected; //pojazd od strony sprzęgu 0 - CabNr=(Train->Dynamic()->PrevConnectedNo==0)?1:-1; - } -*/ - Train->Dynamic()->bDisplayCab=false; - Train->Dynamic()->ABuSetModelShake(vector3(0,0,0)); - ///Train->Dynamic()->MoverParameters->LimPipePress=-1; - ///Train->Dynamic()->MoverParameters->ActFlowSpeed=0; - ///Train->Dynamic()->Mechanik->CloseLog(); - ///SafeDelete(Train->Dynamic()->Mechanik); + { // ABu zmiana pojazdu - przejście do innego + // Ra: to nie może być tak robione, to zbytnia proteza jest + Train->Silence(); // wyłączenie dźwięków opuszczanej kabiny + if (Train->Dynamic()->Mechanik) // AI może sobie samo pójść + if (!Train->Dynamic()->Mechanik->AIControllFlag) // tylko jeśli ręcznie prowadzony + { // jeśli prowadzi AI, to mu nie robimy dywersji! + Train->Dynamic()->MoverParameters->CabDeactivisation(); + Train->Dynamic()->Controller = AIdriver; + // Train->Dynamic()->MoverParameters->SecuritySystem.Status=0; //rozwala CA w EZT + Train->Dynamic()->MoverParameters->ActiveCab = 0; + Train->Dynamic()->MoverParameters->BrakeLevelSet(-2); + Train->Dynamic()->MechInside = false; + } + // int CabNr; + TDynamicObject *temp = Global::changeDynObj; + // CabNr=temp->MoverParameters->ActiveCab; + /* + if (Train->Dynamic()->MoverParameters->ActiveCab==-1) + { + temp=Train->Dynamic()->NextConnected; //pojazd od strony sprzęgu 1 + CabNr=(Train->Dynamic()->NextConnectedNo==0)?1:-1; + } + else + { + temp=Train->Dynamic()->PrevConnected; //pojazd od strony sprzęgu 0 + CabNr=(Train->Dynamic()->PrevConnectedNo==0)?1:-1; + } + */ + Train->Dynamic()->bDisplayCab = false; + Train->Dynamic()->ABuSetModelShake(vector3(0, 0, 0)); + /// Train->Dynamic()->MoverParameters->LimPipePress=-1; + /// Train->Dynamic()->MoverParameters->ActFlowSpeed=0; + /// Train->Dynamic()->Mechanik->CloseLog(); + /// SafeDelete(Train->Dynamic()->Mechanik); - //Train->Dynamic()->mdKabina=NULL; - if (Train->Dynamic()->Mechanik) //AI może sobie samo pójść - if (!Train->Dynamic()->Mechanik->AIControllFlag) //tylko jeśli ręcznie prowadzony - Train->Dynamic()->Mechanik->MoveTo(temp); //przsunięcie obiektu zarządzającego - //Train->DynamicObject=NULL; - Train->DynamicSet(temp); - Controlled=temp; - mvControlled=Controlled->ControlledFind()->MoverParameters; - Global::asHumanCtrlVehicle=Train->Dynamic()->GetName(); - if (Train->Dynamic()->Mechanik) //AI może sobie samo pójść - if (!Train->Dynamic()->Mechanik->AIControllFlag) //tylko jeśli ręcznie prowadzony - {Train->Dynamic()->MoverParameters->LimPipePress=Controlled->MoverParameters->PipePress; - //Train->Dynamic()->MoverParameters->ActFlowSpeed=0; - //Train->Dynamic()->MoverParameters->SecuritySystem.Status=1; - //Train->Dynamic()->MoverParameters->ActiveCab=CabNr; - Train->Dynamic()->MoverParameters->CabActivisation(); //załączenie rozrządu (wirtualne kabiny) - Train->Dynamic()->Controller=Humandriver; - Train->Dynamic()->MechInside=true; - //Train->Dynamic()->Mechanik=new TController(l,r,Controlled->Controller,&Controlled->MoverParameters,&Controlled->TrainParams,Aggressive); - //Train->InitializeCab(CabNr,Train->Dynamic()->asBaseDir+Train->Dynamic()->MoverParameters->TypeName+".mmd"); - } - Train->InitializeCab(Train->Dynamic()->MoverParameters->CabNo,Train->Dynamic()->asBaseDir+Train->Dynamic()->MoverParameters->TypeName+".mmd"); - if (!FreeFlyModeFlag) - {Global::pUserDynamic=Controlled; //renerowanie względem kamery - Train->Dynamic()->bDisplayCab=true; - Train->Dynamic()->ABuSetModelShake(vector3(0,0,0)); //zerowanie przesunięcia przed powrotem? - Train->MechStop(); - FollowView(); //na pozycję mecha - } - Global::changeDynObj=NULL; - } - - glDisable(GL_LIGHTING); - if (Controlled) - SetWindowText(hWnd,AnsiString(Controlled->MoverParameters->Name).c_str()); - else - SetWindowText(hWnd,Global::szSceneryFile); //nazwa scenerii - glBindTexture(GL_TEXTURE_2D, 0); - glColor4f(1.0f,0.0f,0.0f,1.0f); - glLoadIdentity(); - glTranslatef(0.0f,0.0f,-0.50f); - - - if (Global::iTextMode==VK_F1) - {//tekst pokazywany po wciśnięciu [F1] - //Global::iViewMode=VK_F1; - glColor3f(1.0f,1.0f,1.0f); //a, damy białym - OutText1="Time: "+AnsiString((int)GlobalTime->hh)+":"; - int i=GlobalTime->mm; //bo inaczej potrafi zrobić "hh:010" - if (i<10) OutText1+="0"; - OutText1+=AnsiString(i); //minuty - OutText1+=":"; - i=floor(GlobalTime->mr); //bo inaczej potrafi zrobić "hh:mm:010" - if (i<10) OutText1+="0"; - OutText1+=AnsiString(i); - if (Global::iPause) OutText1+=" - paused"; - if (Controlled) - if (Controlled->Mechanik) - {OutText2=Controlled->Mechanik->Relation(); - if (!OutText2.IsEmpty()) //jeśli jest podana relacja, to dodajemy punkt następnego zatrzymania - OutText2=Global::Bezogonkow(OutText2+": -> "+Controlled->Mechanik->NextStop(),true); //dopisanie punktu zatrzymania - } - //double CtrlPos=mvControlled->MainCtrlPos; - //double CtrlPosNo=mvControlled->MainCtrlPosNo; - //OutText2="defrot="+FloatToStrF(1+0.4*(CtrlPos/CtrlPosNo),ffFixed,2,5); - OutText3=""; //Pomoc w sterowaniu - [F9]"; - //OutText3=AnsiString(Global::pCameraRotationDeg); //kąt kamery względem północy - } - else if (Global::iTextMode==VK_F12) - {//opcje włączenia i wyłączenia logowania - OutText1="[0] Debugmode "+AnsiString(DebugModeFlag?"(on)":"(off)"); - OutText2="[1] log.txt "+AnsiString((Global::iWriteLogEnabled&1)?"(on)":"(off)"); - OutText3="[2] Console "+AnsiString((Global::iWriteLogEnabled&2)?"(on)":"(off)"); - } - else if (Global::iTextMode==VK_F2) - {//ABu: info dla najblizszego pojazdu! - TDynamicObject *tmp=FreeFlyModeFlag?Ground.DynamicNearest(Camera.Pos):Controlled; //w trybie latania lokalizujemy wg mapy - if (tmp) - { - if (Global::iScreenMode[Global::iTextMode-VK_F1]==0) - {//jeśli domyślny ekran po pierwszym naciśnięciu - OutText3=""; - OutText1="Vehicle name: "+AnsiString(tmp->MoverParameters->Name); -//yB OutText1+="; d: "+FloatToStrF(tmp->ABuGetDirection(),ffFixed,2,0); - //OutText1=FloatToStrF(tmp->MoverParameters->Couplers[0].CouplingFlag,ffFixed,3,2)+", "; - //OutText1+=FloatToStrF(tmp->MoverParameters->Couplers[1].CouplingFlag,ffFixed,3,2); - if (tmp->Mechanik) //jeśli jest prowadzący - {//ostatnia komenda dla AI - OutText1+=", command: "+tmp->Mechanik->OrderCurrent(); - } - else if (tmp->ctOwner) - OutText1+=", owned by "+AnsiString(tmp->ctOwner->OwnerName()); - if (!tmp->MoverParameters->CommandLast.IsEmpty()) - OutText1+=AnsiString(", put: ")+tmp->MoverParameters->CommandLast; - //OutText1+="; Cab="+AnsiString(tmp->MoverParameters->CabNo); - OutText2="Damage status: "+tmp->MoverParameters->EngineDescription(0);//+" Engine status: "; - OutText2+="; Brake delay: "; - if((tmp->MoverParameters->BrakeDelayFlag&bdelay_G)==bdelay_G) - OutText2+="G"; - if((tmp->MoverParameters->BrakeDelayFlag&bdelay_P)==bdelay_P) - OutText2+="P"; - if((tmp->MoverParameters->BrakeDelayFlag&bdelay_R)==bdelay_R) - OutText2+="R"; - if((tmp->MoverParameters->BrakeDelayFlag&bdelay_M)==bdelay_M) - OutText2+="+Mg"; - OutText2+=AnsiString(", BTP:")+FloatToStrF(tmp->MoverParameters->LoadFlag,ffFixed,5,0); - //if ((tmp->MoverParameters->EnginePowerSource.SourceType==CurrentCollector) || (tmp->MoverParameters->TrainType==dt_EZT)) - {OutText2+=AnsiString("; pant. ")+FloatToStrF(tmp->MoverParameters->PantPress,ffFixed,8,2); - OutText2+=(tmp->MoverParameters->bPantKurek3?"MoverParameters->u,ffFixed,3,3); -// OutText2+=AnsiString(", N:")+FloatToStrF(tmp->MoverParameters->Ntotal,ffFixed,4,0); - OutText2+=AnsiString(", Ft:")+FloatToStrF(tmp->MoverParameters->Ft,ffFixed,4,0); -// OutText3= AnsiString("BP: ")+FloatToStrF(tmp->MoverParameters->BrakePress,ffFixed,5,2)+AnsiString(", "); -// OutText3+= AnsiString("PP: ")+FloatToStrF(tmp->MoverParameters->PipePress,ffFixed,5,2)+AnsiString(", "); -// OutText3+= AnsiString("BVP: ")+FloatToStrF(tmp->MoverParameters->Volume,ffFixed,5,3)+AnsiString(", "); -// OutText3+= FloatToStrF(tmp->MoverParameters->CntrlPipePress,ffFixed,5,3)+AnsiString(", "); -// OutText3+= FloatToStrF(tmp->MoverParameters->Hamulec->GetCRP(),ffFixed,5,3)+AnsiString(", "); -// OutText3+= FloatToStrF(tmp->MoverParameters->BrakeStatus,ffFixed,5,0)+AnsiString(", "); -// OutText3+= AnsiString("HP: ")+FloatToStrF(tmp->MoverParameters->ScndPipePress,ffFixed,5,2)+AnsiString(". "); -// OutText2+= FloatToStrF(tmp->MoverParameters->CompressorPower,ffFixed,5,0)+AnsiString(", "); -//yB if(tmp->MoverParameters->BrakeSubsystem==Knorr) OutText2+=" Knorr"; -//yB if(tmp->MoverParameters->BrakeSubsystem==Oerlikon) OutText2+=" Oerlikon"; -//yB if(tmp->MoverParameters->BrakeSubsystem==Hik) OutText2+=" Hik"; -//yB if(tmp->MoverParameters->BrakeSubsystem==WeLu) OutText2+=" Łestinghałs"; - //OutText2= " GetFirst: "+AnsiString(tmp->GetFirstDynamic(1)->MoverParameters->Name)+" Damage status="+tmp->MoverParameters->EngineDescription(0)+" Engine status: "; - //OutText2+= " GetLast: "+AnsiString(tmp->GetLastDynamic(1)->MoverParameters->Name)+" Damage status="+tmp->MoverParameters->EngineDescription(0)+" Engine status: "; - OutText3=AnsiString("BP: ")+FloatToStrF(tmp->MoverParameters->BrakePress,ffFixed,5,2)+AnsiString(", "); - OutText3+=FloatToStrF(tmp->MoverParameters->BrakeStatus,ffFixed,5,0)+AnsiString(", "); - OutText3+=AnsiString("PP: ")+FloatToStrF(tmp->MoverParameters->PipePress,ffFixed,5,2)+AnsiString("/"); - OutText3+=FloatToStrF(tmp->MoverParameters->ScndPipePress,ffFixed,5,2)+AnsiString("/"); - OutText3+=FloatToStrF(tmp->MoverParameters->EqvtPipePress,ffFixed,5,2)+AnsiString(", "); - OutText3+=AnsiString("BVP: ")+FloatToStrF(tmp->MoverParameters->Volume,ffFixed,5,3)+AnsiString(", "); - OutText3+=FloatToStrF(tmp->MoverParameters->CntrlPipePress,ffFixed,5,3)+AnsiString(", "); - OutText3+=FloatToStrF(tmp->MoverParameters->Hamulec->GetCRP(),ffFixed,5,3)+AnsiString(", "); - OutText3+=FloatToStrF(tmp->MoverParameters->BrakeStatus,ffFixed,5,0)+AnsiString(", "); -// OutText3+=AnsiString("BVP: ")+FloatToStrF(tmp->MoverParameters->BrakeVP(),ffFixed,5,2)+AnsiString(", "); - -// OutText3+=FloatToStrF(tmp->MoverParameters->CntrlPipePress,ffFixed,5,2)+AnsiString(", "); -// OutText3+=FloatToStrF(tmp->MoverParameters->HighPipePress,ffFixed,5,2)+AnsiString(", "); -// OutText3+=FloatToStrF(tmp->MoverParameters->LowPipePress,ffFixed,5,2)+AnsiString(", "); - - if (tmp->MoverParameters->ManualBrakePos>0) - OutText3+=AnsiString("manual brake active. "); - else if (tmp->MoverParameters->LocalBrakePos>0) - OutText3+=AnsiString("local brake active. "); - else - OutText3+=AnsiString("local brake inactive. "); -/* - //OutText3+=AnsiString("LSwTim: ")+FloatToStrF(tmp->MoverParameters->LastSwitchingTime,ffFixed,5,2); - //OutText3+=AnsiString(" Physic: ")+FloatToStrF(tmp->MoverParameters->PhysicActivation,ffFixed,5,2); - //OutText3+=AnsiString(" ESF: ")+FloatToStrF(tmp->MoverParameters->EndSignalsFlag,ffFixed,5,0); - OutText3+=AnsiString(" dPAngF: ")+FloatToStrF(tmp->dPantAngleF,ffFixed,5,0); - OutText3+=AnsiString(" dPAngFT: ")+FloatToStrF(-(tmp->PantTraction1*28.9-136.938),ffFixed,5,0); - if (tmp->lastcabf==1) - { - OutText3+=AnsiString(" pcabc1: ")+FloatToStrF(tmp->MoverParameters->PantFrontUp,ffFixed,5,0); - OutText3+=AnsiString(" pcabc2: ")+FloatToStrF(tmp->MoverParameters->PantRearUp,ffFixed,5,0); - } - if (tmp->lastcabf==-1) - { - OutText3+=AnsiString(" pcabc1: ")+FloatToStrF(tmp->MoverParameters->PantRearUp,ffFixed,5,0); - OutText3+=AnsiString(" pcabc2: ")+FloatToStrF(tmp->MoverParameters->PantFrontUp,ffFixed,5,0); - } -*/ - OutText4=""; - if (tmp->Mechanik) - {//o ile jest ktoś w środku - //OutText4=tmp->Mechanik->StopReasonText(); - //if (!OutText4.IsEmpty()) OutText4+="; "; //aby ładniejszy odstęp był - //if (Controlled->Mechanik && (Controlled->Mechanik->AIControllFlag==AIdriver)) - AnsiString flags="bwaccmlshhhoibsgvdp; "; //flagi AI (definicja w Driver.h) - for (int i=0,j=1;i<19;++i,j<<=1) - if (tmp->Mechanik->DrivigFlags()&j) //jak bit ustawiony - flags[i+1]^=0x20; //to zmiana na wielką literę - OutText4=flags; - OutText4+=AnsiString("Driver: Vd=")+FloatToStrF(tmp->Mechanik->VelDesired,ffFixed,4,0) - +AnsiString(" ad=")+FloatToStrF(tmp->Mechanik->AccDesired,ffFixed,5,2) - +AnsiString(" Pd=")+FloatToStrF(tmp->Mechanik->ActualProximityDist,ffFixed,4,0) - +AnsiString(" Vn=")+FloatToStrF(tmp->Mechanik->VelNext,ffFixed,4,0); - if (tmp->Mechanik->VelNext==0.0) - if (tmp->Mechanik->eSignNext) - {//jeśli ma zapamiętany event semafora - //if (!OutText4.IsEmpty()) OutText4+=", "; //aby ładniejszy odstęp był - OutText4+=" ("+Global::Bezogonkow(tmp->Mechanik->eSignNext->asName)+")"; //nazwa eventu semafora - } - } - if (!OutText4.IsEmpty()) OutText4+="; "; //aby ładniejszy odstęp był - //informacja o sprzęgach nawet bez mechanika - OutText4+="C0="+(tmp->PrevConnected?tmp->PrevConnected->GetName()+":"+AnsiString(tmp->MoverParameters->Couplers[0].CouplingFlag):AnsiString("NULL")); - OutText4+=" C1="+(tmp->NextConnected?tmp->NextConnected->GetName()+":"+AnsiString(tmp->MoverParameters->Couplers[1].CouplingFlag):AnsiString("NULL")); - if (Console::Pressed(VK_F2)) - {WriteLog(OutText1); - WriteLog(OutText2); - WriteLog(OutText3); - WriteLog(OutText4); - } - } //koniec treści podstawowego ekranu FK_V2 - else - {//ekran drugi, czyli tabelka skanowania AI - if (tmp->Mechanik) //żeby była tabelka, musi być AI - {//tabelka jest na użytek testujących scenerie, więc nie musi być "ładna" - glColor3f(0.0f,1.0f,0.0f); //a, damy zielony - //glTranslatef(0.0f,0.0f,-0.50f); - glRasterPos2f(-0.25f,0.20f); - //OutText1="Scan distance: "+AnsiString(tmp->Mechanik->scanmax)+", back: "+AnsiString(tmp->Mechanik->scanback); - OutText1="Time: "+AnsiString((int)GlobalTime->hh)+":"; - int i=GlobalTime->mm; //bo inaczej potrafi zrobić "hh:010" - if (i<10) OutText1+="0"; - OutText1+=AnsiString(i); //minuty - OutText1+=":"; - i=floor(GlobalTime->mr); //bo inaczej potrafi zrobić "hh:mm:010" - if (i<10) OutText1+="0"; - OutText1+=AnsiString(i); - OutText1+=AnsiString(". Vel: ")+FloatToStrF(tmp->GetVelocity(),ffFixed,6,1); - OutText1+=". Scan table:"; - glPrint(Global::Bezogonkow(OutText1).c_str()); - i=-1; - while ((OutText1=tmp->Mechanik->TableText(++i))!="") - {//wyświetlenie pozycji z tabelki - glRasterPos2f(-0.25f,0.19f-0.01f*i); - glPrint(Global::Bezogonkow(OutText1).c_str()); + // Train->Dynamic()->mdKabina=NULL; + if (Train->Dynamic()->Mechanik) // AI może sobie samo pójść + if (!Train->Dynamic()->Mechanik->AIControllFlag) // tylko jeśli ręcznie prowadzony + Train->Dynamic()->Mechanik->MoveTo(temp); // przsunięcie obiektu zarządzającego + // Train->DynamicObject=NULL; + Train->DynamicSet(temp); + Controlled = temp; + mvControlled = Controlled->ControlledFind()->MoverParameters; + Global::asHumanCtrlVehicle = Train->Dynamic()->GetName(); + if (Train->Dynamic()->Mechanik) // AI może sobie samo pójść + if (!Train->Dynamic()->Mechanik->AIControllFlag) // tylko jeśli ręcznie prowadzony + { + Train->Dynamic()->MoverParameters->LimPipePress = + Controlled->MoverParameters->PipePress; + // Train->Dynamic()->MoverParameters->ActFlowSpeed=0; + // Train->Dynamic()->MoverParameters->SecuritySystem.Status=1; + // Train->Dynamic()->MoverParameters->ActiveCab=CabNr; + Train->Dynamic() + ->MoverParameters->CabActivisation(); // załączenie rozrządu (wirtualne kabiny) + Train->Dynamic()->Controller = Humandriver; + Train->Dynamic()->MechInside = true; + // Train->Dynamic()->Mechanik=new + // TController(l,r,Controlled->Controller,&Controlled->MoverParameters,&Controlled->TrainParams,Aggressive); + // Train->InitializeCab(CabNr,Train->Dynamic()->asBaseDir+Train->Dynamic()->MoverParameters->TypeName+".mmd"); + } + Train->InitializeCab(Train->Dynamic()->MoverParameters->CabNo, + Train->Dynamic()->asBaseDir + + Train->Dynamic()->MoverParameters->TypeName + ".mmd"); + if (!FreeFlyModeFlag) + { + Global::pUserDynamic = Controlled; // renerowanie względem kamery + Train->Dynamic()->bDisplayCab = true; + Train->Dynamic()->ABuSetModelShake( + vector3(0, 0, 0)); // zerowanie przesunięcia przed powrotem? + Train->MechStop(); + FollowView(); // na pozycję mecha } - //podsumowanie sensu tabelki - OutText4=AnsiString("Driver: Vd=")+FloatToStrF(tmp->Mechanik->VelDesired,ffFixed,4,0) - +AnsiString(" ad=")+FloatToStrF(tmp->Mechanik->AccDesired,ffFixed,5,2) - +AnsiString(" Pd=")+FloatToStrF(tmp->Mechanik->ActualProximityDist,ffFixed,4,0) - +AnsiString(" Vn=")+FloatToStrF(tmp->Mechanik->VelNext,ffFixed,4,0); - if (tmp->Mechanik->VelNext==0.0) - if (tmp->Mechanik->eSignNext) - {//jeśli ma zapamiętany event semafora - //if (!OutText4.IsEmpty()) OutText4+=", "; //aby ładniejszy odstęp był - OutText4+=" ("+Global::Bezogonkow(tmp->Mechanik->eSignNext->asName)+")"; //nazwa eventu semafora - } - glRasterPos2f(-0.25f,0.19f-0.01f*i); - glPrint(Global::Bezogonkow(OutText4).c_str()); - } - } //koniec ekanu skanowania - } //koniec obsługi, gdy mamy wskaźnik do pojazdu - else - {//wyświetlenie współrzędnych w scenerii oraz kąta kamery, gdy nie mamy wskaźnika - OutText1="Camera position: "+FloatToStrF(Camera.Pos.x,ffFixed,6,2)+" "+FloatToStrF(Camera.Pos.y,ffFixed,6,2)+" "+FloatToStrF(Camera.Pos.z,ffFixed,6,2); - OutText1+=", azimuth: "+FloatToStrF(180.0-RadToDeg(Camera.Yaw),ffFixed,3,0); //ma być azymut, czyli 0 na północy i rośnie na wschód - OutText1+=" "+AnsiString("S SEE NEN NWW SW").SubString(1+2*floor(fmod(8+(Camera.Yaw+0.5*M_PI_4)/M_PI_4,8)),2); - } - //OutText3= AnsiString(" Online documentation (PL, ENG, DE, soon CZ): http://www.eu07.pl"); - //OutText3="enrot="+FloatToStrF(Controlled->MoverParameters->enrot,ffFixed,6,2); - //OutText3="; n="+FloatToStrF(Controlled->MoverParameters->n,ffFixed,6,2); - } //koniec treści podstawowego ekranu FK_V2 - else if (Global::iTextMode==VK_F5) - {//przesiadka do innego pojazdu - if (FreeFlyModeFlag) //jeśli tryb latania - {TDynamicObject *tmp=Ground.DynamicNearest(Camera.Pos,50,true); //łapiemy z obsadą - if (tmp) - if (tmp!=Controlled) - {if (Controlled) //jeśli mielismy pojazd - if (Controlled->Mechanik) //na skutek jakiegoś błędu może czasem zniknąć - Controlled->Mechanik->TakeControl(true); //oddajemy dotychczasowy AI - if (DebugModeFlag?true:tmp->MoverParameters->Vel<=5.0) - {Controlled=tmp; //przejmujemy nowy - mvControlled=Controlled->ControlledFind()->MoverParameters; - if (Train) - Train->Silence(); //wyciszenie dźwięków opuszczanego pojazdu - else - Train=new TTrain(); //jeśli niczym jeszcze nie jeździlismy - if (Train->Init(Controlled)) - {//przejmujemy sterowanie - if (!DebugModeFlag) //w DebugMode nadal prowadzi AI - Controlled->Mechanik->TakeControl(false); - } - else - SafeDelete(Train); //i nie ma czym sterować - //Global::pUserDynamic=Controlled; //renerowanie pojazdu względem kabiny - //Global::iTextMode=VK_F4; - if (Train) InOutKey(); //do kabiny + Global::changeDynObj = NULL; + } + + glDisable(GL_LIGHTING); + if (Controlled) + SetWindowText(hWnd, AnsiString(Controlled->MoverParameters->Name).c_str()); + else + SetWindowText(hWnd, Global::szSceneryFile); // nazwa scenerii + glBindTexture(GL_TEXTURE_2D, 0); + glColor4f(1.0f, 0.0f, 0.0f, 1.0f); + glLoadIdentity(); + glTranslatef(0.0f, 0.0f, -0.50f); + + if (Global::iTextMode == VK_F1) + { // tekst pokazywany po wciśnięciu [F1] + // Global::iViewMode=VK_F1; + glColor3f(1.0f, 1.0f, 1.0f); // a, damy białym + OutText1 = "Time: " + AnsiString((int)GlobalTime->hh) + ":"; + int i = GlobalTime->mm; // bo inaczej potrafi zrobić "hh:010" + if (i < 10) + OutText1 += "0"; + OutText1 += AnsiString(i); // minuty + OutText1 += ":"; + i = floor(GlobalTime->mr); // bo inaczej potrafi zrobić "hh:mm:010" + if (i < 10) + OutText1 += "0"; + OutText1 += AnsiString(i); + if (Global::iPause) + OutText1 += " - paused"; + if (Controlled) + if (Controlled->Mechanik) + { + OutText2 = Controlled->Mechanik->Relation(); + if (!OutText2.IsEmpty()) // jeśli jest podana relacja, to dodajemy punkt następnego + // zatrzymania + OutText2 = + Global::Bezogonkow(OutText2 + ": -> " + Controlled->Mechanik->NextStop(), + true); // dopisanie punktu zatrzymania + } + // double CtrlPos=mvControlled->MainCtrlPos; + // double CtrlPosNo=mvControlled->MainCtrlPosNo; + // OutText2="defrot="+FloatToStrF(1+0.4*(CtrlPos/CtrlPosNo),ffFixed,2,5); + OutText3 = ""; // Pomoc w sterowaniu - [F9]"; + // OutText3=AnsiString(Global::pCameraRotationDeg); //kąt kamery względem północy + } + else if (Global::iTextMode == VK_F12) + { // opcje włączenia i wyłączenia logowania + OutText1 = "[0] Debugmode " + AnsiString(DebugModeFlag ? "(on)" : "(off)"); + OutText2 = "[1] log.txt " + AnsiString((Global::iWriteLogEnabled & 1) ? "(on)" : "(off)"); + OutText3 = "[2] Console " + AnsiString((Global::iWriteLogEnabled & 2) ? "(on)" : "(off)"); + } + else if (Global::iTextMode == VK_F2) + { // ABu: info dla najblizszego pojazdu! + TDynamicObject *tmp = FreeFlyModeFlag ? Ground.DynamicNearest(Camera.Pos) : + Controlled; // w trybie latania lokalizujemy wg mapy + if (tmp) + { + if (Global::iScreenMode[Global::iTextMode - VK_F1] == 0) + { // jeśli domyślny ekran po pierwszym naciśnięciu + OutText3 = ""; + OutText1 = "Vehicle name: " + AnsiString(tmp->MoverParameters->Name); + // yB OutText1+="; d: "+FloatToStrF(tmp->ABuGetDirection(),ffFixed,2,0); + // OutText1=FloatToStrF(tmp->MoverParameters->Couplers[0].CouplingFlag,ffFixed,3,2)+", + // "; + // OutText1+=FloatToStrF(tmp->MoverParameters->Couplers[1].CouplingFlag,ffFixed,3,2); + if (tmp->Mechanik) // jeśli jest prowadzący + { // ostatnia komenda dla AI + OutText1 += ", command: " + tmp->Mechanik->OrderCurrent(); + } + else if (tmp->ctOwner) + OutText1 += ", owned by " + AnsiString(tmp->ctOwner->OwnerName()); + if (!tmp->MoverParameters->CommandLast.IsEmpty()) + OutText1 += AnsiString(", put: ") + tmp->MoverParameters->CommandLast; + // OutText1+="; Cab="+AnsiString(tmp->MoverParameters->CabNo); + OutText2 = "Damage status: " + + tmp->MoverParameters->EngineDescription(0); //+" Engine status: "; + OutText2 += "; Brake delay: "; + if ((tmp->MoverParameters->BrakeDelayFlag & bdelay_G) == bdelay_G) + OutText2 += "G"; + if ((tmp->MoverParameters->BrakeDelayFlag & bdelay_P) == bdelay_P) + OutText2 += "P"; + if ((tmp->MoverParameters->BrakeDelayFlag & bdelay_R) == bdelay_R) + OutText2 += "R"; + if ((tmp->MoverParameters->BrakeDelayFlag & bdelay_M) == bdelay_M) + OutText2 += "+Mg"; + OutText2 += AnsiString(", BTP:") + + FloatToStrF(tmp->MoverParameters->LoadFlag, ffFixed, 5, 0); + // if ((tmp->MoverParameters->EnginePowerSource.SourceType==CurrentCollector) || + // (tmp->MoverParameters->TrainType==dt_EZT)) + { + OutText2 += AnsiString("; pant. ") + + FloatToStrF(tmp->MoverParameters->PantPress, ffFixed, 8, 2); + OutText2 += (tmp->MoverParameters->bPantKurek3 ? "MoverParameters->u,ffFixed,3,3); + // OutText2+=AnsiString(", + // N:")+FloatToStrF(tmp->MoverParameters->Ntotal,ffFixed,4,0); + OutText2 += + AnsiString(", Ft:") + FloatToStrF(tmp->MoverParameters->Ft, ffFixed, 4, 0); + // OutText3= AnsiString("BP: + // ")+FloatToStrF(tmp->MoverParameters->BrakePress,ffFixed,5,2)+AnsiString(", + // "); + // OutText3+= AnsiString("PP: + // ")+FloatToStrF(tmp->MoverParameters->PipePress,ffFixed,5,2)+AnsiString(", + // "); + // OutText3+= AnsiString("BVP: + // ")+FloatToStrF(tmp->MoverParameters->Volume,ffFixed,5,3)+AnsiString(", + // "); + // OutText3+= + // FloatToStrF(tmp->MoverParameters->CntrlPipePress,ffFixed,5,3)+AnsiString(", + // "); + // OutText3+= + // FloatToStrF(tmp->MoverParameters->Hamulec->GetCRP(),ffFixed,5,3)+AnsiString(", + // "); + // OutText3+= + // FloatToStrF(tmp->MoverParameters->BrakeStatus,ffFixed,5,0)+AnsiString(", + // "); + // OutText3+= AnsiString("HP: + // ")+FloatToStrF(tmp->MoverParameters->ScndPipePress,ffFixed,5,2)+AnsiString(". + // "); + // OutText2+= + // FloatToStrF(tmp->MoverParameters->CompressorPower,ffFixed,5,0)+AnsiString(", + // "); + // yB if(tmp->MoverParameters->BrakeSubsystem==Knorr) OutText2+=" Knorr"; + // yB if(tmp->MoverParameters->BrakeSubsystem==Oerlikon) OutText2+=" Oerlikon"; + // yB if(tmp->MoverParameters->BrakeSubsystem==Hik) OutText2+=" Hik"; + // yB if(tmp->MoverParameters->BrakeSubsystem==WeLu) OutText2+=" Łestinghałs"; + // OutText2= " GetFirst: + // "+AnsiString(tmp->GetFirstDynamic(1)->MoverParameters->Name)+" Damage + // status="+tmp->MoverParameters->EngineDescription(0)+" Engine status: "; + // OutText2+= " GetLast: + // "+AnsiString(tmp->GetLastDynamic(1)->MoverParameters->Name)+" Damage + // status="+tmp->MoverParameters->EngineDescription(0)+" Engine status: "; + OutText3 = AnsiString("BP: ") + + FloatToStrF(tmp->MoverParameters->BrakePress, ffFixed, 5, 2) + + AnsiString(", "); + OutText3 += FloatToStrF(tmp->MoverParameters->BrakeStatus, ffFixed, 5, 0) + + AnsiString(", "); + OutText3 += AnsiString("PP: ") + + FloatToStrF(tmp->MoverParameters->PipePress, ffFixed, 5, 2) + + AnsiString("/"); + OutText3 += FloatToStrF(tmp->MoverParameters->ScndPipePress, ffFixed, 5, 2) + + AnsiString("/"); + OutText3 += FloatToStrF(tmp->MoverParameters->EqvtPipePress, ffFixed, 5, 2) + + AnsiString(", "); + OutText3 += AnsiString("BVP: ") + + FloatToStrF(tmp->MoverParameters->Volume, ffFixed, 5, 3) + + AnsiString(", "); + OutText3 += FloatToStrF(tmp->MoverParameters->CntrlPipePress, ffFixed, 5, 3) + + AnsiString(", "); + OutText3 += FloatToStrF(tmp->MoverParameters->Hamulec->GetCRP(), ffFixed, 5, 3) + + AnsiString(", "); + OutText3 += FloatToStrF(tmp->MoverParameters->BrakeStatus, ffFixed, 5, 0) + + AnsiString(", "); + // OutText3+=AnsiString("BVP: + // ")+FloatToStrF(tmp->MoverParameters->BrakeVP(),ffFixed,5,2)+AnsiString(", + // "); + + // OutText3+=FloatToStrF(tmp->MoverParameters->CntrlPipePress,ffFixed,5,2)+AnsiString(", + // "); + // OutText3+=FloatToStrF(tmp->MoverParameters->HighPipePress,ffFixed,5,2)+AnsiString(", + // "); + // OutText3+=FloatToStrF(tmp->MoverParameters->LowPipePress,ffFixed,5,2)+AnsiString(", + // "); + + if (tmp->MoverParameters->ManualBrakePos > 0) + OutText3 += AnsiString("manual brake active. "); + else if (tmp->MoverParameters->LocalBrakePos > 0) + OutText3 += AnsiString("local brake active. "); + else + OutText3 += AnsiString("local brake inactive. "); + /* + //OutText3+=AnsiString("LSwTim: + ")+FloatToStrF(tmp->MoverParameters->LastSwitchingTime,ffFixed,5,2); + //OutText3+=AnsiString(" Physic: + ")+FloatToStrF(tmp->MoverParameters->PhysicActivation,ffFixed,5,2); + //OutText3+=AnsiString(" ESF: + ")+FloatToStrF(tmp->MoverParameters->EndSignalsFlag,ffFixed,5,0); + OutText3+=AnsiString(" dPAngF: ")+FloatToStrF(tmp->dPantAngleF,ffFixed,5,0); + OutText3+=AnsiString(" dPAngFT: + ")+FloatToStrF(-(tmp->PantTraction1*28.9-136.938),ffFixed,5,0); + if (tmp->lastcabf==1) + { + OutText3+=AnsiString(" pcabc1: + ")+FloatToStrF(tmp->MoverParameters->PantFrontUp,ffFixed,5,0); + OutText3+=AnsiString(" pcabc2: + ")+FloatToStrF(tmp->MoverParameters->PantRearUp,ffFixed,5,0); + } + if (tmp->lastcabf==-1) + { + OutText3+=AnsiString(" pcabc1: + ")+FloatToStrF(tmp->MoverParameters->PantRearUp,ffFixed,5,0); + OutText3+=AnsiString(" pcabc2: + ")+FloatToStrF(tmp->MoverParameters->PantFrontUp,ffFixed,5,0); + } + */ + OutText4 = ""; + if (tmp->Mechanik) + { // o ile jest ktoś w środku + // OutText4=tmp->Mechanik->StopReasonText(); + // if (!OutText4.IsEmpty()) OutText4+="; "; //aby ładniejszy odstęp był + // if (Controlled->Mechanik && (Controlled->Mechanik->AIControllFlag==AIdriver)) + AnsiString flags = "bwaccmlshhhoibsgvdp; "; // flagi AI (definicja w Driver.h) + for (int i = 0, j = 1; i < 19; ++i, j <<= 1) + if (tmp->Mechanik->DrivigFlags() & j) // jak bit ustawiony + flags[i + 1] ^= 0x20; // to zmiana na wielką literę + OutText4 = flags; + OutText4 += + AnsiString("Driver: Vd=") + + FloatToStrF(tmp->Mechanik->VelDesired, ffFixed, 4, 0) + AnsiString(" ad=") + + FloatToStrF(tmp->Mechanik->AccDesired, ffFixed, 5, 2) + AnsiString(" Pd=") + + FloatToStrF(tmp->Mechanik->ActualProximityDist, ffFixed, 4, 0) + + AnsiString(" Vn=") + FloatToStrF(tmp->Mechanik->VelNext, ffFixed, 4, 0); + if (tmp->Mechanik->VelNext == 0.0) + if (tmp->Mechanik->eSignNext) + { // jeśli ma zapamiętany event semafora + // if (!OutText4.IsEmpty()) OutText4+=", "; //aby ładniejszy odstęp był + OutText4 += " (" + + Global::Bezogonkow(tmp->Mechanik->eSignNext->asName) + + ")"; // nazwa eventu semafora + } + } + if (!OutText4.IsEmpty()) + OutText4 += "; "; // aby ładniejszy odstęp był + // informacja o sprzęgach nawet bez mechanika + OutText4 += + "C0=" + (tmp->PrevConnected ? + tmp->PrevConnected->GetName() + ":" + + AnsiString(tmp->MoverParameters->Couplers[0].CouplingFlag) : + AnsiString("NULL")); + OutText4 += + " C1=" + (tmp->NextConnected ? + tmp->NextConnected->GetName() + ":" + + AnsiString(tmp->MoverParameters->Couplers[1].CouplingFlag) : + AnsiString("NULL")); + if (Console::Pressed(VK_F2)) + { + WriteLog(OutText1); + WriteLog(OutText2); + WriteLog(OutText3); + WriteLog(OutText4); + } + } // koniec treści podstawowego ekranu FK_V2 + else + { // ekran drugi, czyli tabelka skanowania AI + if (tmp->Mechanik) //żeby była tabelka, musi być AI + { // tabelka jest na użytek testujących scenerie, więc nie musi być "ładna" + glColor3f(0.0f, 1.0f, 0.0f); // a, damy zielony + // glTranslatef(0.0f,0.0f,-0.50f); + glRasterPos2f(-0.25f, 0.20f); + // OutText1="Scan distance: "+AnsiString(tmp->Mechanik->scanmax)+", back: + // "+AnsiString(tmp->Mechanik->scanback); + OutText1 = "Time: " + AnsiString((int)GlobalTime->hh) + ":"; + int i = GlobalTime->mm; // bo inaczej potrafi zrobić "hh:010" + if (i < 10) + OutText1 += "0"; + OutText1 += AnsiString(i); // minuty + OutText1 += ":"; + i = floor(GlobalTime->mr); // bo inaczej potrafi zrobić "hh:mm:010" + if (i < 10) + OutText1 += "0"; + OutText1 += AnsiString(i); + OutText1 += + AnsiString(". Vel: ") + FloatToStrF(tmp->GetVelocity(), ffFixed, 6, 1); + OutText1 += ". Scan table:"; + glPrint(Global::Bezogonkow(OutText1).c_str()); + i = -1; + while ((OutText1 = tmp->Mechanik->TableText(++i)) != "") + { // wyświetlenie pozycji z tabelki + glRasterPos2f(-0.25f, 0.19f - 0.01f * i); + glPrint(Global::Bezogonkow(OutText1).c_str()); + } + // podsumowanie sensu tabelki + OutText4 = + AnsiString("Driver: Vd=") + + FloatToStrF(tmp->Mechanik->VelDesired, ffFixed, 4, 0) + AnsiString(" ad=") + + FloatToStrF(tmp->Mechanik->AccDesired, ffFixed, 5, 2) + AnsiString(" Pd=") + + FloatToStrF(tmp->Mechanik->ActualProximityDist, ffFixed, 4, 0) + + AnsiString(" Vn=") + FloatToStrF(tmp->Mechanik->VelNext, ffFixed, 4, 0); + if (tmp->Mechanik->VelNext == 0.0) + if (tmp->Mechanik->eSignNext) + { // jeśli ma zapamiętany event semafora + // if (!OutText4.IsEmpty()) OutText4+=", "; //aby ładniejszy odstęp był + OutText4 += " (" + + Global::Bezogonkow(tmp->Mechanik->eSignNext->asName) + + ")"; // nazwa eventu semafora + } + glRasterPos2f(-0.25f, 0.19f - 0.01f * i); + glPrint(Global::Bezogonkow(OutText4).c_str()); + } + } // koniec ekanu skanowania + } // koniec obsługi, gdy mamy wskaźnik do pojazdu + else + { // wyświetlenie współrzędnych w scenerii oraz kąta kamery, gdy nie mamy wskaźnika + OutText1 = "Camera position: " + FloatToStrF(Camera.Pos.x, ffFixed, 6, 2) + " " + + FloatToStrF(Camera.Pos.y, ffFixed, 6, 2) + " " + + FloatToStrF(Camera.Pos.z, ffFixed, 6, 2); + OutText1 += ", azimuth: " + + FloatToStrF(180.0 - RadToDeg(Camera.Yaw), ffFixed, 3, + 0); // ma być azymut, czyli 0 na północy i rośnie na wschód + OutText1 += + " " + + AnsiString("S SEE NEN NWW SW") + .SubString(1 + 2 * floor(fmod(8 + (Camera.Yaw + 0.5 * M_PI_4) / M_PI_4, 8)), 2); } - } - Global::iTextMode=0; //tryb neutralny - } -/* + // OutText3= AnsiString(" Online documentation (PL, ENG, DE, soon CZ): + // http://www.eu07.pl"); + // OutText3="enrot="+FloatToStrF(Controlled->MoverParameters->enrot,ffFixed,6,2); + // OutText3="; n="+FloatToStrF(Controlled->MoverParameters->n,ffFixed,6,2); + } // koniec treści podstawowego ekranu FK_V2 + else if (Global::iTextMode == VK_F5) + { // przesiadka do innego pojazdu + if (FreeFlyModeFlag) // jeśli tryb latania + { + TDynamicObject *tmp = Ground.DynamicNearest(Camera.Pos, 50, true); //łapiemy z obsadą + if (tmp) + if (tmp != Controlled) + { + if (Controlled) // jeśli mielismy pojazd + if (Controlled->Mechanik) // na skutek jakiegoś błędu może czasem zniknąć + Controlled->Mechanik->TakeControl(true); // oddajemy dotychczasowy AI + if (DebugModeFlag ? true : tmp->MoverParameters->Vel <= 5.0) + { + Controlled = tmp; // przejmujemy nowy + mvControlled = Controlled->ControlledFind()->MoverParameters; + if (Train) + Train->Silence(); // wyciszenie dźwięków opuszczanego pojazdu + else + Train = new TTrain(); // jeśli niczym jeszcze nie jeździlismy + if (Train->Init(Controlled)) + { // przejmujemy sterowanie + if (!DebugModeFlag) // w DebugMode nadal prowadzi AI + Controlled->Mechanik->TakeControl(false); + } + else + SafeDelete(Train); // i nie ma czym sterować + // Global::pUserDynamic=Controlled; //renerowanie pojazdu względem kabiny + // Global::iTextMode=VK_F4; + if (Train) + InOutKey(); // do kabiny + } + } + Global::iTextMode = 0; // tryb neutralny + } + /* - OutText1=OutText2=OutText3=OutText4=""; - AnsiString flag[10]={"vmax", "tory", "smfr", "pjzd", "mnwr", "pstk", "brak", "brak", "brak", "brak"}; - if(tmp) - if(tmp->Mechanik) - { - for(int i=0;i<15;i++) - { - int tmppar=floor(tmp->Mechanik->ProximityTable[i].Vel); - OutText2+=(tmppar<1000?(tmppar<100?((tmppar<10)&&(tmppar>=0)?" ":" "):" "):"")+IntToStr(tmppar)+" "; - tmppar=floor(tmp->Mechanik->ProximityTable[i].Dist); - OutText3+=(tmppar<1000?(tmppar<100?((tmppar<10)&&(tmppar>=0)?" ":" "):" "):"")+IntToStr(tmppar)+" "; - OutText1+=flag[tmp->Mechanik->ProximityTable[i].Flag]+" "; - } - for(int i=0;i<6;i++) - { - int tmppar=floor(tmp->Mechanik->ReducedTable[i]); - OutText4+=flag[i]+":"+(tmppar<1000?(tmppar<100?((tmppar<10)&&(tmppar>=0)?" ":" "):" "):"")+IntToStr(tmppar)+" "; - } - } -*/ + OutText1=OutText2=OutText3=OutText4=""; + AnsiString flag[10]={"vmax", "tory", "smfr", "pjzd", "mnwr", "pstk", "brak", "brak", + "brak", "brak"}; + if(tmp) + if(tmp->Mechanik) + { + for(int i=0;i<15;i++) + { + int tmppar=floor(tmp->Mechanik->ProximityTable[i].Vel); + OutText2+=(tmppar<1000?(tmppar<100?((tmppar<10)&&(tmppar>=0)?" ":" "):" + "):"")+IntToStr(tmppar)+" "; + tmppar=floor(tmp->Mechanik->ProximityTable[i].Dist); + OutText3+=(tmppar<1000?(tmppar<100?((tmppar<10)&&(tmppar>=0)?" ":" "):" + "):"")+IntToStr(tmppar)+" "; + OutText1+=flag[tmp->Mechanik->ProximityTable[i].Flag]+" "; + } + for(int i=0;i<6;i++) + { + int tmppar=floor(tmp->Mechanik->ReducedTable[i]); + OutText4+=flag[i]+":"+(tmppar<1000?(tmppar<100?((tmppar<10)&&(tmppar>=0)?" ":" + "):" "):"")+IntToStr(tmppar)+" "; + } + } + */ } - else if (Global::iTextMode==VK_F10) - {//tu mozna dodac dopisywanie do logu przebiegu lokomotywy - //Global::iViewMode=VK_F10; - //return false; - OutText1=AnsiString("To quit press [Y] key."); - OutText3=AnsiString("Aby zakonczyc program, przycisnij klawisz [Y]."); + else if (Global::iTextMode == VK_F10) + { // tu mozna dodac dopisywanie do logu przebiegu lokomotywy + // Global::iViewMode=VK_F10; + // return false; + OutText1 = AnsiString("To quit press [Y] key."); + OutText3 = AnsiString("Aby zakonczyc program, przycisnij klawisz [Y]."); } - else - if (Controlled && DebugModeFlag && !Global::iTextMode) + else if (Controlled && DebugModeFlag && !Global::iTextMode) { - OutText1+=AnsiString("; vel ")+FloatToStrF(Controlled->GetVelocity(),ffFixed,6,2); - OutText1+=AnsiString("; pos ")+FloatToStrF(Controlled->GetPosition().x,ffFixed,6,2); - OutText1+=AnsiString(" ; ")+FloatToStrF(Controlled->GetPosition().y,ffFixed,6,2); - OutText1+=AnsiString(" ; ")+FloatToStrF(Controlled->GetPosition().z,ffFixed,6,2); - OutText1+=AnsiString("; dist=")+FloatToStrF(Controlled->MoverParameters->DistCounter,ffFixed,8,4); + OutText1 += AnsiString("; vel ") + FloatToStrF(Controlled->GetVelocity(), ffFixed, 6, 2); + OutText1 += AnsiString("; pos ") + FloatToStrF(Controlled->GetPosition().x, ffFixed, 6, 2); + OutText1 += AnsiString(" ; ") + FloatToStrF(Controlled->GetPosition().y, ffFixed, 6, 2); + OutText1 += AnsiString(" ; ") + FloatToStrF(Controlled->GetPosition().z, ffFixed, 6, 2); + OutText1 += AnsiString("; dist=") + + FloatToStrF(Controlled->MoverParameters->DistCounter, ffFixed, 8, 4); - //double a= acos( DotProduct(Normalize(Controlled->GetDirection()),vWorldFront)); -// OutText+= AnsiString("; angle ")+FloatToStrF(a/M_PI*180,ffFixed,6,2); - OutText1+=AnsiString("; d_omega ")+FloatToStrF(Controlled->MoverParameters->dizel_engagedeltaomega,ffFixed,6,3); - OutText2 =AnsiString("HamZ=")+FloatToStrF(Controlled->MoverParameters->fBrakeCtrlPos,ffFixed,6,1); - OutText2+=AnsiString("; HamP=")+AnsiString(Controlled->MoverParameters->LocalBrakePos); - //mvControlled->MainCtrlPos; - //if (mvControlled->MainCtrlPos<0) - // OutText2+= AnsiString("; nastawnik 0"); -// if (mvControlled->MainCtrlPos>iPozSzereg) - OutText2+= AnsiString("; NasJ=")+AnsiString(mvControlled->MainCtrlPos); -// else -// OutText2+= AnsiString("; nastawnik S") + mvControlled->MainCtrlPos; - OutText2+=AnsiString("(")+AnsiString(mvControlled->MainCtrlActualPos); + // double a= acos( DotProduct(Normalize(Controlled->GetDirection()),vWorldFront)); + // OutText+= AnsiString("; angle ")+FloatToStrF(a/M_PI*180,ffFixed,6,2); + OutText1 += AnsiString("; d_omega ") + + FloatToStrF(Controlled->MoverParameters->dizel_engagedeltaomega, ffFixed, 6, 3); + OutText2 = AnsiString("HamZ=") + + FloatToStrF(Controlled->MoverParameters->fBrakeCtrlPos, ffFixed, 6, 1); + OutText2 += AnsiString("; HamP=") + AnsiString(Controlled->MoverParameters->LocalBrakePos); + // mvControlled->MainCtrlPos; + // if (mvControlled->MainCtrlPos<0) + // OutText2+= AnsiString("; nastawnik 0"); + // if (mvControlled->MainCtrlPos>iPozSzereg) + OutText2 += AnsiString("; NasJ=") + AnsiString(mvControlled->MainCtrlPos); + // else + // OutText2+= AnsiString("; nastawnik S") + mvControlled->MainCtrlPos; + OutText2 += AnsiString("(") + AnsiString(mvControlled->MainCtrlActualPos); - OutText2+=AnsiString("); NasB=")+AnsiString(mvControlled->ScndCtrlPos); - OutText2+=AnsiString("(")+AnsiString(mvControlled->ScndCtrlActualPos); - if (mvControlled->TrainType==dt_EZT) - OutText2+=AnsiString("); I=")+AnsiString(int(mvControlled->ShowCurrent(0))); - else - OutText2+=AnsiString("); I=")+AnsiString(int(mvControlled->Im)); - //OutText2+=AnsiString("; I2=")+FloatToStrF(Controlled->NextConnected->MoverParameters->Im,ffFixed,6,2); - OutText2+=AnsiString("; U=")+AnsiString(int(mvControlled->RunningTraction.TractionVoltage+0.5)); - //OutText2+=AnsiString("; rvent=")+FloatToStrF(mvControlled->RventRot,ffFixed,6,2); - OutText2+=AnsiString("; R=")+FloatToStrF(Controlled->MoverParameters->RunningShape.R,ffFixed,4,1); - OutText2+=AnsiString(" An=")+FloatToStrF(Controlled->MoverParameters->AccN,ffFixed,4,2); //przyspieszenie poprzeczne - OutText2+=AnsiString("; As=")+FloatToStrF(Controlled->MoverParameters->AccS,ffFixed,4,2); //przyspieszenie wzdłużne - //OutText2+=AnsiString("; P=")+FloatToStrF(mvControlled->EnginePower,ffFixed,6,1); - OutText3+=AnsiString("cyl.ham. ")+FloatToStrF(Controlled->MoverParameters->BrakePress,ffFixed,5,2); - OutText3+=AnsiString("; prz.gl. ")+FloatToStrF(Controlled->MoverParameters->PipePress,ffFixed,5,2); - OutText3+=AnsiString("; zb.gl. ")+FloatToStrF(Controlled->MoverParameters->CompressedVolume,ffFixed,6,2); -//youBy - drugi wezyk - OutText3+=AnsiString("; p.zas. ")+FloatToStrF(Controlled->MoverParameters->ScndPipePress,ffFixed,6,2); - - if(Controlled->MoverParameters->EngineType==ElectricInductionMotor) - { - //glTranslatef(0.0f,0.0f,-0.50f); - glColor3f(1.0f,1.0f,1.0f); //a, damy białym - for(int i=0;i<=20;i++) - { - glRasterPos2f(-0.25f,0.16f-0.01f*i); - if(Controlled->MoverParameters->eimc[i]<10) - OutText4=FloatToStrF(Controlled->MoverParameters->eimc[i],ffFixed,6,3); + OutText2 += AnsiString("); NasB=") + AnsiString(mvControlled->ScndCtrlPos); + OutText2 += AnsiString("(") + AnsiString(mvControlled->ScndCtrlActualPos); + if (mvControlled->TrainType == dt_EZT) + OutText2 += AnsiString("); I=") + AnsiString(int(mvControlled->ShowCurrent(0))); else - OutText4=FloatToStrF(Controlled->MoverParameters->eimc[i],ffGeneral,5,3); - glPrint(OutText4.c_str()); - } - for(int i=0;i<=20;i++) - { - glRasterPos2f(-0.2f,0.16f-0.01f*i); - if(Controlled->MoverParameters->eimv[i]<10) - OutText4=FloatToStrF(Controlled->MoverParameters->eimv[i],ffFixed,6,3); + OutText2 += AnsiString("); I=") + AnsiString(int(mvControlled->Im)); + // OutText2+=AnsiString("; + // I2=")+FloatToStrF(Controlled->NextConnected->MoverParameters->Im,ffFixed,6,2); + OutText2 += AnsiString("; U=") + + AnsiString(int(mvControlled->RunningTraction.TractionVoltage + 0.5)); + // OutText2+=AnsiString("; rvent=")+FloatToStrF(mvControlled->RventRot,ffFixed,6,2); + OutText2 += AnsiString("; R=") + + FloatToStrF(Controlled->MoverParameters->RunningShape.R, ffFixed, 4, 1); + OutText2 += AnsiString(" An=") + FloatToStrF(Controlled->MoverParameters->AccN, ffFixed, 4, + 2); // przyspieszenie poprzeczne + OutText2 += AnsiString("; As=") + FloatToStrF(Controlled->MoverParameters->AccS, ffFixed, 4, + 2); // przyspieszenie wzdłużne + // OutText2+=AnsiString("; P=")+FloatToStrF(mvControlled->EnginePower,ffFixed,6,1); + OutText3 += AnsiString("cyl.ham. ") + + FloatToStrF(Controlled->MoverParameters->BrakePress, ffFixed, 5, 2); + OutText3 += AnsiString("; prz.gl. ") + + FloatToStrF(Controlled->MoverParameters->PipePress, ffFixed, 5, 2); + OutText3 += AnsiString("; zb.gl. ") + + FloatToStrF(Controlled->MoverParameters->CompressedVolume, ffFixed, 6, 2); + // youBy - drugi wezyk + OutText3 += AnsiString("; p.zas. ") + + FloatToStrF(Controlled->MoverParameters->ScndPipePress, ffFixed, 6, 2); + + if (Controlled->MoverParameters->EngineType == ElectricInductionMotor) + { + // glTranslatef(0.0f,0.0f,-0.50f); + glColor3f(1.0f, 1.0f, 1.0f); // a, damy białym + for (int i = 0; i <= 20; i++) + { + glRasterPos2f(-0.25f, 0.16f - 0.01f * i); + if (Controlled->MoverParameters->eimc[i] < 10) + OutText4 = FloatToStrF(Controlled->MoverParameters->eimc[i], ffFixed, 6, 3); + else + OutText4 = FloatToStrF(Controlled->MoverParameters->eimc[i], ffGeneral, 5, 3); + glPrint(OutText4.c_str()); + } + for (int i = 0; i <= 20; i++) + { + glRasterPos2f(-0.2f, 0.16f - 0.01f * i); + if (Controlled->MoverParameters->eimv[i] < 10) + OutText4 = FloatToStrF(Controlled->MoverParameters->eimv[i], ffFixed, 6, 3); + else + OutText4 = FloatToStrF(Controlled->MoverParameters->eimv[i], ffGeneral, 5, 3); + glPrint(OutText4.c_str()); + } + OutText4 = ""; + // glTranslatef(0.0f,0.0f,+0.50f); + glColor3f(1.0f, 0.0f, 0.0f); // a, damy czerwonym + } + + // ABu: testy sprzegow-> (potem przeniesc te zmienne z public do protected!) + // OutText3+=AnsiString("; EnginePwr=")+FloatToStrF(mvControlled->EnginePower,ffFixed,1,5); + // OutText3+=AnsiString("; nn=")+FloatToStrF(Controlled->NextConnectedNo,ffFixed,1,0); + // OutText3+=AnsiString("; PR=")+FloatToStrF(Controlled->dPantAngleR,ffFixed,3,0); + // OutText3+=AnsiString("; PF=")+FloatToStrF(Controlled->dPantAngleF,ffFixed,3,0); + // if(Controlled->bDisplayCab==true) + // OutText3+=AnsiString("; Wysw. kab");//+Controlled->mdKabina->GetSMRoot()->Name; + // else + // OutText3+=AnsiString("; test:")+AnsiString(Controlled->MoverParameters->TrainType[1]); + + // OutText3+=FloatToStrF(Train->Dynamic()->MoverParameters->EndSignalsFlag,ffFixed,3,0);; + + // OutText3+=FloatToStrF(Train->Dynamic()->MoverParameters->EndSignalsFlag&byte(((((1+Train->Dynamic()->MoverParameters->CabNo)/2)*30)+2)),ffFixed,3,0);; + + // OutText3+=AnsiString("; + // Ftmax=")+FloatToStrF(Controlled->MoverParameters->Ftmax,ffFixed,3,0); + // OutText3+=AnsiString("; + // FTotal=")+FloatToStrF(Controlled->MoverParameters->FTotal/1000.0f,ffFixed,3,2); + // OutText3+=AnsiString("; + // FTrain=")+FloatToStrF(Controlled->MoverParameters->FTrain/1000.0f,ffFixed,3,2); + // Controlled->mdModel->GetSMRoot()->SetTranslate(vector3(0,1,0)); + + // McZapkie: warto wiedziec w jakim stanie sa przelaczniki + if (mvControlled->ConvOvldFlag) + OutText3 += " C! "; + else if (mvControlled->FuseFlag) + OutText3 += " F! "; + else if (!mvControlled->Mains) + OutText3 += " () "; else - OutText4=FloatToStrF(Controlled->MoverParameters->eimv[i],ffGeneral,5,3); - glPrint(OutText4.c_str()); - } - OutText4=""; - //glTranslatef(0.0f,0.0f,+0.50f); - glColor3f(1.0f,0.0f,0.0f); //a, damy czerwonym - } - - - //ABu: testy sprzegow-> (potem przeniesc te zmienne z public do protected!) - //OutText3+=AnsiString("; EnginePwr=")+FloatToStrF(mvControlled->EnginePower,ffFixed,1,5); - //OutText3+=AnsiString("; nn=")+FloatToStrF(Controlled->NextConnectedNo,ffFixed,1,0); - //OutText3+=AnsiString("; PR=")+FloatToStrF(Controlled->dPantAngleR,ffFixed,3,0); - //OutText3+=AnsiString("; PF=")+FloatToStrF(Controlled->dPantAngleF,ffFixed,3,0); - //if(Controlled->bDisplayCab==true) - //OutText3+=AnsiString("; Wysw. kab");//+Controlled->mdKabina->GetSMRoot()->Name; - //else - //OutText3+=AnsiString("; test:")+AnsiString(Controlled->MoverParameters->TrainType[1]); - - //OutText3+=FloatToStrF(Train->Dynamic()->MoverParameters->EndSignalsFlag,ffFixed,3,0);; - - //OutText3+=FloatToStrF(Train->Dynamic()->MoverParameters->EndSignalsFlag&byte(((((1+Train->Dynamic()->MoverParameters->CabNo)/2)*30)+2)),ffFixed,3,0);; - - //OutText3+=AnsiString("; Ftmax=")+FloatToStrF(Controlled->MoverParameters->Ftmax,ffFixed,3,0); - //OutText3+=AnsiString("; FTotal=")+FloatToStrF(Controlled->MoverParameters->FTotal/1000.0f,ffFixed,3,2); - //OutText3+=AnsiString("; FTrain=")+FloatToStrF(Controlled->MoverParameters->FTrain/1000.0f,ffFixed,3,2); - //Controlled->mdModel->GetSMRoot()->SetTranslate(vector3(0,1,0)); - - //McZapkie: warto wiedziec w jakim stanie sa przelaczniki - if (mvControlled->ConvOvldFlag) - OutText3+=" C! "; - else if (mvControlled->FuseFlag) - OutText3+=" F! "; - else if (!mvControlled->Mains) - OutText3+=" () "; - else - switch (mvControlled->ActiveDir*(mvControlled->Imin==mvControlled->IminLo?1:2)) - { - case 2: {OutText3+=" >> "; break;} - case 1: {OutText3+=" -> "; break;} - case 0: {OutText3+=" -- "; break;} - case -1: {OutText3+=" <- "; break;} - case -2: {OutText3+=" << "; break;} - } - //OutText3+=AnsiString("; dpLocal ")+FloatToStrF(Controlled->MoverParameters->dpLocalValve,ffFixed,10,8); - //OutText3+=AnsiString("; dpMain ")+FloatToStrF(Controlled->MoverParameters->dpMainValve,ffFixed,10,8); - //McZapkie: predkosc szlakowa - if (Controlled->MoverParameters->RunningTrack.Velmax==-1) - {OutText3+=AnsiString(" Vtrack=Vmax");} - else - {OutText3+=AnsiString(" Vtrack ")+FloatToStrF(Controlled->MoverParameters->RunningTrack.Velmax,ffFixed,8,2);} -// WriteLog(Controlled->MoverParameters->TrainType.c_str()); - if ((mvControlled->EnginePowerSource.SourceType==CurrentCollector) || (mvControlled->TrainType==dt_EZT)) - {OutText3+=AnsiString("; pant. ")+FloatToStrF(mvControlled->PantPress,ffFixed,8,2); - OutText3+=(mvControlled->bPantKurek3?"=ZG":"|ZG"); - } - //McZapkie: komenda i jej parametry - if (Controlled->MoverParameters->CommandIn.Command!=AnsiString("")) - OutText4=AnsiString("C:")+AnsiString(Controlled->MoverParameters->CommandIn.Command) - +AnsiString(" V1=")+FloatToStrF(Controlled->MoverParameters->CommandIn.Value1,ffFixed,5,0) - +AnsiString(" V2=")+FloatToStrF(Controlled->MoverParameters->CommandIn.Value2,ffFixed,5,0); - if (Controlled->Mechanik && (Controlled->Mechanik->AIControllFlag==AIdriver)) - OutText4+=AnsiString("AI: Vd=")+FloatToStrF(Controlled->Mechanik->VelDesired,ffFixed,4,0) - +AnsiString(" ad=")+FloatToStrF(Controlled->Mechanik->AccDesired,ffFixed,5,2) - +AnsiString(" Pd=")+FloatToStrF(Controlled->Mechanik->ActualProximityDist,ffFixed,4,0) - +AnsiString(" Vn=")+FloatToStrF(Controlled->Mechanik->VelNext,ffFixed,4,0); - } - -//ABu 150205: prosty help, zeby sie na forum nikt nie pytal, jak ma ruszyc :) - - if (Global::detonatoryOK) - { - //if (Console::Pressed(VK_F9)) ShowHints(); //to nie działa prawidłowo - prosili wyłączyć - if (Global::iTextMode==VK_F9) - {//informacja o wersji, sposobie wyświetlania i błędach OpenGL - //Global::iViewMode=VK_F9; - OutText1=Global::asVersion; //informacja o wersji - OutText2=AnsiString("Rendering mode: ")+(Global::bUseVBO?"VBO":"Display Lists"); - if (Global::iMultiplayer) OutText2+=". Multiplayer is active"; - OutText2+="."; - GLenum err=glGetError(); - if (err!=GL_NO_ERROR) - { - OutText3="OpenGL error "+AnsiString(err)+": "+Global::Bezogonkow(AnsiString((char *)gluErrorString(err))); - } - } - if (Global::iTextMode==VK_F3) - {//wyświetlenie rozkładu jazdy, na razie jakkolwiek - TDynamicObject *tmp=FreeFlyModeFlag?Ground.DynamicNearest(Camera.Pos):Controlled; //w trybie latania lokalizujemy wg mapy - Mtable::TTrainParameters *tt=NULL; - if (tmp) - if (tmp->Mechanik) - {tt=tmp->Mechanik->Timetable(); - if (tt) //musi być rozkład - {//wyświetlanie rozkładu - glColor3f(1.0f,1.0f,1.0f); //a, damy białym - //glTranslatef(0.0f,0.0f,-0.50f); - glRasterPos2f(-0.25f,0.20f); - OutText1=tmp->Mechanik->Relation()+" ("+tmp->Mechanik->Timetable()->TrainName+")"; - glPrint(Global::Bezogonkow(OutText1,true).c_str()); - glRasterPos2f(-0.25f,0.19f); - //glPrint("|============================|=======|=======|=====|"); - //glPrint("| Posterunek | Przyj.| Odjazd| Vmax|"); - //glPrint("|============================|=======|=======|=====|"); - glPrint("|----------------------------|-------|-------|-----|"); - TMTableLine *t; - for (int i=tmp->Mechanik->iStationStart;i<=tt->StationCount;++i) - {//wyświetlenie pozycji z rozkładu - t=tt->TimeTable+i; //linijka rozkładu - OutText1=AnsiString(AnsiString(t->StationName)+" ").SubString(1,26); - OutText2=(t->Ah>=0)?AnsiString(int(100+t->Ah)).SubString(2,2)+":"+AnsiString(int(100+t->Am)).SubString(2,2):AnsiString(" "); - OutText3=(t->Dh>=0)?AnsiString(int(100+t->Dh)).SubString(2,2)+":"+AnsiString(int(100+t->Dm)).SubString(2,2):AnsiString(" "); - OutText4=" "+FloatToStrF(t->vmax,ffFixed,3,0); - OutText4=OutText4.SubString(OutText4.Length()-2,3); //z wyrównaniem do prawej - //if (AnsiString(t->StationWare).Pos("@")) - OutText1="| "+OutText1+" | "+OutText2+" | "+OutText3+" | "+OutText4+" | "+AnsiString(t->StationWare); - glRasterPos2f(-0.25f,0.18f-0.02f*(i-tmp->Mechanik->iStationStart)); - if ((tmp->Mechanik->iStationStartStationIndex)?(iStationIndex):false) - {//czas minął i odjazd był, to nazwa stacji będzie na zielono - glColor3f(0.0f,1.0f,0.0f); //zielone - glRasterPos2f(-0.25f,0.18f-0.02f*(i-tmp->Mechanik->iStationStart)); //dopiero ustawienie pozycji ustala kolor, dziwne... - glPrint(Global::Bezogonkow(OutText1,true).c_str()); - glColor3f(1.0f,1.0f,1.0f); //a reszta białym - } - else //normalne wyświetlanie, bez zmiany kolorów - glPrint(Global::Bezogonkow(OutText1,true).c_str()); - glRasterPos2f(-0.25f,0.17f-0.02f*(i-tmp->Mechanik->iStationStart)); - glPrint("|----------------------------|-------|-------|-----|"); - } - } + switch (mvControlled->ActiveDir * (mvControlled->Imin == mvControlled->IminLo ? 1 : 2)) + { + case 2: + { + OutText3 += " >> "; + break; + } + case 1: + { + OutText3 += " -> "; + break; + } + case 0: + { + OutText3 += " -- "; + break; + } + case -1: + { + OutText3 += " <- "; + break; + } + case -2: + { + OutText3 += " << "; + break; + } + } + // OutText3+=AnsiString("; dpLocal + // ")+FloatToStrF(Controlled->MoverParameters->dpLocalValve,ffFixed,10,8); + // OutText3+=AnsiString("; dpMain + // ")+FloatToStrF(Controlled->MoverParameters->dpMainValve,ffFixed,10,8); + // McZapkie: predkosc szlakowa + if (Controlled->MoverParameters->RunningTrack.Velmax == -1) + { + OutText3 += AnsiString(" Vtrack=Vmax"); + } + else + { + OutText3 += + AnsiString(" Vtrack ") + + FloatToStrF(Controlled->MoverParameters->RunningTrack.Velmax, ffFixed, 8, 2); + } + // WriteLog(Controlled->MoverParameters->TrainType.c_str()); + if ((mvControlled->EnginePowerSource.SourceType == CurrentCollector) || + (mvControlled->TrainType == dt_EZT)) + { + OutText3 += + AnsiString("; pant. ") + FloatToStrF(mvControlled->PantPress, ffFixed, 8, 2); + OutText3 += (mvControlled->bPantKurek3 ? "=ZG" : "|ZG"); + } + // McZapkie: komenda i jej parametry + if (Controlled->MoverParameters->CommandIn.Command != AnsiString("")) + OutText4 = AnsiString("C:") + + AnsiString(Controlled->MoverParameters->CommandIn.Command) + + AnsiString(" V1=") + + FloatToStrF(Controlled->MoverParameters->CommandIn.Value1, ffFixed, 5, 0) + + AnsiString(" V2=") + + FloatToStrF(Controlled->MoverParameters->CommandIn.Value2, ffFixed, 5, 0); + if (Controlled->Mechanik && (Controlled->Mechanik->AIControllFlag == AIdriver)) + OutText4 += + AnsiString("AI: Vd=") + + FloatToStrF(Controlled->Mechanik->VelDesired, ffFixed, 4, 0) + AnsiString(" ad=") + + FloatToStrF(Controlled->Mechanik->AccDesired, ffFixed, 5, 2) + AnsiString(" Pd=") + + FloatToStrF(Controlled->Mechanik->ActualProximityDist, ffFixed, 4, 0) + + AnsiString(" Vn=") + FloatToStrF(Controlled->Mechanik->VelNext, ffFixed, 4, 0); } - OutText1=OutText2=OutText3=OutText4=""; - } - else if (OutText1!="") - {//ABu: i od razu czyszczenie tego, co bylo napisane - //glTranslatef(0.0f,0.0f,-0.50f); - glRasterPos2f(-0.25f,0.20f); - glPrint(OutText1.c_str()); - OutText1=""; - if (OutText2!="") - {glRasterPos2f(-0.25f,0.19f); - glPrint(OutText2.c_str()); - OutText2=""; - } - if (OutText3!="") - {glRasterPos2f(-0.25f,0.18f); - glPrint(OutText3.c_str()); - OutText3=""; - if (OutText4!="") - {glRasterPos2f(-0.25f, 0.17f); - glPrint(OutText4.c_str()); - OutText4=""; - } - } - } - //if ((Global::iTextMode!=VK_F3)) - {//stenogramy dźwięków (ukryć, gdy tabelka skanowania lub rozkład?) - glColor3f(1.0f,1.0f,0.0f); //żółte - for (int i=0;i<5;++i) - {//kilka linijek - if (Global::asTranscript[i].IsEmpty()) - break; //dalej nie trzeba - else + + // ABu 150205: prosty help, zeby sie na forum nikt nie pytal, jak ma ruszyc :) + + if (Global::detonatoryOK) { - glRasterPos2f(-0.20f,-0.05f-0.01f*i); - glPrint(Global::Bezogonkow(Global::asTranscript[i]).c_str()); + // if (Console::Pressed(VK_F9)) ShowHints(); //to nie działa prawidłowo - prosili wyłączyć + if (Global::iTextMode == VK_F9) + { // informacja o wersji, sposobie wyświetlania i błędach OpenGL + // Global::iViewMode=VK_F9; + OutText1 = Global::asVersion; // informacja o wersji + OutText2 = AnsiString("Rendering mode: ") + (Global::bUseVBO ? "VBO" : "Display Lists"); + if (Global::iMultiplayer) + OutText2 += ". Multiplayer is active"; + OutText2 += "."; + GLenum err = glGetError(); + if (err != GL_NO_ERROR) + { + OutText3 = "OpenGL error " + AnsiString(err) + ": " + + Global::Bezogonkow(AnsiString((char *)gluErrorString(err))); + } + } + if (Global::iTextMode == VK_F3) + { // wyświetlenie rozkładu jazdy, na razie jakkolwiek + TDynamicObject *tmp = FreeFlyModeFlag ? + Ground.DynamicNearest(Camera.Pos) : + Controlled; // w trybie latania lokalizujemy wg mapy + Mtable::TTrainParameters *tt = NULL; + if (tmp) + if (tmp->Mechanik) + { + tt = tmp->Mechanik->Timetable(); + if (tt) // musi być rozkład + { // wyświetlanie rozkładu + glColor3f(1.0f, 1.0f, 1.0f); // a, damy białym + // glTranslatef(0.0f,0.0f,-0.50f); + glRasterPos2f(-0.25f, 0.20f); + OutText1 = tmp->Mechanik->Relation() + " (" + + tmp->Mechanik->Timetable()->TrainName + ")"; + glPrint(Global::Bezogonkow(OutText1, true).c_str()); + glRasterPos2f(-0.25f, 0.19f); + // glPrint("|============================|=======|=======|=====|"); + // glPrint("| Posterunek | Przyj.| Odjazd| Vmax|"); + // glPrint("|============================|=======|=======|=====|"); + glPrint("|----------------------------|-------|-------|-----|"); + TMTableLine *t; + for (int i = tmp->Mechanik->iStationStart; i <= tt->StationCount; ++i) + { // wyświetlenie pozycji z rozkładu + t = tt->TimeTable + i; // linijka rozkładu + OutText1 = AnsiString(AnsiString(t->StationName) + + " ").SubString(1, 26); + OutText2 = (t->Ah >= 0) ? + AnsiString(int(100 + t->Ah)).SubString(2, 2) + ":" + + AnsiString(int(100 + t->Am)).SubString(2, 2) : + AnsiString(" "); + OutText3 = (t->Dh >= 0) ? + AnsiString(int(100 + t->Dh)).SubString(2, 2) + ":" + + AnsiString(int(100 + t->Dm)).SubString(2, 2) : + AnsiString(" "); + OutText4 = " " + FloatToStrF(t->vmax, ffFixed, 3, 0); + OutText4 = OutText4.SubString(OutText4.Length() - 2, + 3); // z wyrównaniem do prawej + // if (AnsiString(t->StationWare).Pos("@")) + OutText1 = "| " + OutText1 + " | " + OutText2 + " | " + OutText3 + + " | " + OutText4 + " | " + AnsiString(t->StationWare); + glRasterPos2f(-0.25f, + 0.18f - 0.02f * (i - tmp->Mechanik->iStationStart)); + if ((tmp->Mechanik->iStationStart < tt->StationIndex) ? + (i < tt->StationIndex) : + false) + { // czas minął i odjazd był, to nazwa stacji będzie na zielono + glColor3f(0.0f, 1.0f, 0.0f); // zielone + glRasterPos2f( + -0.25f, + 0.18f - + 0.02f * (i - tmp->Mechanik->iStationStart)); // dopiero + // ustawienie + // pozycji + // ustala + // kolor, + // dziwne... + glPrint(Global::Bezogonkow(OutText1, true).c_str()); + glColor3f(1.0f, 1.0f, 1.0f); // a reszta białym + } + else // normalne wyświetlanie, bez zmiany kolorów + glPrint(Global::Bezogonkow(OutText1, true).c_str()); + glRasterPos2f(-0.25f, + 0.17f - 0.02f * (i - tmp->Mechanik->iStationStart)); + glPrint("|----------------------------|-------|-------|-----|"); + } + } + } + OutText1 = OutText2 = OutText3 = OutText4 = ""; + } + else if (OutText1 != "") + { // ABu: i od razu czyszczenie tego, co bylo napisane + // glTranslatef(0.0f,0.0f,-0.50f); + glRasterPos2f(-0.25f, 0.20f); + glPrint(OutText1.c_str()); + OutText1 = ""; + if (OutText2 != "") + { + glRasterPos2f(-0.25f, 0.19f); + glPrint(OutText2.c_str()); + OutText2 = ""; + } + if (OutText3 != "") + { + glRasterPos2f(-0.25f, 0.18f); + glPrint(OutText3.c_str()); + OutText3 = ""; + if (OutText4 != "") + { + glRasterPos2f(-0.25f, 0.17f); + glPrint(OutText4.c_str()); + OutText4 = ""; + } + } + } + // if ((Global::iTextMode!=VK_F3)) + { // stenogramy dźwięków (ukryć, gdy tabelka skanowania lub rozkład?) + glColor3f(1.0f, 1.0f, 0.0f); //żółte + for (int i = 0; i < 5; ++i) + { // kilka linijek + if (Global::asTranscript[i].IsEmpty()) + break; // dalej nie trzeba + else + { + glRasterPos2f(-0.20f, -0.05f - 0.01f * i); + glPrint(Global::Bezogonkow(Global::asTranscript[i]).c_str()); + } + } + } } - } - } - } - //if (Global::iViewMode!=Global::iTextMode) - //{//Ra: taka maksymalna prowizorka na razie - // WriteLog("Pressed function key F"+AnsiString(Global::iViewMode-111)); - // Global::iTextMode=Global::iViewMode; - //} - glEnable(GL_LIGHTING); - return (true); + // if (Global::iViewMode!=Global::iTextMode) + //{//Ra: taka maksymalna prowizorka na razie + // WriteLog("Pressed function key F"+AnsiString(Global::iViewMode-111)); + // Global::iTextMode=Global::iViewMode; + //} + glEnable(GL_LIGHTING); + return (true); }; bool __fastcall TWorld::Render() { - glColor3b(255, 255, 255); - //glColor3b(255, 0, 255); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix - glLoadIdentity(); - Camera.SetMatrix(); //ustawienie macierzy kamery względem początku scenerii - glLightfv(GL_LIGHT0,GL_POSITION,Global::lightPos); + glColor3b(255, 255, 255); + // glColor3b(255, 0, 255); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + glLoadIdentity(); + Camera.SetMatrix(); // ustawienie macierzy kamery względem początku scenerii + glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos); - if (!Global::bWireFrame) - {//bez nieba w trybie rysowania linii - glDisable(GL_FOG); - Clouds.Render(); - glEnable(GL_FOG); - } - if (Global::bUseVBO) - {//renderowanie przez VBO - if (!Ground.RenderVBO(Camera.Pos)) return false; - if (!Ground.RenderAlphaVBO(Camera.Pos)) - return false; - } - else - {//renderowanie przez Display List - if (!Ground.RenderDL(Camera.Pos)) return false; - if (!Ground.RenderAlphaDL(Camera.Pos)) - return false; - } - TSubModel::iInstance=(int)(Train?Train->Dynamic():0); //żeby nie robić cudzych animacji - //if (Camera.Type==tp_Follow) - if (Train) Train->Update(); - //if (Global::bRenderAlpha) - // if (Controlled) - // Train->RenderAlpha(); - glFlush(); - //Global::bReCompile=false; //Ra: już zrobiona rekompilacja - ResourceManager::Sweep(Timer::GetSimulationTime()); - return true; + if (!Global::bWireFrame) + { // bez nieba w trybie rysowania linii + glDisable(GL_FOG); + Clouds.Render(); + glEnable(GL_FOG); + } + if (Global::bUseVBO) + { // renderowanie przez VBO + if (!Ground.RenderVBO(Camera.Pos)) + return false; + if (!Ground.RenderAlphaVBO(Camera.Pos)) + return false; + } + else + { // renderowanie przez Display List + if (!Ground.RenderDL(Camera.Pos)) + return false; + if (!Ground.RenderAlphaDL(Camera.Pos)) + return false; + } + TSubModel::iInstance = (int)(Train ? Train->Dynamic() : 0); //żeby nie robić cudzych animacji + // if (Camera.Type==tp_Follow) + if (Train) + Train->Update(); + // if (Global::bRenderAlpha) + // if (Controlled) + // Train->RenderAlpha(); + glFlush(); + // Global::bReCompile=false; //Ra: już zrobiona rekompilacja + ResourceManager::Sweep(Timer::GetSimulationTime()); + return true; }; void TWorld::ShowHints(void) -{//Ra: nie używać tego, bo źle działa - glBindTexture(GL_TEXTURE_2D, 0); - glColor4f(0.3f,1.0f,0.3f,1.0f); - glLoadIdentity(); - glTranslatef(0.0f,0.0f,-0.50f); - //glRasterPos2f(-0.25f, 0.20f); - //OutText1="Uruchamianie lokomotywy - pomoc dla niezaawansowanych"; - //glPrint(OutText1.c_str()); +{ // Ra: nie używać tego, bo źle działa + glBindTexture(GL_TEXTURE_2D, 0); + glColor4f(0.3f, 1.0f, 0.3f, 1.0f); + glLoadIdentity(); + glTranslatef(0.0f, 0.0f, -0.50f); + // glRasterPos2f(-0.25f, 0.20f); + // OutText1="Uruchamianie lokomotywy - pomoc dla niezaawansowanych"; + // glPrint(OutText1.c_str()); - //if(TestFlag(Controlled->MoverParameters->SecuritySystem.Status,s_ebrake)) - //hunter-091012 - if(TestFlag(Controlled->MoverParameters->SecuritySystem.Status,s_SHPebrake)||TestFlag(Controlled->MoverParameters->SecuritySystem.Status,s_CAebrake)) - { - OutText1="Gosciu, ale refleks to ty masz szachisty. Teraz zaczekaj."; - OutText2="W tej sytuacji czuwak mozesz zbic dopiero po zatrzymaniu pociagu. "; - if(Controlled->MoverParameters->Vel==0) - OutText3=" (mozesz juz nacisnac spacje)"; - } - else - //if(TestFlag(Controlled->MoverParameters->SecuritySystem.Status,s_alarm)) - if(TestFlag(Controlled->MoverParameters->SecuritySystem.Status,s_CAalarm)||TestFlag(Controlled->MoverParameters->SecuritySystem.Status,s_SHPalarm)) - { - OutText1="Natychmiast zbij czuwak, bo pociag sie zatrzyma!"; - OutText2=" (szybko nacisnij spacje!)"; - } - else - if(TestFlag(Controlled->MoverParameters->SecuritySystem.Status,s_aware)) - { - OutText1="Zbij czuwak, zeby udowodnic, ze nie spisz :) "; - OutText2=" (nacisnij spacje)"; - } - else - if (mvControlled->FuseFlag) - { - OutText1="Czlowieku, delikatniej troche! Gdzie sie spieszysz?"; - OutText2="Wybilo Ci bezpiecznik nadmiarowy, teraz musisz wlaczyc go ponownie."; - OutText3=" ('N', wczesniej nastawnik i boczniki na zero -> '-' oraz '*' do oporu)"; + // if(TestFlag(Controlled->MoverParameters->SecuritySystem.Status,s_ebrake)) + // hunter-091012 + if (TestFlag(Controlled->MoverParameters->SecuritySystem.Status, s_SHPebrake) || + TestFlag(Controlled->MoverParameters->SecuritySystem.Status, s_CAebrake)) + { + OutText1 = "Gosciu, ale refleks to ty masz szachisty. Teraz zaczekaj."; + OutText2 = "W tej sytuacji czuwak mozesz zbic dopiero po zatrzymaniu pociagu. "; + if (Controlled->MoverParameters->Vel == 0) + OutText3 = " (mozesz juz nacisnac spacje)"; + } + else + // if(TestFlag(Controlled->MoverParameters->SecuritySystem.Status,s_alarm)) + if (TestFlag(Controlled->MoverParameters->SecuritySystem.Status, s_CAalarm) || + TestFlag(Controlled->MoverParameters->SecuritySystem.Status, s_SHPalarm)) + { + OutText1 = "Natychmiast zbij czuwak, bo pociag sie zatrzyma!"; + OutText2 = " (szybko nacisnij spacje!)"; + } + else if (TestFlag(Controlled->MoverParameters->SecuritySystem.Status, s_aware)) + { + OutText1 = "Zbij czuwak, zeby udowodnic, ze nie spisz :) "; + OutText2 = " (nacisnij spacje)"; + } + else if (mvControlled->FuseFlag) + { + OutText1 = "Czlowieku, delikatniej troche! Gdzie sie spieszysz?"; + OutText2 = "Wybilo Ci bezpiecznik nadmiarowy, teraz musisz wlaczyc go ponownie."; + OutText3 = " ('N', wczesniej nastawnik i boczniki na zero -> '-' oraz '*' do oporu)"; + } + else if (mvControlled->V == 0) + { + if ((mvControlled->PantFrontVolt == 0.0) || (mvControlled->PantRearVolt == 0.0)) + { + OutText1 = "Jezdziles juz kiedys lokomotywa? Pierwszy raz? Dobra, to zaczynamy."; + OutText2 = "No to co, trzebaby chyba podniesc pantograf?"; + OutText3 = " (wcisnij 'shift+P' - przedni, 'shift+O' - tylny)"; + } + else if (!mvControlled->Mains) + { + OutText1 = "Dobra, mozemy zalaczyc wylacznik szybki lokomotywy."; + OutText2 = " (wcisnij 'shift+M')"; + } + else if (!mvControlled->ConverterAllow) + { + OutText1 = "Teraz wlacz przetwornice."; + OutText2 = " (wcisnij 'shift+X')"; + } + else if (!mvControlled->CompressorAllow) + { + OutText1 = "Teraz wlacz sprezarke."; + OutText2 = " (wcisnij 'shift+C')"; + } + else if (mvControlled->ActiveDir == 0) + { + OutText1 = "Ustaw nastawnik kierunkowy na kierunek, w ktorym chcesz jechac."; + OutText2 = " ('d' - do przodu, 'r' - do tylu)"; + } + else if (Controlled->GetFirstDynamic(1)->MoverParameters->BrakePress > 0) + { + OutText1 = "Odhamuj sklad i zaczekaj az Ci powiem - to moze troche potrwac."; + OutText2 = " ('.' na klawiaturze numerycznej)"; + } + else if (Controlled->MoverParameters->BrakeCtrlPos != 0) + { + OutText1 = "Przelacz kran hamulca w pozycje 'jazda'."; + OutText2 = " ('4' na klawiaturze numerycznej)"; + } + else if (mvControlled->MainCtrlPos == 0) + { + OutText1 = "Teraz juz mozesz ruszyc ustawiajac pierwsza pozycje na nastawniku jazdy."; + OutText2 = " (jeden raz '+' na klawiaturze numerycznej)"; + } + else if ((mvControlled->MainCtrlPos > 0) && (mvControlled->ShowCurrent(1) != 0)) + { + OutText1 = "Dobrze, mozesz teraz wlaczac kolejne pozycje nastawnika."; + OutText2 = " ('+' na klawiaturze numerycznej, tylko z wyczuciem)"; + } + if ((mvControlled->MainCtrlPos > 1) && (mvControlled->ShowCurrent(1) == 0)) + { + OutText1 = "Spieszysz sie gdzies? Zejdz nastawnikiem na zero i probuj jeszcze raz!"; + OutText2 = " (teraz do oporu '-' na klawiaturze numerycznej)"; + } + } + else + { + OutText1 = "Aby przyspieszyc mozesz wrzucac kolejne pozycje nastawnika."; + if (mvControlled->MainCtrlPos == 28) + { + OutText1 = "Przy tym ustawienu mozesz bocznikowac silniki - sprobuj: '/' i '*' "; + } + if (mvControlled->MainCtrlPos == 43) + { + OutText1 = "Przy tym ustawienu mozesz bocznikowac silniki - sprobuj: '/' i '*' "; + } - } - else - if (mvControlled->V==0) - { - if ((mvControlled->PantFrontVolt==0.0)||(mvControlled->PantRearVolt==0.0)) - { - OutText1="Jezdziles juz kiedys lokomotywa? Pierwszy raz? Dobra, to zaczynamy."; - OutText2="No to co, trzebaby chyba podniesc pantograf?"; - OutText3=" (wcisnij 'shift+P' - przedni, 'shift+O' - tylny)"; - } - else - if (!mvControlled->Mains) - { - OutText1="Dobra, mozemy zalaczyc wylacznik szybki lokomotywy."; - OutText2=" (wcisnij 'shift+M')"; - } - else - if (!mvControlled->ConverterAllow) - { - OutText1="Teraz wlacz przetwornice."; - OutText2=" (wcisnij 'shift+X')"; - } - else - if (!mvControlled->CompressorAllow) - { - OutText1="Teraz wlacz sprezarke."; - OutText2=" (wcisnij 'shift+C')"; - } - else - if (mvControlled->ActiveDir==0) - { - OutText1="Ustaw nastawnik kierunkowy na kierunek, w ktorym chcesz jechac."; - OutText2=" ('d' - do przodu, 'r' - do tylu)"; - } - else - if (Controlled->GetFirstDynamic(1)->MoverParameters->BrakePress>0) - { - OutText1="Odhamuj sklad i zaczekaj az Ci powiem - to moze troche potrwac."; - OutText2=" ('.' na klawiaturze numerycznej)"; - } - else - if (Controlled->MoverParameters->BrakeCtrlPos!=0) - { - OutText1="Przelacz kran hamulca w pozycje 'jazda'."; - OutText2=" ('4' na klawiaturze numerycznej)"; - } - else - if (mvControlled->MainCtrlPos==0) - { - OutText1="Teraz juz mozesz ruszyc ustawiajac pierwsza pozycje na nastawniku jazdy."; - OutText2=" (jeden raz '+' na klawiaturze numerycznej)"; - } - else - if((mvControlled->MainCtrlPos>0)&&(mvControlled->ShowCurrent(1)!=0)) - { - OutText1="Dobrze, mozesz teraz wlaczac kolejne pozycje nastawnika."; - OutText2=" ('+' na klawiaturze numerycznej, tylko z wyczuciem)"; - } - if((mvControlled->MainCtrlPos>1)&&(mvControlled->ShowCurrent(1)==0)) - { - OutText1="Spieszysz sie gdzies? Zejdz nastawnikiem na zero i probuj jeszcze raz!"; - OutText2=" (teraz do oporu '-' na klawiaturze numerycznej)"; - } - } - else - { - OutText1="Aby przyspieszyc mozesz wrzucac kolejne pozycje nastawnika."; - if(mvControlled->MainCtrlPos==28) - {OutText1="Przy tym ustawienu mozesz bocznikowac silniki - sprobuj: '/' i '*' ";} - if(mvControlled->MainCtrlPos==43) - {OutText1="Przy tym ustawienu mozesz bocznikowac silniki - sprobuj: '/' i '*' ";} + OutText2 = "Aby zahamowac zejdz nastawnikiem do 0 ('-' do oporu) i ustaw kran hamulca"; + OutText3 = + "w zaleznosci od sily hamowania, jakiej potrzebujesz ('2', '5' lub '8' na kl. num.)"; - OutText2="Aby zahamowac zejdz nastawnikiem do 0 ('-' do oporu) i ustaw kran hamulca"; - OutText3="w zaleznosci od sily hamowania, jakiej potrzebujesz ('2', '5' lub '8' na kl. num.)"; + // else + // if() OutText1="teraz mozesz ruszyc naciskajac jeden raz '+' na klawiaturze numerycznej"; + // else + // if() OutText1="teraz mozesz ruszyc naciskajac jeden raz '+' na klawiaturze numerycznej"; + } + // OutText3=FloatToStrF(Controlled->MoverParameters->SecuritySystem.Status,ffFixed,3,0); - //else - //if() OutText1="teraz mozesz ruszyc naciskajac jeden raz '+' na klawiaturze numerycznej"; - //else - //if() OutText1="teraz mozesz ruszyc naciskajac jeden raz '+' na klawiaturze numerycznej"; - } - //OutText3=FloatToStrF(Controlled->MoverParameters->SecuritySystem.Status,ffFixed,3,0); - - if(OutText1!="") - { - glRasterPos2f(-0.25f, 0.19f); - glPrint(OutText1.c_str()); - OutText1=""; - } - if(OutText2!="") - { - glRasterPos2f(-0.25f, 0.18f); - glPrint(OutText2.c_str()); - OutText2=""; - } - if(OutText3!="") - { - glRasterPos2f(-0.25f, 0.17f); - glPrint(OutText3.c_str()); - OutText3=""; - } + if (OutText1 != "") + { + glRasterPos2f(-0.25f, 0.19f); + glPrint(OutText1.c_str()); + OutText1 = ""; + } + if (OutText2 != "") + { + glRasterPos2f(-0.25f, 0.18f); + glPrint(OutText2.c_str()); + OutText2 = ""; + } + if (OutText3 != "") + { + glRasterPos2f(-0.25f, 0.17f); + glPrint(OutText3.c_str()); + OutText3 = ""; + } }; //--------------------------------------------------------------------------- void __fastcall TWorld::OnCommandGet(DaneRozkaz *pRozkaz) -{//odebranie komunikatu z serwera - if (pRozkaz->iSygn=='EU07') - switch (pRozkaz->iComm) - { - case 0: //odesłanie identyfikatora wersji - Ground.WyslijString(Global::asVersion,0); //przedsatwienie się - break; - case 1: //odesłanie identyfikatora wersji - Ground.WyslijString(Global::szSceneryFile,1); //nazwa scenerii - break; - case 2: //event - if (Global::iMultiplayer) - {//WriteLog("Komunikat: "+AnsiString(pRozkaz->Name1)); - TEvent *e=Ground.FindEvent(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); - if (e) - if ((e->Type==tp_Multiple)||(e->Type==tp_Lights)||bool(e->evJoined)) //tylko jawne albo niejawne Multiple - Ground.AddToQuery(e,NULL); //drugi parametr to dynamic wywołujący - tu brak - } - break; - case 3: //rozkaz dla AI - if (Global::iMultiplayer) - {int i=int(pRozkaz->cString[8]); //długość pierwszego łańcucha (z przodu dwa floaty) - TGroundNode* t=Ground.DynamicFind(AnsiString(pRozkaz->cString+11+i,(unsigned)pRozkaz->cString[10+i])); //nazwa pojazdu jest druga - if (t) - if (t->DynamicObject->Mechanik) - { - t->DynamicObject->Mechanik->PutCommand(AnsiString(pRozkaz->cString+9,i),pRozkaz->fPar[0],pRozkaz->fPar[1],NULL,stopExt); //floaty są z przodu - WriteLog("AI command: "+AnsiString(pRozkaz->cString+9,i)); - } - } - break; - case 4: //badanie zajętości toru - { - TGroundNode* t=Ground.FindGroundNode(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0])),TP_TRACK); - if (t) - if (t->pTrack->IsEmpty()) - Ground.WyslijWolny(t->asName); - } - break; - case 5: //ustawienie parametrów - { - if (*pRozkaz->iPar&1) //ustawienie czasu - {double t=pRozkaz->fPar[1]; - GlobalTime->dd=floor(t); //niby nie powinno być dnia, ale... - if (Global::fMoveLight>=0) - Global::fMoveLight=t; //trzeba by deklinację Słońca przeliczyć - GlobalTime->hh=floor(24*t)-24.0*GlobalTime->dd; - GlobalTime->mm=floor(60*24*t)-60.0*(24.0*GlobalTime->dd+GlobalTime->hh); - GlobalTime->mr=floor(60*60*24*t)-60.0*(60.0*(24.0*GlobalTime->dd+GlobalTime->hh)+GlobalTime->mm); - } - if (*pRozkaz->iPar&2) - {//ustawienie flag zapauzowania - Global::iPause=pRozkaz->fPar[2]; //zakładamy, że wysyłający wie, co robi - } - } - break; - case 6: //pobranie parametrów ruchu pojazdu - if (Global::iMultiplayer) - {//Ra 2014-12: to ma działać również dla pojazdów bez obsady - if (pRozkaz->cString[0]) //jeśli długość nazwy jest niezerowa - {//szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7 - TGroundNode *t; - if (pRozkaz->cString[1]=='*') - t=Ground.DynamicFind(Global::asHumanCtrlVehicle); //nazwa pojazdu użytkownika - else - t=Ground.DynamicFindAny(AnsiString(pRozkaz->cString+1,(unsigned)pRozkaz->cString[0])); //nazwa pojazdu - if (t) - Ground.WyslijNamiary(t); //wysłanie informacji o pojeździe - } - else - {//dla pustego wysyłamy ramki 6 z nazwami pojazdów AI (jeśli potrzebne wszystkie, to rozpoznać np. "*") - Ground.DynamicList(); - } - } - break; - case 8: //ponowne wysłanie informacji o zajętych odcinkach toru - Ground.TrackBusyList(); - break; - case 9: //ponowne wysłanie informacji o zajętych odcinkach izolowanych - Ground.IsolatedBusyList(); - break; - case 10: //badanie zajętości jednego odcinka izolowanego - Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); - break; - case 11: //ustawienie paerametrów ruchu pojazdu -// Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); - break; - - } +{ // odebranie komunikatu z serwera + if (pRozkaz->iSygn == 'EU07') + switch (pRozkaz->iComm) + { + case 0: // odesłanie identyfikatora wersji + Ground.WyslijString(Global::asVersion, 0); // przedsatwienie się + break; + case 1: // odesłanie identyfikatora wersji + Ground.WyslijString(Global::szSceneryFile, 1); // nazwa scenerii + break; + case 2: // event + if (Global::iMultiplayer) + { // WriteLog("Komunikat: "+AnsiString(pRozkaz->Name1)); + TEvent *e = Ground.FindEvent( + AnsiString(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0]))); + if (e) + if ((e->Type == tp_Multiple) || (e->Type == tp_Lights) || + bool(e->evJoined)) // tylko jawne albo niejawne Multiple + Ground.AddToQuery(e, NULL); // drugi parametr to dynamic wywołujący - tu + // brak + } + break; + case 3: // rozkaz dla AI + if (Global::iMultiplayer) + { + int i = + int(pRozkaz->cString[8]); // długość pierwszego łańcucha (z przodu dwa floaty) + TGroundNode *t = Ground.DynamicFind( + AnsiString(pRozkaz->cString + 11 + i, + (unsigned)pRozkaz->cString[10 + i])); // nazwa pojazdu jest druga + if (t) + if (t->DynamicObject->Mechanik) + { + t->DynamicObject->Mechanik->PutCommand(AnsiString(pRozkaz->cString + 9, i), + pRozkaz->fPar[0], pRozkaz->fPar[1], + NULL, stopExt); // floaty są z przodu + WriteLog("AI command: " + AnsiString(pRozkaz->cString + 9, i)); + } + } + break; + case 4: // badanie zajętości toru + { + TGroundNode *t = Ground.FindGroundNode( + AnsiString(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])), TP_TRACK); + if (t) + if (t->pTrack->IsEmpty()) + Ground.WyslijWolny(t->asName); + } + break; + case 5: // ustawienie parametrów + { + if (*pRozkaz->iPar & 1) // ustawienie czasu + { + double t = pRozkaz->fPar[1]; + GlobalTime->dd = floor(t); // niby nie powinno być dnia, ale... + if (Global::fMoveLight >= 0) + Global::fMoveLight = t; // trzeba by deklinację Słońca przeliczyć + GlobalTime->hh = floor(24 * t) - 24.0 * GlobalTime->dd; + GlobalTime->mm = + floor(60 * 24 * t) - 60.0 * (24.0 * GlobalTime->dd + GlobalTime->hh); + GlobalTime->mr = + floor(60 * 60 * 24 * t) - + 60.0 * (60.0 * (24.0 * GlobalTime->dd + GlobalTime->hh) + GlobalTime->mm); + } + if (*pRozkaz->iPar & 2) + { // ustawienie flag zapauzowania + Global::iPause = pRozkaz->fPar[2]; // zakładamy, że wysyłający wie, co robi + } + } + break; + case 6: // pobranie parametrów ruchu pojazdu + if (Global::iMultiplayer) + { // Ra 2014-12: to ma działać również dla pojazdów bez obsady + if (pRozkaz->cString[0]) // jeśli długość nazwy jest niezerowa + { // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7 + TGroundNode *t; + if (pRozkaz->cString[1] == '*') + t = Ground.DynamicFind( + Global::asHumanCtrlVehicle); // nazwa pojazdu użytkownika + else + t = Ground.DynamicFindAny(AnsiString( + pRozkaz->cString + 1, (unsigned)pRozkaz->cString[0])); // nazwa pojazdu + if (t) + Ground.WyslijNamiary(t); // wysłanie informacji o pojeździe + } + else + { // dla pustego wysyłamy ramki 6 z nazwami pojazdów AI (jeśli potrzebne wszystkie, + // to rozpoznać np. "*") + Ground.DynamicList(); + } + } + break; + case 8: // ponowne wysłanie informacji o zajętych odcinkach toru + Ground.TrackBusyList(); + break; + case 9: // ponowne wysłanie informacji o zajętych odcinkach izolowanych + Ground.IsolatedBusyList(); + break; + case 10: // badanie zajętości jednego odcinka izolowanego + Ground.IsolatedBusy(AnsiString(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0]))); + break; + case 11: // ustawienie paerametrów ruchu pojazdu + // Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); + break; + } }; //--------------------------------------------------------------------------- void __fastcall TWorld::ModifyTGA(const AnsiString &dir) -{//rekurencyjna modyfikacje plików TGA - TSearchRec sr; - if (FindFirst(dir+"*.*",faDirectory|faArchive,sr)==0) - {do - { - if (sr.Name[1]!='.') - if ((sr.Attr&faDirectory)) //jeśli katalog, to rekurencja - ModifyTGA(dir+sr.Name+"/"); - else - if (sr.Name.LowerCase().SubString(sr.Name.Length()-3,4)==".tga") - TTexturesManager::GetTextureID(NULL,NULL,AnsiString(dir+sr.Name).c_str()); - } while (FindNext(sr)==0); - FindClose(sr); - } +{ // rekurencyjna modyfikacje plików TGA + TSearchRec sr; + if (FindFirst(dir + "*.*", faDirectory | faArchive, sr) == 0) + { + do + { + if (sr.Name[1] != '.') + if ((sr.Attr & faDirectory)) // jeśli katalog, to rekurencja + ModifyTGA(dir + sr.Name + "/"); + else if (sr.Name.LowerCase().SubString(sr.Name.Length() - 3, 4) == ".tga") + TTexturesManager::GetTextureID(NULL, NULL, AnsiString(dir + sr.Name).c_str()); + } while (FindNext(sr) == 0); + FindClose(sr); + } }; //--------------------------------------------------------------------------- -AnsiString last; //zmienne używane w rekurencji -double shift=0; -void __fastcall TWorld::CreateE3D(const AnsiString &dir,bool dyn) -{//rekurencyjna generowanie plików E3D - TTrack *trk; - double at; - TSearchRec sr; - if (FindFirst(dir+"*.*",faDirectory|faArchive,sr)==0) - {do - { - if (sr.Name[1]!='.') - if ((sr.Attr&faDirectory)) //jeśli katalog, to rekurencja - CreateE3D(dir+sr.Name+"\\",dyn); - else - if (dyn) - { - if (sr.Name.LowerCase().SubString(sr.Name.Length()-3,4)==".mmd") - { - //konwersja pojazdów będzie ułomna, bo nie poustawiają się animacje na submodelach określonych w MMD - //TModelsManager::GetModel(AnsiString(dir+sr.Name).c_str(),true); - if (last!=dir) - {//utworzenie toru dla danego pojazdu - last=dir; - trk=TTrack::Create400m(1,shift); - shift+=10.0; //następny tor będzie deczko dalej, aby nie zabić FPS - at=400.0; - //if (shift>1000) break; //bezpiecznik - } - TGroundNode *tmp=new TGroundNode(); - tmp->DynamicObject=new TDynamicObject(); - //Global::asCurrentTexturePath=dir; //pojazdy mają tekstury we własnych katalogach - at-=tmp->DynamicObject->Init("",dir.SubString(9,dir.Length()-9),"none",sr.Name.SubString(1,sr.Name.Length()-4),trk,at,"nobody",0.0,"none",0.0,"",false,""); - //po wczytaniu CHK zrobić pętlę po ładunkach, aby każdy z nich skonwertować - AnsiString loads,load; - loads=tmp->DynamicObject->MoverParameters->LoadAccepted; //typy ładunków - if (!loads.IsEmpty()) - {loads+=","; //przecinek na końcu - int i=loads.Pos(","); - while (i>1) - {//wypadało by sprawdzić, czy T3D ładunku jest - load=loads.SubString(1,i-1); - if (FileExists(dir+load+".t3d")) //o ile jest plik ładunku, bo inaczej nie ma to sensu - if (!FileExists(dir+load+".e3d")) //a nie ma jeszcze odpowiednika binarnego - at-=tmp->DynamicObject->Init("",dir.SubString(9,dir.Length()-9),"none",sr.Name.SubString(1,sr.Name.Length()-4),trk,at,"nobody",0.0,"none",1.0,load,false,""); - loads.Delete(1,i); //usunięcie z następującym przecinkiem - i=loads.Pos(","); - } - } - if (tmp->DynamicObject->iCabs) - {//jeśli ma jakąkolwiek kabinę - delete Train; - Train=new TTrain(); - if (tmp->DynamicObject->iCabs&1) - {tmp->DynamicObject->MoverParameters->ActiveCab=1; - Train->Init(tmp->DynamicObject,true); - } - if (tmp->DynamicObject->iCabs&4) - {tmp->DynamicObject->MoverParameters->ActiveCab=-1; - Train->Init(tmp->DynamicObject,true); - } - if (tmp->DynamicObject->iCabs&2) - {tmp->DynamicObject->MoverParameters->ActiveCab=0; - Train->Init(tmp->DynamicObject,true); - } - } - Global::asCurrentTexturePath=AnsiString(szTexturePath); //z powrotem defaultowa sciezka do tekstur - } - } - else if (sr.Name.LowerCase().SubString(sr.Name.Length()-3,4)==".t3d") - {//z modelami jest prościej - Global::asCurrentTexturePath=dir; - TModelsManager::GetModel(AnsiString(dir+sr.Name).c_str(),false); - } - } while (FindNext(sr)==0); - FindClose(sr); - } +AnsiString last; // zmienne używane w rekurencji +double shift = 0; +void __fastcall TWorld::CreateE3D(const AnsiString &dir, bool dyn) +{ // rekurencyjna generowanie plików E3D + TTrack *trk; + double at; + TSearchRec sr; + if (FindFirst(dir + "*.*", faDirectory | faArchive, sr) == 0) + { + do + { + if (sr.Name[1] != '.') + if ((sr.Attr & faDirectory)) // jeśli katalog, to rekurencja + CreateE3D(dir + sr.Name + "\\", dyn); + else if (dyn) + { + if (sr.Name.LowerCase().SubString(sr.Name.Length() - 3, 4) == ".mmd") + { + // konwersja pojazdów będzie ułomna, bo nie poustawiają się animacje na + // submodelach określonych w MMD + // TModelsManager::GetModel(AnsiString(dir+sr.Name).c_str(),true); + if (last != dir) + { // utworzenie toru dla danego pojazdu + last = dir; + trk = TTrack::Create400m(1, shift); + shift += 10.0; // następny tor będzie deczko dalej, aby nie zabić FPS + at = 400.0; + // if (shift>1000) break; //bezpiecznik + } + TGroundNode *tmp = new TGroundNode(); + tmp->DynamicObject = new TDynamicObject(); + // Global::asCurrentTexturePath=dir; //pojazdy mają tekstury we własnych + // katalogach + at -= tmp->DynamicObject->Init( + "", dir.SubString(9, dir.Length() - 9), "none", + sr.Name.SubString(1, sr.Name.Length() - 4), trk, at, "nobody", 0.0, + "none", 0.0, "", false, ""); + // po wczytaniu CHK zrobić pętlę po ładunkach, aby każdy z nich skonwertować + AnsiString loads, load; + loads = tmp->DynamicObject->MoverParameters->LoadAccepted; // typy ładunków + if (!loads.IsEmpty()) + { + loads += ","; // przecinek na końcu + int i = loads.Pos(","); + while (i > 1) + { // wypadało by sprawdzić, czy T3D ładunku jest + load = loads.SubString(1, i - 1); + if (FileExists(dir + load + ".t3d")) // o ile jest plik ładunku, bo + // inaczej nie ma to sensu + if (!FileExists( + dir + load + + ".e3d")) // a nie ma jeszcze odpowiednika binarnego + at -= tmp->DynamicObject->Init( + "", dir.SubString(9, dir.Length() - 9), "none", + sr.Name.SubString(1, sr.Name.Length() - 4), trk, at, + "nobody", 0.0, "none", 1.0, load, false, ""); + loads.Delete(1, i); // usunięcie z następującym przecinkiem + i = loads.Pos(","); + } + } + if (tmp->DynamicObject->iCabs) + { // jeśli ma jakąkolwiek kabinę + delete Train; + Train = new TTrain(); + if (tmp->DynamicObject->iCabs & 1) + { + tmp->DynamicObject->MoverParameters->ActiveCab = 1; + Train->Init(tmp->DynamicObject, true); + } + if (tmp->DynamicObject->iCabs & 4) + { + tmp->DynamicObject->MoverParameters->ActiveCab = -1; + Train->Init(tmp->DynamicObject, true); + } + if (tmp->DynamicObject->iCabs & 2) + { + tmp->DynamicObject->MoverParameters->ActiveCab = 0; + Train->Init(tmp->DynamicObject, true); + } + } + Global::asCurrentTexturePath = + AnsiString(szTexturePath); // z powrotem defaultowa sciezka do tekstur + } + } + else if (sr.Name.LowerCase().SubString(sr.Name.Length() - 3, 4) == ".t3d") + { // z modelami jest prościej + Global::asCurrentTexturePath = dir; + TModelsManager::GetModel(AnsiString(dir + sr.Name).c_str(), false); + } + } while (FindNext(sr) == 0); + FindClose(sr); + } }; //--------------------------------------------------------------------------- -void __fastcall TWorld::CabChange(TDynamicObject *old,TDynamicObject *now) -{//ewentualna zmiana kabiny użytkownikowi - if (Train) - if (Train->Dynamic()==old) - Global::changeDynObj=now; //uruchomienie protezy +void __fastcall TWorld::CabChange(TDynamicObject *old, TDynamicObject *now) +{ // ewentualna zmiana kabiny użytkownikowi + if (Train) + if (Train->Dynamic() == old) + Global::changeDynObj = now; // uruchomienie protezy }; //--------------------------------------------------------------------------- - diff --git a/World.h b/World.h index 6e977700..e8cc5ccf 100644 --- a/World.h +++ b/World.h @@ -3,7 +3,6 @@ #ifndef WorldH #define WorldH - #include "Usefull.h" #include "Classes.h" #include "Texture.h" @@ -16,49 +15,50 @@ class TWorld { - void __fastcall InOutKey(); - void __fastcall FollowView(bool wycisz=true); - void __fastcall DistantView(); -public: - bool __fastcall Init(HWND NhWnd, HDC hDC); - HWND hWnd; - GLvoid __fastcall glPrint(const char *fmt); - void __fastcall OnKeyDown(int cKey); - void __fastcall OnKeyUp(int cKey); - //void __fastcall UpdateWindow(); - void __fastcall OnMouseMove(double x, double y); - void __fastcall OnCommandGet(DaneRozkaz *pRozkaz); - bool __fastcall Update(); - void __fastcall TrainDelete(TDynamicObject *d=NULL); - __fastcall TWorld(); - __fastcall ~TWorld(); - //double Aspect; -private: - AnsiString OutText1; //teksty na ekranie - AnsiString OutText2; - AnsiString OutText3; - AnsiString OutText4; - void ShowHints(); - bool __fastcall Render(); - TCamera Camera; - TGround Ground; - TTrain *Train; - TDynamicObject *pDynamicNearest; - bool Paused; - GLuint base; //numer DL dla znaków w napisach - GLuint light; //numer tekstury dla smugi - TSky Clouds; - TEvent *KeyEvents[10]; //eventy wyzwalane z klawiaury - TMoverParameters *mvControlled; //wskaźnik na człon silnikowy, do wyświetlania jego parametrów - int iCheckFPS; //kiedy znów sprawdzić FPS, żeby wyłączać optymalizacji od razu do zera - double fTime50Hz; //bufor czasu dla komunikacji z PoKeys - double fTimeBuffer; //bufor czasu aktualizacji dla stałego kroku fizyki - double fMaxDt; //[s] krok czasowy fizyki (0.01 dla normalnych warunków) - int iPause; //wykrywanie zmian w zapauzowaniu -public: - void __fastcall ModifyTGA(const AnsiString &dir=""); - void __fastcall CreateE3D(const AnsiString &dir="",bool dyn=false); - void __fastcall CabChange(TDynamicObject *old,TDynamicObject *now); + void __fastcall InOutKey(); + void __fastcall FollowView(bool wycisz = true); + void __fastcall DistantView(); + + public: + bool __fastcall Init(HWND NhWnd, HDC hDC); + HWND hWnd; + GLvoid __fastcall glPrint(const char *fmt); + void __fastcall OnKeyDown(int cKey); + void __fastcall OnKeyUp(int cKey); + // void __fastcall UpdateWindow(); + void __fastcall OnMouseMove(double x, double y); + void __fastcall OnCommandGet(DaneRozkaz *pRozkaz); + bool __fastcall Update(); + void __fastcall TrainDelete(TDynamicObject *d = NULL); + __fastcall TWorld(); + __fastcall ~TWorld(); + // double Aspect; + private: + AnsiString OutText1; // teksty na ekranie + AnsiString OutText2; + AnsiString OutText3; + AnsiString OutText4; + void ShowHints(); + bool __fastcall Render(); + TCamera Camera; + TGround Ground; + TTrain *Train; + TDynamicObject *pDynamicNearest; + bool Paused; + GLuint base; // numer DL dla znaków w napisach + GLuint light; // numer tekstury dla smugi + TSky Clouds; + TEvent *KeyEvents[10]; // eventy wyzwalane z klawiaury + TMoverParameters *mvControlled; // wskaźnik na człon silnikowy, do wyświetlania jego parametrów + int iCheckFPS; // kiedy znów sprawdzić FPS, żeby wyłączać optymalizacji od razu do zera + double fTime50Hz; // bufor czasu dla komunikacji z PoKeys + double fTimeBuffer; // bufor czasu aktualizacji dla stałego kroku fizyki + double fMaxDt; //[s] krok czasowy fizyki (0.01 dla normalnych warunków) + int iPause; // wykrywanie zmian w zapauzowaniu + public: + void __fastcall ModifyTGA(const AnsiString &dir = ""); + void __fastcall CreateE3D(const AnsiString &dir = "", bool dyn = false); + void __fastcall CabChange(TDynamicObject *old, TDynamicObject *now); }; //--------------------------------------------------------------------------- #endif diff --git a/dumb3d.cpp b/dumb3d.cpp index f5195b04..6cafc377 100644 --- a/dumb3d.cpp +++ b/dumb3d.cpp @@ -2,116 +2,140 @@ #include "fastmath.h" #include -namespace Math3D { +namespace Math3D +{ void __fastcall vector3::RotateX(double angle) { - double ty= y; - y= (cos(angle)*y-z*sin(angle)); - z= (z*cos(angle)+sin(angle)*ty); + double ty = y; + y = (cos(angle) * y - z * sin(angle)); + z = (z * cos(angle) + sin(angle) * ty); }; void __fastcall vector3::RotateY(double angle) { - double tx= x; - x= (cos(angle)*x+z*sin(angle)); - z= (z*cos(angle)-sin(angle)*tx); + double tx = x; + x = (cos(angle) * x + z * sin(angle)); + z = (z * cos(angle) - sin(angle) * tx); }; void __fastcall vector3::RotateZ(double angle) { - double ty= y; - y= (cos(angle)*y+x*sin(angle)); - x= (x*cos(angle)-sin(angle)*ty); + double ty = y; + y = (cos(angle) * y + x * sin(angle)); + x = (x * cos(angle) - sin(angle) * ty); }; void inline __fastcall vector3::SafeNormalize() { - double l= Length(); - if (l==0) + double l = Length(); + if (l == 0) { - x=y=z=0; + x = y = z = 0; } else { - x/= l; - y/= l; - z/= l; + x /= l; + y /= l; + z /= l; } } // From code in Graphics Gems; p. 766 -inline scalar_t det2x2 (scalar_t a, scalar_t b, scalar_t c, scalar_t d) { - return a*d - b*c; +inline scalar_t det2x2(scalar_t a, scalar_t b, scalar_t c, scalar_t d) { return a * d - b * c; } + +inline scalar_t det3x3(scalar_t a1, scalar_t a2, scalar_t a3, scalar_t b1, scalar_t b2, scalar_t b3, + scalar_t c1, scalar_t c2, scalar_t c3) +{ + return a1 * det2x2(b2, b3, c2, c3) - b1 * det2x2(a2, a3, c2, c3) + c1 * det2x2(a2, a3, b2, b3); } -inline scalar_t det3x3 ( scalar_t a1, scalar_t a2, scalar_t a3, - scalar_t b1, scalar_t b2, scalar_t b3, - scalar_t c1, scalar_t c2, scalar_t c3) { - return a1 * det2x2(b2, b3, c2, c3) - - b1 * det2x2(a2, a3, c2, c3) - + c1 * det2x2(a2, a3, b2, b3); +scalar_t Determinant(const matrix4x4 &m) +{ + scalar_t a1 = m[0][0]; + scalar_t a2 = m[1][0]; + scalar_t a3 = m[2][0]; + scalar_t a4 = m[3][0]; + scalar_t b1 = m[0][1]; + scalar_t b2 = m[1][1]; + scalar_t b3 = m[2][1]; + scalar_t b4 = m[3][1]; + scalar_t c1 = m[0][2]; + scalar_t c2 = m[1][2]; + scalar_t c3 = m[2][2]; + scalar_t c4 = m[3][2]; + scalar_t d1 = m[0][3]; + scalar_t d2 = m[1][3]; + scalar_t d3 = m[2][3]; + scalar_t d4 = m[3][3]; + + return a1 * det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) - + b1 * det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) + + c1 * det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) - + d1 * det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); } -scalar_t Determinant (const matrix4x4& m) { - scalar_t a1 = m[0][0]; scalar_t a2 = m[1][0]; scalar_t a3 = m[2][0]; scalar_t a4 = m[3][0]; - scalar_t b1 = m[0][1]; scalar_t b2 = m[1][1]; scalar_t b3 = m[2][1]; scalar_t b4 = m[3][1]; - scalar_t c1 = m[0][2]; scalar_t c2 = m[1][2]; scalar_t c3 = m[2][2]; scalar_t c4 = m[3][2]; - scalar_t d1 = m[0][3]; scalar_t d2 = m[1][3]; scalar_t d3 = m[2][3]; scalar_t d4 = m[3][3]; +matrix4x4 Adjoint(const matrix4x4 &m) +{ + scalar_t a1 = m[0][0]; + scalar_t a2 = m[0][1]; + scalar_t a3 = m[0][2]; + scalar_t a4 = m[0][3]; + scalar_t b1 = m[1][0]; + scalar_t b2 = m[1][1]; + scalar_t b3 = m[1][2]; + scalar_t b4 = m[1][3]; + scalar_t c1 = m[2][0]; + scalar_t c2 = m[2][1]; + scalar_t c3 = m[2][2]; + scalar_t c4 = m[2][3]; + scalar_t d1 = m[3][0]; + scalar_t d2 = m[3][1]; + scalar_t d3 = m[3][2]; + scalar_t d4 = m[3][3]; - return a1 * det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) - - b1 * det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) - + c1 * det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) - - d1 * det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); + // Adjoint(x,y) = -1^(x+y) * a(y,x) + // Where a(i,j) is the 3x3 determinant of m with row i and col j removed + matrix4x4 retVal; + retVal(0)[0] = det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); + retVal(0)[1] = -det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); + retVal(0)[2] = det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); + retVal(0)[3] = -det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); + + retVal(1)[0] = -det3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); + retVal(1)[1] = det3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); + retVal(1)[2] = -det3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); + retVal(1)[3] = det3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); + + retVal(2)[0] = det3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); + retVal(2)[1] = -det3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); + retVal(2)[2] = det3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); + retVal(2)[3] = -det3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); + + retVal(3)[0] = -det3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); + retVal(3)[1] = det3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); + retVal(3)[2] = -det3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); + retVal(3)[3] = det3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); + + return retVal; } -matrix4x4 Adjoint (const matrix4x4& m) { - scalar_t a1 = m[0][0]; scalar_t a2 = m[0][1]; scalar_t a3 = m[0][2]; scalar_t a4 = m[0][3]; - scalar_t b1 = m[1][0]; scalar_t b2 = m[1][1]; scalar_t b3 = m[1][2]; scalar_t b4 = m[1][3]; - scalar_t c1 = m[2][0]; scalar_t c2 = m[2][1]; scalar_t c3 = m[2][2]; scalar_t c4 = m[2][3]; - scalar_t d1 = m[3][0]; scalar_t d2 = m[3][1]; scalar_t d3 = m[3][2]; scalar_t d4 = m[3][3]; +matrix4x4 Inverse(const matrix4x4 &m) +{ + matrix4x4 retVal = Adjoint(m); + scalar_t det = Determinant(m); + assert(det); - // Adjoint(x,y) = -1^(x+y) * a(y,x) - // Where a(i,j) is the 3x3 determinant of m with row i and col j removed - matrix4x4 retVal; - retVal(0)[0] = det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); - retVal(0)[1] = -det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); - retVal(0)[2] = det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); - retVal(0)[3] = -det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); - - retVal(1)[0] = -det3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); - retVal(1)[1] = det3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); - retVal(1)[2] = -det3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); - retVal(1)[3] = det3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); - - retVal(2)[0] = det3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); - retVal(2)[1] = -det3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); - retVal(2)[2] = det3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); - retVal(2)[3] = -det3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); - - retVal(3)[0] = -det3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); - retVal(3)[1] = det3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); - retVal(3)[2] = -det3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); - retVal(3)[3] = det3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); - - return retVal; -} + for (int i = 0; i < 4; ++i) + { + for (int j = 0; j < 4; ++j) + { + retVal(i)[j] /= det; + } + } -matrix4x4 Inverse (const matrix4x4& m) { - matrix4x4 retVal = Adjoint(m); - scalar_t det = Determinant(m); - assert(det); - - for (int i=0;i<4;++i) { - for (int j=0;j<4;++j) { - retVal(i)[j] /= det; - } - } - - return retVal; + return retVal; } } - - //************************************** // Testing from here on. //************************************** @@ -123,240 +147,255 @@ using namespace std; static int failures = 0; -void ReportFailure (const char* className, const char* testName, bool passed) { - cout << className; - if (passed) - cout << " passed test "; - else { - cout << " FAILED test "; - ++failures; - } - cout << testName << "." << endl; +void ReportFailure(const char *className, const char *testName, bool passed) +{ + cout << className; + if (passed) + cout << " passed test "; + else + { + cout << " FAILED test "; + ++failures; + } + cout << testName << "." << endl; } -const char* vector3Name = "vector3"; -const char* matrix4x4Name = "matrix4x4"; +const char *vector3Name = "vector3"; +const char *matrix4x4Name = "matrix4x4"; -void Testvector3Constructors(void) { - // Default ctor... just make sure it compiles - vector3 defaultCtorTest; - - // Initializer ctor test (3 param) - vector3 initCtorTest(1, 2, 3); - ReportFailure (vector3Name, "initialized ctor (3 parameter version)", (initCtorTest[0] == 1 && initCtorTest[1] == 2 && initCtorTest[2] == 3 && initCtorTest[3] == 1)); - - // Initializer ctor test (4 param) - vector3 initCtorTest2 (1,2,3,4); - ReportFailure (vector3Name, "initialized ctor (4 parameter version)", (initCtorTest2[0] == 1 && initCtorTest2[1] == 2 && initCtorTest2[2] == 3 && initCtorTest2[3] == 4)); +void Testvector3Constructors(void) +{ + // Default ctor... just make sure it compiles + vector3 defaultCtorTest; - scalar_t initArray[] = { 1, 2, 3, 4}; - vector3 initCtorArrayTest3 (initArray); - ReportFailure (vector3Name, "array initialized ctor (3 parameter version)", (initCtorArrayTest3[0] == 1 && initCtorArrayTest3[1] == 2 && initCtorArrayTest3[2] == 3 && initCtorArrayTest3[3] == 1)); + // Initializer ctor test (3 param) + vector3 initCtorTest(1, 2, 3); + ReportFailure(vector3Name, "initialized ctor (3 parameter version)", + (initCtorTest[0] == 1 && initCtorTest[1] == 2 && initCtorTest[2] == 3 && + initCtorTest[3] == 1)); - vector3 initCtorArrayTest4 (initArray, 4); - ReportFailure (vector3Name, "array initialized ctor (4 parameter version)", (initCtorArrayTest4[0] == 1 && initCtorArrayTest4[1] == 2 && initCtorArrayTest4[2] == 3 && initCtorArrayTest4[3] == 4)); - - // Copy ctor test - vector3 copyCtorTest(initCtorTest2); - ReportFailure (vector3Name, "copy ctor", (copyCtorTest[0] == 1 && copyCtorTest[1] == 2 && copyCtorTest[2] == 3 && copyCtorTest[3] == 4)); + // Initializer ctor test (4 param) + vector3 initCtorTest2(1, 2, 3, 4); + ReportFailure(vector3Name, "initialized ctor (4 parameter version)", + (initCtorTest2[0] == 1 && initCtorTest2[1] == 2 && initCtorTest2[2] == 3 && + initCtorTest2[3] == 4)); + + scalar_t initArray[] = {1, 2, 3, 4}; + vector3 initCtorArrayTest3(initArray); + ReportFailure(vector3Name, "array initialized ctor (3 parameter version)", + (initCtorArrayTest3[0] == 1 && initCtorArrayTest3[1] == 2 && + initCtorArrayTest3[2] == 3 && initCtorArrayTest3[3] == 1)); + + vector3 initCtorArrayTest4(initArray, 4); + ReportFailure(vector3Name, "array initialized ctor (4 parameter version)", + (initCtorArrayTest4[0] == 1 && initCtorArrayTest4[1] == 2 && + initCtorArrayTest4[2] == 3 && initCtorArrayTest4[3] == 4)); + + // Copy ctor test + vector3 copyCtorTest(initCtorTest2); + ReportFailure(vector3Name, "copy ctor", (copyCtorTest[0] == 1 && copyCtorTest[1] == 2 && + copyCtorTest[2] == 3 && copyCtorTest[3] == 4)); } -void Testvector3Comparison(void) { - vector3 alpha(1,1,1); - vector3 beta(alpha); - vector3 gamma(2,3,4); - - ReportFailure (vector3Name, "equivalence operator test 1", (alpha==beta)); - ReportFailure (vector3Name, "equivalence operator test 2", (!(alpha == gamma))); - ReportFailure (vector3Name, "comparison operator test 1", !(alpha < beta)); - ReportFailure (vector3Name, "comparison operator test 2", (alpha < gamma)); - ReportFailure (vector3Name, "comparison operator test 3", !(gamma < beta)); +void Testvector3Comparison(void) +{ + vector3 alpha(1, 1, 1); + vector3 beta(alpha); + vector3 gamma(2, 3, 4); + + ReportFailure(vector3Name, "equivalence operator test 1", (alpha == beta)); + ReportFailure(vector3Name, "equivalence operator test 2", (!(alpha == gamma))); + ReportFailure(vector3Name, "comparison operator test 1", !(alpha < beta)); + ReportFailure(vector3Name, "comparison operator test 2", (alpha < gamma)); + ReportFailure(vector3Name, "comparison operator test 3", !(gamma < beta)); } -void Testvector3Assignment (void) { - vector3 alpha(1,1,1,1); - vector3 beta(10,10,10,10); - alpha = beta; - ReportFailure (vector3Name, "assignment operator", (alpha == beta)); +void Testvector3Assignment(void) +{ + vector3 alpha(1, 1, 1, 1); + vector3 beta(10, 10, 10, 10); + alpha = beta; + ReportFailure(vector3Name, "assignment operator", (alpha == beta)); } -void Testvector3UnaryOps (void) { - vector3 alpha(10,10,10,10); - vector3 beta(-10,-10,-10,-10); - alpha = -alpha; - ReportFailure(vector3Name, "negation operator", (alpha==beta)); - - ReportFailure(vector3Name, "length squared 3 element version", LengthSquared3(alpha) == 300); - ReportFailure(vector3Name, "length 3 element version", Length3(alpha) == SQRT_FUNCTION(300)); - ReportFailure(vector3Name, "length squared 4 element version", LengthSquared4(alpha) == 400); - ReportFailure(vector3Name, "length 4 element version", Length4(alpha) == SQRT_FUNCTION(400)); - - // Manually normalize beta - // Done without /= on vector3, as we want to be independant of failure of /= - // Earlier failures should be resolved before later ones (just like C++) - beta = alpha; - for (int i=0;i<3;++i) beta(i) /= SQRT_FUNCTION(300); - beta(3) = 1; - ReportFailure(vector3Name, "normalize 3 element version", Normalize3(alpha) == beta); - - beta = alpha; - for (int i=0;i<4;++i) beta(i) /= SQRT_FUNCTION(400); - ReportFailure(vector3Name, "normalize 4 element version", Normalize4(alpha) == beta); +void Testvector3UnaryOps(void) +{ + vector3 alpha(10, 10, 10, 10); + vector3 beta(-10, -10, -10, -10); + alpha = -alpha; + ReportFailure(vector3Name, "negation operator", (alpha == beta)); + + ReportFailure(vector3Name, "length squared 3 element version", LengthSquared3(alpha) == 300); + ReportFailure(vector3Name, "length 3 element version", Length3(alpha) == SQRT_FUNCTION(300)); + ReportFailure(vector3Name, "length squared 4 element version", LengthSquared4(alpha) == 400); + ReportFailure(vector3Name, "length 4 element version", Length4(alpha) == SQRT_FUNCTION(400)); + + // Manually normalize beta + // Done without /= on vector3, as we want to be independant of failure of /= + // Earlier failures should be resolved before later ones (just like C++) + beta = alpha; + for (int i = 0; i < 3; ++i) + beta(i) /= SQRT_FUNCTION(300); + beta(3) = 1; + ReportFailure(vector3Name, "normalize 3 element version", Normalize3(alpha) == beta); + + beta = alpha; + for (int i = 0; i < 4; ++i) + beta(i) /= SQRT_FUNCTION(400); + ReportFailure(vector3Name, "normalize 4 element version", Normalize4(alpha) == beta); } -void Testvector3BinaryOps (void) { - // Vector * Matrix is tested in Testmatrix4x4BinaryOps - vector3 testVec(1,1,1,1); - vector3 deltaVec(1,2,3,4); - vector3 crossVec(1, -2, 1, 1); // testVec x deltaVec +void Testvector3BinaryOps(void) +{ + // Vector * Matrix is tested in Testmatrix4x4BinaryOps + vector3 testVec(1, 1, 1, 1); + vector3 deltaVec(1, 2, 3, 4); + vector3 crossVec(1, -2, 1, 1); // testVec x deltaVec - vector3 factorVec(10,10,10,10); - vector3 sumVec(2,3,4,5); - vector3 difVec(0,-1,-2,-3); - vector3 testVec2; - - ReportFailure(vector3Name, "scalar multiply 1", (testVec * 10) == factorVec); - ReportFailure(vector3Name, "scalar multiply 2", (10 * testVec) == factorVec); - testVec2 = testVec; - ReportFailure(vector3Name, "scalar multiply and store", (testVec2 *= 10) == factorVec); - - ReportFailure(vector3Name, "scalar divide", (factorVec / 10) == testVec); - testVec2 = factorVec; - ReportFailure(vector3Name, "scalar divide and store", (testVec2 /= 10) == testVec); - - ReportFailure(vector3Name, "vector addition", (testVec + deltaVec) == sumVec); - testVec2 = testVec; - ReportFailure(vector3Name, "vector addition and store", (testVec2 += deltaVec) == sumVec); - - ReportFailure(vector3Name, "vector subtraction", (testVec - deltaVec) == difVec); - testVec2 = testVec; - ReportFailure(vector3Name, "vector subtraction and store", (testVec2 -= deltaVec) == difVec); - - ReportFailure(vector3Name, "3 element dot product", 6 == DotProduct3(testVec, deltaVec)); - ReportFailure(vector3Name, "4 element dot product", 10 == DotProduct4(testVec, deltaVec)); + vector3 factorVec(10, 10, 10, 10); + vector3 sumVec(2, 3, 4, 5); + vector3 difVec(0, -1, -2, -3); + vector3 testVec2; - ReportFailure(vector3Name, "cross product", crossVec == CrossProduct(testVec, deltaVec)); + ReportFailure(vector3Name, "scalar multiply 1", (testVec * 10) == factorVec); + ReportFailure(vector3Name, "scalar multiply 2", (10 * testVec) == factorVec); + testVec2 = testVec; + ReportFailure(vector3Name, "scalar multiply and store", (testVec2 *= 10) == factorVec); + + ReportFailure(vector3Name, "scalar divide", (factorVec / 10) == testVec); + testVec2 = factorVec; + ReportFailure(vector3Name, "scalar divide and store", (testVec2 /= 10) == testVec); + + ReportFailure(vector3Name, "vector addition", (testVec + deltaVec) == sumVec); + testVec2 = testVec; + ReportFailure(vector3Name, "vector addition and store", (testVec2 += deltaVec) == sumVec); + + ReportFailure(vector3Name, "vector subtraction", (testVec - deltaVec) == difVec); + testVec2 = testVec; + ReportFailure(vector3Name, "vector subtraction and store", (testVec2 -= deltaVec) == difVec); + + ReportFailure(vector3Name, "3 element dot product", 6 == DotProduct3(testVec, deltaVec)); + ReportFailure(vector3Name, "4 element dot product", 10 == DotProduct4(testVec, deltaVec)); + + ReportFailure(vector3Name, "cross product", crossVec == CrossProduct(testVec, deltaVec)); } -void Testvector3 (void) { - // Accessors cannot be tested effectively... - // They are really trivial, and so don't really need testing, - // but more importantly, how do you test the ctors without assuming - // the accessors work? Conversely, how do you test the acccessors - // without assuming the ctors work? Chicken and egg problem, and I - // decided on testing the ctors, not the accessors. - Testvector3Constructors(); - Testvector3Comparison(); - Testvector3Assignment(); - Testvector3UnaryOps(); - Testvector3BinaryOps(); +void Testvector3(void) +{ + // Accessors cannot be tested effectively... + // They are really trivial, and so don't really need testing, + // but more importantly, how do you test the ctors without assuming + // the accessors work? Conversely, how do you test the acccessors + // without assuming the ctors work? Chicken and egg problem, and I + // decided on testing the ctors, not the accessors. + Testvector3Constructors(); + Testvector3Comparison(); + Testvector3Assignment(); + Testvector3UnaryOps(); + Testvector3BinaryOps(); } -void Testmatrix4x4Constructors (void) { - // Check if default ctor compiles - matrix4x4 defaultTest; - - scalar_t initArray[] = { 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15 }; - matrix4x4 arrayTest; - arrayTest.C_Matrix(initArray); - bool passedTest = true; - for (int x=0;x<4;++x) for (int y=0;y<4;++y) - if (arrayTest[x][y] != initArray[(y<<2) + x]) passedTest = false; - ReportFailure(matrix4x4Name, "array constructor", passedTest); +void Testmatrix4x4Constructors(void) +{ + // Check if default ctor compiles + matrix4x4 defaultTest; - matrix4x4 copyTest(arrayTest); - passedTest = true; - for (int x=0;x<4;++x) for (int y=0;y<4;++y) - if (arrayTest[x][y] != copyTest[x][y]) passedTest = false; - ReportFailure(matrix4x4Name, "copy constructor", passedTest); + scalar_t initArray[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + matrix4x4 arrayTest; + arrayTest.C_Matrix(initArray); + bool passedTest = true; + for (int x = 0; x < 4; ++x) + for (int y = 0; y < 4; ++y) + if (arrayTest[x][y] != initArray[(y << 2) + x]) + passedTest = false; + ReportFailure(matrix4x4Name, "array constructor", passedTest); + + matrix4x4 copyTest(arrayTest); + passedTest = true; + for (int x = 0; x < 4; ++x) + for (int y = 0; y < 4; ++y) + if (arrayTest[x][y] != copyTest[x][y]) + passedTest = false; + ReportFailure(matrix4x4Name, "copy constructor", passedTest); } -void Testmatrix4x4Comparison (void) { - scalar_t initArray[] = { 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15 }; - scalar_t initArray2[] = { 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 1, 1, 1 }; - matrix4x4 alpha, beta, gamma; - alpha.C_Matrix(initArray); - beta.C_Matrix(initArray); - gamma.C_Matrix(initArray2); - - ReportFailure(matrix4x4Name, "equality test 1", alpha == beta); - ReportFailure(matrix4x4Name, "equality test 2", !(alpha == gamma)); - ReportFailure(matrix4x4Name, "comparison test 1", alpha < gamma); - ReportFailure(matrix4x4Name, "comparison test 2", !(gamma < alpha)); - ReportFailure(matrix4x4Name, "comparison test 3", !(alpha < beta)); +void Testmatrix4x4Comparison(void) +{ + scalar_t initArray[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + scalar_t initArray2[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + matrix4x4 alpha, beta, gamma; + alpha.C_Matrix(initArray); + beta.C_Matrix(initArray); + gamma.C_Matrix(initArray2); + + ReportFailure(matrix4x4Name, "equality test 1", alpha == beta); + ReportFailure(matrix4x4Name, "equality test 2", !(alpha == gamma)); + ReportFailure(matrix4x4Name, "comparison test 1", alpha < gamma); + ReportFailure(matrix4x4Name, "comparison test 2", !(gamma < alpha)); + ReportFailure(matrix4x4Name, "comparison test 3", !(alpha < beta)); } -void Testmatrix4x4BinaryOps (void) { - scalar_t initVector[] = { 0, 1, 2, 3 }; - scalar_t initMatrix[] = { 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15 }; - scalar_t resultVector[] = { 0 * 0 + 1 * 1 + 2 * 2 + 3 * 3, - 0 * 4 + 1 * 5 + 2 * 6 + 3 * 7, - 0 * 8 + 1 * 9 + 2 * 10 + 3 * 11, - 0 * 12 + 1 * 13 + 2 * 14 + 3 * 15 }; - - vector3 vector1 (initVector, 4); - matrix4x4 matrix1; - matrix1.C_Matrix(initMatrix); - vector3 vectorTest (resultVector, 4); - ReportFailure (matrix4x4Name, "matrix * vector", vectorTest == matrix1 * vector1); - - scalar_t initMatrix2[] = { 15, 14, 13, 12, - 11, 10, 9, 8, - 7, 6, 5, 4, - 3, 2, 1, 0 }; - - matrix4x4 matrix2; - matrix2.C_Matrix(initMatrix2); - matrix4x4 resultMatrix; - for (int x=0;x<4;++x) for (int y=0;y<4;++y) { - resultMatrix(x)[y] = 0; - for (int i=0;i<4;++i) resultMatrix(x)[y] += matrix1[i][y] * matrix2[x][i]; - } - ReportFailure (matrix4x4Name, "matrix * matrix", resultMatrix == matrix1 * matrix2); +void Testmatrix4x4BinaryOps(void) +{ + scalar_t initVector[] = {0, 1, 2, 3}; + scalar_t initMatrix[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + scalar_t resultVector[] = {0 * 0 + 1 * 1 + 2 * 2 + 3 * 3, 0 * 4 + 1 * 5 + 2 * 6 + 3 * 7, + 0 * 8 + 1 * 9 + 2 * 10 + 3 * 11, 0 * 12 + 1 * 13 + 2 * 14 + 3 * 15}; + + vector3 vector1(initVector, 4); + matrix4x4 matrix1; + matrix1.C_Matrix(initMatrix); + vector3 vectorTest(resultVector, 4); + ReportFailure(matrix4x4Name, "matrix * vector", vectorTest == matrix1 * vector1); + + scalar_t initMatrix2[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + matrix4x4 matrix2; + matrix2.C_Matrix(initMatrix2); + matrix4x4 resultMatrix; + for (int x = 0; x < 4; ++x) + for (int y = 0; y < 4; ++y) + { + resultMatrix(x)[y] = 0; + for (int i = 0; i < 4; ++i) + resultMatrix(x)[y] += matrix1[i][y] * matrix2[x][i]; + } + ReportFailure(matrix4x4Name, "matrix * matrix", resultMatrix == matrix1 * matrix2); } -void Testmatrix4x4 (void) { - Testmatrix4x4Constructors(); - Testmatrix4x4Comparison(); - Testmatrix4x4BinaryOps(); +void Testmatrix4x4(void) +{ + Testmatrix4x4Constructors(); + Testmatrix4x4Comparison(); + Testmatrix4x4BinaryOps(); } -int main (int, char*[]) { - int vectorFailures = 0; - int matrixFailures = 0; - Testvector3(); - vectorFailures = failures; - failures = 0; - - Testmatrix4x4(); - matrixFailures = failures; +int main(int, char *[]) +{ + int vectorFailures = 0; + int matrixFailures = 0; + Testvector3(); + vectorFailures = failures; + failures = 0; - cout << endl << "****************************************" << endl; - cout << "* *" << endl; - if (vectorFailures + matrixFailures == 0) - cout << "* No failures detected in Math3D *" << endl; - else { - cout << "* FAILURES DETECTED IN MATH3D! *" << endl; - cout << "* Total vector3 failures: " << vectorFailures << " *" << endl; - cout << "* Total matrix4x4 failures: " << matrixFailures << " *" << endl; - cout << "* Total Failures in Math3D: " << vectorFailures + matrixFailures << " *" << endl; - - } - cout << "* *" << endl; - cout << "****************************************" << endl; + Testmatrix4x4(); + matrixFailures = failures; - return 0; + cout << endl << "****************************************" << endl; + cout << "* *" << endl; + if (vectorFailures + matrixFailures == 0) + cout << "* No failures detected in Math3D *" << endl; + else + { + cout << "* FAILURES DETECTED IN MATH3D! *" << endl; + cout << "* Total vector3 failures: " << vectorFailures << " *" << endl; + cout << "* Total matrix4x4 failures: " << matrixFailures << " *" << endl; + cout << "* Total Failures in Math3D: " << vectorFailures + matrixFailures << " *" + << endl; + } + cout << "* *" << endl; + cout << "****************************************" << endl; + + return 0; } #endif \ No newline at end of file diff --git a/dumb3d.h b/dumb3d.h index fa9b73c1..31494bdd 100644 --- a/dumb3d.h +++ b/dumb3d.h @@ -4,7 +4,8 @@ //#include #include -namespace Math3D { +namespace Math3D +{ // Define this to have Math3D.cp generate a main which tests these classes //#define TEST_MATH3D @@ -17,16 +18,20 @@ namespace Math3D { typedef double scalar_t; // inline pass-throughs to various basic math functions // written in this style to allow for easy substitution with more efficient versions -inline scalar_t SINE_FUNCTION (scalar_t x) { return sin(x); } -inline scalar_t COSINE_FUNCTION (scalar_t x) { return cos(x); } -inline scalar_t SQRT_FUNCTION (scalar_t x) { return sqrt(x); } +inline scalar_t SINE_FUNCTION(scalar_t x) { return sin(x); } +inline scalar_t COSINE_FUNCTION(scalar_t x) { return cos(x); } +inline scalar_t SQRT_FUNCTION(scalar_t x) { return sqrt(x); } // 2 element vector -class vector2 { -public: - vector2 (void) {} - __fastcall vector2 (scalar_t a, scalar_t b) - { x=a; y=b; } +class vector2 +{ + public: + vector2(void) {} + __fastcall vector2(scalar_t a, scalar_t b) + { + x = a; + y = b; + } double x; union { @@ -35,15 +40,20 @@ public: }; }; // 3 element vector -class vector3 { -public: - vector3 (void) {} - __fastcall vector3 (scalar_t a, scalar_t b, scalar_t c) - { x=a; y=b; z=c; } +class vector3 +{ + public: + vector3(void) {} + __fastcall vector3(scalar_t a, scalar_t b, scalar_t c) + { + x = a; + y = b; + z = c; + } - // The int parameter is the number of elements to copy from initArray (3 or 4) -// explicit vector3(scalar_t* initArray, int arraySize = 3) -// { for (int i = 0;ix)>0.02) return false; //sześcian zamiast kuli - if (fabs(z-v->z)>0.02) return false; - if (fabs(y-v->y)>0.02) return false; - return true; - }; + // union + // { + // struct + // { + double x, y, z; + // }; + // scalar_t e[3]; + // }; + bool inline __fastcall Equal(vector3 *v) + { // sprawdzenie odległości punktów + if (fabs(x - v->x) > 0.02) + return false; // sześcian zamiast kuli + if (fabs(z - v->z) > 0.02) + return false; + if (fabs(y - v->y) > 0.02) + return false; + return true; + }; -private: + private: }; // 4 element matrix -class matrix4x4 { -public: - matrix4x4 (void) {} +class matrix4x4 +{ + public: + matrix4x4(void) {} - // When defining matrices in C arrays, it is easiest to define them with - // the column increasing fastest. However, some APIs (OpenGL in particular) do this - // backwards, hence the "constructor" from C matrices, or from OpenGL matrices. - // Note that matrices are stored internally in OpenGL format. - void C_Matrix (scalar_t* initArray) - { int i = 0; for (int y=0;y<4;++y) for (int x=0;x<4;++x) (*this)(x)[y] = initArray[i++]; } - void OpenGL_Matrix (scalar_t* initArray) - { int i = 0; for (int x = 0; x < 4; ++x) for (int y=0;y<4;++y) (*this)(x)[y] = initArray[i++]; } - - // [] is to read, () is to write (const correctness) - // m[x][y] or m(x)[y] is the correct form - const scalar_t* operator[] (int i) const { return &e[i<<2]; } - scalar_t* operator() (int i) { return &e[i<<2]; } - - // Low-level access to the array. - const scalar_t* readArray (void) { return e; } - scalar_t* getArray(void) { return e; } + // When defining matrices in C arrays, it is easiest to define them with + // the column increasing fastest. However, some APIs (OpenGL in particular) do this + // backwards, hence the "constructor" from C matrices, or from OpenGL matrices. + // Note that matrices are stored internally in OpenGL format. + void C_Matrix(scalar_t *initArray) + { + int i = 0; + for (int y = 0; y < 4; ++y) + for (int x = 0; x < 4; ++x) + (*this)(x)[y] = initArray[i++]; + } + void OpenGL_Matrix(scalar_t *initArray) + { + int i = 0; + for (int x = 0; x < 4; ++x) + for (int y = 0; y < 4; ++y) + (*this)(x)[y] = initArray[i++]; + } - // Construct various matrices; REPLACES CURRENT CONTENTS OF THE MATRIX! - // Written this way to work in-place and hence be somewhat more efficient - void Identity (void) { for (int i=0;i<16;++i) e[i] = 0; e[0] = 1; e[5] = 1; e[10] = 1; e[15] = 1; } - inline matrix4x4& Rotation (scalar_t angle, vector3 axis); - inline matrix4x4& Translation(const vector3& translation); - inline matrix4x4& Scale (scalar_t x, scalar_t y, scalar_t z); - inline matrix4x4& BasisChange (const vector3& v, const vector3& n); - inline matrix4x4& BasisChange (const vector3& u, const vector3& v, const vector3& n); - inline matrix4x4& ProjectionMatrix (bool perspective, scalar_t l, scalar_t r, scalar_t t, scalar_t b, scalar_t n, scalar_t f); - void InitialRotate() - {//taka specjalna rotacja, nie ma co ciągać trygonometrii - double f; - for (int i=0;i<16;i+=4) - {e[i]=-e[i]; //zmiana znaku X - f=e[i+1]; e[i+1]=e[i+2]; e[i+2]=f; //zamiana Y i Z - } - }; - inline bool IdentityIs() - {//sprawdzenie jednostkowości - for (int i=0;i<16;++i) - if (e[i]!=((i%5)?0.0:1.0)) //jedynki tylko na 0, 5, 10 i 15 - return false; - return true; - } + // [] is to read, () is to write (const correctness) + // m[x][y] or m(x)[y] is the correct form + const scalar_t *operator[](int i) const { return &e[i << 2]; } + scalar_t *operator()(int i) { return &e[i << 2]; } -private: - scalar_t e[16]; + // Low-level access to the array. + const scalar_t *readArray(void) { return e; } + scalar_t *getArray(void) { return e; } + + // Construct various matrices; REPLACES CURRENT CONTENTS OF THE MATRIX! + // Written this way to work in-place and hence be somewhat more efficient + void Identity(void) + { + for (int i = 0; i < 16; ++i) + e[i] = 0; + e[0] = 1; + e[5] = 1; + e[10] = 1; + e[15] = 1; + } + inline matrix4x4 &Rotation(scalar_t angle, vector3 axis); + inline matrix4x4 &Translation(const vector3 &translation); + inline matrix4x4 &Scale(scalar_t x, scalar_t y, scalar_t z); + inline matrix4x4 &BasisChange(const vector3 &v, const vector3 &n); + inline matrix4x4 &BasisChange(const vector3 &u, const vector3 &v, const vector3 &n); + inline matrix4x4 &ProjectionMatrix(bool perspective, scalar_t l, scalar_t r, scalar_t t, + scalar_t b, scalar_t n, scalar_t f); + void InitialRotate() + { // taka specjalna rotacja, nie ma co ciągać trygonometrii + double f; + for (int i = 0; i < 16; i += 4) + { + e[i] = -e[i]; // zmiana znaku X + f = e[i + 1]; + e[i + 1] = e[i + 2]; + e[i + 2] = f; // zamiana Y i Z + } + }; + inline bool IdentityIs() + { // sprawdzenie jednostkowości + for (int i = 0; i < 16; ++i) + if (e[i] != ((i % 5) ? 0.0 : 1.0)) // jedynki tylko na 0, 5, 10 i 15 + return false; + return true; + } + + private: + scalar_t e[16]; }; // Scalar operations // Returns false if there are 0 solutions -inline bool SolveQuadratic (scalar_t a, scalar_t b, scalar_t c, scalar_t* x1, scalar_t* x2); +inline bool SolveQuadratic(scalar_t a, scalar_t b, scalar_t c, scalar_t *x1, scalar_t *x2); // Vector operations -inline bool operator== (const vector3&, const vector3&); -inline bool operator< (const vector3&, const vector3&); +inline bool operator==(const vector3 &, const vector3 &); +inline bool operator<(const vector3 &, const vector3 &); -inline vector3 operator- (const vector3&); -inline vector3 operator* (const vector3&, scalar_t); -inline vector3 operator* (scalar_t, const vector3&); -inline vector3& operator*= (vector3&, scalar_t); -inline vector3 operator/ (const vector3&, scalar_t); -inline vector3& operator/= (vector3&, scalar_t); +inline vector3 operator-(const vector3 &); +inline vector3 operator*(const vector3 &, scalar_t); +inline vector3 operator*(scalar_t, const vector3 &); +inline vector3 &operator*=(vector3 &, scalar_t); +inline vector3 operator/(const vector3 &, scalar_t); +inline vector3 &operator/=(vector3 &, scalar_t); -inline vector3 operator+ (const vector3&, const vector3&); -inline vector3& operator+= (vector3&, const vector3&); -inline vector3 operator- (const vector3&, const vector3&); -inline vector3& operator-= (vector3&, const vector3&); +inline vector3 operator+(const vector3 &, const vector3 &); +inline vector3 &operator+=(vector3 &, const vector3 &); +inline vector3 operator-(const vector3 &, const vector3 &); +inline vector3 &operator-=(vector3 &, const vector3 &); // X3 is the 3 element version of a function, X4 is four element -inline scalar_t LengthSquared3 (const vector3&); -inline scalar_t LengthSquared4 (const vector3&); -inline scalar_t Length3 (const vector3&); -inline scalar_t Length4 (const vector3&); -inline vector3 Normalize (const vector3&); -inline vector3 Normalize4 (const vector3&); -inline scalar_t DotProduct (const vector3&, const vector3&); -inline scalar_t DotProduct4 (const vector3&, const vector3&); +inline scalar_t LengthSquared3(const vector3 &); +inline scalar_t LengthSquared4(const vector3 &); +inline scalar_t Length3(const vector3 &); +inline scalar_t Length4(const vector3 &); +inline vector3 Normalize(const vector3 &); +inline vector3 Normalize4(const vector3 &); +inline scalar_t DotProduct(const vector3 &, const vector3 &); +inline scalar_t DotProduct4(const vector3 &, const vector3 &); // Cross product is only defined for 3 elements -inline vector3 CrossProduct (const vector3&, const vector3&); +inline vector3 CrossProduct(const vector3 &, const vector3 &); -inline vector3 operator* (const matrix4x4&, const vector3&); +inline vector3 operator*(const matrix4x4 &, const vector3 &); // Matrix operations -inline bool operator== (const matrix4x4&, const matrix4x4&); -inline bool operator< (const matrix4x4&, const matrix4x4&); +inline bool operator==(const matrix4x4 &, const matrix4x4 &); +inline bool operator<(const matrix4x4 &, const matrix4x4 &); -inline matrix4x4 operator* (const matrix4x4&, const matrix4x4&); +inline matrix4x4 operator*(const matrix4x4 &, const matrix4x4 &); -inline matrix4x4 Transpose (const matrix4x4&); -scalar_t Determinant (const matrix4x4&); -matrix4x4 Adjoint (const matrix4x4&); -matrix4x4 Inverse (const matrix4x4&); +inline matrix4x4 Transpose(const matrix4x4 &); +scalar_t Determinant(const matrix4x4 &); +matrix4x4 Adjoint(const matrix4x4 &); +matrix4x4 Inverse(const matrix4x4 &); // Inline implementations follow -inline bool SolveQuadratic (scalar_t a, scalar_t b, scalar_t c, scalar_t* x1, scalar_t* x2) { - // If a == 0, solve a linear equation - if (a == 0) { - if (b == 0) return false; - *x1 = c / b; - *x2 = *x1; - return true; - } else { - scalar_t det = b * b - 4 * a * c; - if (det < 0) return false; - det = SQRT_FUNCTION(det) / (2 * a); - scalar_t prefix = -b / (2*a); - *x1 = prefix + det; - *x2 = prefix - det; - return true; - } -} - -inline bool operator== (const vector3& v1, const vector3& v2) -{ return (v1.x==v2.x&&v1.y==v2.y&&v1.z==v2.z); } - -inline bool operator< (const vector3& v1, const vector3& v2) { -// for (int i=0;i<4;++i) - // if (v1[i] < v2[i]) return true; - // else if (v1[i] > v2[i]) return false; - - return false; -} - -inline vector3 operator- (const vector3& v) -{ return vector3(-v.x, -v.y, -v.z); } - -inline vector3 operator* (const vector3& v, scalar_t k) -{ return vector3(k*v.x, k*v.y, k*v.z); } - -inline vector3 operator* (scalar_t k, const vector3& v) -{ return v * k; } - -inline vector3& operator*= (vector3& v, scalar_t k) -{ v.x*= k; v.y*= k; v.z*= k; return v; }; - -inline vector3 operator/ (const vector3& v, scalar_t k) -{ return vector3(v.x/k, v.y/k, v.z/k); } - -inline vector3& operator/= (vector3& v, scalar_t k) -{ v.x/= k; v.y/= k; v.z/= k; return v; } - -inline scalar_t LengthSquared3 (const vector3& v) -{ return DotProduct(v,v); } -inline scalar_t LengthSquared4 (const vector3& v) -{ return DotProduct4(v,v); } - -inline scalar_t Length3 (const vector3& v) -{ return SQRT_FUNCTION(LengthSquared3(v)); } -inline scalar_t Length4 (const vector3& v) -{ return SQRT_FUNCTION(LengthSquared4(v)); } - -inline vector3 Normalize (const vector3& v) -{ vector3 retVal = v / Length3(v); return retVal; } -inline vector3 SafeNormalize(const vector3& v) +inline bool SolveQuadratic(scalar_t a, scalar_t b, scalar_t c, scalar_t *x1, scalar_t *x2) { - double l= Length3(v); - vector3 retVal; - if (l==0) - retVal.x=retVal.y=retVal.z=0; - else - retVal=v/l; - return retVal; -} -inline vector3 Normalize4 (const vector3& v) -{ return v / Length4(v); } - -inline vector3 operator+ (const vector3& v1, const vector3& v2) -{ return vector3(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z); } - -inline vector3& operator+= (vector3& v1, const vector3& v2) -{ v1.x+= v2.x; v1.y+= v2.y; v1.z+= v2.z; return v1;} - -inline vector3 operator- (const vector3& v1, const vector3& v2) -{ return vector3(v1.x-v2.x, v1.y-v2.y, v1.z-v2.z); } - -inline vector3& operator-= (vector3& v1, const vector3& v2) -{ v1.x-= v2.x; v1.y-= v2.y; v1.z-= v2.z; return v1;} - -inline scalar_t DotProduct (const vector3& v1, const vector3& v2) -{ return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; } - -inline scalar_t DotProduct4 (const vector3& v1, const vector3& v2) -{ return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; } - -inline vector3 CrossProduct (const vector3& v1, const vector3& v2) { -return vector3( v1.y * v2.z - v1.z * v2.y - ,v2.x * v1.z - v2.z * v1.x - ,v1.x * v2.y - v1.y * v2.x); + // If a == 0, solve a linear equation + if (a == 0) + { + if (b == 0) + return false; + *x1 = c / b; + *x2 = *x1; + return true; + } + else + { + scalar_t det = b * b - 4 * a * c; + if (det < 0) + return false; + det = SQRT_FUNCTION(det) / (2 * a); + scalar_t prefix = -b / (2 * a); + *x1 = prefix + det; + *x2 = prefix - det; + return true; + } } -inline vector3 operator* (const matrix4x4& m, const vector3& v) { - return vector3( v.x*m[0][0] + v.y*m[1][0] + v.z*m[2][0] + m[3][0], - v.x*m[0][1] + v.y*m[1][1] + v.z*m[2][1] + m[3][1], - v.x*m[0][2] + v.y*m[1][2] + v.z*m[2][2] + m[3][2]); +inline bool operator==(const vector3 &v1, const vector3 &v2) +{ + return (v1.x == v2.x && v1.y == v2.y && v1.z == v2.z); +} +inline bool operator<(const vector3 &v1, const vector3 &v2) +{ + // for (int i=0;i<4;++i) + // if (v1[i] < v2[i]) return true; + // else if (v1[i] > v2[i]) return false; + + return false; +} + +inline vector3 operator-(const vector3 &v) { return vector3(-v.x, -v.y, -v.z); } + +inline vector3 operator*(const vector3 &v, scalar_t k) +{ + return vector3(k * v.x, k * v.y, k * v.z); +} + +inline vector3 operator*(scalar_t k, const vector3 &v) { return v * k; } + +inline vector3 &operator*=(vector3 &v, scalar_t k) +{ + v.x *= k; + v.y *= k; + v.z *= k; + return v; +}; + +inline vector3 operator/(const vector3 &v, scalar_t k) +{ + return vector3(v.x / k, v.y / k, v.z / k); +} + +inline vector3 &operator/=(vector3 &v, scalar_t k) +{ + v.x /= k; + v.y /= k; + v.z /= k; + return v; +} + +inline scalar_t LengthSquared3(const vector3 &v) { return DotProduct(v, v); } +inline scalar_t LengthSquared4(const vector3 &v) { return DotProduct4(v, v); } + +inline scalar_t Length3(const vector3 &v) { return SQRT_FUNCTION(LengthSquared3(v)); } +inline scalar_t Length4(const vector3 &v) { return SQRT_FUNCTION(LengthSquared4(v)); } + +inline vector3 Normalize(const vector3 &v) +{ + vector3 retVal = v / Length3(v); + return retVal; +} +inline vector3 SafeNormalize(const vector3 &v) +{ + double l = Length3(v); + vector3 retVal; + if (l == 0) + retVal.x = retVal.y = retVal.z = 0; + else + retVal = v / l; + return retVal; +} +inline vector3 Normalize4(const vector3 &v) { return v / Length4(v); } + +inline vector3 operator+(const vector3 &v1, const vector3 &v2) +{ + return vector3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); +} + +inline vector3 &operator+=(vector3 &v1, const vector3 &v2) +{ + v1.x += v2.x; + v1.y += v2.y; + v1.z += v2.z; + return v1; +} + +inline vector3 operator-(const vector3 &v1, const vector3 &v2) +{ + return vector3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); +} + +inline vector3 &operator-=(vector3 &v1, const vector3 &v2) +{ + v1.x -= v2.x; + v1.y -= v2.y; + v1.z -= v2.z; + return v1; +} + +inline scalar_t DotProduct(const vector3 &v1, const vector3 &v2) +{ + return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; +} + +inline scalar_t DotProduct4(const vector3 &v1, const vector3 &v2) +{ + return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; +} + +inline vector3 CrossProduct(const vector3 &v1, const vector3 &v2) +{ + return vector3(v1.y * v2.z - v1.z * v2.y, v2.x * v1.z - v2.z * v1.x, v1.x * v2.y - v1.y * v2.x); +} + +inline vector3 operator*(const matrix4x4 &m, const vector3 &v) +{ + return vector3(v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0] + m[3][0], + v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1] + m[3][1], + v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2] + m[3][2]); } void inline __fastcall vector3::Normalize() { - double il= 1/Length(); - x*= il; - y*= il; - z*= il; + double il = 1 / Length(); + x *= il; + y *= il; + z *= il; } -double inline __fastcall vector3::Length() +double inline __fastcall vector3::Length() { return SQRT_FUNCTION(x * x + y * y + z * z); } + +inline bool operator==(const matrix4x4 &m1, const matrix4x4 &m2) { - return SQRT_FUNCTION(x*x+y*y+z*z); + for (int x = 0; x < 4; ++x) + for (int y = 0; y < 4; ++y) + if (m1[x][y] != m2[x][y]) + return false; + return true; } -inline bool operator== (const matrix4x4& m1, const matrix4x4& m2) { - for (int x=0;x<4;++x) for (int y=0;y<4;++y) - if (m1[x][y] != m2[x][y]) return false; - return true; -} - -inline bool operator< (const matrix4x4& m1, const matrix4x4& m2) { - for (int x=0;x<4;++x) for (int y=0;y<4;++y) - if (m1[x][y] < m2[x][y]) return true; - else if (m1[x][y] > m2[x][y]) return false; - return false; -} - -inline matrix4x4 operator* (const matrix4x4& m1, const matrix4x4& m2) { - matrix4x4 retVal; - for (int x=0;x<4;++x) for (int y=0;y<4;++y) { - retVal(x)[y] = 0; - for (int i=0;i<4;++i) retVal(x)[y] += m1[i][y] * m2[x][i]; - } - return retVal; -} - -inline matrix4x4 Transpose (const matrix4x4& m) { - matrix4x4 retVal; - for (int x=0;x<4;++x) for (int y=0;y<4;++y) - retVal(x)[y] = m[y][x]; - return retVal; -} - -inline matrix4x4& matrix4x4::Rotation (scalar_t angle, vector3 axis) { - scalar_t c = COSINE_FUNCTION(angle); - scalar_t s = SINE_FUNCTION(angle); - // One minus c (short name for legibility of formulai) - scalar_t omc = (1 - c); - - if (LengthSquared3(axis) != 1) axis = Normalize(axis); - - scalar_t x = axis.x; - scalar_t y = axis.y; - scalar_t z = axis.z; - scalar_t xs = x * s; - scalar_t ys = y * s; - scalar_t zs = z * s; - scalar_t xyomc = x * y * omc; - scalar_t xzomc = x * z * omc; - scalar_t yzomc = y * z * omc; - - e[0] = x*x*omc + c; - e[1] = xyomc + zs; - e[2] = xzomc - ys; - e[3] = 0; - - e[4] = xyomc - zs; - e[5] = y*y*omc + c; - e[6] = yzomc + xs; - e[7] = 0; - - e[8] = xzomc + ys; - e[9] = yzomc - xs; - e[10] = z*z*omc + c; - e[11] = 0; - - e[12] = 0; - e[13] = 0; - e[14] = 0; - e[15] = 1; - - return *this; -} - -inline matrix4x4& matrix4x4::Translation(const vector3& translation) { - Identity(); - e[12] = translation.x; - e[13] = translation.y; - e[14] = translation.z; - return *this; -} - -inline matrix4x4& matrix4x4::Scale (scalar_t x, scalar_t y, scalar_t z) { - Identity(); - e[0] = x; - e[5] = y; - e[10] = z; - return *this; -} - -inline matrix4x4& matrix4x4::BasisChange (const vector3& u, const vector3& v, const vector3& n) { - e[0] = u.x; - e[1] = v.x; - e[2] = n.x; - e[3] = 0; - - e[4] = u.y; - e[5] = v.y; - e[6] = n.y; - e[7] = 0; - - e[8] = u.z; - e[9] = v.z; - e[10] = n.z; - e[11] = 0; - - e[12] = 0; - e[13] = 0; - e[14] = 0; - e[15] = 1; - - return *this; -} - -inline matrix4x4& matrix4x4::BasisChange (const vector3& v, const vector3& n) { - vector3 u = CrossProduct(v,n); - return BasisChange (u, v, n); -} - -inline matrix4x4& matrix4x4::ProjectionMatrix (bool perspective, scalar_t left_plane, scalar_t right_plane, - scalar_t top_plane, scalar_t bottom_plane, - scalar_t near_plane, scalar_t far_plane) +inline bool operator<(const matrix4x4 &m1, const matrix4x4 &m2) { - scalar_t A = (right_plane + left_plane) / (right_plane - left_plane); - scalar_t B = (top_plane + bottom_plane) / (top_plane - bottom_plane); - scalar_t C = (far_plane + near_plane) / (far_plane - near_plane); - - Identity(); - if (perspective) { - e[0] = 2 * near_plane / (right_plane - left_plane); - e[5] = 2 * near_plane / (top_plane - bottom_plane); - e[8] = A; - e[9] = B; - e[10] = C; - e[11] = -1; - e[14] = 2 * far_plane * near_plane / (far_plane - near_plane); - } else { - e[0] = 2 / (right_plane - left_plane); - e[5] = 2 / (top_plane - bottom_plane); - e[10] = -2 / (far_plane - near_plane); - e[12] = A; - e[13] = B; - e[14] = C; - } - return *this; + for (int x = 0; x < 4; ++x) + for (int y = 0; y < 4; ++y) + if (m1[x][y] < m2[x][y]) + return true; + else if (m1[x][y] > m2[x][y]) + return false; + return false; } -double inline __fastcall SquareMagnitude(const vector3& v) +inline matrix4x4 operator*(const matrix4x4 &m1, const matrix4x4 &m2) { - return v.x*v.x+v.y*v.y+v.z*v.z; + matrix4x4 retVal; + for (int x = 0; x < 4; ++x) + for (int y = 0; y < 4; ++y) + { + retVal(x)[y] = 0; + for (int i = 0; i < 4; ++i) + retVal(x)[y] += m1[i][y] * m2[x][i]; + } + return retVal; +} + +inline matrix4x4 Transpose(const matrix4x4 &m) +{ + matrix4x4 retVal; + for (int x = 0; x < 4; ++x) + for (int y = 0; y < 4; ++y) + retVal(x)[y] = m[y][x]; + return retVal; +} + +inline matrix4x4 &matrix4x4::Rotation(scalar_t angle, vector3 axis) +{ + scalar_t c = COSINE_FUNCTION(angle); + scalar_t s = SINE_FUNCTION(angle); + // One minus c (short name for legibility of formulai) + scalar_t omc = (1 - c); + + if (LengthSquared3(axis) != 1) + axis = Normalize(axis); + + scalar_t x = axis.x; + scalar_t y = axis.y; + scalar_t z = axis.z; + scalar_t xs = x * s; + scalar_t ys = y * s; + scalar_t zs = z * s; + scalar_t xyomc = x * y * omc; + scalar_t xzomc = x * z * omc; + scalar_t yzomc = y * z * omc; + + e[0] = x * x * omc + c; + e[1] = xyomc + zs; + e[2] = xzomc - ys; + e[3] = 0; + + e[4] = xyomc - zs; + e[5] = y * y * omc + c; + e[6] = yzomc + xs; + e[7] = 0; + + e[8] = xzomc + ys; + e[9] = yzomc - xs; + e[10] = z * z * omc + c; + e[11] = 0; + + e[12] = 0; + e[13] = 0; + e[14] = 0; + e[15] = 1; + + return *this; +} + +inline matrix4x4 &matrix4x4::Translation(const vector3 &translation) +{ + Identity(); + e[12] = translation.x; + e[13] = translation.y; + e[14] = translation.z; + return *this; +} + +inline matrix4x4 &matrix4x4::Scale(scalar_t x, scalar_t y, scalar_t z) +{ + Identity(); + e[0] = x; + e[5] = y; + e[10] = z; + return *this; +} + +inline matrix4x4 &matrix4x4::BasisChange(const vector3 &u, const vector3 &v, const vector3 &n) +{ + e[0] = u.x; + e[1] = v.x; + e[2] = n.x; + e[3] = 0; + + e[4] = u.y; + e[5] = v.y; + e[6] = n.y; + e[7] = 0; + + e[8] = u.z; + e[9] = v.z; + e[10] = n.z; + e[11] = 0; + + e[12] = 0; + e[13] = 0; + e[14] = 0; + e[15] = 1; + + return *this; +} + +inline matrix4x4 &matrix4x4::BasisChange(const vector3 &v, const vector3 &n) +{ + vector3 u = CrossProduct(v, n); + return BasisChange(u, v, n); +} + +inline matrix4x4 &matrix4x4::ProjectionMatrix(bool perspective, scalar_t left_plane, + scalar_t right_plane, scalar_t top_plane, + scalar_t bottom_plane, scalar_t near_plane, + scalar_t far_plane) +{ + scalar_t A = (right_plane + left_plane) / (right_plane - left_plane); + scalar_t B = (top_plane + bottom_plane) / (top_plane - bottom_plane); + scalar_t C = (far_plane + near_plane) / (far_plane - near_plane); + + Identity(); + if (perspective) + { + e[0] = 2 * near_plane / (right_plane - left_plane); + e[5] = 2 * near_plane / (top_plane - bottom_plane); + e[8] = A; + e[9] = B; + e[10] = C; + e[11] = -1; + e[14] = 2 * far_plane * near_plane / (far_plane - near_plane); + } + else + { + e[0] = 2 / (right_plane - left_plane); + e[5] = 2 / (top_plane - bottom_plane); + e[10] = -2 / (far_plane - near_plane); + e[12] = A; + e[13] = B; + e[14] = C; + } + return *this; +} + +double inline __fastcall SquareMagnitude(const vector3 &v) +{ + return v.x * v.x + v.y * v.y + v.z * v.z; } } // close namespace @@ -454,22 +546,25 @@ double inline __fastcall SquareMagnitude(const vector3& v) #ifdef OSTREAM_MATH3D #include // Streaming support -std::ostream& operator<< (std::ostream& os, const Math3D::vector3& v) { - os << '['; - for (int i=0; i<4; ++i) - os << ' ' << v[i]; - return os << ']'; +std::ostream &operator<<(std::ostream &os, const Math3D::vector3 &v) +{ + os << '['; + for (int i = 0; i < 4; ++i) + os << ' ' << v[i]; + return os << ']'; } -std::ostream& operator<< (std::ostream& os, const Math3D::matrix4x4& m) { - for (int y=0; y<4; ++y) { - os << '['; - for (int x=0;x<4;++x) - os << ' ' << m[x][y]; - os << " ]" << std::endl; - } - return os; +std::ostream &operator<<(std::ostream &os, const Math3D::matrix4x4 &m) +{ + for (int y = 0; y < 4; ++y) + { + os << '['; + for (int x = 0; x < 4; ++x) + os << ' ' << m[x][y]; + os << " ]" << std::endl; + } + return os; } -#endif // OSTREAM_MATH3D +#endif // OSTREAM_MATH3D #endif diff --git a/geometry.cpp b/geometry.cpp index 2a4b517d..f1af70bf 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -4,113 +4,97 @@ #include "Geometry.h" -inline double __fastcall sqr(double a) { return ( a*a ); }; +inline double __fastcall sqr(double a) { return (a * a); }; -__fastcall TLine::TLine() -{ -}; +__fastcall TLine::TLine(){}; __fastcall TLine::TLine(vector3 NPoint, vector3 NVector) { - Vector= NVector; Point= NPoint; + Vector = NVector; + Point = NPoint; }; -__fastcall TLine::~TLine() -{ -}; +__fastcall TLine::~TLine(){}; -TPlane __fastcall TLine::GetPlane() -{ - return(TPlane(Point,Vector)); -}; +TPlane __fastcall TLine::GetPlane() { return (TPlane(Point, Vector)); }; double __fastcall TLine::GetDistance(vector3 Point1) { - return ( (sqr((Point1.x-Point.x)*Vector.x-(Point1.y-Point.y)*Vector.y)- - sqr((Point1.y-Point.y)*Vector.y-(Point1.z-Point.z)*Vector.z)- - sqr((Point1.z-Point.z)*Vector.z-(Point1.x-Point.x)*Vector.x))/ - (sqr(Vector.x)+sqr(Vector.y)+sqr(Vector.z)) ); + return ((sqr((Point1.x - Point.x) * Vector.x - (Point1.y - Point.y) * Vector.y) - + sqr((Point1.y - Point.y) * Vector.y - (Point1.z - Point.z) * Vector.z) - + sqr((Point1.z - Point.z) * Vector.z - (Point1.x - Point.x) * Vector.x)) / + (sqr(Vector.x) + sqr(Vector.y) + sqr(Vector.z))); ; - - }; //--------------------------------------------------------------------------- __fastcall TPlane::TPlane() { - Vector= vector3(0,0,0); - d= 0; + Vector = vector3(0, 0, 0); + d = 0; }; __fastcall TPlane::TPlane(vector3 NVector, double nd) { - Vector= NVector; d= nd; + Vector = NVector; + d = nd; } __fastcall TPlane::TPlane(vector3 Point, vector3 NVector) { - Vector= NVector; d= -NVector.x*Point.x-NVector.y*Point.y-NVector.z*Point.z; + Vector = NVector; + d = -NVector.x * Point.x - NVector.y * Point.y - NVector.z * Point.z; }; -__fastcall TPlane::TPlane(vector3 Point1, vector3 Vector1, vector3 Vector2) +__fastcall TPlane::TPlane(vector3 Point1, vector3 Vector1, vector3 Vector2) { - Vector= CrossProduct(Vector1,Vector2); d= -Vector.x*Point1.x-Vector.y*Point1.y-Vector.z*Point1.z; + Vector = CrossProduct(Vector1, Vector2); + d = -Vector.x * Point1.x - Vector.y * Point1.y - Vector.z * Point1.z; }; -__fastcall TPlane::~TPlane() -{ -}; +__fastcall TPlane::~TPlane(){}; void __fastcall TPlane::Normalize() { - double mgn= Vector.Length(); - Vector= Vector/mgn; d/= mgn; + double mgn = Vector.Length(); + Vector = Vector / mgn; + d /= mgn; }; double __fastcall TPlane::GetSide(vector3 Point) { - return (Vector.x*Point.x+Vector.y*Point.y+Vector.z*Point.z+d); + return (Vector.x * Point.x + Vector.y * Point.y + Vector.z * Point.z + d); }; -//void __fastcall TPlane::Transform(D3DMATRIX &Transformations) +// void __fastcall TPlane::Transform(D3DMATRIX &Transformations) //{ // vector3 src= Vector; // D3DMath_VectorMatrixMultiply(Vector,src,Transformations); //}; -bool __fastcall TPlane::Defined() -{ - return !(Vector==vector3(0,0,0)); -}; +bool __fastcall TPlane::Defined() { return !(Vector == vector3(0, 0, 0)); }; //--------------------------------------------------------------------------- -inline double __fastcall Sum(vector3 &Vector) -{ - return( Vector.x+Vector.y+Vector.z ); -}; - +inline double __fastcall Sum(vector3 &Vector) { return (Vector.x + Vector.y + Vector.z); }; bool __fastcall CrossPoint(vector3 &RetPoint, TLine &Line, TPlane &Plane) { - double ro= DotProduct(Plane.Vector,Line.Vector); - if (ro==0) - return( false ); - ro= (DotProduct(Plane.Vector,Line.Point)+Plane.d)/ro; - RetPoint= Line.Point-(Line.Vector*ro); - return( true ); + double ro = DotProduct(Plane.Vector, Line.Vector); + if (ro == 0) + return (false); + ro = (DotProduct(Plane.Vector, Line.Point) + Plane.d) / ro; + RetPoint = Line.Point - (Line.Vector * ro); + return (true); }; -inline double __fastcall GetLength(vector3& Vector) -{ - return ( Vector.Length() ); -}; +inline double __fastcall GetLength(vector3 &Vector) { return (Vector.Length()); }; -inline vector3 __fastcall SetLength(vector3& Vector, double Length) +inline vector3 __fastcall SetLength(vector3 &Vector, double Length) { Vector.Normalize(); - return ( Vector*Length ); + return (Vector * Length); }; //--------------------------------------------------------------------------- //#pragma package(smart_init) diff --git a/geometry.h b/geometry.h index 0c0f4497..3b58f0a9 100644 --- a/geometry.h +++ b/geometry.h @@ -11,7 +11,7 @@ class TPlane; class TLine { -public: + public: vector3 Vector, Point; __fastcall TLine(); __fastcall TLine(vector3 NPoint, vector3 NVector); @@ -24,17 +24,17 @@ public: class TPlane { -public: + public: vector3 Vector; double d; __fastcall TPlane(); __fastcall TPlane(vector3 NVector, double nd); __fastcall TPlane(vector3 NPoint, vector3 NVector); - __fastcall TPlane(vector3 Point1, vector3 Vector1, vector3 Vector2); + __fastcall TPlane(vector3 Point1, vector3 Vector1, vector3 Vector2); __fastcall ~TPlane(); void __fastcall Normalize(); double __fastcall GetSide(vector3 Point); -// void __fastcall Transform(D3DMATRIX &Transformations); + // void __fastcall Transform(D3DMATRIX &Transformations); bool __fastcall Defined(); }; diff --git a/parser.cpp b/parser.cpp index 548d15a6..6c33b838 100644 --- a/parser.cpp +++ b/parser.cpp @@ -10,185 +10,192 @@ */ - ///////////////////////////////////////////////////////////////////////////////////////////////////// // cParser -- generic class for parsing text data. // constructors -cParser::cParser(std::string Stream,buffertype Type,std::string Path,bool tr) +cParser::cParser(std::string Stream, buffertype Type, std::string Path, bool tr) { - LoadTraction=tr; - // build comments map - mComments.insert(commentmap::value_type("/*","*/")); - mComments.insert(commentmap::value_type("//","\n")); - //mComments.insert(commentmap::value_type("--","\n")); //Ra: to chyba nie używane - // store to calculate sub-sequent includes from relative path - mPath=Path; - // reset pointers and attach proper type of buffer - switch (Type) - { - case buffer_FILE: - Path.append(Stream); - mStream=new std::ifstream(Path.c_str()); - break; - case buffer_TEXT: - mStream=new std::istringstream(Stream); - break; - default: - mStream=NULL; - } - mIncludeParser=NULL; - // calculate stream size - if (mStream) - { - mSize=mStream->rdbuf()->pubseekoff(0,std::ios_base::end); - mStream->rdbuf()->pubseekoff(0,std::ios_base::beg); - } - else - mSize=0; + LoadTraction = tr; + // build comments map + mComments.insert(commentmap::value_type("/*", "*/")); + mComments.insert(commentmap::value_type("//", "\n")); + // mComments.insert(commentmap::value_type("--","\n")); //Ra: to chyba nie używane + // store to calculate sub-sequent includes from relative path + mPath = Path; + // reset pointers and attach proper type of buffer + switch (Type) + { + case buffer_FILE: + Path.append(Stream); + mStream = new std::ifstream(Path.c_str()); + break; + case buffer_TEXT: + mStream = new std::istringstream(Stream); + break; + default: + mStream = NULL; + } + mIncludeParser = NULL; + // calculate stream size + if (mStream) + { + mSize = mStream->rdbuf()->pubseekoff(0, std::ios_base::end); + mStream->rdbuf()->pubseekoff(0, std::ios_base::beg); + } + else + mSize = 0; } // destructor cParser::~cParser() { - if (mIncludeParser) delete mIncludeParser; - if (mStream) delete mStream; - mComments.clear(); + if (mIncludeParser) + delete mIncludeParser; + if (mStream) + delete mStream; + mComments.clear(); } // methods -bool cParser::getTokens(int Count,bool ToLower,const char* Break) +bool cParser::getTokens(int Count, bool ToLower, const char *Break) { -/* - if (LoadTraction==true) - trtest="niemaproblema"; //wczytywać - else - trtest="x"; //nie wczytywać -*/ - int i; - this->str(""); - this->clear(); - for (i=0;istr(string); - else - { - std::string temp=this->str(); - temp.append("\n"); - temp.append(string); - this->str(temp); - } - } - if (istr(""); + this->clear(); + for (i = 0; i < Count; ++i) + { + std::string string = readToken(ToLower, Break); + // collect parameters + if (i == 0) + this->str(string); + else + { + std::string temp = this->str(); + temp.append("\n"); + temp.append(string); + this->str(temp); + } + } + if (i < Count) + return false; + else + return true; } -std::string cParser::readToken(bool ToLower,const char* Break) +std::string cParser::readToken(bool ToLower, const char *Break) { - std::string token=""; - size_t pos; //początek podmienianego ciągu - // see if there's include parsing going on. clean up when it's done. - if (mIncludeParser) - { - token=(*mIncludeParser).readToken(ToLower,Break); - if (!token.empty()) - {pos=token.find("(p"); - // check if the token is a parameter which should be replaced with stored true value - if (pos!=std::string::npos) //!=npos to znalezione - { - std::string parameter=token.substr(pos+2,token.find(")",pos)-pos+2); //numer parametru - token.erase(pos,token.find(")",pos)-pos+1); //najpierw usunięcie "(pN)" - size_t nr=atoi(parameter.c_str())-1; - if (nrpeek()!=EOF&& strchr( Break, c = mStream->get() ) == NULL) - { - if (ToLower) c=tolower(c); - token+=c; - if (trimComments(token)) // don't glue together words separated with comment - break; - } - } while (token=="" && mStream->peek()!=EOF); // double check to deal with trailing spaces - // launch child parser if include directive found. - // NOTE: parameter collecting uses default set of token separators. - 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 - std::string parameter=readToken(false); //w parametrach nie zmniejszamy - while (parameter.compare("end")!=0) - { - parameters.push_back(parameter); - parameter=readToken(ToLower); - } - //if (trtest2.find("tr/")!=0) - mIncludeParser=new cParser(includefile,buffer_FILE,mPath,LoadTraction); - if (mIncludeParser->mSize<=0) - ErrorLog("Missed include: "+AnsiString(includefile.c_str())); - } - else - while (token.compare("end")!=0) - token=readToken(ToLower); - token=readToken(ToLower,Break); - } - return token; + // get the token yourself if there's no child to delegate it to. + char c; + do + { + while (mStream->peek() != EOF && strchr(Break, c = mStream->get()) == NULL) + { + if (ToLower) + c = tolower(c); + token += c; + if (trimComments(token)) // don't glue together words separated with comment + break; + } + } while (token == "" && mStream->peek() != EOF); // double check to deal with trailing spaces + // launch child parser if include directive found. + // NOTE: parameter collecting uses default set of token separators. + 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 + std::string parameter = readToken(false); // w parametrach nie zmniejszamy + while (parameter.compare("end") != 0) + { + parameters.push_back(parameter); + parameter = readToken(ToLower); + } + // if (trtest2.find("tr/")!=0) + mIncludeParser = new cParser(includefile, buffer_FILE, mPath, LoadTraction); + if (mIncludeParser->mSize <= 0) + ErrorLog("Missed include: " + AnsiString(includefile.c_str())); + } + else + while (token.compare("end") != 0) + token = readToken(ToLower); + token = readToken(ToLower, Break); + } + return token; } bool cParser::trimComments(std::string &String) { - for (commentmap::iterator cmIt=mComments.begin();cmIt!=mComments.end();++cmIt) - { - if (String.find((*cmIt).first)!=std::string::npos) - { - readComment((*cmIt).second); - String.resize(String.find((*cmIt).first)); - return true; - } - } - return false; + for (commentmap::iterator cmIt = mComments.begin(); cmIt != mComments.end(); ++cmIt) + { + if (String.find((*cmIt).first) != std::string::npos) + { + readComment((*cmIt).second); + String.resize(String.find((*cmIt).first)); + return true; + } + } + return false; } std::string cParser::readComment(const std::string Break) -{//pobieranie znaków aż do znalezienia znacznika końca - std::string token=""; - while (mStream->peek()!=EOF) - {//o ile nie koniec pliku - token+=mStream->get(); //pobranie znaku - if (token.find(Break)!=std::string::npos) //szukanie znacznika końca - break; - } - return token; +{ // pobieranie znaków aż do znalezienia znacznika końca + std::string token = ""; + while (mStream->peek() != EOF) + { // o ile nie koniec pliku + token += mStream->get(); // pobranie znaku + if (token.find(Break) != std::string::npos) // szukanie znacznika końca + break; + } + return token; } int cParser::getProgress() const { - return mStream->rdbuf()->pubseekoff( 0, std::ios_base::cur ) * 100 / mSize; + return mStream->rdbuf()->pubseekoff(0, std::ios_base::cur) * 100 / mSize; } - diff --git a/parser.h b/parser.h index e14573cb..e4d0e524 100644 --- a/parser.h +++ b/parser.h @@ -2,7 +2,7 @@ #if !defined(rainKERNELTEXTPARSER_H_INCLUDED) #define rainKERNELTEXTPARSER_H_INCLUDED -#pragma warning ( disable : 4786 ) // 'containers too long for debug' warning +#pragma warning(disable : 4786) // 'containers too long for debug' warning #include #include @@ -16,40 +16,52 @@ class cParser : public std::stringstream { -public: - //parameters: - enum buffertype {buffer_FILE,buffer_TEXT}; - //constructors: - cParser(std::string Stream,buffertype Type=buffer_TEXT,std::string Path="",bool tr=true); - //destructor: - virtual ~cParser(); - //methods: - template - inline void getToken(OutputT& output) {getTokens(); *this >> output;}; - inline void ignoreToken() {readToken();}; - inline void ignoreTokens(int count) {for (int i=0;ieof();}; - bool ok() {return !mStream->fail();}; - bool getTokens(int Count=1,bool ToLower=true,const char* Break="\n\t ;"); - int getProgress() const; // percentage of file processed. - //load traction? - bool LoadTraction; -protected: - // methods: - std::string readToken(bool ToLower=true,const char* Break="\n\t ;"); - std::string readComment(const std::string Break="\n\t ;"); - std::string trtest; - bool trimComments(std::string& String); - // members: - std::istream *mStream; // relevant kind of buffer is attached on creation. - std::string mPath; // path to open stream, for relative path lookups. - int mSize; // size of open stream, for progress report. - typedef std::map commentmap; - commentmap mComments; - cParser *mIncludeParser; // child class to handle include directives. - std::vector parameters; // parameter list for included file. + public: + // parameters: + enum buffertype + { + buffer_FILE, + buffer_TEXT + }; + // constructors: + cParser(std::string Stream, buffertype Type = buffer_TEXT, std::string Path = "", + bool tr = true); + // destructor: + virtual ~cParser(); + // methods: + template inline void getToken(OutputT &output) + { + getTokens(); + *this >> output; + }; + inline void ignoreToken() { readToken(); }; + inline void ignoreTokens(int count) + { + for (int i = 0; i < count; i++) + readToken(); + }; + inline bool expectToken(std::string value) { return readToken() == value; }; + bool eof() { return mStream->eof(); }; + bool ok() { return !mStream->fail(); }; + bool getTokens(int Count = 1, bool ToLower = true, const char *Break = "\n\t ;"); + int getProgress() const; // percentage of file processed. + // load traction? + bool LoadTraction; + + protected: + // methods: + std::string readToken(bool ToLower = true, const char *Break = "\n\t ;"); + std::string readComment(const std::string Break = "\n\t ;"); + std::string trtest; + bool trimComments(std::string &String); + // members: + std::istream *mStream; // relevant kind of buffer is attached on creation. + std::string mPath; // path to open stream, for relative path lookups. + int mSize; // size of open stream, for progress report. + typedef std::map commentmap; + commentmap mComments; + cParser *mIncludeParser; // child class to handle include directives. + std::vector parameters; // parameter list for included file. }; #endif // ..!defined(rainKERNELTEXTPARSER_H_INCLUDED) - diff --git a/sky.cpp b/sky.cpp index 388f2125..e541725e 100644 --- a/sky.cpp +++ b/sky.cpp @@ -1,65 +1,58 @@ //--------------------------------------------------------------------------- -#include "system.hpp" -#include "classes.hpp" +#include "system.hpp" +#include "classes.hpp" #pragma hdrstop #include "sky.h" #include "Globals.h" //--------------------------------------------------------------------------- -GLfloat lightPos[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; +GLfloat lightPos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; -__fastcall TSky::~TSky() -{ -}; - -__fastcall TSky::TSky() -{ -}; +__fastcall TSky::~TSky(){}; +__fastcall TSky::TSky(){}; void __fastcall TSky::Init() { - WriteLog(Global::asSky.c_str()); - WriteLog("init"); - AnsiString asModel; - asModel=Global::asSky; - if ((asModel!="1") && (asModel!="0")) -// { - mdCloud=TModelsManager::GetModel(asModel.c_str()); -// } + WriteLog(Global::asSky.c_str()); + WriteLog("init"); + AnsiString asModel; + asModel = Global::asSky; + if ((asModel != "1") && (asModel != "0")) + // { + mdCloud = TModelsManager::GetModel(asModel.c_str()); + // } }; - void __fastcall TSky::Render() { - if (mdCloud) - {//jeśli jest model nieba - glPushMatrix(); - //glDisable(GL_DEPTH_TEST); - glTranslatef(Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z); - glLightfv(GL_LIGHT0,GL_POSITION,lightPos); - if (Global::bUseVBO) - {//renderowanie z VBO - mdCloud->RaRender(100,0); - mdCloud->RaRenderAlpha(100,0); - } - else - {//renderowanie z Display List - mdCloud->Render(100,0); - mdCloud->RenderAlpha(100,0); - } - //glEnable(GL_DEPTH_TEST); - glClear(GL_DEPTH_BUFFER_BIT); - //glEnable(GL_LIGHTING); - glPopMatrix(); - glLightfv(GL_LIGHT0,GL_POSITION,Global::lightPos); - } + if (mdCloud) + { // jeśli jest model nieba + glPushMatrix(); + // glDisable(GL_DEPTH_TEST); + glTranslatef(Global::pCameraPosition.x, Global::pCameraPosition.y, + Global::pCameraPosition.z); + glLightfv(GL_LIGHT0, GL_POSITION, lightPos); + if (Global::bUseVBO) + { // renderowanie z VBO + mdCloud->RaRender(100, 0); + mdCloud->RaRenderAlpha(100, 0); + } + else + { // renderowanie z Display List + mdCloud->Render(100, 0); + mdCloud->RenderAlpha(100, 0); + } + // glEnable(GL_DEPTH_TEST); + glClear(GL_DEPTH_BUFFER_BIT); + // glEnable(GL_LIGHTING); + glPopMatrix(); + glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos); + } }; - - //--------------------------------------------------------------------------- #pragma package(smart_init) diff --git a/sky.h b/sky.h index 84746e74..72244900 100644 --- a/sky.h +++ b/sky.h @@ -7,13 +7,14 @@ class TSky { -private: - TModel3d *mdCloud; -public: - __fastcall TSky(); - __fastcall ~TSky(); - void __fastcall Init(); - void __fastcall Render(); + private: + TModel3d *mdCloud; + + public: + __fastcall TSky(); + __fastcall ~TSky(); + void __fastcall Init(); + void __fastcall Render(); }; //--------------------------------------------------------------------------- diff --git a/usefull.h b/usefull.h index 44c9de57..7a982fde 100644 --- a/usefull.h +++ b/usefull.h @@ -9,21 +9,35 @@ //#define B2(t) (3*t*t*(1-t)) //#define B3(t) (3*t*(1-t)*(1-t)) //#define B4(t) ((1-t)*(1-t)*(1-t)) -//Ra: to jest mocno nieoptymalne: 10+3*4=22 mnożenia, 6 odejmowań, 3*3=9 dodawań -//Ra: po przeliczeniu współczynników mamy: 3*3=9 mnożeń i 3*3=9 dodawań +// Ra: to jest mocno nieoptymalne: 10+3*4=22 mnożenia, 6 odejmowań, 3*3=9 dodawań +// Ra: po przeliczeniu współczynników mamy: 3*3=9 mnożeń i 3*3=9 dodawań //#define Interpolate(t,p1,cp1,cp2,p2) (B4(t)*p1+B3(t)*cp1+B2(t)*cp2+B1(t)*p2) -//Ra: "delete NULL" nic nie zrobi, więc "if (a!=NULL)" jest zbędne +// Ra: "delete NULL" nic nie zrobi, więc "if (a!=NULL)" jest zbędne //#define SafeFree(a) if (a!=NULL) free(a) -#define SafeDelete(a) { delete (a); a=NULL; } -#define SafeDeleteArray(a) { delete[] (a); a=NULL; } +#define SafeDelete(a) \ + { \ + delete (a); \ + a = NULL; \ + } +#define SafeDeleteArray(a) \ + { \ + delete[](a); \ + a = NULL; \ + } -#define sign(x) ((x)<0?-1:((x)>0?1:0)) +#define sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0)) -#define DegToRad(a) ((M_PI/180.0)*(a)) //(a) w nawiasie, bo może być dodawaniem -#define RadToDeg(r) ((180.0/M_PI)*(r)) +#define DegToRad(a) ((M_PI / 180.0) * (a)) //(a) w nawiasie, bo może być dodawaniem +#define RadToDeg(r) ((180.0 / M_PI) * (r)) -#define Fix(a,b,c) {if (ac) a=c;} +#define Fix(a, b, c) \ + { \ + if (a < b) \ + a = b; \ + if (a > c) \ + a = c; \ + } #define asModelsPath AnsiString("models\\") #define asSceneryPath AnsiString("scenery\\") @@ -33,12 +47,8 @@ #define szTexturePath "textures\\" //#define szDefaultTextureExt ".dds" - - //#define DevelopTime //FIXME //#define EditorMode //--------------------------------------------------------------------------- #endif - - diff --git a/wavread.cpp b/wavread.cpp index 83a491ff..23821fd8 100644 --- a/wavread.cpp +++ b/wavread.cpp @@ -1,7 +1,7 @@ //----------------------------------------------------------------------------- // File: WavRead.cpp // -// Desc: Wave file support for loading and playing Wave files using DirectSound +// Desc: Wave file support for loading and playing Wave files using DirectSound // buffers. // // Copyright (c) 1999 Microsoft Corp. All rights reserved. @@ -9,80 +9,86 @@ #include #include "WavRead.h" - - - //----------------------------------------------------------------------------- // Defines, constants, and global variables //----------------------------------------------------------------------------- -#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } -#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } - - - +#define SAFE_DELETE(p) \ + { \ + if (p) \ + { \ + delete (p); \ + (p) = NULL; \ + } \ + } +#define SAFE_RELEASE(p) \ + { \ + if (p) \ + { \ + (p)->Release(); \ + (p) = NULL; \ + } \ + } //----------------------------------------------------------------------------- // Name: ReadMMIO() // Desc: Support function for reading from a multimedia I/O stream //----------------------------------------------------------------------------- -HRESULT ReadMMIO( HMMIO hmmioIn, MMCKINFO* pckInRIFF, WAVEFORMATEX** ppwfxInfo ) +HRESULT ReadMMIO(HMMIO hmmioIn, MMCKINFO *pckInRIFF, WAVEFORMATEX **ppwfxInfo) { - MMCKINFO ckIn; // chunk info. for general use. - PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. + MMCKINFO ckIn; // chunk info. for general use. + PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. *ppwfxInfo = NULL; - if( ( 0 != mmioDescend( hmmioIn, pckInRIFF, NULL, 0 ) ) ) + if ((0 != mmioDescend(hmmioIn, pckInRIFF, NULL, 0))) return E_FAIL; - if( (pckInRIFF->ckid != FOURCC_RIFF) || - (pckInRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E') ) ) + if ((pckInRIFF->ckid != FOURCC_RIFF) || (pckInRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E'))) return E_FAIL; // Search the input file for for the 'fmt ' chunk. ckIn.ckid = mmioFOURCC('f', 'm', 't', ' '); - if( 0 != mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK) ) + if (0 != mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK)) return E_FAIL; // Expect the 'fmt' chunk to be at least as large as ; // if there are extra parameters at the end, we'll ignore them - if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) ) - return E_FAIL; + if (ckIn.cksize < (LONG)sizeof(PCMWAVEFORMAT)) + return E_FAIL; // Read the 'fmt ' chunk into . - if( mmioRead( hmmioIn, (HPSTR) &pcmWaveFormat, - sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) ) + if (mmioRead(hmmioIn, (HPSTR)&pcmWaveFormat, sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat)) return E_FAIL; // Allocate the waveformatex, but if its not pcm format, read the next // word, and thats how many extra bytes to allocate. - if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM ) + if (pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM) { - if( NULL == ( *ppwfxInfo = new WAVEFORMATEX ) ) + if (NULL == (*ppwfxInfo = new WAVEFORMATEX)) return E_FAIL; // Copy the bytes from the pcm structure to the waveformatex structure - memcpy( *ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat) ); + memcpy(*ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat)); (*ppwfxInfo)->cbSize = 0; } else { // Read in length of extra bytes. WORD cbExtraBytes = 0L; - if( mmioRead( hmmioIn, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) ) + if (mmioRead(hmmioIn, (CHAR *)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD)) return E_FAIL; - *ppwfxInfo = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ]; - if( NULL == *ppwfxInfo ) + *ppwfxInfo = (WAVEFORMATEX *)new CHAR[sizeof(WAVEFORMATEX) + cbExtraBytes]; + if (NULL == *ppwfxInfo) return E_FAIL; // Copy the bytes from the pcm structure to the waveformatex structure - memcpy( *ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat) ); + memcpy(*ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat)); (*ppwfxInfo)->cbSize = cbExtraBytes; // Now, read those extra bytes into the structure, if cbExtraAlloc != 0. - if( mmioRead( hmmioIn, (CHAR*)(((BYTE*)&((*ppwfxInfo)->cbSize))+sizeof(WORD)), - cbExtraBytes ) != cbExtraBytes ) + if (mmioRead(hmmioIn, (CHAR *)(((BYTE *)&((*ppwfxInfo)->cbSize)) + sizeof(WORD)), + cbExtraBytes) != cbExtraBytes) { delete *ppwfxInfo; *ppwfxInfo = NULL; @@ -91,7 +97,7 @@ HRESULT ReadMMIO( HMMIO hmmioIn, MMCKINFO* pckInRIFF, WAVEFORMATEX** ppwfxInfo ) } // Ascend the input file out of the 'fmt ' chunk. - if( 0 != mmioAscend( hmmioIn, &ckIn, 0 ) ) + if (0 != mmioAscend(hmmioIn, &ckIn, 0)) { delete *ppwfxInfo; *ppwfxInfo = NULL; @@ -101,27 +107,24 @@ HRESULT ReadMMIO( HMMIO hmmioIn, MMCKINFO* pckInRIFF, WAVEFORMATEX** ppwfxInfo ) return S_OK; } - - - //----------------------------------------------------------------------------- // Name: WaveOpenFile() // Desc: This function will open a wave input file and prepare it for reading, // so the data can be easily read with WaveReadFile. Returns 0 if // successful, the error code if not. //----------------------------------------------------------------------------- -HRESULT WaveOpenFile( CHAR* strFileName, HMMIO* phmmioIn, WAVEFORMATEX** ppwfxInfo, - MMCKINFO* pckInRIFF ) +HRESULT WaveOpenFile(CHAR *strFileName, HMMIO *phmmioIn, WAVEFORMATEX **ppwfxInfo, + MMCKINFO *pckInRIFF) { HRESULT hr; - HMMIO hmmioIn = NULL; - - if( NULL == ( hmmioIn = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF|MMIO_READ ) ) ) + HMMIO hmmioIn = NULL; + + if (NULL == (hmmioIn = mmioOpen(strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ))) return E_FAIL; - if( FAILED( hr = ReadMMIO( hmmioIn, pckInRIFF, ppwfxInfo ) ) ) + if (FAILED(hr = ReadMMIO(hmmioIn, pckInRIFF, ppwfxInfo))) { - mmioClose( hmmioIn, 0 ); + mmioClose(hmmioIn, 0); return hr; } @@ -130,9 +133,6 @@ HRESULT WaveOpenFile( CHAR* strFileName, HMMIO* phmmioIn, WAVEFORMATEX** ppwfxIn return S_OK; } - - - //----------------------------------------------------------------------------- // Name: WaveStartDataRead() // Desc: Routine has to be called before WaveReadFile as it searches for the @@ -141,88 +141,73 @@ HRESULT WaveOpenFile( CHAR* strFileName, HMMIO* phmmioIn, WAVEFORMATEX** ppwfxIn // moved to a separate routine so there was more control on the chunks // that are before the data chunk, such as 'fact', etc... //----------------------------------------------------------------------------- -HRESULT WaveStartDataRead( HMMIO* phmmioIn, MMCKINFO* pckIn, - MMCKINFO* pckInRIFF ) +HRESULT WaveStartDataRead(HMMIO *phmmioIn, MMCKINFO *pckIn, MMCKINFO *pckInRIFF) { // Seek to the data - if( -1 == mmioSeek( *phmmioIn, pckInRIFF->dwDataOffset + sizeof(FOURCC), - SEEK_SET ) ) + if (-1 == mmioSeek(*phmmioIn, pckInRIFF->dwDataOffset + sizeof(FOURCC), SEEK_SET)) return E_FAIL; // Search the input file for for the 'data' chunk. pckIn->ckid = mmioFOURCC('d', 'a', 't', 'a'); - if( 0 != mmioDescend( *phmmioIn, pckIn, pckInRIFF, MMIO_FINDCHUNK ) ) + if (0 != mmioDescend(*phmmioIn, pckIn, pckInRIFF, MMIO_FINDCHUNK)) return E_FAIL; return S_OK; } - - - //----------------------------------------------------------------------------- // Name: WaveReadFile() // Desc: Reads wave data from the wave file. Make sure we're descended into // the data chunk before calling this function. // hmmioIn - Handle to mmio. -// cbRead - # of bytes to read. +// cbRead - # of bytes to read. // pbDest - Destination buffer to put bytes. // cbActualRead - # of bytes actually read. //----------------------------------------------------------------------------- -HRESULT WaveReadFile( HMMIO hmmioIn, UINT cbRead, BYTE* pbDest, - MMCKINFO* pckIn, UINT* cbActualRead ) +HRESULT WaveReadFile(HMMIO hmmioIn, UINT cbRead, BYTE *pbDest, MMCKINFO *pckIn, UINT *cbActualRead) { - MMIOINFO mmioinfoIn; // current status of + MMIOINFO mmioinfoIn; // current status of *cbActualRead = 0; - if( 0 != mmioGetInfo( hmmioIn, &mmioinfoIn, 0 ) ) + if (0 != mmioGetInfo(hmmioIn, &mmioinfoIn, 0)) return E_FAIL; - + UINT cbDataIn = cbRead; - if( cbDataIn > pckIn->cksize ) - cbDataIn = pckIn->cksize; + if (cbDataIn > pckIn->cksize) + cbDataIn = pckIn->cksize; pckIn->cksize -= cbDataIn; - - for( DWORD cT = 0; cT < cbDataIn; cT++ ) + + for (DWORD cT = 0; cT < cbDataIn; cT++) { // Copy the bytes from the io to the buffer. - if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead ) + if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) { - if( 0 != mmioAdvance( hmmioIn, &mmioinfoIn, MMIO_READ ) ) + if (0 != mmioAdvance(hmmioIn, &mmioinfoIn, MMIO_READ)) return E_FAIL; - if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead ) + if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) return E_FAIL; } // Actual copy. - *((BYTE*)pbDest+cT) = *((BYTE*)mmioinfoIn.pchNext); + *((BYTE *)pbDest + cT) = *((BYTE *)mmioinfoIn.pchNext); mmioinfoIn.pchNext++; } - if( 0 != mmioSetInfo( hmmioIn, &mmioinfoIn, 0 ) ) + if (0 != mmioSetInfo(hmmioIn, &mmioinfoIn, 0)) return E_FAIL; *cbActualRead = cbDataIn; return S_OK; } - - - //----------------------------------------------------------------------------- // Name: CWaveSoundRead() // Desc: Constructs the class //----------------------------------------------------------------------------- -CWaveSoundRead::CWaveSoundRead() -{ - m_pwfx = NULL; -} - - - +CWaveSoundRead::CWaveSoundRead() { m_pwfx = NULL; } //----------------------------------------------------------------------------- // Name: ~CWaveSoundRead() @@ -231,69 +216,51 @@ CWaveSoundRead::CWaveSoundRead() CWaveSoundRead::~CWaveSoundRead() { Close(); - SAFE_DELETE( m_pwfx ); + SAFE_DELETE(m_pwfx); } - - - //----------------------------------------------------------------------------- // Name: Open() // Desc: Opens a wave file for reading //----------------------------------------------------------------------------- -HRESULT CWaveSoundRead::Open( CHAR* strFilename ) +HRESULT CWaveSoundRead::Open(CHAR *strFilename) { - SAFE_DELETE( m_pwfx ); + SAFE_DELETE(m_pwfx); - HRESULT hr; - - if( FAILED( hr = WaveOpenFile( strFilename, &m_hmmioIn, &m_pwfx, &m_ckInRiff ) ) ) + HRESULT hr; + + if (FAILED(hr = WaveOpenFile(strFilename, &m_hmmioIn, &m_pwfx, &m_ckInRiff))) return hr; - if( FAILED( hr = Reset() ) ) + if (FAILED(hr = Reset())) return hr; return hr; } - - - //----------------------------------------------------------------------------- // Name: Reset() -// Desc: Resets the internal m_ckIn pointer so reading starts from the -// beginning of the file again +// Desc: Resets the internal m_ckIn pointer so reading starts from the +// beginning of the file again //----------------------------------------------------------------------------- -HRESULT CWaveSoundRead::Reset() -{ - return WaveStartDataRead( &m_hmmioIn, &m_ckIn, &m_ckInRiff ); -} - - - +HRESULT CWaveSoundRead::Reset() { return WaveStartDataRead(&m_hmmioIn, &m_ckIn, &m_ckInRiff); } //----------------------------------------------------------------------------- // Name: Read() // Desc: Reads a wave file into a pointer and returns how much read // using m_ckIn to determine where to start reading from //----------------------------------------------------------------------------- -HRESULT CWaveSoundRead::Read( UINT nSizeToRead, BYTE* pbData, UINT* pnSizeRead ) +HRESULT CWaveSoundRead::Read(UINT nSizeToRead, BYTE *pbData, UINT *pnSizeRead) { - return WaveReadFile( m_hmmioIn, nSizeToRead, pbData, &m_ckIn, pnSizeRead ); + return WaveReadFile(m_hmmioIn, nSizeToRead, pbData, &m_ckIn, pnSizeRead); } - - - //----------------------------------------------------------------------------- // Name: Close() -// Desc: Closes an open wave file +// Desc: Closes an open wave file //----------------------------------------------------------------------------- HRESULT CWaveSoundRead::Close() { - mmioClose( m_hmmioIn, 0 ); + mmioClose(m_hmmioIn, 0); return S_OK; } - - - diff --git a/wavread.h b/wavread.h index 7f7fe460..98dae891 100644 --- a/wavread.h +++ b/wavread.h @@ -9,17 +9,13 @@ #ifndef WAVE_READ_H #define WAVE_READ_H - #include #include - -HRESULT WaveOpenFile( CHAR* strFileName, HMMIO* phmmioIn, WAVEFORMATEX** ppwfxInfo, - MMCKINFO* pckInRIFF ); -HRESULT WaveStartDataRead( HMMIO* phmmioIn, MMCKINFO* pckIn, - MMCKINFO* pckInRIFF ); -HRESULT WaveReadFile( HMMIO hmmioIn, UINT cbRead, BYTE* pbDest, - MMCKINFO* pckIn, UINT* cbActualRead ); +HRESULT WaveOpenFile(CHAR *strFileName, HMMIO *phmmioIn, WAVEFORMATEX **ppwfxInfo, + MMCKINFO *pckInRIFF); +HRESULT WaveStartDataRead(HMMIO *phmmioIn, MMCKINFO *pckIn, MMCKINFO *pckInRIFF); +HRESULT WaveReadFile(HMMIO hmmioIn, UINT cbRead, BYTE *pbDest, MMCKINFO *pckIn, UINT *cbActualRead); //----------------------------------------------------------------------------- // Name: class CWaveSoundRead @@ -27,25 +23,20 @@ HRESULT WaveReadFile( HMMIO hmmioIn, UINT cbRead, BYTE* pbDest, //----------------------------------------------------------------------------- class CWaveSoundRead { -public: - WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure - HMMIO m_hmmioIn; // MM I/O handle for the WAVE - MMCKINFO m_ckIn; // Multimedia RIFF chunk - MMCKINFO m_ckInRiff; // Use in opening a WAVE file + public: + WAVEFORMATEX *m_pwfx; // Pointer to WAVEFORMATEX structure + HMMIO m_hmmioIn; // MM I/O handle for the WAVE + MMCKINFO m_ckIn; // Multimedia RIFF chunk + MMCKINFO m_ckInRiff; // Use in opening a WAVE file -public: + public: CWaveSoundRead(); ~CWaveSoundRead(); - HRESULT Open( CHAR* strFilename ); + HRESULT Open(CHAR *strFilename); HRESULT Reset(); - HRESULT Read( UINT nSizeToRead, BYTE* pbData, UINT* pnSizeRead ); + HRESULT Read(UINT nSizeToRead, BYTE *pbData, UINT *pnSizeRead); HRESULT Close(); - }; - #endif WAVE_READ_H - - -