16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-23 16:49:18 +02:00

continued refactoring: traction, events, event launchers, sounds; additional diagnostics timers, minor performance enhancements and bug fixes

This commit is contained in:
tmj-fstate
2017-10-14 03:53:13 +02:00
parent a12b84f50f
commit 09dbb3c639
23 changed files with 921 additions and 484 deletions

View File

@@ -2985,20 +2985,27 @@ void TController::RecognizeCommand()
c->Command = ""; // usunięcie obsłużonej komendy c->Command = ""; // usunięcie obsłużonej komendy
} }
void TController::PutCommand(std::string NewCommand, double NewValue1, double NewValue2, void TController::PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation, TStopReason reason)
const TLocation &NewLocation, TStopReason reason)
{ // wysłanie komendy przez event PutValues, jak pojazd ma obsadę, to wysyła tutaj, a nie do pojazdu { // wysłanie komendy przez event PutValues, jak pojazd ma obsadę, to wysyła tutaj, a nie do pojazdu
// bezpośrednio // bezpośrednio
#ifdef EU07_USE_OLD_GROUNDCODE
vector3 sl; vector3 sl;
sl.x = -NewLocation.X; // zamiana na współrzędne scenerii sl.x = -NewLocation.X; // zamiana na współrzędne scenerii
sl.z = NewLocation.Y; sl.z = NewLocation.Y;
sl.y = NewLocation.Z; sl.y = NewLocation.Z;
#else
// zamiana na współrzędne scenerii
glm::dvec3 sl { -NewLocation.X, NewLocation.Y, NewLocation.Z };
#endif
if (!PutCommand(NewCommand, NewValue1, NewValue2, &sl, reason)) if (!PutCommand(NewCommand, NewValue1, NewValue2, &sl, reason))
mvOccupied->PutCommand(NewCommand, NewValue1, NewValue2, NewLocation); mvOccupied->PutCommand(NewCommand, NewValue1, NewValue2, NewLocation);
} }
bool TController::PutCommand(std::string NewCommand, double NewValue1, double NewValue2, #ifdef EU07_USE_OLD_GROUNDCODE
const vector3 *NewLocation, TStopReason reason) bool TController::PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const vector3 *NewLocation, TStopReason reason)
#else
bool TController::PutCommand( std::string NewCommand, double NewValue1, double NewValue2, glm::dvec3 const *NewLocation, TStopReason reason )
#endif
{ // analiza komendy { // analiza komendy
if (NewCommand == "CabSignal") if (NewCommand == "CabSignal")
{ // SHP wyzwalane jest przez człon z obsadą, ale obsługiwane przez silnikowy { // SHP wyzwalane jest przez człon z obsadą, ale obsługiwane przez silnikowy
@@ -4229,13 +4236,12 @@ TController::UpdateSituation(double dt) {
~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders ~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders
if (fabs(VelSignal) >= if (fabs(VelSignal) >=
1.0) // 0.1 nie wysyła się do samochodow, bo potem nie ruszą 1.0) // 0.1 nie wysyła się do samochodow, bo potem nie ruszą
PutCommand("SetVelocity", VelSignal, VelNext, PutCommand("SetVelocity", VelSignal, VelNext, nullptr); // komenda robi dodatkowe operacje
NULL); // komenda robi dodatkowe operacje
break; break;
case cm_ShuntVelocity: // od wersji 357 Tm nie budzi wyłączonej lokomotywy case cm_ShuntVelocity: // od wersji 357 Tm nie budzi wyłączonej lokomotywy
if (!(OrderList[OrderPos] & if (!(OrderList[OrderPos] &
~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders ~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders
PutCommand("ShuntVelocity", VelSignal, VelNext, NULL); PutCommand("ShuntVelocity", VelSignal, VelNext, nullptr);
else if (iCoupler) // jeśli jedzie w celu połączenia else if (iCoupler) // jeśli jedzie w celu połączenia
SetVelocity(VelSignal, VelNext); SetVelocity(VelSignal, VelNext);
break; break;
@@ -5306,7 +5312,11 @@ TTrack * TController::BackwardTraceRoute(double &fDistance, double &fDirection,
} }
// sprawdzanie zdarzeń semaforów i ograniczeń szlakowych // sprawdzanie zdarzeń semaforów i ograniczeń szlakowych
#ifdef EU07_USE_OLD_GROUNDCODE
void TController::SetProximityVelocity(double dist, double vel, const vector3 *pos) void TController::SetProximityVelocity(double dist, double vel, const vector3 *pos)
#else
void TController::SetProximityVelocity( double dist, double vel, glm::dvec3 const *pos )
#endif
{ // Ra:przeslanie do AI prędkości { // Ra:przeslanie do AI prędkości
/* /*
//!!!! zastąpić prawidłową reakcją AI na SetProximityVelocity !!!! //!!!! zastąpić prawidłową reakcją AI na SetProximityVelocity !!!!
@@ -5318,7 +5328,7 @@ void TController::SetProximityVelocity(double dist, double vel, const vector3 *p
if ((vel<0)?true:dist>0.1*(MoverParameters->Vel*MoverParameters->Vel-vel*vel)+50) if ((vel<0)?true:dist>0.1*(MoverParameters->Vel*MoverParameters->Vel-vel*vel)+50)
{//jeśli jest dalej od umownej drogi hamowania {//jeśli jest dalej od umownej drogi hamowania
*/ */
PutCommand("SetProximityVelocity", dist, vel, pos); PutCommand( "SetProximityVelocity", dist, vel, pos );
/* /*
} }
else else

View File

@@ -313,10 +313,12 @@ private:
public: public:
Mtable::TTrainParameters *Timetable() { Mtable::TTrainParameters *Timetable() {
return TrainParams; }; return TrainParams; };
void PutCommand(std::string NewCommand, double NewValue1, double NewValue2, void PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation, TStopReason reason = stopComm);
const TLocation &NewLocation, TStopReason reason = stopComm); #ifdef EU07_USE_OLD_GROUNDCODE
bool PutCommand(std::string NewCommand, double NewValue1, double NewValue2, bool PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const vector3 *NewLocation, TStopReason reason = stopComm);
const vector3 *NewLocation, TStopReason reason = stopComm); #else
bool PutCommand( std::string NewCommand, double NewValue1, double NewValue2, glm::dvec3 const *NewLocation, TStopReason reason = stopComm );
#endif
void UpdateSituation(double dt); // uruchamiac przynajmniej raz na sekundę void UpdateSituation(double dt); // uruchamiac przynajmniej raz na sekundę
// procedury dotyczace rozkazow dla maszynisty // procedury dotyczace rozkazow dla maszynisty
// uaktualnia informacje o prędkości // uaktualnia informacje o prędkości
@@ -376,7 +378,11 @@ private:
bool BackwardTrackBusy(TTrack *Track); bool BackwardTrackBusy(TTrack *Track);
TEvent *CheckTrackEventBackward(double fDirection, TTrack *Track); TEvent *CheckTrackEventBackward(double fDirection, TTrack *Track);
TTrack *BackwardTraceRoute(double &fDistance, double &fDirection, TTrack *Track, TEvent *&Event); TTrack *BackwardTraceRoute(double &fDistance, double &fDirection, TTrack *Track, TEvent *&Event);
#ifdef EU07_USE_OLD_GROUNDCODE
void SetProximityVelocity(double dist, double vel, const vector3 *pos); void SetProximityVelocity(double dist, double vel, const vector3 *pos);
#else
void SetProximityVelocity( double dist, double vel, glm::dvec3 const *pos );
#endif
TCommandType BackwardScan(); TCommandType BackwardScan();
public: public:

View File

@@ -2613,77 +2613,36 @@ bool TDynamicObject::Update(double dt, double dt1)
NoVoltTime = 0; NoVoltTime = 0;
tmpTraction.TractionVoltage = v; tmpTraction.TractionVoltage = v;
} }
else else {
{ NoVoltTime += dt;
/* if( NoVoltTime > 0.2 ) {
if (MoverParameters->Vel>0.1f) //jeśli jedzie // jeśli brak zasilania dłużej niż 0.2 sekundy (25km/h pod izolatorem daje 0.15s)
if (NoVoltTime==0.0) //tylko przy pierwszym zaniku napięcia // Ra 2F1H: prowizorka, trzeba przechować napięcie, żeby nie wywalało WS pod izolatorem
if (MoverParameters->PantFrontUp||MoverParameters->PantRearUp) if( MoverParameters->Vel > 0.5 ) {
//if // jeśli jedzie
((pants[0].fParamPants->PantTraction>1.0)||(pants[1].fParamPants->PantTraction>1.0)) // Ra 2014-07: doraźna blokada logowania zimnych lokomotyw - zrobić to trzeba inaczej
{//wspomagacz usuwania problemów z siecią if( MoverParameters->PantFrontUp || MoverParameters->PantRearUp )
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 (NoVoltTime>0.02) //tu można ograniczyć czas rozłączenia
// if (DebugModeFlag) //logowanie nie zawsze // if (DebugModeFlag) //logowanie nie zawsze
if ((MoverParameters->Mains) && if( ( MoverParameters->Mains )
((MoverParameters->EngineType != ElectricInductionMotor) && ( ( MoverParameters->EngineType != ElectricInductionMotor )
|| (MoverParameters->GetTrainsetVoltage() < 0.1f))) || ( MoverParameters->GetTrainsetVoltage() < 0.1f ) ) ) {
{ // Ra 15-01: logować tylko, jeśli WS załączony // Ra 15-01: logować tylko, jeśli WS załączony
// yB 16-03: i nie jest to asynchron zasilany z daleka // yB 16-03: i nie jest to asynchron zasilany z daleka
// if (MoverParameters->PantFrontUp&&pants)
// Ra 15-01: bezwzględne współrzędne pantografu nie są dostępne, // Ra 15-01: bezwzględne współrzędne pantografu nie są dostępne,
// więc lepiej się tego nie zaloguje // więc lepiej się tego nie zaloguje
ErrorLog("Voltage loss: by " + MoverParameters->Name + " at " + ErrorLog(
to_string(vPosition.x, 2, 7) + " " + "Bad traction: " + MoverParameters->Name
to_string(vPosition.y, 2, 7) + " " + + " lost power for " + to_string( NoVoltTime, 2 ) + " sec. at "
to_string(vPosition.z, 2, 7) + ", time " + + to_string( glm::dvec3{ vPosition } ) );
to_string(NoVoltTime, 2, 7));
// 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 // Ra 2F1H: nie było sensu wpisywać tu zera po upływie czasu, bo zmienna była
// tymczasowa, a napięcie zerowane od razu // tymczasowa, a napięcie zerowane od razu
tmpTraction.TractionVoltage = 0; // Ra 2013-12: po co tak? 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 else
tmpTraction.TractionVoltage = 0.95 * MoverParameters->EnginePowerSource.MaxVoltage; tmpTraction.TractionVoltage = 0.95 * MoverParameters->EnginePowerSource.MaxVoltage;
@@ -3199,22 +3158,22 @@ bool TDynamicObject::Update(double dt, double dt1)
else if ( ( true == MoverParameters->PantRearUp ) else if ( ( true == MoverParameters->PantRearUp )
&& ( PantDiff < 0.01 ) ) && ( PantDiff < 0.01 ) )
{ {
if ((MoverParameters->PantRearVolt == 0.0) && if( ( MoverParameters->PantRearVolt == 0.0 )
(MoverParameters->PantFrontVolt == 0.0)) && ( MoverParameters->PantFrontVolt == 0.0 ) ) {
sPantUp.Play(vol, 0, MechInside, vPosition); sPantUp.Play( vol, 0, MechInside, vPosition );
if (p->hvPowerWire) // TODO: wyliczyć trzeba prąd przypadający na }
// pantograf i if (p->hvPowerWire) {
// wstawić do GetVoltage() // TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage()
{ MoverParameters->PantRearVolt = p->hvPowerWire->VoltageGet( MoverParameters->Voltage, fPantCurrent );
MoverParameters->PantRearVolt =
p->hvPowerWire->VoltageGet(MoverParameters->Voltage, fPantCurrent);
fCurrent -= fPantCurrent; // taki prąd płynie przez powyższy pantograf fCurrent -= fPantCurrent; // taki prąd płynie przez powyższy pantograf
} }
else else
MoverParameters->PantRearVolt = 0.0; MoverParameters->PantRearVolt = 0.0;
} }
else else {
// Global::iPause ^= 2;
MoverParameters->PantRearVolt = 0.0; MoverParameters->PantRearVolt = 0.0;
}
break; break;
} // pozostałe na razie nie obsługiwane } // pozostałe na razie nie obsługiwane
if( MoverParameters->PantPress > ( if( MoverParameters->PantPress > (
@@ -3281,8 +3240,8 @@ bool TDynamicObject::Update(double dt, double dt1)
p->fAngleU = acos((p->fLenL1 * cos(k) + p->fHoriz) / p->fLenU1); // górne ramię p->fAngleU = acos((p->fLenL1 * cos(k) + p->fHoriz) / p->fLenU1); // górne ramię
// wyliczyć aktualną wysokość z wzoru sinusowego // wyliczyć aktualną wysokość z wzoru sinusowego
// h=a*sin()+b*sin() // h=a*sin()+b*sin()
p->PantWys = p->fLenL1 * sin(k) + p->fLenU1 * sin(p->fAngleU) + // wysokość całości
p->fHeight; // wysokość całości p->PantWys = p->fLenL1 * sin(k) + p->fLenU1 * sin(p->fAngleU) + p->fHeight;
} }
} }
} // koniec pętli po pantografach } // koniec pętli po pantografach
@@ -4438,10 +4397,8 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
// pants[i].fParamPants->vPos.z=0; //niezerowe dla pantografów // pants[i].fParamPants->vPos.z=0; //niezerowe dla pantografów
// asymetrycznych // asymetrycznych
pants[ i ].fParamPants->PantTraction = pants[ i ].fParamPants->PantWys; pants[ i ].fParamPants->PantTraction = pants[ i ].fParamPants->PantWys;
pants[ i ].fParamPants->fWidth = // połowa szerokości ślizgu; jest w "Power: CSW="
0.5 * pants[ i ].fParamPants->fWidth = 0.5 * MoverParameters->EnginePowerSource.CollectorParameters.CSW;
MoverParameters->EnginePowerSource.CollectorParameters
.CSW; // połowa szerokości ślizgu; jest w "Power: CSW="
} }
} }
} }
@@ -4932,7 +4889,12 @@ void TDynamicObject::RadioStop()
if( ( MoverParameters->SecuritySystem.RadioStop ) if( ( MoverParameters->SecuritySystem.RadioStop )
&& ( MoverParameters->Radio ) ) { && ( MoverParameters->Radio ) ) {
// jeśli pojazd ma RadioStop i jest on aktywny // jeśli pojazd ma RadioStop i jest on aktywny
#ifdef EU07_USE_OLD_GROUNDCODE
Mechanik->PutCommand( "Emergency_brake", 1.0, 1.0, &vPosition, stopRadio ); Mechanik->PutCommand( "Emergency_brake", 1.0, 1.0, &vPosition, stopRadio );
#else
// HAX cast until math types unification
Mechanik->PutCommand( "Emergency_brake", 1.0, 1.0, &static_cast<glm::dvec3>(vPosition), stopRadio );
#endif
// add onscreen notification for human driver // add onscreen notification for human driver
// TODO: do it selectively for the 'local' driver once the multiplayer is in // TODO: do it selectively for the 'local' driver once the multiplayer is in
if( false == Mechanik->AIControllFlag ) { if( false == Mechanik->AIControllFlag ) {
@@ -5404,10 +5366,8 @@ vehicle_table::update( double Deltatime, int Iterationcount ) {
for( auto *vehicle : m_items ) { for( auto *vehicle : m_items ) {
// Ra: zmienić warunek na sprawdzanie pantografów w jednej zmiennej: czy pantografy i czy podniesione // Ra: zmienić warunek na sprawdzanie pantografów w jednej zmiennej: czy pantografy i czy podniesione
if( vehicle->MoverParameters->EnginePowerSource.SourceType == CurrentCollector ) { if( vehicle->MoverParameters->EnginePowerSource.SourceType == CurrentCollector ) {
/*
// TODO: re-implement // TODO: re-implement
GetTraction( vehicle ); update_traction( vehicle );
*/
} }
vehicle->MoverParameters->ComputeConstans(); vehicle->MoverParameters->ComputeConstans();
vehicle->CoupleDist(); vehicle->CoupleDist();
@@ -5447,3 +5407,97 @@ vehicle_table::update( double Deltatime, int Iterationcount ) {
} }
*/ */
} }
// legacy method, checks for presence and height of traction wire for specified vehicle
void
vehicle_table::update_traction( TDynamicObject *Vehicle ) {
auto const vFront = glm::make_vec3( Vehicle->VectorFront().getArray() ); // wektor normalny dla płaszczyzny ruchu pantografu
auto const vUp = glm::make_vec3( Vehicle->VectorUp().getArray() ); // wektor pionu pudła (pochylony od pionu na przechyłce)
auto const vLeft = glm::make_vec3( Vehicle->VectorLeft().getArray() ); // wektor odległości w bok (odchylony od poziomu na przechyłce)
auto const position = glm::dvec3 { Vehicle->GetPosition() }; // współrzędne środka pojazdu
for( int pantographindex = 0; pantographindex < Vehicle->iAnimType[ ANIM_PANTS ]; ++pantographindex ) {
// pętla po pantografach
auto pantograph { Vehicle->pants[ pantographindex ].fParamPants };
if( true == (
pantographindex == TMoverParameters::side::front ?
Vehicle->MoverParameters->PantFrontUp :
Vehicle->MoverParameters->PantRearUp ) ) {
// jeśli pantograf podniesiony
auto const pant0 { position + ( vLeft * pantograph->vPos.z ) + ( vUp * pantograph->vPos.y ) + ( vFront * pantograph->vPos.x ) };
if( pantograph->hvPowerWire != nullptr ) {
// jeżeli znamy drut z poprzedniego przebiegu
for( int attempts = 0; attempts < 30; ++attempts ) {
// powtarzane aż do znalezienia odpowiedniego odcinka na liście dwukierunkowej
if( pantograph->hvPowerWire->iLast & 0x3 ) {
// dla ostatniego i przedostatniego przęsła wymuszamy szukanie innego
// nie to, że nie ma, ale trzeba sprawdzić inne
pantograph->hvPowerWire = nullptr;
break;
}
if( pantograph->hvPowerWire->hvParallel ) {
// jeśli przęsło tworzy bieżnię wspólną, to trzeba sprawdzić pozostałe
// nie to, że nie ma, ale trzeba sprawdzić inne
pantograph->hvPowerWire = nullptr;
break;
}
// obliczamy wyraz wolny równania płaszczyzny (to miejsce nie jest odpowienie)
// podstawiamy równanie parametryczne drutu do równania płaszczyzny pantografu
auto const fRaParam =
-( glm::dot( pantograph->hvPowerWire->pPoint1, vFront ) - glm::dot( pant0, vFront ) )
/ glm::dot( pantograph->hvPowerWire->vParametric, vFront );
if( fRaParam < -0.001 ) {
// histereza rzędu 7cm na 70m typowego przęsła daje 1 promil
pantograph->hvPowerWire = pantograph->hvPowerWire->hvNext[ 0 ];
continue;
}
if( fRaParam > 1.001 ) {
pantograph->hvPowerWire = pantograph->hvPowerWire->hvNext[ 1 ];
continue;
}
// jeśli t jest w przedziale, wyznaczyć odległość wzdłuż wektorów vUp i vLeft
// punkt styku płaszczyzny z drutem (dla generatora łuku el.)
auto const vStyk { pantograph->hvPowerWire->pPoint1 + fRaParam * pantograph->hvPowerWire->vParametric };
auto const vGdzie { vStyk - pant0 }; // wektor
// odległość w pionie musi być w zasięgu ruchu "pionowego" pantografu
// musi się mieścić w przedziale ruchu pantografu
auto const fVertical { glm::dot( vGdzie, vUp ) };
// odległość w bok powinna być mniejsza niż pół szerokości pantografu
// to się musi mieścić w przedziale zależnym od szerokości pantografu
auto const fHorizontal { std::abs( glm::dot( vGdzie, vLeft ) ) - pantograph->fWidth };
// jeśli w pionie albo w bok jest za daleko, to dany drut jest nieużyteczny
if( fHorizontal <= 0.0 ) {
// koniec pętli, aktualny drut pasuje
pantograph->PantTraction = fVertical;
break;
}
else {
// the wire is outside contact area and as of now we don't have good detection of parallel sections
// as such there's no guaratee there isn't parallel section present.
// therefore we don't bother checking if the wire is still within range of guide horns
// but simply force area search for potential better option
pantograph->hvPowerWire = nullptr;
break;
}
}
}
if( pantograph->hvPowerWire == nullptr ) {
// look in the region for a suitable traction piece if we don't already have any
simulation::Region->update_traction( Vehicle, pantographindex );
}
if( ( pantograph->hvPowerWire == nullptr )
&& ( false == Global::bLiveTraction ) ) {
// jeśli drut nie znaleziony ale można oszukiwać to dajemy coś tam dla picu
Vehicle->pants[ pantographindex ].fParamPants->PantTraction = 1.4;
}
}
else {
// pantograph is down
pantograph->hvPowerWire = nullptr;
}
}
}

View File

@@ -492,6 +492,9 @@ public:
// legacy method, calculates changes in simulation state over specified time // legacy method, calculates changes in simulation state over specified time
void void
update( double dt, int iter ); update( double dt, int iter );
// legacy method, checks for presence and height of traction wire for specified vehicle
void
update_traction( TDynamicObject *Vehicle );
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -17,36 +17,14 @@ http://mozilla.org/MPL/2.0/.
#include "EvLaunch.h" #include "EvLaunch.h"
#include "Globals.h" #include "Globals.h"
#include "Logs.h" #include "Logs.h"
#include "Usefull.h"
#include "McZapkie/mctools.h"
#include "Event.h" #include "Event.h"
#include "MemCell.h" #include "MemCell.h"
#include "mtable.h"
#include "Timer.h" #include "Timer.h"
#include "parser.h" #include "parser.h"
#include "Console.h" #include "Console.h"
using namespace Mtable;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
TEventLauncher::TEventLauncher()
{ // ustawienie początkowych wartości dla wszystkich zmiennych
iKey = 0;
DeltaTime = -1;
UpdatedTime = 0;
fVal1 = fVal2 = 0;
iHour = iMinute = -1; // takiego czasu nigdy nie będzie
dRadius = 0;
Event1 = Event2 = NULL;
MemCell = NULL;
iCheckMask = 0;
}
void TEventLauncher::Init()
{
}
// encodes expected key in a short, where low byte represents the actual key, // encodes expected key in a short, where low byte represents the actual key,
// and the high byte holds modifiers: 0x1 = shift, 0x2 = ctrl, 0x4 = alt // and the high byte holds modifiers: 0x1 = shift, 0x2 = ctrl, 0x4 = alt
int vk_to_glfw_key( int const Keycode ) { int vk_to_glfw_key( int const Keycode ) {
@@ -145,7 +123,7 @@ bool TEventLauncher::Load(cParser *parser)
return true; return true;
}; };
bool TEventLauncher::Render() bool TEventLauncher::check_conditions()
{ //"renderowanie" wyzwalacza { //"renderowanie" wyzwalacza
bool bCond = false; bool bCond = false;
if (iKey != 0) if (iKey != 0)
@@ -199,13 +177,13 @@ bool TEventLauncher::Render()
return bCond; // sprawdzanie dRadius w Ground.cpp return bCond; // sprawdzanie dRadius w Ground.cpp
} }
bool TEventLauncher::IsGlobal() // sprawdzenie, czy jest globalnym wyzwalaczem czasu
{ // sprawdzenie, czy jest globalnym wyzwalaczem czasu bool TEventLauncher::IsGlobal() const {
if (DeltaTime == 0)
if (iHour >= 0) return ( ( DeltaTime == 0 )
if (iMinute >= 0) && ( iHour >= 0 )
if (dRadius < 0.0) // bez ograniczenia zasięgu && ( iMinute >= 0 )
return true; && ( dRadius < 0.0 ) ); // bez ograniczenia zasięgu
return false;
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -10,32 +10,43 @@ http://mozilla.org/MPL/2.0/.
#pragma once #pragma once
#include <string> #include <string>
#include "Classes.h"
class TEventLauncher #include "Classes.h"
{ #include "scenenode.h"
private:
int iKey; class TEventLauncher : public editor::basic_node {
double DeltaTime;
double UpdatedTime; public:
double fVal1; // constructor
double fVal2; TEventLauncher( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {}
std::string szText; // legacy constructor
int iHour, iMinute; // minuta uruchomienia TEventLauncher() = default;
public:
double dRadius; // methods
bool Load( cParser *parser );
// checks conditions associated with the event. returns: true if the conditions are met
bool check_conditions();
bool IsGlobal() const;
// members
std::string asEvent1Name; std::string asEvent1Name;
std::string asEvent2Name; std::string asEvent2Name;
std::string asMemCellName; std::string asMemCellName;
TEvent *Event1; TEvent *Event1 { nullptr };
TEvent *Event2; TEvent *Event2 { nullptr };
TMemCell *MemCell; TMemCell *MemCell { nullptr };
int iCheckMask; int iCheckMask { 0 };
TEventLauncher(); double dRadius { 0.0 };
void Init();
bool Load(cParser *parser); private:
bool Render(); // members
bool IsGlobal(); int iKey { 0 };
double DeltaTime { -1.0 };
double UpdatedTime { 0.0 };
double fVal1 { 0.0 };
double fVal2 { 0.0 };
std::string szText;
int iHour { -1 };
int iMinute { -1 }; // minuta uruchomienia
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

292
Event.cpp
View File

@@ -727,6 +727,32 @@ event_manager::~event_manager() {
} }
} }
// adds specified event launcher to the list of global launchers
void
event_manager::queue( TEventLauncher *Launcher ) {
m_launcherqueue.emplace_back( Launcher );
}
// legacy method, updates event queues
void
event_manager::update() {
// process currently queued events
CheckQuery();
// test list of global events for possible new additions to the queue
for( auto *launcher : m_launcherqueue ) {
if( true == launcher->check_conditions() ) {
// NOTE: we're presuming global events aren't going to use event2
WriteLog( "Eventlauncher " + launcher->name() );
if( launcher->Event1 ) {
Global::AddToQuery( launcher->Event1, nullptr );
}
}
}
}
// adds provided event to the collection. returns: true on success // adds provided event to the collection. returns: true on success
// TODO: return handle instead of pointer // TODO: return handle instead of pointer
bool bool
@@ -826,7 +852,11 @@ event_manager::AddToQuery( TEvent *Event, TDynamicObject *Owner ) {
for( auto dynamic : Event->Params[ 6 ].asTrack->Dynamics ) { for( auto dynamic : Event->Params[ 6 ].asTrack->Dynamics ) {
Event->Params[ 5 ].asMemCell->PutCommand( Event->Params[ 5 ].asMemCell->PutCommand(
dynamic->Mechanik, dynamic->Mechanik,
#ifdef EU07_USE_OLD_GROUNDCODE
&Event->Params[ 4 ].nGroundNode->pCenter ); &Event->Params[ 4 ].nGroundNode->pCenter );
#else
Event->Params[ 4 ].asLocation );
#endif
} }
//if (DebugModeFlag) //if (DebugModeFlag)
WriteLog( WriteLog(
@@ -924,7 +954,11 @@ event_manager::CheckQuery() {
for( auto dynamic : m_workevent->Params[ 6 ].asTrack->Dynamics ) { for( auto dynamic : m_workevent->Params[ 6 ].asTrack->Dynamics ) {
m_workevent->Params[ 5 ].asMemCell->PutCommand( m_workevent->Params[ 5 ].asMemCell->PutCommand(
dynamic->Mechanik, dynamic->Mechanik,
#ifdef EU07_USE_OLD_GROUNDCODE
&m_workevent->Params[ 4 ].nGroundNode->pCenter ); &m_workevent->Params[ 4 ].nGroundNode->pCenter );
#else
m_workevent->Params[ 4 ].asLocation );
#endif
} }
//if (DebugModeFlag) //if (DebugModeFlag)
WriteLog("Type: UpdateValues & Track command - [" + WriteLog("Type: UpdateValues & Track command - [" +
@@ -950,7 +984,11 @@ event_manager::CheckQuery() {
*/ */
m_workevent->Params[ 9 ].asMemCell->PutCommand( m_workevent->Params[ 9 ].asMemCell->PutCommand(
m_workevent->Activator->Mechanik, m_workevent->Activator->Mechanik,
#ifdef EU07_USE_OLD_GROUNDCODE
&m_workevent->Params[ 8 ].nGroundNode->pCenter ); &m_workevent->Params[ 8 ].nGroundNode->pCenter );
#else
m_workevent->Params[ 8 ].asLocation );
#endif
} }
WriteLog( "Type: GetValues" ); WriteLog( "Type: GetValues" );
break; break;
@@ -1273,263 +1311,263 @@ void
event_manager::InitEvents() { event_manager::InitEvents() {
//łączenie eventów z pozostałymi obiektami //łączenie eventów z pozostałymi obiektami
for( auto *Current : m_events ) { for( auto *event : m_events ) {
switch (Current->Type) { switch( event->Type ) {
case tp_AddValues: // sumowanie wartości case tp_AddValues: // sumowanie wartości
case tp_UpdateValues: { // zmiana wartości case tp_UpdateValues: { // zmiana wartości
auto *cell = simulation::Memory.find( Current->asNodeName ); // nazwa komórki powiązanej z eventem auto *cell = simulation::Memory.find( event->asNodeName ); // nazwa komórki powiązanej z eventem
if( cell != nullptr ) { // McZapkie-100302 if( cell != nullptr ) { // McZapkie-100302
if( Current->iFlags & ( conditional_trackoccupied | conditional_trackfree ) ) { if( event->iFlags & ( conditional_trackoccupied | conditional_trackfree ) ) {
// jeśli chodzi o zajetosc toru (tor może być inny, niż wpisany w komórce) // jeśli chodzi o zajetosc toru (tor może być inny, niż wpisany w komórce)
// nazwa toru ta sama, co nazwa komórki // nazwa toru ta sama, co nazwa komórki
Current->Params[ 9 ].asTrack = simulation::Paths.find( Current->asNodeName ); event->Params[ 9 ].asTrack = simulation::Paths.find( event->asNodeName );
if( Current->Params[ 9 ].asTrack == nullptr ) { if( event->Params[ 9 ].asTrack == nullptr ) {
ErrorLog( "Bad event: track \"" + Current->asNodeName + "\" referenced in event \"" + Current->asName + "\" doesn't exist" ); ErrorLog( "Bad event: track \"" + event->asNodeName + "\" referenced in event \"" + event->asName + "\" doesn't exist" );
} }
} }
Current->Params[ 4 ].asLocation = &( cell->location() ); event->Params[ 4 ].asLocation = &( cell->location() );
Current->Params[ 5 ].asMemCell = cell; // komórka do aktualizacji event->Params[ 5 ].asMemCell = cell; // komórka do aktualizacji
if( Current->iFlags & ( conditional_memcompare ) ) { if( event->iFlags & ( conditional_memcompare ) ) {
// komórka do badania warunku // komórka do badania warunku
Current->Params[ 9 ].asMemCell = cell; event->Params[ 9 ].asMemCell = cell;
} }
if( false == cell->asTrackName.empty() ) { if( false == cell->asTrackName.empty() ) {
// tor powiązany z komórką powiązaną z eventem // tor powiązany z komórką powiązaną z eventem
// tu potrzebujemy wskaźnik do komórki w (tmp) // tu potrzebujemy wskaźnik do komórki w (tmp)
Current->Params[ 6 ].asTrack = simulation::Paths.find( cell->asTrackName ); event->Params[ 6 ].asTrack = simulation::Paths.find( cell->asTrackName );
if( Current->Params[ 6 ].asTrack == nullptr ) { if( event->Params[ 6 ].asTrack == nullptr ) {
ErrorLog( "Bad memcell: track \"" + cell->asTrackName + "\" referenced in memcell \"" + cell->name() + "\" doesn't exist" ); ErrorLog( "Bad memcell: track \"" + cell->asTrackName + "\" referenced in memcell \"" + cell->name() + "\" doesn't exist" );
} }
} }
else { else {
Current->Params[ 6 ].asTrack = nullptr; event->Params[ 6 ].asTrack = nullptr;
} }
} }
else { else {
// nie ma komórki, to nie będzie działał poprawnie // nie ma komórki, to nie będzie działał poprawnie
Current->m_ignored = true; // deaktywacja event->m_ignored = true; // deaktywacja
ErrorLog( "Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: event \"" + event->asName + "\" cannot find memcell \"" + event->asNodeName + "\"" );
} }
break; break;
} }
case tp_LogValues: { case tp_LogValues: {
// skojarzenie z memcell // skojarzenie z memcell
if( Current->asNodeName.empty() ) { // brak skojarzenia daje logowanie wszystkich if( event->asNodeName.empty() ) { // brak skojarzenia daje logowanie wszystkich
Current->Params[ 9 ].asMemCell = nullptr; event->Params[ 9 ].asMemCell = nullptr;
break; break;
} }
} }
case tp_GetValues: case tp_GetValues:
case tp_WhoIs: { case tp_WhoIs: {
auto *cell = simulation::Memory.find( Current->asNodeName ); auto *cell = simulation::Memory.find( event->asNodeName );
if( cell != nullptr ) { if( cell != nullptr ) {
Current->Params[ 8 ].asLocation = &( cell->location() ); event->Params[ 8 ].asLocation = &( cell->location() );
Current->Params[ 9 ].asMemCell = cell; event->Params[ 9 ].asMemCell = cell;
if( ( Current->Type == tp_GetValues ) if( ( event->Type == tp_GetValues )
&& ( cell->IsVelocity() ) ) { && ( cell->IsVelocity() ) ) {
// jeśli odczyt komórki a komórka zawiera komendę SetVelocity albo ShuntVelocity // jeśli odczyt komórki a komórka zawiera komendę SetVelocity albo ShuntVelocity
// to event nie będzie dodawany do kolejki // to event nie będzie dodawany do kolejki
Current->bEnabled = false; event->bEnabled = false;
} }
} }
else { else {
// nie ma komórki, to nie będzie działał poprawnie // nie ma komórki, to nie będzie działał poprawnie
Current->m_ignored = true; // deaktywacja event->m_ignored = true; // deaktywacja
ErrorLog( "Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: event \"" + event->asName + "\" cannot find memcell \"" + event->asNodeName + "\"" );
} }
break; break;
} }
case tp_CopyValues: { case tp_CopyValues: {
// skopiowanie komórki do innej // skopiowanie komórki do innej
auto *cell = simulation::Memory.find( Current->asNodeName ); // komórka docelowa auto *cell = simulation::Memory.find( event->asNodeName ); // komórka docelowa
if( cell != nullptr ) { if( cell != nullptr ) {
Current->Params[ 4 ].asLocation = &( cell->location() ); event->Params[ 4 ].asLocation = &( cell->location() );
Current->Params[ 5 ].asMemCell = cell; // komórka docelowa event->Params[ 5 ].asMemCell = cell; // komórka docelowa
if( false == cell->asTrackName.empty() ) { if( false == cell->asTrackName.empty() ) {
// tor powiązany z komórką powiązaną z eventem // tor powiązany z komórką powiązaną z eventem
// tu potrzebujemy wskaźnik do komórki w (tmp) // tu potrzebujemy wskaźnik do komórki w (tmp)
Current->Params[ 6 ].asTrack = simulation::Paths.find( cell->asTrackName ); event->Params[ 6 ].asTrack = simulation::Paths.find( cell->asTrackName );
if( Current->Params[ 6 ].asTrack == nullptr ) { if( event->Params[ 6 ].asTrack == nullptr ) {
ErrorLog( "Bad memcell: track \"" + cell->asTrackName + "\" referenced in memcell \"" + cell->name() + "\" doesn't exists" ); ErrorLog( "Bad memcell: track \"" + cell->asTrackName + "\" referenced in memcell \"" + cell->name() + "\" doesn't exists" );
} }
} }
else { else {
Current->Params[ 6 ].asTrack = nullptr; event->Params[ 6 ].asTrack = nullptr;
} }
} }
else { else {
ErrorLog( "Bad event: copyvalues event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: copyvalues event \"" + event->asName + "\" cannot find memcell \"" + event->asNodeName + "\"" );
} }
std::string const cellastext { Current->Params[ 9 ].asText }; std::string const cellastext { event->Params[ 9 ].asText };
cell = simulation::Memory.find( Current->Params[ 9 ].asText ); // komórka źódłowa cell = simulation::Memory.find( event->Params[ 9 ].asText ); // komórka źódłowa
SafeDeleteArray( Current->Params[ 9 ].asText ); // usunięcie nazwy komórki SafeDeleteArray( event->Params[ 9 ].asText ); // usunięcie nazwy komórki
if( cell != nullptr ) { if( cell != nullptr ) {
Current->Params[ 8 ].asLocation = &( cell->location() ); event->Params[ 8 ].asLocation = &( cell->location() );
Current->Params[ 9 ].asMemCell = cell; // komórka źródłowa event->Params[ 9 ].asMemCell = cell; // komórka źródłowa
} }
else { else {
ErrorLog( "Bad event: copyvalues event \"" + Current->asName + "\" cannot find memcell \"" + cellastext + "\"" ); ErrorLog( "Bad event: copyvalues event \"" + event->asName + "\" cannot find memcell \"" + cellastext + "\"" );
} }
break; break;
} }
case tp_Animation: { case tp_Animation: {
// animacja modelu // animacja modelu
// retrieve target name parameter // retrieve target name parameter
std::string const cellastext = Current->Params[ 9 ].asText; std::string const cellastext = event->Params[ 9 ].asText;
SafeDeleteArray( Current->Params[ 9 ].asText ); SafeDeleteArray( event->Params[ 9 ].asText );
// egzemplarz modelu do animowania // egzemplarz modelu do animowania
auto *instance = simulation::Instances.find( Current->asNodeName ); auto *instance = simulation::Instances.find( event->asNodeName );
if( instance != nullptr ) { if( instance != nullptr ) {
if( Current->Params[ 0 ].asInt == 4 ) { if( event->Params[ 0 ].asInt == 4 ) {
// model dla całomodelowych animacji // model dla całomodelowych animacji
Current->Params[ 9 ].asModel = instance; event->Params[ 9 ].asModel = instance;
} }
else { else {
// standardowo przypisanie submodelu // standardowo przypisanie submodelu
Current->Params[ 9 ].asAnimContainer = instance->GetContainer( cellastext ); // submodel event->Params[ 9 ].asAnimContainer = instance->GetContainer( cellastext ); // submodel
if( Current->Params[ 9 ].asAnimContainer ) { if( event->Params[ 9 ].asAnimContainer ) {
Current->Params[ 9 ].asAnimContainer->WillBeAnimated(); // oflagowanie animacji event->Params[ 9 ].asAnimContainer->WillBeAnimated(); // oflagowanie animacji
if( Current->Params[ 9 ].asAnimContainer->Event() == nullptr ) { if( event->Params[ 9 ].asAnimContainer->Event() == nullptr ) {
// nie szukać, gdy znaleziony // nie szukać, gdy znaleziony
Current->Params[ 9 ].asAnimContainer->EventAssign( event->Params[ 9 ].asAnimContainer->EventAssign(
FindEvent( Current->asNodeName + "." + cellastext + ":done" ) ); FindEvent( event->asNodeName + "." + cellastext + ":done" ) );
} }
} }
} }
} }
else { else {
ErrorLog( "Bad event: animation event \"" + Current->asName + "\" cannot find model instance \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: animation event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" );
} }
Current->asNodeName = ""; event->asNodeName = "";
break; break;
} }
case tp_Lights: { case tp_Lights: {
// zmiana świeteł modelu // zmiana świeteł modelu
auto *instance = simulation::Instances.find( Current->asNodeName ); auto *instance = simulation::Instances.find( event->asNodeName );
if( instance != nullptr ) if( instance != nullptr )
Current->Params[ 9 ].asModel = instance; event->Params[ 9 ].asModel = instance;
else else
ErrorLog( "Bad event: lights event \"" + Current->asName + "\" cannot find model instance \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: lights event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" );
Current->asNodeName = ""; event->asNodeName = "";
break; break;
} }
case tp_Visible: { case tp_Visible: {
// ukrycie albo przywrócenie obiektu // ukrycie albo przywrócenie obiektu
editor::basic_node *node = simulation::Instances.find( Current->asNodeName ); // najpierw model editor::basic_node *node = simulation::Instances.find( event->asNodeName ); // najpierw model
if( node == nullptr ) { if( node == nullptr ) {
// albo tory? // albo tory?
node = simulation::Paths.find( Current->asNodeName ); node = simulation::Paths.find( event->asNodeName );
} }
if( node == nullptr ) { if( node == nullptr ) {
// może druty? // może druty?
node = simulation::Traction.find( Current->asNodeName ); node = simulation::Traction.find( event->asNodeName );
} }
if( node != nullptr ) if( node != nullptr )
Current->Params[ 9 ].asEditorNode = node; event->Params[ 9 ].asEditorNode = node;
else else
ErrorLog( "Bad event: visibility event \"" + Current->asName + "\" cannot find item \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: visibility event \"" + event->asName + "\" cannot find item \"" + event->asNodeName + "\"" );
Current->asNodeName = ""; event->asNodeName = "";
break; break;
} }
case tp_Switch: { case tp_Switch: {
// przełożenie zwrotnicy albo zmiana stanu obrotnicy // przełożenie zwrotnicy albo zmiana stanu obrotnicy
auto *track = simulation::Paths.find( Current->asNodeName ); auto *track = simulation::Paths.find( event->asNodeName );
if( track != nullptr ) { if( track != nullptr ) {
// dowiązanie toru // dowiązanie toru
if( track->iAction == NULL ) { if( track->iAction == NULL ) {
// jeśli nie jest zwrotnicą ani obrotnicą to będzie się zmieniał stan uszkodzenia // jeśli nie jest zwrotnicą ani obrotnicą to będzie się zmieniał stan uszkodzenia
track->iAction |= 0x100; track->iAction |= 0x100;
} }
Current->Params[ 9 ].asTrack = track; event->Params[ 9 ].asTrack = track;
if( ( Current->Params[ 0 ].asInt == 0 ) if( ( event->Params[ 0 ].asInt == 0 )
&& ( Current->Params[ 2 ].asdouble >= 0.0 ) ) { && ( event->Params[ 2 ].asdouble >= 0.0 ) ) {
// jeśli przełącza do stanu 0 & jeśli jest zdefiniowany dodatkowy ruch iglic // jeśli przełącza do stanu 0 & jeśli jest zdefiniowany dodatkowy ruch iglic
// przesłanie parametrów // przesłanie parametrów
Current->Params[ 9 ].asTrack->Switch( event->Params[ 9 ].asTrack->Switch(
Current->Params[ 0 ].asInt, event->Params[ 0 ].asInt,
Current->Params[ 1 ].asdouble, event->Params[ 1 ].asdouble,
Current->Params[ 2 ].asdouble ); event->Params[ 2 ].asdouble );
} }
} }
else { else {
ErrorLog( "Bad event: switch event \"" + Current->asName + "\" cannot find track \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: switch event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" );
} }
Current->asNodeName = ""; event->asNodeName = "";
break; break;
} }
case tp_Sound: { case tp_Sound: {
// odtworzenie dźwięku // odtworzenie dźwięku
auto *sound = simulation::Sounds.find( Current->asNodeName ); auto *sound = simulation::Sounds.find( event->asNodeName );
if( sound != nullptr ) if( sound != nullptr )
Current->Params[ 9 ].tsTextSound = sound; event->Params[ 9 ].tsTextSound = sound;
else else
ErrorLog( "Bad event: sound event \"" + Current->asName + "\" cannot find static sound \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: sound event \"" + event->asName + "\" cannot find static sound \"" + event->asNodeName + "\"" );
Current->asNodeName = ""; event->asNodeName = "";
break; break;
} }
case tp_TrackVel: { case tp_TrackVel: {
// ustawienie prędkości na torze // ustawienie prędkości na torze
if( false == Current->asNodeName.empty() ) { if( false == event->asNodeName.empty() ) {
auto *track = simulation::Paths.find( Current->asNodeName ); auto *track = simulation::Paths.find( event->asNodeName );
if( track != nullptr ) { if( track != nullptr ) {
// flaga zmiany prędkości toru jest istotna dla skanowania // flaga zmiany prędkości toru jest istotna dla skanowania
track->iAction |= 0x200; track->iAction |= 0x200;
Current->Params[ 9 ].asTrack = track; event->Params[ 9 ].asTrack = track;
} }
else { else {
ErrorLog( "Bad event: track velocity event \"" + Current->asName + "\" cannot find track \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: track velocity event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" );
} }
} }
Current->asNodeName = ""; event->asNodeName = "";
break; break;
} }
case tp_DynVel: { case tp_DynVel: {
// komunikacja z pojazdem o konkretnej nazwie // komunikacja z pojazdem o konkretnej nazwie
if( Current->asNodeName == "activator" ) if( event->asNodeName == "activator" )
Current->Params[ 9 ].asDynamic = nullptr; event->Params[ 9 ].asDynamic = nullptr;
else { else {
auto *vehicle = simulation::Vehicles.find( Current->asNodeName ); auto *vehicle = simulation::Vehicles.find( event->asNodeName );
if( vehicle != nullptr ) if( vehicle != nullptr )
Current->Params[ 9 ].asDynamic = vehicle; event->Params[ 9 ].asDynamic = vehicle;
else else
Error( "Bad event: vehicle velocity event \"" + Current->asName + "\" cannot find vehicle \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: vehicle velocity event \"" + event->asName + "\" cannot find vehicle \"" + event->asNodeName + "\"" );
} }
Current->asNodeName = ""; event->asNodeName = "";
break; break;
} }
case tp_Multiple: { case tp_Multiple: {
std::string cellastext; std::string cellastext;
if( Current->Params[ 9 ].asText != nullptr ) { // przepisanie nazwy do bufora if( event->Params[ 9 ].asText != nullptr ) { // przepisanie nazwy do bufora
cellastext = Current->Params[ 9 ].asText; cellastext = event->Params[ 9 ].asText;
SafeDeleteArray( Current->Params[ 9 ].asText ); SafeDeleteArray( event->Params[ 9 ].asText );
Current->Params[ 9 ].asPointer = nullptr; // zerowanie wskaźnika, aby wykryć brak obeiktu event->Params[ 9 ].asPointer = nullptr; // zerowanie wskaźnika, aby wykryć brak obeiktu
} }
if( Current->iFlags & ( conditional_trackoccupied | conditional_trackfree ) ) { if( event->iFlags & ( conditional_trackoccupied | conditional_trackfree ) ) {
// jeśli chodzi o zajetosc toru // jeśli chodzi o zajetosc toru
Current->Params[ 9 ].asTrack = simulation::Paths.find( cellastext ); event->Params[ 9 ].asTrack = simulation::Paths.find( cellastext );
if( Current->Params[ 9 ].asTrack == nullptr ) { if( event->Params[ 9 ].asTrack == nullptr ) {
ErrorLog( "Bad event: multi-event \"" + Current->asName + "\" cannot find track \"" + cellastext + "\"" ); ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find track \"" + cellastext + "\"" );
Current->iFlags &= ~( conditional_trackoccupied | conditional_trackfree ); // zerowanie flag event->iFlags &= ~( conditional_trackoccupied | conditional_trackfree ); // zerowanie flag
} }
} }
else if( Current->iFlags & ( conditional_memstring | conditional_memval1 | conditional_memval2 ) ) { else if( event->iFlags & ( conditional_memstring | conditional_memval1 | conditional_memval2 ) ) {
// jeśli chodzi o komorke pamieciową // jeśli chodzi o komorke pamieciową
Current->Params[ 9 ].asMemCell = simulation::Memory.find( cellastext ); event->Params[ 9 ].asMemCell = simulation::Memory.find( cellastext );
if( Current->Params[ 9 ].asMemCell == nullptr ) { if( event->Params[ 9 ].asMemCell == nullptr ) {
ErrorLog( "Bad event: multi-event \"" + Current->asName + "\" cannot find memory cell \"" + cellastext + "\"" ); ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find memory cell \"" + cellastext + "\"" );
Current->iFlags &= ~( conditional_memstring | conditional_memval1 | conditional_memval2 ); event->iFlags &= ~( conditional_memstring | conditional_memval1 | conditional_memval2 );
} }
} }
for( int i = 0; i < 8; ++i ) { for( int i = 0; i < 8; ++i ) {
if( Current->Params[ i ].asText != nullptr ) { if( event->Params[ i ].asText != nullptr ) {
cellastext = Current->Params[ i ].asText; cellastext = event->Params[ i ].asText;
SafeDeleteArray( Current->Params[ i ].asText ); SafeDeleteArray( event->Params[ i ].asText );
Current->Params[ i ].asEvent = FindEvent( cellastext ); event->Params[ i ].asEvent = FindEvent( cellastext );
if( Current->Params[ i ].asEvent == nullptr ) { if( event->Params[ i ].asEvent == nullptr ) {
// Ra: tylko w logu informacja o braku // Ra: tylko w logu informacja o braku
ErrorLog( "Bad event: multi-event \"" + Current->asName + "\" cannot find event \"" + cellastext + "\"" ); ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find event \"" + cellastext + "\"" );
} }
} }
} }
@@ -1537,14 +1575,14 @@ event_manager::InitEvents() {
} }
case tp_Voltage: { case tp_Voltage: {
// zmiana napięcia w zasilaczu (TractionPowerSource) // zmiana napięcia w zasilaczu (TractionPowerSource)
if( false == Current->asNodeName.empty() ) { if( false == event->asNodeName.empty() ) {
auto *powersource = simulation::Powergrid.find( Current->asNodeName ); // podłączenie zasilacza auto *powersource = simulation::Powergrid.find( event->asNodeName ); // podłączenie zasilacza
if( powersource != nullptr ) if( powersource != nullptr )
Current->Params[ 9 ].psPower = powersource; event->Params[ 9 ].psPower = powersource;
else else
ErrorLog( "Bad event: voltage event \"" + Current->asName + "\" cannot find power source \"" + Current->asNodeName + "\"" ); ErrorLog( "Bad event: voltage event \"" + event->asName + "\" cannot find power source \"" + event->asNodeName + "\"" );
} }
Current->asNodeName = ""; event->asNodeName = "";
break; break;
} }
case tp_Message: { case tp_Message: {
@@ -1554,7 +1592,37 @@ event_manager::InitEvents() {
} // switch } // switch
if( Current->fDelay < 0 ) { AddToQuery( Current, nullptr ); } if( event->fDelay < 0 ) { AddToQuery( event, nullptr ); }
}
}
// legacy method, initializes event launchers after deserialization from scenario file
void
event_manager::InitLaunchers() {
for( auto *launcher : m_launchers.sequence() ) {
if( launcher->iCheckMask != 0 ) {
if( launcher->asMemCellName != "none" ) {
// jeśli jest powiązana komórka pamięci
launcher->MemCell = simulation::Memory.find( launcher->asMemCellName );
if( launcher->MemCell == nullptr ) {
ErrorLog( "Bad scenario: event launcher \"" + launcher->name() + "\" cannot find memcell \"" + launcher->asMemCellName + "\"" );
}
}
else {
launcher->MemCell = nullptr;
}
}
launcher->Event1 = (
launcher->asEvent1Name != "none" ?
simulation::Events.FindEvent( launcher->asEvent1Name ) :
nullptr );
launcher->Event2 = (
launcher->asEvent2Name != "none" ?
simulation::Events.FindEvent( launcher->asEvent2Name ) :
nullptr );
} }
} }

11
Event.h
View File

@@ -63,7 +63,9 @@ union TParam
{ {
void *asPointer; void *asPointer;
TMemCell *asMemCell; TMemCell *asMemCell;
#ifdef EU07_USE_OLD_GROUNDCODE
TGroundNode *nGroundNode; TGroundNode *nGroundNode;
#endif
editor::basic_node *asEditorNode; editor::basic_node *asEditorNode;
glm::dvec3 const *asLocation; glm::dvec3 const *asLocation;
TTrack *asTrack; TTrack *asTrack;
@@ -125,6 +127,12 @@ public:
// destructor // destructor
~event_manager(); ~event_manager();
// methods // methods
// adds specified event launcher to the list of global launchers
void
queue( TEventLauncher *Launcher );
// legacy method, updates event queues
void
update();
// adds provided event to the collection. returns: true on success // adds provided event to the collection. returns: true on success
// TBD, TODO: return handle to the event // TBD, TODO: return handle to the event
bool bool
@@ -144,6 +152,9 @@ public:
// legacy method, initializes events after deserialization from scenario file // legacy method, initializes events after deserialization from scenario file
void void
InitEvents(); InitEvents();
// legacy method, initializes event launchers after deserialization from scenario file
void
InitLaunchers();
private: private:
// types // types

View File

@@ -190,7 +190,7 @@ void TGroundNode::RenderHidden()
} }
return; return;
case TP_EVLAUNCH: case TP_EVLAUNCH:
if (EvLaunch->Render()) if (EvLaunch->check_conditions())
if ((EvLaunch->dRadius < 0) || (mgn < EvLaunch->dRadius)) if ((EvLaunch->dRadius < 0) || (mgn < EvLaunch->dRadius))
{ {
WriteLog("Eventlauncher " + asName); WriteLog("Eventlauncher " + asName);
@@ -1006,7 +1006,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
} }
} }
break; break;
#endif
case TP_EVLAUNCH: case TP_EVLAUNCH:
parser->getTokens(3); parser->getTokens(3);
*parser *parser
@@ -1018,7 +1017,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
tmp->EvLaunch = new TEventLauncher(); tmp->EvLaunch = new TEventLauncher();
tmp->EvLaunch->Load(parser); tmp->EvLaunch->Load(parser);
break; break;
#ifdef EU07_USE_OLD_GROUNDCODE
case TP_TRACK: case TP_TRACK:
tmp->pTrack = new TTrack( tmp->asName ); tmp->pTrack = new TTrack( tmp->asName );
if (Global::iWriteLogEnabled & 4) if (Global::iWriteLogEnabled & 4)
@@ -1600,7 +1598,6 @@ TEvent * TGround::FindEvent(const std::string &asEventName)
lookup->second : lookup->second :
nullptr ); nullptr );
} }
#endif
void TGround::FirstInit() void TGround::FirstInit()
{ // ustalanie zależności na scenerii przed wczytaniem pojazdów { // ustalanie zależności na scenerii przed wczytaniem pojazdów
@@ -1668,18 +1665,14 @@ void TGround::FirstInit()
WriteLog("InitNormals OK"); WriteLog("InitNormals OK");
#ifdef EU07_USE_OLD_GROUNDCODE
InitTracks(); //łączenie odcinków ze sobą i przyklejanie eventów InitTracks(); //łączenie odcinków ze sobą i przyklejanie eventów
WriteLog("InitTracks OK"); WriteLog("InitTracks OK");
InitTraction(); //łączenie drutów ze sobą InitTraction(); //łączenie drutów ze sobą
WriteLog("InitTraction OK"); WriteLog("InitTraction OK");
InitEvents(); InitEvents();
WriteLog( "InitEvents OK" ); WriteLog( "InitEvents OK" );
#endif
InitLaunchers(); InitLaunchers();
WriteLog("InitLaunchers OK"); WriteLog("InitLaunchers OK");
WriteLog("FirstInit is done"); WriteLog("FirstInit is done");
}; };
@@ -1839,7 +1832,6 @@ bool TGround::Init(std::string File)
} }
else if (str == "event") else if (str == "event")
{ {
#ifdef EU07_USE_OLD_GROUNDCODE
TEvent *tmp = new TEvent(); TEvent *tmp = new TEvent();
tmp->Load(&parser, pOrigin); tmp->Load(&parser, pOrigin);
if (tmp->Type == tp_Unknown) if (tmp->Type == tp_Unknown)
@@ -1904,7 +1896,6 @@ bool TGround::Init(std::string File)
} }
} }
} }
#endif
} }
else if (str == "rotate") else if (str == "rotate")
{ {
@@ -2126,14 +2117,13 @@ bool TGround::Init(std::string File)
if (!bInitDone) if (!bInitDone)
FirstInit(); // jeśli nie było w scenerii FirstInit(); // jeśli nie było w scenerii
#ifdef EU07_USE_OLD_TERRAINCODE
if (Global::pTerrainCompact) if (Global::pTerrainCompact)
TerrainWrite(); // Ra: teraz można zapisać teren w jednym pliku TerrainWrite(); // Ra: teraz można zapisać teren w jednym pliku
#endif
Global::iPause &= ~0x10; // koniec pauzy wczytywania Global::iPause &= ~0x10; // koniec pauzy wczytywania
return true; return true;
} }
#ifdef EU07_USE_OLD_GROUNDCODE
bool TGround::InitEvents() bool TGround::InitEvents()
{ //łączenie eventów z pozostałymi obiektami { //łączenie eventów z pozostałymi obiektami
TGroundNode *tmp, *trk; TGroundNode *tmp, *trk;
@@ -2816,7 +2806,7 @@ void TGround::TrackJoin(TGroundNode *Current)
} }
} }
} }
#ifdef EU07_USE_OLD_GROUNDCODE
// McZapkie-070602: wyzwalacze zdarzen // McZapkie-070602: wyzwalacze zdarzen
bool TGround::InitLaunchers() bool TGround::InitLaunchers()
{ {
@@ -2837,26 +2827,16 @@ bool TGround::InitLaunchers()
} }
else else
EventLauncher->MemCell = nullptr; EventLauncher->MemCell = nullptr;
#ifdef EU07_USE_OLD_GROUNDCODE
EventLauncher->Event1 = ( EventLauncher->asEvent1Name != "none") ? EventLauncher->Event1 = ( EventLauncher->asEvent1Name != "none") ?
FindEvent(EventLauncher->asEvent1Name) : FindEvent(EventLauncher->asEvent1Name) :
nullptr; nullptr;
EventLauncher->Event2 = ( EventLauncher->asEvent2Name != "none") ? EventLauncher->Event2 = ( EventLauncher->asEvent2Name != "none") ?
FindEvent(EventLauncher->asEvent2Name) : FindEvent(EventLauncher->asEvent2Name) :
nullptr; nullptr;
#else
EventLauncher->Event1 = ( EventLauncher->asEvent1Name != "none") ?
simulation::Events.FindEvent(EventLauncher->asEvent1Name) :
nullptr;
EventLauncher->Event2 = ( EventLauncher->asEvent2Name != "none") ?
simulation::Events.FindEvent(EventLauncher->asEvent2Name) :
nullptr;
#endif
} }
return true; return true;
} }
#ifdef EU07_USE_OLD_GROUNDCODE
TTrack * TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude) TTrack * TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude)
{ // wyszukiwanie innego toru kończącego się w (Point) { // wyszukiwanie innego toru kończącego się w (Point)
TTrack *tmp; TTrack *tmp;
@@ -3539,7 +3519,7 @@ TGround::Update_Hidden() {
} }
} }
} }
#endif
// Winger 170204 - szukanie trakcji nad pantografami // Winger 170204 - szukanie trakcji nad pantografami
bool TGround::GetTraction(TDynamicObject *model) bool TGround::GetTraction(TDynamicObject *model)
{ // aktualizacja drutu zasilającego dla każdego pantografu, żeby odczytać napięcie { // aktualizacja drutu zasilającego dla każdego pantografu, żeby odczytać napięcie
@@ -3774,7 +3754,7 @@ bool TGround::GetTraction(TDynamicObject *model)
return true; return true;
}; };
#endif
#ifdef _WINDOWS #ifdef _WINDOWS
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void TGround::Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) void TGround::Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam)

View File

@@ -277,15 +277,13 @@ class TGround
TGround(); TGround();
~TGround(); ~TGround();
void Free(); void Free();
#ifdef EU07_USE_OLD_GROUNDCODE
bool Init( std::string File ); bool Init( std::string File );
void FirstInit(); void FirstInit();
#ifdef EU07_USE_OLD_GROUNDCODE
void InitTracks(); void InitTracks();
void InitTraction(); void InitTraction();
bool InitEvents(); bool InitEvents();
#endif
bool InitLaunchers(); bool InitLaunchers();
#ifdef EU07_USE_OLD_GROUNDCODE
TTrack * FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude); TTrack * FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude);
TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TGroundNode *Exclude); TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TGroundNode *Exclude);
TTraction * TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n); TTraction * TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n);
@@ -295,9 +293,7 @@ class TGround
void UpdatePhys(double dt, int iter); // aktualizacja fizyki stałym krokiem void UpdatePhys(double dt, int iter); // aktualizacja fizyki stałym krokiem
bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS
void Update_Hidden(); // updates invisible elements of the scene void Update_Hidden(); // updates invisible elements of the scene
#endif
bool GetTraction(TDynamicObject *model); bool GetTraction(TDynamicObject *model);
#ifdef EU07_USE_OLD_GROUNDCODE
bool AddToQuery( TEvent *Event, TDynamicObject *Node ); bool AddToQuery( TEvent *Event, TDynamicObject *Node );
bool CheckQuery(); bool CheckQuery();
TGroundNode * DynamicFindAny(std::string const &Name); TGroundNode * DynamicFindAny(std::string const &Name);

View File

@@ -129,7 +129,11 @@ bool TMemCell::Load(cParser *parser)
return true; return true;
} }
#ifdef EU07_USE_OLD_GROUNDCODE
void TMemCell::PutCommand(TController *Mech, vector3 *Loc) void TMemCell::PutCommand(TController *Mech, vector3 *Loc)
#else
void TMemCell::PutCommand( TController *Mech, glm::dvec3 const *Loc )
#endif
{ // wysłanie zawartości komórki do AI { // wysłanie zawartości komórki do AI
if (Mech) if (Mech)
Mech->PutCommand(szText, fValue1, fValue2, Loc); Mech->PutCommand(szText, fValue1, fValue2, Loc);

View File

@@ -37,7 +37,11 @@ class TMemCell : public editor::basic_node {
bool bool
Load(cParser *parser); Load(cParser *parser);
void void
#ifdef EU07_USE_OLD_GROUNDCODE
PutCommand( TController *Mech, Math3D::vector3 *Loc ); PutCommand( TController *Mech, Math3D::vector3 *Loc );
#else
PutCommand( TController *Mech, glm::dvec3 const *Loc );
#endif
bool bool
Compare( std::string const &szTestText, double const fTestValue1, double const fTestValue2, int const CheckMask ); Compare( std::string const &szTestText, double const fTestValue1, double const fTestValue2, int const CheckMask );
std::string const & std::string const &

View File

@@ -108,4 +108,11 @@ protected:
// members // members
type_sequence m_items; type_sequence m_items;
type_map m_itemmap; type_map m_itemmap;
public:
// data access
typename type_sequence &
sequence() {
return m_items; }
}; };

View File

@@ -11,8 +11,9 @@ http://mozilla.org/MPL/2.0/.
#include "Timer.h" #include "Timer.h"
#include "Globals.h" #include "Globals.h"
namespace Timer namespace Timer {
{
subsystem_stopwatches subsystem;
double DeltaTime, DeltaRenderTime; double DeltaTime, DeltaRenderTime;
double fFPS{ 0.0f }; double fFPS{ 0.0f };

36
Timer.h
View File

@@ -9,8 +9,7 @@ http://mozilla.org/MPL/2.0/.
#pragma once #pragma once
namespace Timer namespace Timer {
{
double GetTime(); double GetTime();
@@ -28,6 +27,39 @@ double GetFPS();
void ResetTimers(); void ResetTimers();
void UpdateTimers(bool pause); void UpdateTimers(bool pause);
class stopwatch {
public:
void
start() {
m_start = std::chrono::steady_clock::now(); }
void
stop() {
m_accumulator = 0.95f * m_accumulator + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - m_start ) ).count() / 1000.f; }
float
average() const {
return m_accumulator / 20.f;}
private:
std::chrono::time_point<std::chrono::steady_clock> m_start { std::chrono::steady_clock::now() };
float m_accumulator { 1000.f / 30.f * 20.f }; // 20 last samples, initial 'neutral' rate of 30 fps
};
struct subsystem_stopwatches {
stopwatch gfx_total;
stopwatch gfx_color;
stopwatch gfx_shadows;
stopwatch gfx_reflections;
stopwatch gfx_swap;
stopwatch sim_total;
stopwatch sim_dynamics;
stopwatch sim_events;
stopwatch sim_ai;
};
extern subsystem_stopwatches subsystem;
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -953,6 +953,7 @@ void TWorld::FollowView(bool wycisz) {
bool TWorld::Update() { bool TWorld::Update() {
Timer::UpdateTimers(Global::iPause != 0); Timer::UpdateTimers(Global::iPause != 0);
Timer::subsystem.sim_total.start();
if( (Global::iPause == false) if( (Global::iPause == false)
|| (m_init == false) ) { || (m_init == false) ) {
@@ -1026,6 +1027,7 @@ bool TWorld::Update() {
// this means at count > 20 simulation and render are going to desync. is that right? // this means at count > 20 simulation and render are going to desync. is that right?
// NOTE: experimentally changing this to prevent the desync. // NOTE: experimentally changing this to prevent the desync.
// TODO: test what happens if we hit more than 20 * 0.01 sec slices, i.e. less than 5 fps // TODO: test what happens if we hit more than 20 * 0.01 sec slices, i.e. less than 5 fps
Timer::subsystem.sim_dynamics.start();
#ifdef EU07_USE_OLD_GROUNDCODE #ifdef EU07_USE_OLD_GROUNDCODE
if( true == Global::FullPhysics ) { if( true == Global::FullPhysics ) {
// mixed calculation mode, steps calculated in ~0.05s chunks // mixed calculation mode, steps calculated in ~0.05s chunks
@@ -1067,6 +1069,7 @@ bool TWorld::Update() {
simulation::State.update( stepdeltatime, updatecount ); simulation::State.update( stepdeltatime, updatecount );
} }
#endif #endif
Timer::subsystem.sim_dynamics.stop();
// secondary fixed step simulation time routines // secondary fixed step simulation time routines
while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) { while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) {
@@ -1110,7 +1113,7 @@ bool TWorld::Update() {
Ground.CheckQuery(); Ground.CheckQuery();
Ground.Update_Hidden(); Ground.Update_Hidden();
#else #else
simulation::Events.CheckQuery(); simulation::Events.update();
simulation::Region->update(); simulation::Region->update();
#endif #endif
@@ -1144,6 +1147,8 @@ bool TWorld::Update() {
Update_Camera( dt ); Update_Camera( dt );
Timer::subsystem.sim_total.stop();
GfxRenderer.Update( dt ); GfxRenderer.Update( dt );
ResourceSweep(); ResourceSweep();
@@ -1659,20 +1664,14 @@ TWorld::Update_UI() {
"VBO" : "VBO" :
"Display Lists" ) "Display Lists" )
+ " "; + " ";
// dump last opengl error, if any
GLenum glerror = ::glGetError();
if( glerror != GL_NO_ERROR ) {
std::string glerrorstring( (char *)::gluErrorString( glerror ) );
win1250_to_ascii( glerrorstring );
Global::LastGLError = std::to_string( glerror ) + " (" + glerrorstring + ")";
}
if( false == Global::LastGLError.empty() ) { if( false == Global::LastGLError.empty() ) {
uitextline2 += uitextline2 +=
"Last openGL error: " "Last openGL error: "
+ Global::LastGLError; + Global::LastGLError;
} }
// renderer stats // renderer stats
uitextline3 = GfxRenderer.Info(); uitextline3 = GfxRenderer.info_times();
uitextline4 = GfxRenderer.info_stats();
break; break;
} }
@@ -1683,6 +1682,9 @@ TWorld::Update_UI() {
if( Global::iMultiplayer ) { if( Global::iMultiplayer ) {
uitextline1 += " (multiplayer mode is active)"; uitextline1 += " (multiplayer mode is active)";
} }
uitextline3 =
"vehicles: " + to_string( Timer::subsystem.sim_dynamics.average(), 2 ) + " msec"
+ " update total: " + to_string( Timer::subsystem.sim_total.average(), 2 ) + " msec";
break; break;
} }

View File

@@ -315,23 +315,32 @@ opengl_renderer::Init( GLFWwindow *Window ) {
bool bool
opengl_renderer::Render() { opengl_renderer::Render() {
if( m_drawstart != std::chrono::steady_clock::time_point() ) { Timer::subsystem.gfx_total.stop();
m_drawtime = std::max( 20.f, 0.95f * m_drawtime + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - m_drawstart ) ).count() / 1000.f ); Timer::subsystem.gfx_total.start(); // note: gfx_total is actually frame total, clean this up
} Timer::subsystem.gfx_color.start();
m_drawstart = std::chrono::steady_clock::now();
auto const drawstartcolorpass = m_drawstart;
m_renderpass.draw_mode = rendermode::none; // force setup anew m_renderpass.draw_mode = rendermode::none; // force setup anew
m_debuginfo.clear(); m_debugtimestext.clear();
++m_framestamp; m_debugstats = debug_stats();
Render_pass( rendermode::color ); Render_pass( rendermode::color );
Timer::subsystem.gfx_color.stop();
Timer::subsystem.gfx_swap.start();
glfwSwapBuffers( m_window );
Timer::subsystem.gfx_swap.stop();
m_drawcount = m_cellqueue.size(); m_drawcount = m_cellqueue.size();
// accumulate last 20 frames worth of render time (cap at 1000 fps to prevent calculations going awry) m_debugtimestext
m_drawtimecolorpass = std::max( 20.f, 0.95f * m_drawtimecolorpass + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - drawstartcolorpass ) ).count() / 1000.f ); += "frame: " + to_string( Timer::subsystem.gfx_color.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) "
m_debuginfo += "frame total: " + to_string( m_drawtimecolorpass / 20.f, 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) "; += "gpu side: " + to_string( Timer::subsystem.gfx_swap.average(), 2 ) + " msec "
+= "(" + to_string( Timer::subsystem.gfx_color.average() + Timer::subsystem.gfx_swap.average(), 2 ) + " msec total)";
m_debugstatstext =
"drawcalls: " + to_string( m_debugstats.drawcalls )
+ "; dyn: " + to_string( m_debugstats.dynamics ) + " mod: " + to_string( m_debugstats.models ) + " sub: " + to_string( m_debugstats.submodels )
+ "; trk: " + to_string( m_debugstats.paths ) + " shp: " + to_string( m_debugstats.shapes )
+ " trc: " + to_string( m_debugstats.traction ) + " lin: " + to_string( m_debugstats.lines );
glfwSwapBuffers( m_window ); ++m_framestamp;
return true; // for now always succeed return true; // for now always succeed
} }
@@ -464,7 +473,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
if( World.InitPerformed() ) { if( World.InitPerformed() ) {
// setup // setup
auto const shadowdrawstart = std::chrono::steady_clock::now(); Timer::subsystem.gfx_shadows.start();
::glBindFramebufferEXT( GL_FRAMEBUFFER, m_shadowframebuffer ); ::glBindFramebufferEXT( GL_FRAMEBUFFER, m_shadowframebuffer );
@@ -500,9 +509,8 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
::glDisable( GL_SCISSOR_TEST ); ::glDisable( GL_SCISSOR_TEST );
::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch back to primary render target ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch back to primary render target
Timer::subsystem.gfx_shadows.stop();
m_drawtimeshadowpass = 0.95f * m_drawtimeshadowpass + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - shadowdrawstart ) ).count() / 1000.f; m_debugtimestext += "shadows: " + to_string( Timer::subsystem.gfx_shadows.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) ";
m_debuginfo += "shadows: " + to_string( m_drawtimeshadowpass / 20.f, 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) ";
} }
break; break;
} }
@@ -602,7 +610,7 @@ bool
opengl_renderer::Render_reflections() { opengl_renderer::Render_reflections() {
auto const &time = simulation::Time.data(); auto const &time = simulation::Time.data();
auto const timestamp = time.wDay * 60 * 24 + time.wHour * 60 + time.wMinute; auto const timestamp = time.wDay * 24 * 60 + time.wHour * 60 + time.wMinute;
if( ( timestamp - m_environmentupdatetime < 5 ) if( ( timestamp - m_environmentupdatetime < 5 )
&& ( glm::length( m_renderpass.camera.position() - m_environmentupdatelocation ) < 1000.0 ) ) { && ( glm::length( m_renderpass.camera.position() - m_environmentupdatelocation ) < 1000.0 ) ) {
// run update every 5+ mins of simulation time, or at least 1km from the last location // run update every 5+ mins of simulation time, or at least 1km from the last location
@@ -1477,12 +1485,6 @@ opengl_renderer::Render( TGroundRect *Groundcell ) {
break; break;
} }
} }
#ifdef EU07_USE_OLD_TERRAINCODE
if( Groundcell->nTerrain ) {
Render( Groundcell->nTerrain );
}
#endif
// add the subcells of the cell to the draw queue // add the subcells of the cell to the draw queue
switch( m_renderpass.draw_mode ) { switch( m_renderpass.draw_mode ) {
@@ -1645,16 +1647,7 @@ opengl_renderer::Render( scene::basic_region *Region ) {
Update_Lights( simulation::Lights ); Update_Lights( simulation::Lights );
Render( std::begin( m_sectionqueue ), std::end( m_sectionqueue ) ); Render( std::begin( m_sectionqueue ), std::end( m_sectionqueue ) );
/* // draw queue is filled while rendering sections
// draw queue was filled while rendering content of ground cells. now sort the nodes based on their distance to viewer...
// TODO: move sorting for translucent phase, for opaque geometry render cells in initial order to reduce vbo switching
std::sort(
std::begin( m_cellqueue ),
std::end( m_cellqueue ),
[]( distancecell_pair const &Left, distancecell_pair const &Right ) {
return ( Left.first < Right.first ); } );
*/
// ...then render the opaque content of the visible cells.
Render( std::begin( m_cellqueue ), std::end( m_cellqueue ) ); Render( std::begin( m_cellqueue ), std::end( m_cellqueue ) );
break; break;
} }
@@ -1749,7 +1742,7 @@ opengl_renderer::Render( section_sequence::iterator First, section_sequence::ite
glEnable( GL_LIGHTING ); glEnable( GL_LIGHTING );
#endif #endif
// shapes // shapes
for( auto const &shape : section->m_shapes ) { Render( shape ); } for( auto const &shape : section->m_shapes ) { Render( shape, true ); }
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
} }
@@ -1852,7 +1845,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
glEnable( GL_LIGHTING ); glEnable( GL_LIGHTING );
#endif #endif
// opaque non-instanced shapes // opaque non-instanced shapes
for( auto const &shape : cell->m_shapesopaque ) { Render( shape ); } for( auto const &shape : cell->m_shapesopaque ) { Render( shape, false ); }
// tracks // tracks
// TODO: update after path node refactoring // TODO: update after path node refactoring
for( auto *path : cell->m_paths ) { Render( path ); } for( auto *path : cell->m_paths ) { Render( path ); }
@@ -1871,7 +1864,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
// render // render
// opaque non-instanced shapes // opaque non-instanced shapes
for( auto const &shape : cell->m_shapesopaque ) { Render( shape ); } for( auto const &shape : cell->m_shapesopaque ) { Render( shape, false ); }
// TODO: add other content types // TODO: add other content types
// post-render cleanup // post-render cleanup
@@ -1887,7 +1880,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render // render
// opaque non-instanced shapes // opaque non-instanced shapes
for( auto const &shape : cell->m_shapesopaque ) { Render( shape ); } for( auto const &shape : cell->m_shapesopaque ) { Render( shape, false ); }
// tracks // tracks
// TODO: add path to the node picking list // TODO: add path to the node picking list
for( auto *path : cell->m_paths ) { Render( path ); } for( auto *path : cell->m_paths ) { Render( path ); }
@@ -1922,6 +1915,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
Render( dynamic ); Render( dynamic );
} }
} }
break;
} }
case rendermode::pickscenery: { case rendermode::pickscenery: {
// opaque parts of instanced models // opaque parts of instanced models
@@ -1944,9 +1938,46 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
} }
void void
opengl_renderer::Render( scene::shape_node const &Shape ) { opengl_renderer::Render( scene::shape_node const &Shape, bool const Ignorerange ) {
/*
double distancesquared;
switch( m_renderpass.draw_mode ) {
case rendermode::shadows: {
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
break;
}
default: {
distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
break;
}
}
if( ( distancesquared < Node->fSquareMinRadius )
|| ( distancesquared >= Node->fSquareRadius ) ) {
return false;
}
*/
auto const &data{ Shape.data() };
if( false == Ignorerange ) {
double distancesquared;
switch( m_renderpass.draw_mode ) {
case rendermode::shadows: {
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = SquareMagnitude( ( data.area.center - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
break;
}
default: {
distancesquared = SquareMagnitude( ( data.area.center - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
break;
}
}
if( ( distancesquared < data.rangesquared_min )
|| ( distancesquared >= data.rangesquared_max ) ) {
return;
}
}
auto const &data { Shape.data() };
// setup // setup
Bind_Material( data.material ); Bind_Material( data.material );
switch( m_renderpass.draw_mode ) { switch( m_renderpass.draw_mode ) {
@@ -1971,6 +2002,9 @@ opengl_renderer::Render( scene::shape_node const &Shape ) {
} }
// render // render
m_geometry.draw( data.geometry ); m_geometry.draw( data.geometry );
// debug data
++m_debugstats.shapes;
++m_debugstats.drawcalls;
} }
void void
@@ -2021,19 +2055,7 @@ opengl_renderer::Render( TAnimModel *Instance ) {
bool bool
opengl_renderer::Render( TGroundNode *Node ) { opengl_renderer::Render( TGroundNode *Node ) {
#ifdef EU07_USE_OLD_TERRAINCODE
switch (Node->iType)
{ // obiekty renderowane niezależnie od odległości
case TP_SUBMODEL:
::glPushMatrix();
auto const originoffset = Node->pCenter - m_renderpass.camera.position();
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
TSubModel::fSquareDist = 0;
Render( Node->smTerrain );
::glPopMatrix();
return true;
}
#endif
double distancesquared; double distancesquared;
switch( m_renderpass.draw_mode ) { switch( m_renderpass.draw_mode ) {
case rendermode::shadows: { case rendermode::shadows: {
@@ -2073,6 +2095,9 @@ opengl_renderer::Render( TGroundNode *Node ) {
::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render // render
Render( Node->pTrack ); Render( Node->pTrack );
// debug
++m_debugstats.paths;
++m_debugstats.drawcalls;
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
return true; return true;
@@ -2155,7 +2180,9 @@ opengl_renderer::Render( TGroundNode *Node ) {
} }
// render // render
m_geometry.draw( Node->Piece->geometry ); m_geometry.draw( Node->Piece->geometry );
// debug
// ++m_debugstats.lines;
// ++m_debugstats.drawcalls;
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
@@ -2201,6 +2228,9 @@ opengl_renderer::Render( TGroundNode *Node ) {
} }
// render // render
m_geometry.draw( Node->Piece->geometry ); m_geometry.draw( Node->Piece->geometry );
// debug
++m_debugstats.shapes;
++m_debugstats.drawcalls;
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
@@ -2236,6 +2266,9 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
if( false == Dynamic->renderme ) { if( false == Dynamic->renderme ) {
return false; return false;
} }
// debug data
++m_debugstats.dynamics;
// setup // setup
TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji
glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.camera.position(); glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.camera.position();
@@ -2437,6 +2470,9 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, float c
// render // render
Render( Model->Root ); Render( Model->Root );
// debug data
++m_debugstats.models;
// post-render cleanup // post-render cleanup
return true; return true;
@@ -2468,6 +2504,10 @@ opengl_renderer::Render( TSubModel *Submodel ) {
&& ( TSubModel::fSquareDist >= Submodel->fSquareMinDist ) && ( TSubModel::fSquareDist >= Submodel->fSquareMinDist )
&& ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) { && ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) {
// debug data
++m_debugstats.submodels;
++m_debugstats.drawcalls;
if( Submodel->iFlags & 0xC000 ) { if( Submodel->iFlags & 0xC000 ) {
::glPushMatrix(); ::glPushMatrix();
if( Submodel->fMatrix ) if( Submodel->fMatrix )
@@ -2717,6 +2757,9 @@ opengl_renderer::Render( TTrack *Track ) {
return; return;
} }
++m_debugstats.paths;
++m_debugstats.drawcalls;
switch( m_renderpass.draw_mode ) { switch( m_renderpass.draw_mode ) {
case rendermode::color: case rendermode::color:
case rendermode::reflections: { case rendermode::reflections: {
@@ -2867,7 +2910,7 @@ opengl_renderer::Render_Alpha( cell_sequence::reverse_iterator First, cell_seque
::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render // render
// NOTE: we can reuse the method used to draw opaque geometry // NOTE: we can reuse the method used to draw opaque geometry
for( auto const &shape : cell->m_shapestranslucent ) { Render( shape ); } for( auto const &shape : cell->m_shapestranslucent ) { Render( shape, false ); }
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
} }
@@ -3003,6 +3046,9 @@ opengl_renderer::Render_Alpha( TTraction *Traction ) {
// render // render
m_geometry.draw( Traction->m_geometry ); m_geometry.draw( Traction->m_geometry );
// debug data
++m_debugstats.traction;
++m_debugstats.drawcalls;
} }
#endif #endif
bool bool
@@ -3056,6 +3102,9 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
// render // render
m_geometry.draw( Node->hvTraction->m_geometry ); m_geometry.draw( Node->hvTraction->m_geometry );
// debug data
++m_debugstats.traction;
++m_debugstats.drawcalls;
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
@@ -3116,6 +3165,8 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
// render // render
m_geometry.draw( Node->Piece->geometry ); m_geometry.draw( Node->Piece->geometry );
// ++m_debugstats.lines;
// ++m_debugstats.drawcalls;
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
@@ -3141,7 +3192,9 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
// render // render
m_geometry.draw( Node->Piece->geometry ); m_geometry.draw( Node->Piece->geometry );
// debug data
++m_debugstats.shapes;
++m_debugstats.drawcalls;
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
@@ -3285,6 +3338,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
&& ( TSubModel::fSquareDist >= Submodel->fSquareMinDist ) && ( TSubModel::fSquareDist >= Submodel->fSquareMinDist )
&& ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) { && ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) {
// debug data
++m_debugstats.submodels;
++m_debugstats.drawcalls;
if( Submodel->iFlags & 0xC000 ) { if( Submodel->iFlags & 0xC000 ) {
::glPushMatrix(); ::glPushMatrix();
if( Submodel->fMatrix ) if( Submodel->fMatrix )
@@ -3580,10 +3637,10 @@ opengl_renderer::Update( double const Deltatime ) {
} }
m_updateaccumulator = 0.0; m_updateaccumulator = 0.0;
m_framerate = 1000.f / ( m_drawtime / 20.f ); m_framerate = 1000.f / ( Timer::subsystem.gfx_total.average() );
// adjust draw ranges etc, based on recent performance // adjust draw ranges etc, based on recent performance
auto const framerate = 1000.f / (m_drawtimecolorpass / 20.f); auto const framerate = 1000.f / Timer::subsystem.gfx_color.average();
float targetfactor; float targetfactor;
if( framerate > 90.0 ) { targetfactor = 3.0f; } if( framerate > 90.0 ) { targetfactor = 3.0f; }
@@ -3620,7 +3677,7 @@ opengl_renderer::Update( double const Deltatime ) {
} }
if( true == DebugModeFlag ) { if( true == DebugModeFlag ) {
m_debuginfo += m_textures.info(); m_debugtimestext += m_textures.info();
} }
if( ( true == Global::ControlPicking ) if( ( true == Global::ControlPicking )
@@ -3639,13 +3696,26 @@ opengl_renderer::Update( double const Deltatime ) {
else { else {
m_picksceneryitem = nullptr; m_picksceneryitem = nullptr;
} }
}; // dump last opengl error, if any
auto const glerror = ::glGetError();
if( glerror != GL_NO_ERROR ) {
std::string glerrorstring( ( char * )::gluErrorString( glerror ) );
win1250_to_ascii( glerrorstring );
Global::LastGLError = std::to_string( glerror ) + " (" + glerrorstring + ")";
}
}
// debug performance string // debug performance string
std::string const & std::string const &
opengl_renderer::Info() const { opengl_renderer::info_times() const {
return m_debuginfo; return m_debugtimestext;
}
std::string const &
opengl_renderer::info_stats() const {
return m_debugstatstext;
} }
void void

View File

@@ -203,7 +203,9 @@ public:
Update_Pick_Node(); Update_Pick_Node();
// debug performance string // debug performance string
std::string const & std::string const &
Info() const; info_times() const;
std::string const &
info_stats() const;
// members // members
GLenum static const sunlight{ GL_LIGHT0 }; GLenum static const sunlight{ GL_LIGHT0 };
@@ -227,6 +229,17 @@ private:
diffuse diffuse
}; };
struct debug_stats {
int dynamics { 0 };
int models { 0 };
int submodels { 0 };
int paths { 0 };
int traction { 0 };
int shapes { 0 };
int lines { 0 };
int drawcalls { 0 };
};
#ifdef EU07_USE_OLD_GROUNDCODE #ifdef EU07_USE_OLD_GROUNDCODE
using distancesubcell_pair = std::pair< double, TSubRect * >; using distancesubcell_pair = std::pair< double, TSubRect * >;
#else #else
@@ -289,7 +302,7 @@ private:
void void
Render( cell_sequence::iterator First, cell_sequence::iterator Last ); Render( cell_sequence::iterator First, cell_sequence::iterator Last );
void void
Render( scene::shape_node const &Shape ); Render( scene::shape_node const &Shape, bool const Ignorerange );
void void
Render( TAnimModel *Instance ); Render( TAnimModel *Instance );
#endif #endif
@@ -383,14 +396,12 @@ private:
units_state m_unitstate; units_state m_unitstate;
unsigned int m_framestamp; // id of currently rendered gfx frame unsigned int m_framestamp; // id of currently rendered gfx frame
float m_drawtime { 1000.f / 30.f * 20.f }; // start with presumed 'neutral' average of 30 fps
std::chrono::steady_clock::time_point m_drawstart; // cached start time of previous frame
float m_framerate; float m_framerate;
float m_drawtimecolorpass { 1000.f / 30.f * 20.f };
float m_drawtimeshadowpass { 0.f };
double m_updateaccumulator { 0.0 }; double m_updateaccumulator { 0.0 };
std::string m_debuginfo; std::string m_debugtimestext;
std::string m_pickdebuginfo; std::string m_pickdebuginfo;
debug_stats m_debugstats;
std::string m_debugstatstext;
glm::vec4 m_baseambient { 0.0f, 0.0f, 0.0f, 1.0f }; glm::vec4 m_baseambient { 0.0f, 0.0f, 0.0f, 1.0f };
glm::vec4 m_shadowcolor { 0.65f, 0.65f, 0.65f, 1.f }; glm::vec4 m_shadowcolor { 0.65f, 0.65f, 0.65f, 1.f };

298
scene.cpp
View File

@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
#include "scene.h" #include "scene.h"
#include "globals.h" #include "globals.h"
#include "timer.h"
#include "renderer.h" #include "renderer.h"
#include "logs.h" #include "logs.h"
@@ -19,12 +20,32 @@ namespace scene {
// legacy method, updates sounds and polls event launchers within radius around specified point // legacy method, updates sounds and polls event launchers within radius around specified point
void void
basic_cell::update() { basic_cell::update() {
/*
// renderowanie obiektów aktywnych a niewidocznych // sounds
for( auto node = subcell->nRenderHidden; node; node = node->nNext3 ) { auto const deltatime = Timer::GetDeltaTime();
node->RenderHidden(); for( auto *sound : m_sounds ) {
if( ( sound->GetStatus() & DSBSTATUS_PLAYING ) == DSBPLAY_LOOPING ) {
sound->Play( 1, DSBPLAY_LOOPING, true, sound->vSoundPosition );
sound->AdjFreq( 1.0, deltatime );
}
} }
*/ // event launchers
for( auto *launcher : m_eventlaunchers ) {
if( ( true == launcher->check_conditions() )
&& ( SquareMagnitude( launcher->location() - Global::pCameraPosition ) < launcher->dRadius ) ) {
WriteLog( "Eventlauncher " + launcher->name() );
if( ( true == Global::shiftState )
&& ( launcher->Event2 != nullptr ) ) {
simulation::Events.AddToQuery( launcher->Event2, nullptr );
}
else if( launcher->Event1 ) {
simulation::Events.AddToQuery( launcher->Event1, nullptr );
}
}
}
// TBD, TODO: move to sound renderer // TBD, TODO: move to sound renderer
for( auto *path : m_paths ) { for( auto *path : m_paths ) {
// dźwięki pojazdów, również niewidocznych // dźwięki pojazdów, również niewidocznych
@@ -32,6 +53,83 @@ basic_cell::update() {
} }
} }
// legacy method, finds and assigns traction piece to specified pantograph of provided vehicle
void
basic_cell::update_traction( TDynamicObject *Vehicle, int const Pantographindex ) {
// Winger 170204 - szukanie trakcji nad pantografami
auto const vFront = glm::make_vec3( Vehicle->VectorFront().getArray() ); // wektor normalny dla płaszczyzny ruchu pantografu
auto const vUp = glm::make_vec3( Vehicle->VectorUp().getArray() ); // wektor pionu pudła (pochylony od pionu na przechyłce)
auto const vLeft = glm::make_vec3( Vehicle->VectorLeft().getArray() ); // wektor odległości w bok (odchylony od poziomu na przechyłce)
auto const position = glm::dvec3 { Vehicle->GetPosition() }; // współrzędne środka pojazdu
auto pantograph = Vehicle->pants[ Pantographindex ].fParamPants;
auto const pantographposition = position + ( vLeft * pantograph->vPos.z ) + ( vUp * pantograph->vPos.y ) + ( vFront * pantograph->vPos.x );
for( auto *traction : m_traction ) {
// współczynniki równania parametrycznego
auto const paramfrontdot = glm::dot( traction->vParametric, vFront );
auto const fRaParam =
-( glm::dot( traction->pPoint1, vFront ) - glm::dot( pantographposition, vFront ) )
/ ( paramfrontdot != 0.0 ?
paramfrontdot :
0.001 ); // div0 trap
if( ( fRaParam < -0.001 )
|| ( fRaParam > 1.001 ) ) { continue; }
// jeśli tylko jest w przedziale, wyznaczyć odległość wzdłuż wektorów vUp i vLeft
// punkt styku płaszczyzny z drutem (dla generatora łuku el.)
auto const vStyk = traction->pPoint1 + fRaParam * traction->vParametric;
// wektor musi się mieścić w przedziale ruchu pantografu
auto const vGdzie = vStyk - pantographposition;
auto fVertical = glm::dot( vGdzie, vUp );
if( fVertical >= 0.0 ) {
// jeśli ponad pantografem (bo może łapać druty spod wiaduktu)
auto const fHorizontal = std::abs( glm::dot( vGdzie, vLeft ) ) - pantograph->fWidth;
if( ( Global::bEnableTraction )
&& ( fVertical < pantograph->PantWys - 0.15 ) ) {
// 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
// i do tego jeszcze wejdzie pod ślizg
if( fHorizontal <= 0.0 ) {
// 0.635 dla AKP-1 AKP-4E
pantograph->PantWys = -1.0; // ujemna liczba oznacza połamanie
pantograph->hvPowerWire = nullptr; // bo inaczej się zasila w nieskończoność z połamanego
if( Vehicle->MoverParameters->EnginePowerSource.CollectorParameters.CollectorsNo > 0 ) {
// liczba pantografów teraz będzie mniejsza
--Vehicle->MoverParameters->EnginePowerSource.CollectorParameters.CollectorsNo;
}
if( DebugModeFlag ) {
ErrorLog( "Bad traction: " + Vehicle->name() + " broke pantograph at " + to_string( pantographposition ) );
}
}
}
else if( fVertical < pantograph->PantTraction ) {
// ale niżej, niż poprzednio znaleziony
if( fHorizontal <= 0.0 ) {
// 0.635 dla AKP-1 AKP-4E
// to się musi mieścić w przedziale zaleznym od szerokości pantografu
pantograph->hvPowerWire = traction; // jakiś znaleziony
pantograph->PantTraction = fVertical; // zapamiętanie nowej wysokości
}
else if( fHorizontal < pantograph->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
// korekta wysokości o nabieżnik - drut nad nabieżnikiem jest geometrycznie jakby nieco wyżej
fVertical += 0.15 * fHorizontal / pantograph->fWidthExtra;
if( fVertical < pantograph->PantTraction ) {
// gdy po korekcie jest niżej, niż poprzednio znaleziony
// gdyby to wystarczyło, to możemy go uznać
pantograph->hvPowerWire = traction; // może być
pantograph->PantTraction = fVertical; // na razie liniowo na nabieżniku, dokładność poprawi się później
}
}
}
}
}
}
// adds provided shape to the cell // adds provided shape to the cell
void void
basic_cell::insert( shape_node Shape ) { basic_cell::insert( shape_node Shape ) {
@@ -107,18 +205,48 @@ basic_cell::insert( TAnimModel *Instance ) {
} }
} }
// adds provided sound instance to the cell
void
basic_cell::insert( TTextSound *Sound ) {
m_active = true;
m_sounds.emplace_back( Sound );
}
// adds provided sound instance to the cell
void
basic_cell::insert( TEventLauncher *Launcher ) {
m_active = true;
m_eventlaunchers.emplace_back( Launcher );
}
// registers provided path in the lookup directory of the cell // registers provided path in the lookup directory of the cell
void void
basic_cell::register_end( TTrack *Path ) { basic_cell::register_end( TTrack *Path ) {
m_directories.paths.emplace( Path ); m_directories.paths.emplace_back( Path );
// eliminate potential duplicates
m_directories.paths.erase(
std::unique(
std::begin( m_directories.paths ),
std::end( m_directories.paths ) ),
std::end( m_directories.paths ) );
} }
// registers provided traction piece in the lookup directory of the cell // registers provided traction piece in the lookup directory of the cell
void void
basic_cell::register_end( TTraction *Traction ) { basic_cell::register_end( TTraction *Traction ) {
m_directories.traction.emplace( Traction ); m_directories.traction.emplace_back( Traction );
// eliminate potential duplicates
m_directories.traction.erase(
std::unique(
std::begin( m_directories.traction ),
std::end( m_directories.traction ) ),
std::end( m_directories.traction ) );
} }
// find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance // find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance
@@ -263,6 +391,29 @@ basic_section::update( glm::dvec3 const &Location, float const Radius ) {
} }
} }
// legacy method, finds and assigns traction piece(s) to pantographs of provided vehicle
void
basic_section::update_traction( TDynamicObject *Vehicle, int const Pantographindex ) {
auto const vFront = glm::make_vec3( Vehicle->VectorFront().getArray() ); // wektor normalny dla płaszczyzny ruchu pantografu
auto const vUp = glm::make_vec3( Vehicle->VectorUp().getArray() ); // wektor pionu pudła (pochylony od pionu na przechyłce)
auto const vLeft = glm::make_vec3( Vehicle->VectorLeft().getArray() ); // wektor odległości w bok (odchylony od poziomu na przechyłce)
auto const position = glm::dvec3{ Vehicle->GetPosition() }; // współrzędne środka pojazdu
auto pantograph = Vehicle->pants[ Pantographindex ].fParamPants;
auto const pantographposition = position + ( vLeft * pantograph->vPos.z ) + ( vUp * pantograph->vPos.y ) + ( vFront * pantograph->vPos.x );
auto const radius { 0.0 }; // { EU07_CELLSIZE * 0.5 }; // experimentally limited, check if it has any negative effect
auto const squaredradii { std::pow( ( 0.5 * M_SQRT2 * EU07_CELLSIZE + 0.25 * EU07_CELLSIZE ) + radius, 2 ) };
for( auto &cell : m_cells ) {
// we reject early cells which aren't within our area of interest
if( glm::length2( cell.area().center - pantographposition ) < squaredradii ) {
cell.update_traction( Vehicle, Pantographindex );
}
}
}
// adds provided shape to the section // adds provided shape to the section
void void
basic_section::insert( shape_node Shape ) { basic_section::insert( shape_node Shape ) {
@@ -289,47 +440,6 @@ basic_section::insert( shape_node Shape ) {
} }
} }
// adds provided path to the section
void
basic_section::insert( TTrack *Path ) {
// pass the node to the appropriate partitioning cell
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
cell( Path->location() ).insert( Path );
}
// adds provided path to the section
void
basic_section::insert( TTraction *Traction ) {
// pass the node to the appropriate partitioning cell
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
cell( Traction->location() ).insert( Traction );
}
// adds provided model instance to the section
void
basic_section::insert( TAnimModel *Instance ) {
// pass the node to the appropriate partitioning cell
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
cell( Instance->location() ).insert( Instance );
}
// registers specified end point of the provided path in the lookup directory of the region
void
basic_section::register_end( TTrack *Path, glm::dvec3 const &Point ) {
cell( Point ).register_end( Path );
}
// registers specified end point of the provided traction piece in the lookup directory of the region
void
basic_section::register_end( TTraction *Traction, glm::dvec3 const &Point ) {
cell( Point ).register_end( Traction );
}
// find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance // find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance
std::tuple<TDynamicObject *, float> std::tuple<TDynamicObject *, float>
basic_section::find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled ) { basic_section::find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled ) {
@@ -467,26 +577,11 @@ basic_section::cell( glm::dvec3 const &Location ) {
basic_region::basic_region() { basic_region::basic_region() {
m_sections.fill( nullptr ); m_sections.fill( nullptr );
/*
// initialize centers of sections:
// calculate center of 'top left' region section...
auto const centeroffset = -( EU07_REGIONSIDESECTIONCOUNT / 2 * EU07_SECTIONSIZE ) + EU07_SECTIONSIZE / 2;
glm::dvec3 regioncornercenter { centeroffset, 0, centeroffset };
auto row { 0 }, column { 0 };
// ...move through section array assigning centers left to right, front/top to back/bottom
for( auto &section : m_sections ) {
section.center( regioncornercenter + glm::dvec3{ column * EU07_SECTIONSIZE, 0.0, row * EU07_SECTIONSIZE } );
if( ++column >= EU07_REGIONSIDESECTIONCOUNT ) {
++row;
column = 0;
}
}
*/
} }
basic_region::~basic_region() { basic_region::~basic_region() {
for( auto section : m_sections ) { if( section != nullptr ) { delete section; } } for( auto *section : m_sections ) { if( section != nullptr ) { delete section; } }
} }
// legacy method, updates sounds and polls event launchers around camera // legacy method, updates sounds and polls event launchers around camera
@@ -500,6 +595,25 @@ basic_region::update() {
} }
} }
// legacy method, finds and assigns traction piece(s) to pantographs of provided vehicle
void
basic_region::update_traction( TDynamicObject *Vehicle, int const Pantographindex ) {
// TODO: convert vectors to transformation matrix and pass them down the chain along with calculated position
auto const vFront = glm::make_vec3( Vehicle->VectorFront().getArray() ); // wektor normalny dla płaszczyzny ruchu pantografu
auto const vUp = glm::make_vec3( Vehicle->VectorUp().getArray() ); // wektor pionu pudła (pochylony od pionu na przechyłce)
auto const vLeft = glm::make_vec3( Vehicle->VectorLeft().getArray() ); // wektor odległości w bok (odchylony od poziomu na przechyłce)
auto const position = glm::dvec3 { Vehicle->GetPosition() }; // współrzędne środka pojazdu
auto p = Vehicle->pants[ Pantographindex ].fParamPants;
auto const pant0 = position + ( vLeft * p->vPos.z ) + ( vUp * p->vPos.y ) + ( vFront * p->vPos.x );
p->PantTraction = std::numeric_limits<double>::max(); // taka za duża wartość
auto const &sectionlist = sections( pant0, 0.0 );
for( auto *section : sectionlist ) {
section->update_traction( Vehicle, Pantographindex );
}
}
void void
basic_region::insert_shape( shape_node Shape, scratch_data &Scratchpad ) { basic_region::insert_shape( shape_node Shape, scratch_data &Scratchpad ) {
@@ -566,15 +680,15 @@ void
basic_region::insert_path( TTrack *Path, scratch_data &Scratchpad ) { basic_region::insert_path( TTrack *Path, scratch_data &Scratchpad ) {
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done // NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto center = Path->location(); auto location = Path->location();
if( point_inside( center ) ) { if( point_inside( location ) ) {
// NOTE: nodes placed outside of region boundaries are discarded // NOTE: nodes placed outside of region boundaries are discarded
section( center ).insert( Path ); section( location ).insert( Path );
} }
else { else {
// tracks are guaranteed to hava a name so we can skip the check // tracks are guaranteed to hava a name so we can skip the check
ErrorLog( "Bad scenario: track node \"" + Path->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" ); ErrorLog( "Bad scenario: track node \"" + Path->name() + "\" placed in location outside region bounds (" + to_string( location ) + ")" );
} }
// also register path ends in appropriate sections, for path merging lookups // also register path ends in appropriate sections, for path merging lookups
// TODO: clean this up during track refactoring // TODO: clean this up during track refactoring
@@ -588,15 +702,15 @@ void
basic_region::insert_traction( TTraction *Traction, scratch_data &Scratchpad ) { basic_region::insert_traction( TTraction *Traction, scratch_data &Scratchpad ) {
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done // NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto center = Traction->location(); auto location = Traction->location();
if( point_inside( center ) ) { if( point_inside( location ) ) {
// NOTE: nodes placed outside of region boundaries are discarded // NOTE: nodes placed outside of region boundaries are discarded
section( center ).insert( Traction ); section( location ).insert( Traction );
} }
else { else {
// tracks are guaranteed to hava a name so we can skip the check // tracks are guaranteed to hava a name so we can skip the check
ErrorLog( "Bad scenario: traction node \"" + Traction->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" ); ErrorLog( "Bad scenario: traction node \"" + Traction->name() + "\" placed in location outside region bounds (" + to_string( location ) + ")" );
} }
// also register traction ends in appropriate sections, for path merging lookups // also register traction ends in appropriate sections, for path merging lookups
// TODO: clean this up during track refactoring // TODO: clean this up during track refactoring
@@ -610,15 +724,15 @@ void
basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ) { basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ) {
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done // NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto center = Instance->location(); auto location = Instance->location();
if( point_inside( center ) ) { if( point_inside( location ) ) {
// NOTE: nodes placed outside of region boundaries are discarded // NOTE: nodes placed outside of region boundaries are discarded
section( center ).insert( Instance ); section( location ).insert( Instance );
} }
else { else {
// tracks are guaranteed to hava a name so we can skip the check // tracks are guaranteed to hava a name so we can skip the check
ErrorLog( "Bad scenario: model node \"" + Instance->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" ); ErrorLog( "Bad scenario: model node \"" + Instance->name() + "\" placed in location outside region bounds (" + to_string( location ) + ")" );
} }
} }
@@ -626,20 +740,34 @@ basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad )
void void
basic_region::insert_sound( TTextSound *Sound, scratch_data &Scratchpad ) { basic_region::insert_sound( TTextSound *Sound, scratch_data &Scratchpad ) {
/*
// TODO: implement
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done // NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto center = Sound->location(); auto location = Sound->location();
if( point_inside( center ) ) { if( point_inside( location ) ) {
// NOTE: nodes placed outside of region boundaries are discarded // NOTE: nodes placed outside of region boundaries are discarded
section( center ).insert( Instance ); section( location ).insert( Sound );
} }
else { else {
// tracks are guaranteed to hava a name so we can skip the check // tracks are guaranteed to hava a name so we can skip the check
ErrorLog( "Bad scenario: model node \"" + Instance->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" ); ErrorLog( "Bad scenario: sound node \"" + Sound->name() + "\" placed in location outside region bounds (" + to_string( location ) + ")" );
}
}
// inserts provided event launcher in the region
void
basic_region::insert_launcher( TEventLauncher *Launcher, scratch_data &Scratchpad ) {
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto location = Launcher->location();
if( point_inside( location ) ) {
// NOTE: nodes placed outside of region boundaries are discarded
section( location ).insert( Launcher );
}
else {
// tracks are guaranteed to hava a name so we can skip the check
ErrorLog( "Bad scenario: event launcher \"" + Launcher->name() + "\" placed in location outside region bounds (" + to_string( location ) + ")" );
} }
*/
} }
// find a vehicle located neares to specified location, within specified radius, optionally discarding vehicles without drivers // find a vehicle located neares to specified location, within specified radius, optionally discarding vehicles without drivers
@@ -757,7 +885,7 @@ void
basic_region::register_path( TTrack *Path, glm::dvec3 const &Point ) { basic_region::register_path( TTrack *Path, glm::dvec3 const &Point ) {
if( point_inside( Point ) ) { if( point_inside( Point ) ) {
section( Point ).register_end( Path, Point ); section( Point ).register_node( Path, Point );
} }
} }
@@ -766,7 +894,7 @@ void
basic_region::register_traction( TTraction *Traction, glm::dvec3 const &Point ) { basic_region::register_traction( TTraction *Traction, glm::dvec3 const &Point ) {
if( point_inside( Point ) ) { if( point_inside( Point ) ) {
section( Point ).register_end( Traction, Point ); section( Point ).register_node( Traction, Point );
} }
} }

56
scene.h
View File

@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
#include <deque> #include <deque>
#include <array> #include <array>
#include <stack> #include <stack>
#include <unordered_set>
#include "parser.h" #include "parser.h"
#include "openglgeometrybank.h" #include "openglgeometrybank.h"
@@ -24,7 +25,7 @@ namespace scene {
int const EU07_CELLSIZE = 250; int const EU07_CELLSIZE = 250;
int const EU07_SECTIONSIZE = 1000; int const EU07_SECTIONSIZE = 1000;
int const EU07_REGIONSIDESECTIONCOUNT = 500; // number of 1km sections along a side of square region int const EU07_REGIONSIDESECTIONCOUNT = 500; // number of sections along a side of square region
struct scratch_data { struct scratch_data {
@@ -42,6 +43,8 @@ struct scratch_data {
TDynamicObject * driver { nullptr }; TDynamicObject * driver { nullptr };
bool is_open { false }; bool is_open { false };
} trainset; } trainset;
bool initialized { false };
}; };
// basic element of rudimentary partitioning scheme for the section. fixed size, no further subdivision // basic element of rudimentary partitioning scheme for the section. fixed size, no further subdivision
@@ -55,6 +58,9 @@ public:
// legacy method, updates sounds and polls event launchers within radius around specified point // legacy method, updates sounds and polls event launchers within radius around specified point
void void
update(); update();
// legacy method, finds and assigns traction piece to specified pantograph of provided vehicle
void
update_traction( TDynamicObject *Vehicle, int const Pantographindex );
// adds provided shape to the cell // adds provided shape to the cell
void void
insert( shape_node Shape ); insert( shape_node Shape );
@@ -67,6 +73,12 @@ public:
// adds provided model instance to the cell // adds provided model instance to the cell
void void
insert( TAnimModel *Instance ); insert( TAnimModel *Instance );
// adds provided sound instance to the cell
void
insert( TTextSound *Sound );
// adds provided event launcher to the cell
void
insert( TEventLauncher *Launcher );
// registers provided path in the lookup directory of the cell // registers provided path in the lookup directory of the cell
void void
register_end( TTrack *Path ); register_end( TTrack *Path );
@@ -100,10 +112,12 @@ private:
// types // types
using shapenode_sequence = std::vector<shape_node>; using shapenode_sequence = std::vector<shape_node>;
using path_sequence = std::vector<TTrack *>; using path_sequence = std::vector<TTrack *>;
using path_set = std::set<TTrack *>; // using path_set = std::unordered_set<TTrack *>;
using traction_sequence = std::vector<TTraction *>; using traction_sequence = std::vector<TTraction *>;
using traction_set = std::set<TTraction *>; // using traction_set = std::unordered_set<TTraction *>;
using instance_sequence = std::vector<TAnimModel *>; using instance_sequence = std::vector<TAnimModel *>;
using sound_sequence = std::vector<TTextSound *>;
using eventlauncher_sequence = std::vector<TEventLauncher *>;
// members // members
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE + 0.25 * EU07_CELLSIZE ) }; scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE + 0.25 * EU07_CELLSIZE ) };
bool m_active { false }; // whether the cell holds any actual data bool m_active { false }; // whether the cell holds any actual data
@@ -114,10 +128,12 @@ private:
instance_sequence m_instancesopaque; instance_sequence m_instancesopaque;
instance_sequence m_instancetranslucent; instance_sequence m_instancetranslucent;
traction_sequence m_traction; traction_sequence m_traction;
sound_sequence m_sounds;
eventlauncher_sequence m_eventlaunchers;
// search helpers // search helpers
struct lookup_data { struct lookup_data {
path_set paths; path_sequence paths;
traction_set traction; traction_sequence traction;
} m_directories; } m_directories;
}; };
@@ -131,24 +147,22 @@ public:
// legacy method, updates sounds and polls event launchers within radius around specified point // legacy method, updates sounds and polls event launchers within radius around specified point
void void
update( glm::dvec3 const &Location, float const Radius ); update( glm::dvec3 const &Location, float const Radius );
// legacy method, finds and assigns traction piece to specified pantograph of provided vehicle
void
update_traction( TDynamicObject *Vehicle, int const Pantographindex );
// adds provided shape to the section // adds provided shape to the section
void void
insert( shape_node Shape ); insert( shape_node Shape );
// adds provided path to the section // adds provided node to the section
template <class Type_>
void void
insert( TTrack *Path ); insert( Type_ *Node ) {
// adds provided path to the section cell( Node->location() ).insert( Node ); }
// registers provided node in the lookup directory of the section enclosing specified point
template <class Type_>
void void
insert( TTraction *Traction ); register_node( Type_ *Node, glm::dvec3 const &Point ) {
// adds provided model instance to the section cell( Point ).register_end( Node ); }
void
insert( TAnimModel *Instance );
// registers specified end point of the provided path in the lookup directory of the region
void
register_end( TTrack *Path, glm::dvec3 const &Point );
// registers specified end point of the provided traction piece in the lookup directory of the region
void
register_end( TTraction *Traction, glm::dvec3 const &Point );
// find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance // find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance
std::tuple<TDynamicObject *, float> std::tuple<TDynamicObject *, float>
find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled ); find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled );
@@ -206,6 +220,9 @@ public:
// legacy method, updates sounds and polls event launchers around camera // legacy method, updates sounds and polls event launchers around camera
void void
update(); update();
// legacy method, finds and assigns traction piece to specified pantograph of provided vehicle
void
update_traction( TDynamicObject *Vehicle, int const Pantographindex );
// inserts provided shape in the region // inserts provided shape in the region
void void
insert_shape( shape_node Shape, scratch_data &Scratchpad ); insert_shape( shape_node Shape, scratch_data &Scratchpad );
@@ -221,6 +238,9 @@ public:
// inserts provided sound in the region // inserts provided sound in the region
void void
insert_sound( TTextSound *Sound, scratch_data &Scratchpad ); insert_sound( TTextSound *Sound, scratch_data &Scratchpad );
// inserts provided event launcher in the region
void
insert_launcher( TEventLauncher *Launcher, scratch_data &Scratchpad );
// find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance // find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance
std::tuple<TDynamicObject *, float> std::tuple<TDynamicObject *, float>
find_vehicle( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled ); find_vehicle( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled );

View File

@@ -26,8 +26,8 @@ struct lighting_data {
inline inline
bool bool
operator==( lighting_data const &Left, lighting_data const &Right ) { operator==( lighting_data const &Left, lighting_data const &Right ) {
return ( ( Left.diffuse == Right.diffuse ) return ( ( Left.diffuse == Right.diffuse )
&& ( Left.ambient == Right.ambient ) && ( Left.ambient == Right.ambient )
&& ( Left.specular == Right.specular ) ); } && ( Left.specular == Right.specular ) ); }
inline inline

View File

@@ -43,8 +43,8 @@ state_manager::deserialize( std::string const &Scenariofile ) {
if( false == scenarioparser.ok() ) { return false; } if( false == scenarioparser.ok() ) { return false; }
deserialize( scenarioparser ); deserialize( scenarioparser );
// TODO: initialize links between loaded nodes
Global::iPause &= ~0x10; // koniec pauzy wczytywania
return true; return true;
} }
@@ -126,6 +126,11 @@ state_manager::deserialize( cParser &Input ) {
token = Input.getToken<std::string>(); token = Input.getToken<std::string>();
} }
if( false == importscratchpad.initialized ) {
// manually perform scenario initialization
deserialize_firstinit( Input, importscratchpad );
}
} }
void void
@@ -247,11 +252,15 @@ state_manager::deserialize_event( cParser &Input, scene::scratch_data &Scratchpa
void void
state_manager::deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) { state_manager::deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) {
// TODO: implement if( true == Scratchpad.initialized ) { return; }
simulation::Paths.InitTracks(); simulation::Paths.InitTracks();
simulation::Traction.InitTraction(); simulation::Traction.InitTraction();
simulation::Events.InitEvents(); simulation::Events.InitEvents();
simulation::Events.InitLaunchers();
simulation::Memory.InitCells(); simulation::Memory.InitCells();
Scratchpad.initialized = true;
} }
void void
@@ -283,7 +292,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
if( false == simulation::Vehicles.insert( vehicle ) ) { if( false == simulation::Vehicles.insert( vehicle ) ) {
ErrorLog( "Bad scenario: vehicle with duplicate name, \"" + vehicle->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); ErrorLog( "Bad scenario: vehicle with duplicate name \"" + vehicle->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
} }
if( ( vehicle->MoverParameters->CategoryFlag == 1 ) // trains only if( ( vehicle->MoverParameters->CategoryFlag == 1 ) // trains only
@@ -303,7 +312,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
simulation::Region->insert_path( path, Scratchpad ); simulation::Region->insert_path( path, Scratchpad );
} }
else { else {
ErrorLog( "Bad scenario: track with duplicate name, \"" + path->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); ErrorLog( "Bad scenario: track with duplicate name \"" + path->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
/* /*
delete path; delete path;
delete pathnode; delete pathnode;
@@ -320,7 +329,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
simulation::Region->insert_traction( traction, Scratchpad ); simulation::Region->insert_traction( traction, Scratchpad );
} }
else { else {
ErrorLog( "Bad scenario: traction piece with duplicate name, \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); ErrorLog( "Bad scenario: traction piece with duplicate name \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
} }
} }
else if( nodedata.type == "tractionpowersource" ) { else if( nodedata.type == "tractionpowersource" ) {
@@ -336,7 +345,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
*/ */
} }
else { else {
ErrorLog( "Bad scenario: power grid source with duplicate name, \"" + powersource->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); ErrorLog( "Bad scenario: power grid source with duplicate name \"" + powersource->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
} }
} }
else if( nodedata.type == "model" ) { else if( nodedata.type == "model" ) {
@@ -355,7 +364,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
simulation::Region->insert_instance( instance, Scratchpad ); simulation::Region->insert_instance( instance, Scratchpad );
} }
else { else {
ErrorLog( "Bad scenario: 3d model instance with duplicate name, \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); ErrorLog( "Bad scenario: 3d model instance with duplicate name \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
} }
} }
} }
@@ -382,12 +391,25 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
*/ */
} }
else { else {
ErrorLog( "Bad scenario: memory cell with duplicate name, \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); ErrorLog( "Bad scenario: memory cell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
} }
} }
else if( nodedata.type == "eventlauncher" ) { else if( nodedata.type == "eventlauncher" ) {
// TODO: implement
skip_until( Input, "end" ); auto *eventlauncher{ deserialize_eventlauncher( Input, Scratchpad, nodedata ) };
if( simulation::Events.insert( eventlauncher ) ) {
// event launchers can be either global, or local with limited range of activation
// each gets assigned different caretaker
if( true == eventlauncher->IsGlobal() ) {
simulation::Events.queue( eventlauncher );
}
else {
simulation::Region->insert_launcher( eventlauncher, Scratchpad );
}
}
else {
ErrorLog( "Bad scenario: event launcher with duplicate name \"" + eventlauncher->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
}
} }
else if( nodedata.type == "sound" ) { else if( nodedata.type == "sound" ) {
@@ -396,7 +418,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
simulation::Region->insert_sound( sound, Scratchpad ); simulation::Region->insert_sound( sound, Scratchpad );
} }
else { else {
ErrorLog( "Bad scenario: sound node with duplicate name, \"" + sound->m_name + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); ErrorLog( "Bad scenario: sound node with duplicate name \"" + sound->m_name + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
} }
} }
@@ -604,6 +626,23 @@ state_manager::deserialize_memorycell( cParser &Input, scene::scratch_data &Scra
return memorycell; return memorycell;
} }
TEventLauncher *
state_manager::deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
glm::dvec3 location;
Input.getTokens( 3 );
Input
>> location.x
>> location.y
>> location.z;
auto *eventlauncher = new TEventLauncher( Nodedata );
eventlauncher->Load( &Input );
eventlauncher->location( transform( location, Scratchpad ) );
return eventlauncher;
}
TAnimModel * TAnimModel *
state_manager::deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { state_manager::deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {

View File

@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
#include "scene.h" #include "scene.h"
#include "event.h" #include "event.h"
#include "memcell.h" #include "memcell.h"
#include "evlaunch.h"
#include "track.h" #include "track.h"
#include "traction.h" #include "traction.h"
#include "tractionpower.h" #include "tractionpower.h"
@@ -60,6 +61,7 @@ private:
TTraction * deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TTraction * deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TTractionPowerSource * deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TTractionPowerSource * deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TEventLauncher * deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TTextSound * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TTextSound * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );