mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-20 12:39:17 +02:00
continued refactoring: traction, events, event launchers, sounds; additional diagnostics timers, minor performance enhancements and bug fixes
This commit is contained in:
26
Driver.cpp
26
Driver.cpp
@@ -2985,20 +2985,27 @@ void TController::RecognizeCommand()
|
||||
c->Command = ""; // usunięcie obsłużonej komendy
|
||||
}
|
||||
|
||||
void TController::PutCommand(std::string NewCommand, double NewValue1, double NewValue2,
|
||||
const TLocation &NewLocation, TStopReason reason)
|
||||
void TController::PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation, TStopReason reason)
|
||||
{ // wysłanie komendy przez event PutValues, jak pojazd ma obsadę, to wysyła tutaj, a nie do pojazdu
|
||||
// bezpośrednio
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
vector3 sl;
|
||||
sl.x = -NewLocation.X; // zamiana na współrzędne scenerii
|
||||
sl.z = NewLocation.Y;
|
||||
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))
|
||||
mvOccupied->PutCommand(NewCommand, NewValue1, NewValue2, NewLocation);
|
||||
}
|
||||
|
||||
bool TController::PutCommand(std::string NewCommand, double NewValue1, double NewValue2,
|
||||
const vector3 *NewLocation, TStopReason reason)
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
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
|
||||
if (NewCommand == "CabSignal")
|
||||
{ // 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
|
||||
if (fabs(VelSignal) >=
|
||||
1.0) // 0.1 nie wysyła się do samochodow, bo potem nie ruszą
|
||||
PutCommand("SetVelocity", VelSignal, VelNext,
|
||||
NULL); // komenda robi dodatkowe operacje
|
||||
PutCommand("SetVelocity", VelSignal, VelNext, nullptr); // komenda robi dodatkowe operacje
|
||||
break;
|
||||
case cm_ShuntVelocity: // od wersji 357 Tm nie budzi wyłączonej lokomotywy
|
||||
if (!(OrderList[OrderPos] &
|
||||
~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders
|
||||
PutCommand("ShuntVelocity", VelSignal, VelNext, NULL);
|
||||
PutCommand("ShuntVelocity", VelSignal, VelNext, nullptr);
|
||||
else if (iCoupler) // jeśli jedzie w celu połączenia
|
||||
SetVelocity(VelSignal, VelNext);
|
||||
break;
|
||||
@@ -5306,7 +5312,11 @@ TTrack * TController::BackwardTraceRoute(double &fDistance, double &fDirection,
|
||||
}
|
||||
|
||||
// sprawdzanie zdarzeń semaforów i ograniczeń szlakowych
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
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
|
||||
/*
|
||||
//!!!! 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)
|
||||
{//jeśli jest dalej od umownej drogi hamowania
|
||||
*/
|
||||
PutCommand("SetProximityVelocity", dist, vel, pos);
|
||||
PutCommand( "SetProximityVelocity", dist, vel, pos );
|
||||
/*
|
||||
}
|
||||
else
|
||||
|
||||
14
Driver.h
14
Driver.h
@@ -313,10 +313,12 @@ private:
|
||||
public:
|
||||
Mtable::TTrainParameters *Timetable() {
|
||||
return TrainParams; };
|
||||
void PutCommand(std::string NewCommand, double NewValue1, double NewValue2,
|
||||
const TLocation &NewLocation, TStopReason reason = stopComm);
|
||||
bool PutCommand(std::string NewCommand, double NewValue1, double NewValue2,
|
||||
const vector3 *NewLocation, TStopReason reason = stopComm);
|
||||
void PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation, TStopReason reason = stopComm);
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool PutCommand(std::string NewCommand, double NewValue1, double NewValue2, 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ę
|
||||
// procedury dotyczace rozkazow dla maszynisty
|
||||
// uaktualnia informacje o prędkości
|
||||
@@ -376,7 +378,11 @@ private:
|
||||
bool BackwardTrackBusy(TTrack *Track);
|
||||
TEvent *CheckTrackEventBackward(double fDirection, TTrack *Track);
|
||||
TTrack *BackwardTraceRoute(double &fDistance, double &fDirection, TTrack *Track, TEvent *&Event);
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
void SetProximityVelocity(double dist, double vel, const vector3 *pos);
|
||||
#else
|
||||
void SetProximityVelocity( double dist, double vel, glm::dvec3 const *pos );
|
||||
#endif
|
||||
TCommandType BackwardScan();
|
||||
|
||||
public:
|
||||
|
||||
214
DynObj.cpp
214
DynObj.cpp
@@ -2613,77 +2613,36 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
NoVoltTime = 0;
|
||||
tmpTraction.TractionVoltage = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
if (MoverParameters->Vel>0.1f) //jeśli jedzie
|
||||
if (NoVoltTime==0.0) //tylko przy pierwszym zaniku napięcia
|
||||
if (MoverParameters->PantFrontUp||MoverParameters->PantRearUp)
|
||||
//if
|
||||
((pants[0].fParamPants->PantTraction>1.0)||(pants[1].fParamPants->PantTraction>1.0))
|
||||
{//wspomagacz usuwania problemów z siecią
|
||||
if (!Global::iPause)
|
||||
{//Ra: tymczasowa teleportacja do miejsca, gdzie brakuje prądu
|
||||
Global::SetCameraPosition(vPosition+vector3(0,0,5)); //nowa
|
||||
pozycja dla
|
||||
generowania obiektów
|
||||
Global::pCamera->Init(vPosition+vector3(0,0,5),Global::pFreeCameraInitAngle[0]);
|
||||
//przestawienie
|
||||
}
|
||||
Global:l::pGround->Silence(Global::pCamera->Pos); //wyciszenie
|
||||
wszystkiego
|
||||
z poprzedniej pozycji
|
||||
Globa:iPause|=1; //tymczasowe zapauzowanie, gdy problem z
|
||||
siecią
|
||||
}
|
||||
*/
|
||||
NoVoltTime = NoVoltTime + dt;
|
||||
if (NoVoltTime > 0.2) // jeśli brak zasilania dłużej niż 0.2 sekundy (25km/h pod
|
||||
// izolatorem daje 0.15s)
|
||||
{ // Ra 2F1H: prowizorka, trzeba przechować napięcie, żeby nie wywalało
|
||||
// WS pod
|
||||
// izolatorem
|
||||
if (MoverParameters->Vel > 0.5) // jeśli jedzie
|
||||
if (MoverParameters->PantFrontUp ||
|
||||
MoverParameters->PantRearUp) // Ra 2014-07: doraźna blokada logowania
|
||||
// zimnych lokomotyw - zrobić to trzeba
|
||||
// inaczej
|
||||
else {
|
||||
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
|
||||
// Ra 2014-07: doraźna blokada logowania zimnych lokomotyw - zrobić to trzeba inaczej
|
||||
if( MoverParameters->PantFrontUp || MoverParameters->PantRearUp )
|
||||
// if (NoVoltTime>0.02) //tu można ograniczyć czas rozłączenia
|
||||
// if (DebugModeFlag) //logowanie nie zawsze
|
||||
if ((MoverParameters->Mains) &&
|
||||
((MoverParameters->EngineType != ElectricInductionMotor)
|
||||
|| (MoverParameters->GetTrainsetVoltage() < 0.1f)))
|
||||
{ // Ra 15-01: logować tylko, jeśli WS załączony
|
||||
// yB 16-03: i nie jest to asynchron zasilany z daleka
|
||||
// if (MoverParameters->PantFrontUp&&pants)
|
||||
if( ( MoverParameters->Mains )
|
||||
&& ( ( MoverParameters->EngineType != ElectricInductionMotor )
|
||||
|| ( MoverParameters->GetTrainsetVoltage() < 0.1f ) ) ) {
|
||||
// Ra 15-01: logować tylko, jeśli WS załączony
|
||||
// yB 16-03: i nie jest to asynchron zasilany z daleka
|
||||
// Ra 15-01: bezwzględne współrzędne pantografu nie są dostępne,
|
||||
// więc lepiej się tego nie zaloguje
|
||||
ErrorLog("Voltage loss: by " + MoverParameters->Name + " at " +
|
||||
to_string(vPosition.x, 2, 7) + " " +
|
||||
to_string(vPosition.y, 2, 7) + " " +
|
||||
to_string(vPosition.z, 2, 7) + ", time " +
|
||||
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));
|
||||
ErrorLog(
|
||||
"Bad traction: " + MoverParameters->Name
|
||||
+ " lost power for " + to_string( NoVoltTime, 2 ) + " sec. at "
|
||||
+ to_string( glm::dvec3{ vPosition } ) );
|
||||
}
|
||||
// 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
|
||||
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
|
||||
tmpTraction.TractionVoltage = 0.95 * MoverParameters->EnginePowerSource.MaxVoltage;
|
||||
@@ -3199,22 +3158,22 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
else if ( ( true == MoverParameters->PantRearUp )
|
||||
&& ( PantDiff < 0.01 ) )
|
||||
{
|
||||
if ((MoverParameters->PantRearVolt == 0.0) &&
|
||||
(MoverParameters->PantFrontVolt == 0.0))
|
||||
sPantUp.Play(vol, 0, MechInside, vPosition);
|
||||
if (p->hvPowerWire) // TODO: wyliczyć trzeba prąd przypadający na
|
||||
// pantograf i
|
||||
// wstawić do GetVoltage()
|
||||
{
|
||||
MoverParameters->PantRearVolt =
|
||||
p->hvPowerWire->VoltageGet(MoverParameters->Voltage, fPantCurrent);
|
||||
if( ( MoverParameters->PantRearVolt == 0.0 )
|
||||
&& ( MoverParameters->PantFrontVolt == 0.0 ) ) {
|
||||
sPantUp.Play( vol, 0, MechInside, vPosition );
|
||||
}
|
||||
if (p->hvPowerWire) {
|
||||
// TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage()
|
||||
MoverParameters->PantRearVolt = p->hvPowerWire->VoltageGet( MoverParameters->Voltage, fPantCurrent );
|
||||
fCurrent -= fPantCurrent; // taki prąd płynie przez powyższy pantograf
|
||||
}
|
||||
else
|
||||
MoverParameters->PantRearVolt = 0.0;
|
||||
}
|
||||
else
|
||||
else {
|
||||
// Global::iPause ^= 2;
|
||||
MoverParameters->PantRearVolt = 0.0;
|
||||
}
|
||||
break;
|
||||
} // pozostałe na razie nie obsługiwane
|
||||
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ę
|
||||
// wyliczyć aktualną wysokość z wzoru sinusowego
|
||||
// h=a*sin()+b*sin()
|
||||
p->PantWys = p->fLenL1 * sin(k) + p->fLenU1 * sin(p->fAngleU) +
|
||||
p->fHeight; // wysokość całości
|
||||
// wysokość całości
|
||||
p->PantWys = p->fLenL1 * sin(k) + p->fLenU1 * sin(p->fAngleU) + p->fHeight;
|
||||
}
|
||||
}
|
||||
} // 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
|
||||
// asymetrycznych
|
||||
pants[ i ].fParamPants->PantTraction = pants[ i ].fParamPants->PantWys;
|
||||
pants[ i ].fParamPants->fWidth =
|
||||
0.5 *
|
||||
MoverParameters->EnginePowerSource.CollectorParameters
|
||||
.CSW; // połowa szerokości ślizgu; jest w "Power: CSW="
|
||||
// połowa szerokości ślizgu; jest w "Power: CSW="
|
||||
pants[ i ].fParamPants->fWidth = 0.5 * MoverParameters->EnginePowerSource.CollectorParameters.CSW;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4932,7 +4889,12 @@ void TDynamicObject::RadioStop()
|
||||
if( ( MoverParameters->SecuritySystem.RadioStop )
|
||||
&& ( MoverParameters->Radio ) ) {
|
||||
// jeśli pojazd ma RadioStop i jest on aktywny
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
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
|
||||
// TODO: do it selectively for the 'local' driver once the multiplayer is in
|
||||
if( false == Mechanik->AIControllFlag ) {
|
||||
@@ -5404,10 +5366,8 @@ vehicle_table::update( double Deltatime, int Iterationcount ) {
|
||||
for( auto *vehicle : m_items ) {
|
||||
// Ra: zmienić warunek na sprawdzanie pantografów w jednej zmiennej: czy pantografy i czy podniesione
|
||||
if( vehicle->MoverParameters->EnginePowerSource.SourceType == CurrentCollector ) {
|
||||
/*
|
||||
// TODO: re-implement
|
||||
GetTraction( vehicle );
|
||||
*/
|
||||
update_traction( vehicle );
|
||||
}
|
||||
vehicle->MoverParameters->ComputeConstans();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
DynObj.h
3
DynObj.h
@@ -492,6 +492,9 @@ public:
|
||||
// legacy method, calculates changes in simulation state over specified time
|
||||
void
|
||||
update( double dt, int iter );
|
||||
// legacy method, checks for presence and height of traction wire for specified vehicle
|
||||
void
|
||||
update_traction( TDynamicObject *Vehicle );
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
40
EvLaunch.cpp
40
EvLaunch.cpp
@@ -17,36 +17,14 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "EvLaunch.h"
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
#include "Usefull.h"
|
||||
#include "McZapkie/mctools.h"
|
||||
#include "Event.h"
|
||||
#include "MemCell.h"
|
||||
#include "mtable.h"
|
||||
#include "Timer.h"
|
||||
#include "parser.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,
|
||||
// and the high byte holds modifiers: 0x1 = shift, 0x2 = ctrl, 0x4 = alt
|
||||
int vk_to_glfw_key( int const Keycode ) {
|
||||
@@ -145,7 +123,7 @@ bool TEventLauncher::Load(cParser *parser)
|
||||
return true;
|
||||
};
|
||||
|
||||
bool TEventLauncher::Render()
|
||||
bool TEventLauncher::check_conditions()
|
||||
{ //"renderowanie" wyzwalacza
|
||||
bool bCond = false;
|
||||
if (iKey != 0)
|
||||
@@ -199,13 +177,13 @@ bool TEventLauncher::Render()
|
||||
return bCond; // sprawdzanie dRadius w Ground.cpp
|
||||
}
|
||||
|
||||
bool TEventLauncher::IsGlobal()
|
||||
{ // sprawdzenie, czy jest globalnym wyzwalaczem czasu
|
||||
if (DeltaTime == 0)
|
||||
if (iHour >= 0)
|
||||
if (iMinute >= 0)
|
||||
if (dRadius < 0.0) // bez ograniczenia zasięgu
|
||||
return true;
|
||||
return false;
|
||||
// sprawdzenie, czy jest globalnym wyzwalaczem czasu
|
||||
bool TEventLauncher::IsGlobal() const {
|
||||
|
||||
return ( ( DeltaTime == 0 )
|
||||
&& ( iHour >= 0 )
|
||||
&& ( iMinute >= 0 )
|
||||
&& ( dRadius < 0.0 ) ); // bez ograniczenia zasięgu
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
55
EvLaunch.h
55
EvLaunch.h
@@ -10,32 +10,43 @@ http://mozilla.org/MPL/2.0/.
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "Classes.h"
|
||||
|
||||
class TEventLauncher
|
||||
{
|
||||
private:
|
||||
int iKey;
|
||||
double DeltaTime;
|
||||
double UpdatedTime;
|
||||
double fVal1;
|
||||
double fVal2;
|
||||
std::string szText;
|
||||
int iHour, iMinute; // minuta uruchomienia
|
||||
public:
|
||||
double dRadius;
|
||||
#include "Classes.h"
|
||||
#include "scenenode.h"
|
||||
|
||||
class TEventLauncher : public editor::basic_node {
|
||||
|
||||
public:
|
||||
// constructor
|
||||
TEventLauncher( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {}
|
||||
// legacy constructor
|
||||
TEventLauncher() = default;
|
||||
|
||||
// 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 asEvent2Name;
|
||||
std::string asMemCellName;
|
||||
TEvent *Event1;
|
||||
TEvent *Event2;
|
||||
TMemCell *MemCell;
|
||||
int iCheckMask;
|
||||
TEventLauncher();
|
||||
void Init();
|
||||
bool Load(cParser *parser);
|
||||
bool Render();
|
||||
bool IsGlobal();
|
||||
TEvent *Event1 { nullptr };
|
||||
TEvent *Event2 { nullptr };
|
||||
TMemCell *MemCell { nullptr };
|
||||
int iCheckMask { 0 };
|
||||
double dRadius { 0.0 };
|
||||
|
||||
private:
|
||||
// members
|
||||
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
292
Event.cpp
@@ -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
|
||||
// TODO: return handle instead of pointer
|
||||
bool
|
||||
@@ -826,7 +852,11 @@ event_manager::AddToQuery( TEvent *Event, TDynamicObject *Owner ) {
|
||||
for( auto dynamic : Event->Params[ 6 ].asTrack->Dynamics ) {
|
||||
Event->Params[ 5 ].asMemCell->PutCommand(
|
||||
dynamic->Mechanik,
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
&Event->Params[ 4 ].nGroundNode->pCenter );
|
||||
#else
|
||||
Event->Params[ 4 ].asLocation );
|
||||
#endif
|
||||
}
|
||||
//if (DebugModeFlag)
|
||||
WriteLog(
|
||||
@@ -924,7 +954,11 @@ event_manager::CheckQuery() {
|
||||
for( auto dynamic : m_workevent->Params[ 6 ].asTrack->Dynamics ) {
|
||||
m_workevent->Params[ 5 ].asMemCell->PutCommand(
|
||||
dynamic->Mechanik,
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
&m_workevent->Params[ 4 ].nGroundNode->pCenter );
|
||||
#else
|
||||
m_workevent->Params[ 4 ].asLocation );
|
||||
#endif
|
||||
}
|
||||
//if (DebugModeFlag)
|
||||
WriteLog("Type: UpdateValues & Track command - [" +
|
||||
@@ -950,7 +984,11 @@ event_manager::CheckQuery() {
|
||||
*/
|
||||
m_workevent->Params[ 9 ].asMemCell->PutCommand(
|
||||
m_workevent->Activator->Mechanik,
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
&m_workevent->Params[ 8 ].nGroundNode->pCenter );
|
||||
#else
|
||||
m_workevent->Params[ 8 ].asLocation );
|
||||
#endif
|
||||
}
|
||||
WriteLog( "Type: GetValues" );
|
||||
break;
|
||||
@@ -1273,263 +1311,263 @@ void
|
||||
event_manager::InitEvents() {
|
||||
|
||||
//łą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_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( 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)
|
||||
// nazwa toru ta sama, co nazwa komórki
|
||||
Current->Params[ 9 ].asTrack = simulation::Paths.find( Current->asNodeName );
|
||||
if( Current->Params[ 9 ].asTrack == nullptr ) {
|
||||
ErrorLog( "Bad event: track \"" + Current->asNodeName + "\" referenced in event \"" + Current->asName + "\" doesn't exist" );
|
||||
event->Params[ 9 ].asTrack = simulation::Paths.find( event->asNodeName );
|
||||
if( event->Params[ 9 ].asTrack == nullptr ) {
|
||||
ErrorLog( "Bad event: track \"" + event->asNodeName + "\" referenced in event \"" + event->asName + "\" doesn't exist" );
|
||||
}
|
||||
}
|
||||
Current->Params[ 4 ].asLocation = &( cell->location() );
|
||||
Current->Params[ 5 ].asMemCell = cell; // komórka do aktualizacji
|
||||
if( Current->iFlags & ( conditional_memcompare ) ) {
|
||||
event->Params[ 4 ].asLocation = &( cell->location() );
|
||||
event->Params[ 5 ].asMemCell = cell; // komórka do aktualizacji
|
||||
if( event->iFlags & ( conditional_memcompare ) ) {
|
||||
// komórka do badania warunku
|
||||
Current->Params[ 9 ].asMemCell = cell;
|
||||
event->Params[ 9 ].asMemCell = cell;
|
||||
}
|
||||
if( false == cell->asTrackName.empty() ) {
|
||||
// tor powiązany z komórką powiązaną z eventem
|
||||
// tu potrzebujemy wskaźnik do komórki w (tmp)
|
||||
Current->Params[ 6 ].asTrack = simulation::Paths.find( cell->asTrackName );
|
||||
if( Current->Params[ 6 ].asTrack == nullptr ) {
|
||||
event->Params[ 6 ].asTrack = simulation::Paths.find( cell->asTrackName );
|
||||
if( event->Params[ 6 ].asTrack == nullptr ) {
|
||||
ErrorLog( "Bad memcell: track \"" + cell->asTrackName + "\" referenced in memcell \"" + cell->name() + "\" doesn't exist" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
Current->Params[ 6 ].asTrack = nullptr;
|
||||
event->Params[ 6 ].asTrack = nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// nie ma komórki, to nie będzie działał poprawnie
|
||||
Current->m_ignored = true; // deaktywacja
|
||||
ErrorLog( "Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"" );
|
||||
event->m_ignored = true; // deaktywacja
|
||||
ErrorLog( "Bad event: event \"" + event->asName + "\" cannot find memcell \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_LogValues: {
|
||||
// skojarzenie z memcell
|
||||
if( Current->asNodeName.empty() ) { // brak skojarzenia daje logowanie wszystkich
|
||||
Current->Params[ 9 ].asMemCell = nullptr;
|
||||
if( event->asNodeName.empty() ) { // brak skojarzenia daje logowanie wszystkich
|
||||
event->Params[ 9 ].asMemCell = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case tp_GetValues:
|
||||
case tp_WhoIs: {
|
||||
auto *cell = simulation::Memory.find( Current->asNodeName );
|
||||
auto *cell = simulation::Memory.find( event->asNodeName );
|
||||
if( cell != nullptr ) {
|
||||
Current->Params[ 8 ].asLocation = &( cell->location() );
|
||||
Current->Params[ 9 ].asMemCell = cell;
|
||||
if( ( Current->Type == tp_GetValues )
|
||||
event->Params[ 8 ].asLocation = &( cell->location() );
|
||||
event->Params[ 9 ].asMemCell = cell;
|
||||
if( ( event->Type == tp_GetValues )
|
||||
&& ( cell->IsVelocity() ) ) {
|
||||
// jeśli odczyt komórki a komórka zawiera komendę SetVelocity albo ShuntVelocity
|
||||
// to event nie będzie dodawany do kolejki
|
||||
Current->bEnabled = false;
|
||||
event->bEnabled = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// nie ma komórki, to nie będzie działał poprawnie
|
||||
Current->m_ignored = true; // deaktywacja
|
||||
ErrorLog( "Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"" );
|
||||
event->m_ignored = true; // deaktywacja
|
||||
ErrorLog( "Bad event: event \"" + event->asName + "\" cannot find memcell \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_CopyValues: {
|
||||
// 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 ) {
|
||||
Current->Params[ 4 ].asLocation = &( cell->location() );
|
||||
Current->Params[ 5 ].asMemCell = cell; // komórka docelowa
|
||||
event->Params[ 4 ].asLocation = &( cell->location() );
|
||||
event->Params[ 5 ].asMemCell = cell; // komórka docelowa
|
||||
if( false == cell->asTrackName.empty() ) {
|
||||
// tor powiązany z komórką powiązaną z eventem
|
||||
// tu potrzebujemy wskaźnik do komórki w (tmp)
|
||||
Current->Params[ 6 ].asTrack = simulation::Paths.find( cell->asTrackName );
|
||||
if( Current->Params[ 6 ].asTrack == nullptr ) {
|
||||
event->Params[ 6 ].asTrack = simulation::Paths.find( cell->asTrackName );
|
||||
if( event->Params[ 6 ].asTrack == nullptr ) {
|
||||
ErrorLog( "Bad memcell: track \"" + cell->asTrackName + "\" referenced in memcell \"" + cell->name() + "\" doesn't exists" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
Current->Params[ 6 ].asTrack = nullptr;
|
||||
event->Params[ 6 ].asTrack = nullptr;
|
||||
}
|
||||
}
|
||||
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 };
|
||||
cell = simulation::Memory.find( Current->Params[ 9 ].asText ); // komórka źódłowa
|
||||
SafeDeleteArray( Current->Params[ 9 ].asText ); // usunięcie nazwy komórki
|
||||
std::string const cellastext { event->Params[ 9 ].asText };
|
||||
cell = simulation::Memory.find( event->Params[ 9 ].asText ); // komórka źódłowa
|
||||
SafeDeleteArray( event->Params[ 9 ].asText ); // usunięcie nazwy komórki
|
||||
if( cell != nullptr ) {
|
||||
Current->Params[ 8 ].asLocation = &( cell->location() );
|
||||
Current->Params[ 9 ].asMemCell = cell; // komórka źródłowa
|
||||
event->Params[ 8 ].asLocation = &( cell->location() );
|
||||
event->Params[ 9 ].asMemCell = cell; // komórka źródłowa
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad event: copyvalues event \"" + Current->asName + "\" cannot find memcell \"" + cellastext + "\"" );
|
||||
ErrorLog( "Bad event: copyvalues event \"" + event->asName + "\" cannot find memcell \"" + cellastext + "\"" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_Animation: {
|
||||
// animacja modelu
|
||||
// retrieve target name parameter
|
||||
std::string const cellastext = Current->Params[ 9 ].asText;
|
||||
SafeDeleteArray( Current->Params[ 9 ].asText );
|
||||
std::string const cellastext = event->Params[ 9 ].asText;
|
||||
SafeDeleteArray( event->Params[ 9 ].asText );
|
||||
// egzemplarz modelu do animowania
|
||||
auto *instance = simulation::Instances.find( Current->asNodeName );
|
||||
auto *instance = simulation::Instances.find( event->asNodeName );
|
||||
if( instance != nullptr ) {
|
||||
if( Current->Params[ 0 ].asInt == 4 ) {
|
||||
if( event->Params[ 0 ].asInt == 4 ) {
|
||||
// model dla całomodelowych animacji
|
||||
Current->Params[ 9 ].asModel = instance;
|
||||
event->Params[ 9 ].asModel = instance;
|
||||
}
|
||||
else {
|
||||
// standardowo przypisanie submodelu
|
||||
Current->Params[ 9 ].asAnimContainer = instance->GetContainer( cellastext ); // submodel
|
||||
if( Current->Params[ 9 ].asAnimContainer ) {
|
||||
Current->Params[ 9 ].asAnimContainer->WillBeAnimated(); // oflagowanie animacji
|
||||
if( Current->Params[ 9 ].asAnimContainer->Event() == nullptr ) {
|
||||
event->Params[ 9 ].asAnimContainer = instance->GetContainer( cellastext ); // submodel
|
||||
if( event->Params[ 9 ].asAnimContainer ) {
|
||||
event->Params[ 9 ].asAnimContainer->WillBeAnimated(); // oflagowanie animacji
|
||||
if( event->Params[ 9 ].asAnimContainer->Event() == nullptr ) {
|
||||
// nie szukać, gdy znaleziony
|
||||
Current->Params[ 9 ].asAnimContainer->EventAssign(
|
||||
FindEvent( Current->asNodeName + "." + cellastext + ":done" ) );
|
||||
event->Params[ 9 ].asAnimContainer->EventAssign(
|
||||
FindEvent( event->asNodeName + "." + cellastext + ":done" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
case tp_Lights: {
|
||||
// zmiana świeteł modelu
|
||||
auto *instance = simulation::Instances.find( Current->asNodeName );
|
||||
auto *instance = simulation::Instances.find( event->asNodeName );
|
||||
if( instance != nullptr )
|
||||
Current->Params[ 9 ].asModel = instance;
|
||||
event->Params[ 9 ].asModel = instance;
|
||||
else
|
||||
ErrorLog( "Bad event: lights event \"" + Current->asName + "\" cannot find model instance \"" + Current->asNodeName + "\"" );
|
||||
Current->asNodeName = "";
|
||||
ErrorLog( "Bad event: lights event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" );
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Visible: {
|
||||
// ukrycie albo przywrócenie obiektu
|
||||
editor::basic_node *node = simulation::Instances.find( Current->asNodeName ); // najpierw model
|
||||
editor::basic_node *node = simulation::Instances.find( event->asNodeName ); // najpierw model
|
||||
if( node == nullptr ) {
|
||||
// albo tory?
|
||||
node = simulation::Paths.find( Current->asNodeName );
|
||||
node = simulation::Paths.find( event->asNodeName );
|
||||
}
|
||||
if( node == nullptr ) {
|
||||
// może druty?
|
||||
node = simulation::Traction.find( Current->asNodeName );
|
||||
node = simulation::Traction.find( event->asNodeName );
|
||||
}
|
||||
if( node != nullptr )
|
||||
Current->Params[ 9 ].asEditorNode = node;
|
||||
event->Params[ 9 ].asEditorNode = node;
|
||||
else
|
||||
ErrorLog( "Bad event: visibility event \"" + Current->asName + "\" cannot find item \"" + Current->asNodeName + "\"" );
|
||||
Current->asNodeName = "";
|
||||
ErrorLog( "Bad event: visibility event \"" + event->asName + "\" cannot find item \"" + event->asNodeName + "\"" );
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Switch: {
|
||||
// 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 ) {
|
||||
// dowiązanie toru
|
||||
if( track->iAction == NULL ) {
|
||||
// jeśli nie jest zwrotnicą ani obrotnicą to będzie się zmieniał stan uszkodzenia
|
||||
track->iAction |= 0x100;
|
||||
}
|
||||
Current->Params[ 9 ].asTrack = track;
|
||||
if( ( Current->Params[ 0 ].asInt == 0 )
|
||||
&& ( Current->Params[ 2 ].asdouble >= 0.0 ) ) {
|
||||
event->Params[ 9 ].asTrack = track;
|
||||
if( ( event->Params[ 0 ].asInt == 0 )
|
||||
&& ( event->Params[ 2 ].asdouble >= 0.0 ) ) {
|
||||
// jeśli przełącza do stanu 0 & jeśli jest zdefiniowany dodatkowy ruch iglic
|
||||
// przesłanie parametrów
|
||||
Current->Params[ 9 ].asTrack->Switch(
|
||||
Current->Params[ 0 ].asInt,
|
||||
Current->Params[ 1 ].asdouble,
|
||||
Current->Params[ 2 ].asdouble );
|
||||
event->Params[ 9 ].asTrack->Switch(
|
||||
event->Params[ 0 ].asInt,
|
||||
event->Params[ 1 ].asdouble,
|
||||
event->Params[ 2 ].asdouble );
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
case tp_Sound: {
|
||||
// odtworzenie dźwięku
|
||||
auto *sound = simulation::Sounds.find( Current->asNodeName );
|
||||
auto *sound = simulation::Sounds.find( event->asNodeName );
|
||||
if( sound != nullptr )
|
||||
Current->Params[ 9 ].tsTextSound = sound;
|
||||
event->Params[ 9 ].tsTextSound = sound;
|
||||
else
|
||||
ErrorLog( "Bad event: sound event \"" + Current->asName + "\" cannot find static sound \"" + Current->asNodeName + "\"" );
|
||||
Current->asNodeName = "";
|
||||
ErrorLog( "Bad event: sound event \"" + event->asName + "\" cannot find static sound \"" + event->asNodeName + "\"" );
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_TrackVel: {
|
||||
// ustawienie prędkości na torze
|
||||
if( false == Current->asNodeName.empty() ) {
|
||||
auto *track = simulation::Paths.find( Current->asNodeName );
|
||||
if( false == event->asNodeName.empty() ) {
|
||||
auto *track = simulation::Paths.find( event->asNodeName );
|
||||
if( track != nullptr ) {
|
||||
// flaga zmiany prędkości toru jest istotna dla skanowania
|
||||
track->iAction |= 0x200;
|
||||
Current->Params[ 9 ].asTrack = track;
|
||||
event->Params[ 9 ].asTrack = track;
|
||||
}
|
||||
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;
|
||||
}
|
||||
case tp_DynVel: {
|
||||
// komunikacja z pojazdem o konkretnej nazwie
|
||||
if( Current->asNodeName == "activator" )
|
||||
Current->Params[ 9 ].asDynamic = nullptr;
|
||||
if( event->asNodeName == "activator" )
|
||||
event->Params[ 9 ].asDynamic = nullptr;
|
||||
else {
|
||||
auto *vehicle = simulation::Vehicles.find( Current->asNodeName );
|
||||
auto *vehicle = simulation::Vehicles.find( event->asNodeName );
|
||||
if( vehicle != nullptr )
|
||||
Current->Params[ 9 ].asDynamic = vehicle;
|
||||
event->Params[ 9 ].asDynamic = vehicle;
|
||||
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;
|
||||
}
|
||||
case tp_Multiple: {
|
||||
std::string cellastext;
|
||||
if( Current->Params[ 9 ].asText != nullptr ) { // przepisanie nazwy do bufora
|
||||
cellastext = Current->Params[ 9 ].asText;
|
||||
SafeDeleteArray( Current->Params[ 9 ].asText );
|
||||
Current->Params[ 9 ].asPointer = nullptr; // zerowanie wskaźnika, aby wykryć brak obeiktu
|
||||
if( event->Params[ 9 ].asText != nullptr ) { // przepisanie nazwy do bufora
|
||||
cellastext = event->Params[ 9 ].asText;
|
||||
SafeDeleteArray( event->Params[ 9 ].asText );
|
||||
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
|
||||
Current->Params[ 9 ].asTrack = simulation::Paths.find( cellastext );
|
||||
if( Current->Params[ 9 ].asTrack == nullptr ) {
|
||||
ErrorLog( "Bad event: multi-event \"" + Current->asName + "\" cannot find track \"" + cellastext + "\"" );
|
||||
Current->iFlags &= ~( conditional_trackoccupied | conditional_trackfree ); // zerowanie flag
|
||||
event->Params[ 9 ].asTrack = simulation::Paths.find( cellastext );
|
||||
if( event->Params[ 9 ].asTrack == nullptr ) {
|
||||
ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find track \"" + cellastext + "\"" );
|
||||
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ą
|
||||
Current->Params[ 9 ].asMemCell = simulation::Memory.find( cellastext );
|
||||
if( Current->Params[ 9 ].asMemCell == nullptr ) {
|
||||
ErrorLog( "Bad event: multi-event \"" + Current->asName + "\" cannot find memory cell \"" + cellastext + "\"" );
|
||||
Current->iFlags &= ~( conditional_memstring | conditional_memval1 | conditional_memval2 );
|
||||
event->Params[ 9 ].asMemCell = simulation::Memory.find( cellastext );
|
||||
if( event->Params[ 9 ].asMemCell == nullptr ) {
|
||||
ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find memory cell \"" + cellastext + "\"" );
|
||||
event->iFlags &= ~( conditional_memstring | conditional_memval1 | conditional_memval2 );
|
||||
}
|
||||
}
|
||||
for( int i = 0; i < 8; ++i ) {
|
||||
if( Current->Params[ i ].asText != nullptr ) {
|
||||
cellastext = Current->Params[ i ].asText;
|
||||
SafeDeleteArray( Current->Params[ i ].asText );
|
||||
Current->Params[ i ].asEvent = FindEvent( cellastext );
|
||||
if( Current->Params[ i ].asEvent == nullptr ) {
|
||||
if( event->Params[ i ].asText != nullptr ) {
|
||||
cellastext = event->Params[ i ].asText;
|
||||
SafeDeleteArray( event->Params[ i ].asText );
|
||||
event->Params[ i ].asEvent = FindEvent( cellastext );
|
||||
if( event->Params[ i ].asEvent == nullptr ) {
|
||||
// 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: {
|
||||
// zmiana napięcia w zasilaczu (TractionPowerSource)
|
||||
if( false == Current->asNodeName.empty() ) {
|
||||
auto *powersource = simulation::Powergrid.find( Current->asNodeName ); // podłączenie zasilacza
|
||||
if( false == event->asNodeName.empty() ) {
|
||||
auto *powersource = simulation::Powergrid.find( event->asNodeName ); // podłączenie zasilacza
|
||||
if( powersource != nullptr )
|
||||
Current->Params[ 9 ].psPower = powersource;
|
||||
event->Params[ 9 ].psPower = powersource;
|
||||
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;
|
||||
}
|
||||
case tp_Message: {
|
||||
@@ -1554,7 +1592,37 @@ event_manager::InitEvents() {
|
||||
|
||||
} // 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
11
Event.h
@@ -63,7 +63,9 @@ union TParam
|
||||
{
|
||||
void *asPointer;
|
||||
TMemCell *asMemCell;
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
TGroundNode *nGroundNode;
|
||||
#endif
|
||||
editor::basic_node *asEditorNode;
|
||||
glm::dvec3 const *asLocation;
|
||||
TTrack *asTrack;
|
||||
@@ -125,6 +127,12 @@ public:
|
||||
// destructor
|
||||
~event_manager();
|
||||
// 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
|
||||
// TBD, TODO: return handle to the event
|
||||
bool
|
||||
@@ -144,6 +152,9 @@ public:
|
||||
// legacy method, initializes events after deserialization from scenario file
|
||||
void
|
||||
InitEvents();
|
||||
// legacy method, initializes event launchers after deserialization from scenario file
|
||||
void
|
||||
InitLaunchers();
|
||||
|
||||
private:
|
||||
// types
|
||||
|
||||
32
Ground.cpp
32
Ground.cpp
@@ -190,7 +190,7 @@ void TGroundNode::RenderHidden()
|
||||
}
|
||||
return;
|
||||
case TP_EVLAUNCH:
|
||||
if (EvLaunch->Render())
|
||||
if (EvLaunch->check_conditions())
|
||||
if ((EvLaunch->dRadius < 0) || (mgn < EvLaunch->dRadius))
|
||||
{
|
||||
WriteLog("Eventlauncher " + asName);
|
||||
@@ -1006,7 +1006,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TP_EVLAUNCH:
|
||||
parser->getTokens(3);
|
||||
*parser
|
||||
@@ -1018,7 +1017,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
tmp->EvLaunch = new TEventLauncher();
|
||||
tmp->EvLaunch->Load(parser);
|
||||
break;
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
case TP_TRACK:
|
||||
tmp->pTrack = new TTrack( tmp->asName );
|
||||
if (Global::iWriteLogEnabled & 4)
|
||||
@@ -1600,7 +1598,6 @@ TEvent * TGround::FindEvent(const std::string &asEventName)
|
||||
lookup->second :
|
||||
nullptr );
|
||||
}
|
||||
#endif
|
||||
|
||||
void TGround::FirstInit()
|
||||
{ // ustalanie zależności na scenerii przed wczytaniem pojazdów
|
||||
@@ -1668,18 +1665,14 @@ void TGround::FirstInit()
|
||||
|
||||
WriteLog("InitNormals OK");
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
InitTracks(); //łączenie odcinków ze sobą i przyklejanie eventów
|
||||
WriteLog("InitTracks OK");
|
||||
InitTraction(); //łączenie drutów ze sobą
|
||||
WriteLog("InitTraction OK");
|
||||
InitEvents();
|
||||
WriteLog( "InitEvents OK" );
|
||||
#endif
|
||||
|
||||
InitLaunchers();
|
||||
WriteLog("InitLaunchers OK");
|
||||
|
||||
WriteLog("FirstInit is done");
|
||||
};
|
||||
|
||||
@@ -1839,7 +1832,6 @@ bool TGround::Init(std::string File)
|
||||
}
|
||||
else if (str == "event")
|
||||
{
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
TEvent *tmp = new TEvent();
|
||||
tmp->Load(&parser, pOrigin);
|
||||
if (tmp->Type == tp_Unknown)
|
||||
@@ -1904,7 +1896,6 @@ bool TGround::Init(std::string File)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (str == "rotate")
|
||||
{
|
||||
@@ -2126,14 +2117,13 @@ bool TGround::Init(std::string File)
|
||||
|
||||
if (!bInitDone)
|
||||
FirstInit(); // jeśli nie było w scenerii
|
||||
#ifdef EU07_USE_OLD_TERRAINCODE
|
||||
|
||||
if (Global::pTerrainCompact)
|
||||
TerrainWrite(); // Ra: teraz można zapisać teren w jednym pliku
|
||||
#endif
|
||||
Global::iPause &= ~0x10; // koniec pauzy wczytywania
|
||||
return true;
|
||||
}
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
|
||||
bool TGround::InitEvents()
|
||||
{ //łączenie eventów z pozostałymi obiektami
|
||||
TGroundNode *tmp, *trk;
|
||||
@@ -2816,7 +2806,7 @@ void TGround::TrackJoin(TGroundNode *Current)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
// McZapkie-070602: wyzwalacze zdarzen
|
||||
bool TGround::InitLaunchers()
|
||||
{
|
||||
@@ -2837,26 +2827,16 @@ bool TGround::InitLaunchers()
|
||||
}
|
||||
else
|
||||
EventLauncher->MemCell = nullptr;
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
EventLauncher->Event1 = ( EventLauncher->asEvent1Name != "none") ?
|
||||
FindEvent(EventLauncher->asEvent1Name) :
|
||||
nullptr;
|
||||
EventLauncher->Event2 = ( EventLauncher->asEvent2Name != "none") ?
|
||||
FindEvent(EventLauncher->asEvent2Name) :
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
TTrack * TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude)
|
||||
{ // wyszukiwanie innego toru kończącego się w (Point)
|
||||
TTrack *tmp;
|
||||
@@ -3539,7 +3519,7 @@ TGround::Update_Hidden() {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Winger 170204 - szukanie trakcji nad pantografami
|
||||
bool TGround::GetTraction(TDynamicObject *model)
|
||||
{ // aktualizacja drutu zasilającego dla każdego pantografu, żeby odczytać napięcie
|
||||
@@ -3774,7 +3754,7 @@ bool TGround::GetTraction(TDynamicObject *model)
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
#endif
|
||||
#ifdef _WINDOWS
|
||||
//---------------------------------------------------------------------------
|
||||
void TGround::Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
6
Ground.h
6
Ground.h
@@ -277,15 +277,13 @@ class TGround
|
||||
TGround();
|
||||
~TGround();
|
||||
void Free();
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool Init( std::string File );
|
||||
void FirstInit();
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
void InitTracks();
|
||||
void InitTraction();
|
||||
bool InitEvents();
|
||||
#endif
|
||||
bool InitLaunchers();
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
TTrack * FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude);
|
||||
TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TGroundNode *Exclude);
|
||||
TTraction * TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n);
|
||||
@@ -295,9 +293,7 @@ class TGround
|
||||
void UpdatePhys(double dt, int iter); // aktualizacja fizyki stałym krokiem
|
||||
bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS
|
||||
void Update_Hidden(); // updates invisible elements of the scene
|
||||
#endif
|
||||
bool GetTraction(TDynamicObject *model);
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool AddToQuery( TEvent *Event, TDynamicObject *Node );
|
||||
bool CheckQuery();
|
||||
TGroundNode * DynamicFindAny(std::string const &Name);
|
||||
|
||||
@@ -129,7 +129,11 @@ bool TMemCell::Load(cParser *parser)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
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
|
||||
if (Mech)
|
||||
Mech->PutCommand(szText, fValue1, fValue2, Loc);
|
||||
|
||||
@@ -37,7 +37,11 @@ class TMemCell : public editor::basic_node {
|
||||
bool
|
||||
Load(cParser *parser);
|
||||
void
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
PutCommand( TController *Mech, Math3D::vector3 *Loc );
|
||||
#else
|
||||
PutCommand( TController *Mech, glm::dvec3 const *Loc );
|
||||
#endif
|
||||
bool
|
||||
Compare( std::string const &szTestText, double const fTestValue1, double const fTestValue2, int const CheckMask );
|
||||
std::string const &
|
||||
|
||||
7
Names.h
7
Names.h
@@ -108,4 +108,11 @@ protected:
|
||||
// members
|
||||
type_sequence m_items;
|
||||
type_map m_itemmap;
|
||||
|
||||
public:
|
||||
// data access
|
||||
typename type_sequence &
|
||||
sequence() {
|
||||
return m_items; }
|
||||
|
||||
};
|
||||
|
||||
@@ -11,8 +11,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Timer.h"
|
||||
#include "Globals.h"
|
||||
|
||||
namespace Timer
|
||||
{
|
||||
namespace Timer {
|
||||
|
||||
subsystem_stopwatches subsystem;
|
||||
|
||||
double DeltaTime, DeltaRenderTime;
|
||||
double fFPS{ 0.0f };
|
||||
|
||||
36
Timer.h
36
Timer.h
@@ -9,8 +9,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Timer
|
||||
{
|
||||
namespace Timer {
|
||||
|
||||
double GetTime();
|
||||
|
||||
@@ -28,6 +27,39 @@ double GetFPS();
|
||||
void ResetTimers();
|
||||
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
20
World.cpp
20
World.cpp
@@ -953,6 +953,7 @@ void TWorld::FollowView(bool wycisz) {
|
||||
bool TWorld::Update() {
|
||||
|
||||
Timer::UpdateTimers(Global::iPause != 0);
|
||||
Timer::subsystem.sim_total.start();
|
||||
|
||||
if( (Global::iPause == 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?
|
||||
// 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
|
||||
Timer::subsystem.sim_dynamics.start();
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
if( true == Global::FullPhysics ) {
|
||||
// mixed calculation mode, steps calculated in ~0.05s chunks
|
||||
@@ -1067,6 +1069,7 @@ bool TWorld::Update() {
|
||||
simulation::State.update( stepdeltatime, updatecount );
|
||||
}
|
||||
#endif
|
||||
Timer::subsystem.sim_dynamics.stop();
|
||||
|
||||
// secondary fixed step simulation time routines
|
||||
while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) {
|
||||
@@ -1110,7 +1113,7 @@ bool TWorld::Update() {
|
||||
Ground.CheckQuery();
|
||||
Ground.Update_Hidden();
|
||||
#else
|
||||
simulation::Events.CheckQuery();
|
||||
simulation::Events.update();
|
||||
simulation::Region->update();
|
||||
#endif
|
||||
|
||||
@@ -1144,6 +1147,8 @@ bool TWorld::Update() {
|
||||
|
||||
Update_Camera( dt );
|
||||
|
||||
Timer::subsystem.sim_total.stop();
|
||||
|
||||
GfxRenderer.Update( dt );
|
||||
ResourceSweep();
|
||||
|
||||
@@ -1659,20 +1664,14 @@ TWorld::Update_UI() {
|
||||
"VBO" :
|
||||
"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() ) {
|
||||
uitextline2 +=
|
||||
"Last openGL error: "
|
||||
+ Global::LastGLError;
|
||||
}
|
||||
// renderer stats
|
||||
uitextline3 = GfxRenderer.Info();
|
||||
uitextline3 = GfxRenderer.info_times();
|
||||
uitextline4 = GfxRenderer.info_stats();
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1683,6 +1682,9 @@ TWorld::Update_UI() {
|
||||
if( Global::iMultiplayer ) {
|
||||
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;
|
||||
}
|
||||
|
||||
190
renderer.cpp
190
renderer.cpp
@@ -315,23 +315,32 @@ opengl_renderer::Init( GLFWwindow *Window ) {
|
||||
bool
|
||||
opengl_renderer::Render() {
|
||||
|
||||
if( m_drawstart != std::chrono::steady_clock::time_point() ) {
|
||||
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 );
|
||||
}
|
||||
m_drawstart = std::chrono::steady_clock::now();
|
||||
auto const drawstartcolorpass = m_drawstart;
|
||||
Timer::subsystem.gfx_total.stop();
|
||||
Timer::subsystem.gfx_total.start(); // note: gfx_total is actually frame total, clean this up
|
||||
Timer::subsystem.gfx_color.start();
|
||||
|
||||
m_renderpass.draw_mode = rendermode::none; // force setup anew
|
||||
m_debuginfo.clear();
|
||||
++m_framestamp;
|
||||
m_debugtimestext.clear();
|
||||
m_debugstats = debug_stats();
|
||||
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();
|
||||
// accumulate last 20 frames worth of render time (cap at 1000 fps to prevent calculations going awry)
|
||||
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 );
|
||||
m_debuginfo += "frame total: " + to_string( m_drawtimecolorpass / 20.f, 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) ";
|
||||
m_debugtimestext
|
||||
+= "frame: " + to_string( Timer::subsystem.gfx_color.average(), 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
|
||||
}
|
||||
@@ -464,7 +473,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
|
||||
if( World.InitPerformed() ) {
|
||||
// setup
|
||||
auto const shadowdrawstart = std::chrono::steady_clock::now();
|
||||
Timer::subsystem.gfx_shadows.start();
|
||||
|
||||
::glBindFramebufferEXT( GL_FRAMEBUFFER, m_shadowframebuffer );
|
||||
|
||||
@@ -500,9 +509,8 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
::glDisable( GL_SCISSOR_TEST );
|
||||
|
||||
::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch back to primary render target
|
||||
|
||||
m_drawtimeshadowpass = 0.95f * m_drawtimeshadowpass + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - shadowdrawstart ) ).count() / 1000.f;
|
||||
m_debuginfo += "shadows: " + to_string( m_drawtimeshadowpass / 20.f, 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) ";
|
||||
Timer::subsystem.gfx_shadows.stop();
|
||||
m_debugtimestext += "shadows: " + to_string( Timer::subsystem.gfx_shadows.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -602,7 +610,7 @@ bool
|
||||
opengl_renderer::Render_reflections() {
|
||||
|
||||
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 )
|
||||
&& ( 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
|
||||
@@ -1477,12 +1485,6 @@ opengl_renderer::Render( TGroundRect *Groundcell ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef EU07_USE_OLD_TERRAINCODE
|
||||
if( Groundcell->nTerrain ) {
|
||||
|
||||
Render( Groundcell->nTerrain );
|
||||
}
|
||||
#endif
|
||||
|
||||
// add the subcells of the cell to the draw queue
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
@@ -1645,16 +1647,7 @@ opengl_renderer::Render( scene::basic_region *Region ) {
|
||||
Update_Lights( simulation::Lights );
|
||||
|
||||
Render( std::begin( m_sectionqueue ), std::end( m_sectionqueue ) );
|
||||
/*
|
||||
// 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.
|
||||
// draw queue is filled while rendering sections
|
||||
Render( std::begin( m_cellqueue ), std::end( m_cellqueue ) );
|
||||
break;
|
||||
}
|
||||
@@ -1749,7 +1742,7 @@ opengl_renderer::Render( section_sequence::iterator First, section_sequence::ite
|
||||
glEnable( GL_LIGHTING );
|
||||
#endif
|
||||
// shapes
|
||||
for( auto const &shape : section->m_shapes ) { Render( shape ); }
|
||||
for( auto const &shape : section->m_shapes ) { Render( shape, true ); }
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
}
|
||||
@@ -1852,7 +1845,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
|
||||
glEnable( GL_LIGHTING );
|
||||
#endif
|
||||
// opaque non-instanced shapes
|
||||
for( auto const &shape : cell->m_shapesopaque ) { Render( shape ); }
|
||||
for( auto const &shape : cell->m_shapesopaque ) { Render( shape, false ); }
|
||||
// tracks
|
||||
// TODO: update after path node refactoring
|
||||
for( auto *path : cell->m_paths ) { Render( path ); }
|
||||
@@ -1871,7 +1864,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
|
||||
|
||||
// render
|
||||
// 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
|
||||
|
||||
// post-render cleanup
|
||||
@@ -1887,7 +1880,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
// render
|
||||
// opaque non-instanced shapes
|
||||
for( auto const &shape : cell->m_shapesopaque ) { Render( shape ); }
|
||||
for( auto const &shape : cell->m_shapesopaque ) { Render( shape, false ); }
|
||||
// tracks
|
||||
// TODO: add path to the node picking list
|
||||
for( auto *path : cell->m_paths ) { Render( path ); }
|
||||
@@ -1922,6 +1915,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
|
||||
Render( dynamic );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rendermode::pickscenery: {
|
||||
// opaque parts of instanced models
|
||||
@@ -1944,9 +1938,46 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
|
||||
}
|
||||
|
||||
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
|
||||
Bind_Material( data.material );
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
@@ -1971,6 +2002,9 @@ opengl_renderer::Render( scene::shape_node const &Shape ) {
|
||||
}
|
||||
// render
|
||||
m_geometry.draw( data.geometry );
|
||||
// debug data
|
||||
++m_debugstats.shapes;
|
||||
++m_debugstats.drawcalls;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2021,19 +2055,7 @@ opengl_renderer::Render( TAnimModel *Instance ) {
|
||||
|
||||
bool
|
||||
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;
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::shadows: {
|
||||
@@ -2073,6 +2095,9 @@ opengl_renderer::Render( TGroundNode *Node ) {
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
// render
|
||||
Render( Node->pTrack );
|
||||
// debug
|
||||
++m_debugstats.paths;
|
||||
++m_debugstats.drawcalls;
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
return true;
|
||||
@@ -2155,7 +2180,9 @@ opengl_renderer::Render( TGroundNode *Node ) {
|
||||
}
|
||||
// render
|
||||
m_geometry.draw( Node->Piece->geometry );
|
||||
|
||||
// debug
|
||||
// ++m_debugstats.lines;
|
||||
// ++m_debugstats.drawcalls;
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
|
||||
@@ -2201,6 +2228,9 @@ opengl_renderer::Render( TGroundNode *Node ) {
|
||||
}
|
||||
// render
|
||||
m_geometry.draw( Node->Piece->geometry );
|
||||
// debug
|
||||
++m_debugstats.shapes;
|
||||
++m_debugstats.drawcalls;
|
||||
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
@@ -2236,6 +2266,9 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
|
||||
if( false == Dynamic->renderme ) {
|
||||
return false;
|
||||
}
|
||||
// debug data
|
||||
++m_debugstats.dynamics;
|
||||
|
||||
// setup
|
||||
TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji
|
||||
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( Model->Root );
|
||||
|
||||
// debug data
|
||||
++m_debugstats.models;
|
||||
|
||||
// post-render cleanup
|
||||
|
||||
return true;
|
||||
@@ -2468,6 +2504,10 @@ opengl_renderer::Render( TSubModel *Submodel ) {
|
||||
&& ( TSubModel::fSquareDist >= Submodel->fSquareMinDist )
|
||||
&& ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) {
|
||||
|
||||
// debug data
|
||||
++m_debugstats.submodels;
|
||||
++m_debugstats.drawcalls;
|
||||
|
||||
if( Submodel->iFlags & 0xC000 ) {
|
||||
::glPushMatrix();
|
||||
if( Submodel->fMatrix )
|
||||
@@ -2717,6 +2757,9 @@ opengl_renderer::Render( TTrack *Track ) {
|
||||
return;
|
||||
}
|
||||
|
||||
++m_debugstats.paths;
|
||||
++m_debugstats.drawcalls;
|
||||
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::color:
|
||||
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 );
|
||||
// render
|
||||
// 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
|
||||
::glPopMatrix();
|
||||
}
|
||||
@@ -3003,6 +3046,9 @@ opengl_renderer::Render_Alpha( TTraction *Traction ) {
|
||||
|
||||
// render
|
||||
m_geometry.draw( Traction->m_geometry );
|
||||
// debug data
|
||||
++m_debugstats.traction;
|
||||
++m_debugstats.drawcalls;
|
||||
}
|
||||
#endif
|
||||
bool
|
||||
@@ -3056,6 +3102,9 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
|
||||
|
||||
// render
|
||||
m_geometry.draw( Node->hvTraction->m_geometry );
|
||||
// debug data
|
||||
++m_debugstats.traction;
|
||||
++m_debugstats.drawcalls;
|
||||
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
@@ -3116,6 +3165,8 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
|
||||
|
||||
// render
|
||||
m_geometry.draw( Node->Piece->geometry );
|
||||
// ++m_debugstats.lines;
|
||||
// ++m_debugstats.drawcalls;
|
||||
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
@@ -3141,7 +3192,9 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
|
||||
|
||||
// render
|
||||
m_geometry.draw( Node->Piece->geometry );
|
||||
|
||||
// debug data
|
||||
++m_debugstats.shapes;
|
||||
++m_debugstats.drawcalls;
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
|
||||
@@ -3285,6 +3338,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
||||
&& ( TSubModel::fSquareDist >= Submodel->fSquareMinDist )
|
||||
&& ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) {
|
||||
|
||||
// debug data
|
||||
++m_debugstats.submodels;
|
||||
++m_debugstats.drawcalls;
|
||||
|
||||
if( Submodel->iFlags & 0xC000 ) {
|
||||
::glPushMatrix();
|
||||
if( Submodel->fMatrix )
|
||||
@@ -3580,10 +3637,10 @@ opengl_renderer::Update( double const Deltatime ) {
|
||||
}
|
||||
|
||||
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
|
||||
auto const framerate = 1000.f / (m_drawtimecolorpass / 20.f);
|
||||
auto const framerate = 1000.f / Timer::subsystem.gfx_color.average();
|
||||
|
||||
float targetfactor;
|
||||
if( framerate > 90.0 ) { targetfactor = 3.0f; }
|
||||
@@ -3620,7 +3677,7 @@ opengl_renderer::Update( double const Deltatime ) {
|
||||
}
|
||||
|
||||
if( true == DebugModeFlag ) {
|
||||
m_debuginfo += m_textures.info();
|
||||
m_debugtimestext += m_textures.info();
|
||||
}
|
||||
|
||||
if( ( true == Global::ControlPicking )
|
||||
@@ -3639,13 +3696,26 @@ opengl_renderer::Update( double const Deltatime ) {
|
||||
else {
|
||||
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
|
||||
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
|
||||
|
||||
25
renderer.h
25
renderer.h
@@ -203,7 +203,9 @@ public:
|
||||
Update_Pick_Node();
|
||||
// debug performance string
|
||||
std::string const &
|
||||
Info() const;
|
||||
info_times() const;
|
||||
std::string const &
|
||||
info_stats() const;
|
||||
|
||||
// members
|
||||
GLenum static const sunlight{ GL_LIGHT0 };
|
||||
@@ -227,6 +229,17 @@ private:
|
||||
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
|
||||
using distancesubcell_pair = std::pair< double, TSubRect * >;
|
||||
#else
|
||||
@@ -289,7 +302,7 @@ private:
|
||||
void
|
||||
Render( cell_sequence::iterator First, cell_sequence::iterator Last );
|
||||
void
|
||||
Render( scene::shape_node const &Shape );
|
||||
Render( scene::shape_node const &Shape, bool const Ignorerange );
|
||||
void
|
||||
Render( TAnimModel *Instance );
|
||||
#endif
|
||||
@@ -383,14 +396,12 @@ private:
|
||||
units_state m_unitstate;
|
||||
|
||||
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_drawtimecolorpass { 1000.f / 30.f * 20.f };
|
||||
float m_drawtimeshadowpass { 0.f };
|
||||
double m_updateaccumulator { 0.0 };
|
||||
std::string m_debuginfo;
|
||||
std::string m_debugtimestext;
|
||||
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_shadowcolor { 0.65f, 0.65f, 0.65f, 1.f };
|
||||
|
||||
298
scene.cpp
298
scene.cpp
@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "scene.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "timer.h"
|
||||
#include "renderer.h"
|
||||
#include "logs.h"
|
||||
|
||||
@@ -19,12 +20,32 @@ namespace scene {
|
||||
// legacy method, updates sounds and polls event launchers within radius around specified point
|
||||
void
|
||||
basic_cell::update() {
|
||||
/*
|
||||
// renderowanie obiektów aktywnych a niewidocznych
|
||||
for( auto node = subcell->nRenderHidden; node; node = node->nNext3 ) {
|
||||
node->RenderHidden();
|
||||
|
||||
// sounds
|
||||
auto const deltatime = Timer::GetDeltaTime();
|
||||
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
|
||||
for( auto *path : m_paths ) {
|
||||
// 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
|
||||
void
|
||||
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
|
||||
void
|
||||
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
|
||||
void
|
||||
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
|
||||
@@ -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
|
||||
void
|
||||
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
|
||||
std::tuple<TDynamicObject *, float>
|
||||
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() {
|
||||
|
||||
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 §ion : 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() {
|
||||
|
||||
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
|
||||
@@ -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 §ionlist = sections( pant0, 0.0 );
|
||||
for( auto *section : sectionlist ) {
|
||||
section->update_traction( Vehicle, Pantographindex );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_region::insert_shape( shape_node Shape, scratch_data &Scratchpad ) {
|
||||
|
||||
@@ -566,15 +680,15 @@ void
|
||||
basic_region::insert_path( TTrack *Path, scratch_data &Scratchpad ) {
|
||||
|
||||
// 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
|
||||
section( center ).insert( Path );
|
||||
section( location ).insert( Path );
|
||||
}
|
||||
else {
|
||||
// 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
|
||||
// TODO: clean this up during track refactoring
|
||||
@@ -588,15 +702,15 @@ void
|
||||
basic_region::insert_traction( TTraction *Traction, scratch_data &Scratchpad ) {
|
||||
|
||||
// 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
|
||||
section( center ).insert( Traction );
|
||||
section( location ).insert( Traction );
|
||||
}
|
||||
else {
|
||||
// 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
|
||||
// TODO: clean this up during track refactoring
|
||||
@@ -610,15 +724,15 @@ void
|
||||
basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ) {
|
||||
|
||||
// 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
|
||||
section( center ).insert( Instance );
|
||||
section( location ).insert( Instance );
|
||||
}
|
||||
else {
|
||||
// tracks are guaranteed to hava a name so we can skip the check
|
||||
ErrorLog( "Bad scenario: model node \"" + Instance->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
|
||||
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
|
||||
basic_region::insert_sound( TTextSound *Sound, scratch_data &Scratchpad ) {
|
||||
|
||||
/*
|
||||
// TODO: implement
|
||||
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
||||
auto center = Sound->location();
|
||||
auto location = Sound->location();
|
||||
|
||||
if( point_inside( center ) ) {
|
||||
if( point_inside( location ) ) {
|
||||
// NOTE: nodes placed outside of region boundaries are discarded
|
||||
section( center ).insert( Instance );
|
||||
section( location ).insert( Sound );
|
||||
}
|
||||
else {
|
||||
// tracks are guaranteed to hava a name so we can skip the check
|
||||
ErrorLog( "Bad scenario: model node \"" + Instance->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
|
||||
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
|
||||
@@ -757,7 +885,7 @@ void
|
||||
basic_region::register_path( TTrack *Path, glm::dvec3 const &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 ) {
|
||||
|
||||
if( point_inside( Point ) ) {
|
||||
section( Point ).register_end( Traction, Point );
|
||||
section( Point ).register_node( Traction, Point );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
56
scene.h
56
scene.h
@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <deque>
|
||||
#include <array>
|
||||
#include <stack>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "parser.h"
|
||||
#include "openglgeometrybank.h"
|
||||
@@ -24,7 +25,7 @@ namespace scene {
|
||||
|
||||
int const EU07_CELLSIZE = 250;
|
||||
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 {
|
||||
|
||||
@@ -42,6 +43,8 @@ struct scratch_data {
|
||||
TDynamicObject * driver { nullptr };
|
||||
bool is_open { false };
|
||||
} trainset;
|
||||
|
||||
bool initialized { false };
|
||||
};
|
||||
|
||||
// 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
|
||||
void
|
||||
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
|
||||
void
|
||||
insert( shape_node Shape );
|
||||
@@ -67,6 +73,12 @@ public:
|
||||
// adds provided model instance to the cell
|
||||
void
|
||||
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
|
||||
void
|
||||
register_end( TTrack *Path );
|
||||
@@ -100,10 +112,12 @@ private:
|
||||
// types
|
||||
using shapenode_sequence = std::vector<shape_node>;
|
||||
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_set = std::set<TTraction *>;
|
||||
// using traction_set = std::unordered_set<TTraction *>;
|
||||
using instance_sequence = std::vector<TAnimModel *>;
|
||||
using sound_sequence = std::vector<TTextSound *>;
|
||||
using eventlauncher_sequence = std::vector<TEventLauncher *>;
|
||||
// members
|
||||
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
|
||||
@@ -114,10 +128,12 @@ private:
|
||||
instance_sequence m_instancesopaque;
|
||||
instance_sequence m_instancetranslucent;
|
||||
traction_sequence m_traction;
|
||||
sound_sequence m_sounds;
|
||||
eventlauncher_sequence m_eventlaunchers;
|
||||
// search helpers
|
||||
struct lookup_data {
|
||||
path_set paths;
|
||||
traction_set traction;
|
||||
path_sequence paths;
|
||||
traction_sequence traction;
|
||||
} m_directories;
|
||||
};
|
||||
|
||||
@@ -131,24 +147,22 @@ public:
|
||||
// legacy method, updates sounds and polls event launchers within radius around specified point
|
||||
void
|
||||
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
|
||||
void
|
||||
insert( shape_node Shape );
|
||||
// adds provided path to the section
|
||||
// adds provided node to the section
|
||||
template <class Type_>
|
||||
void
|
||||
insert( TTrack *Path );
|
||||
// adds provided path to the section
|
||||
insert( Type_ *Node ) {
|
||||
cell( Node->location() ).insert( Node ); }
|
||||
// registers provided node in the lookup directory of the section enclosing specified point
|
||||
template <class Type_>
|
||||
void
|
||||
insert( TTraction *Traction );
|
||||
// adds provided model instance to the section
|
||||
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 );
|
||||
register_node( Type_ *Node, glm::dvec3 const &Point ) {
|
||||
cell( Point ).register_end( Node ); }
|
||||
// find a vehicle located nearest to specified point, within specified radius, optionally ignoring vehicles without drivers. reurns: located vehicle and distance
|
||||
std::tuple<TDynamicObject *, float>
|
||||
find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled );
|
||||
@@ -206,6 +220,9 @@ public:
|
||||
// legacy method, updates sounds and polls event launchers around camera
|
||||
void
|
||||
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
|
||||
void
|
||||
insert_shape( shape_node Shape, scratch_data &Scratchpad );
|
||||
@@ -221,6 +238,9 @@ public:
|
||||
// inserts provided sound in the region
|
||||
void
|
||||
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
|
||||
std::tuple<TDynamicObject *, float>
|
||||
find_vehicle( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled );
|
||||
|
||||
@@ -26,8 +26,8 @@ struct lighting_data {
|
||||
inline
|
||||
bool
|
||||
operator==( lighting_data const &Left, lighting_data const &Right ) {
|
||||
return ( ( Left.diffuse == Right.diffuse )
|
||||
&& ( Left.ambient == Right.ambient )
|
||||
return ( ( Left.diffuse == Right.diffuse )
|
||||
&& ( Left.ambient == Right.ambient )
|
||||
&& ( Left.specular == Right.specular ) ); }
|
||||
|
||||
inline
|
||||
|
||||
@@ -43,8 +43,8 @@ state_manager::deserialize( std::string const &Scenariofile ) {
|
||||
if( false == scenarioparser.ok() ) { return false; }
|
||||
|
||||
deserialize( scenarioparser );
|
||||
// TODO: initialize links between loaded nodes
|
||||
|
||||
Global::iPause &= ~0x10; // koniec pauzy wczytywania
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -126,6 +126,11 @@ state_manager::deserialize( cParser &Input ) {
|
||||
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
|
||||
if( false == importscratchpad.initialized ) {
|
||||
// manually perform scenario initialization
|
||||
deserialize_firstinit( Input, importscratchpad );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -247,11 +252,15 @@ state_manager::deserialize_event( cParser &Input, scene::scratch_data &Scratchpa
|
||||
void
|
||||
state_manager::deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// TODO: implement
|
||||
if( true == Scratchpad.initialized ) { return; }
|
||||
|
||||
simulation::Paths.InitTracks();
|
||||
simulation::Traction.InitTraction();
|
||||
simulation::Events.InitEvents();
|
||||
simulation::Events.InitLaunchers();
|
||||
simulation::Memory.InitCells();
|
||||
|
||||
Scratchpad.initialized = true;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -283,7 +292,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
|
||||
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
|
||||
@@ -303,7 +312,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
simulation::Region->insert_path( path, Scratchpad );
|
||||
}
|
||||
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 pathnode;
|
||||
@@ -320,7 +329,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
simulation::Region->insert_traction( traction, Scratchpad );
|
||||
}
|
||||
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" ) {
|
||||
@@ -336,7 +345,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
*/
|
||||
}
|
||||
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" ) {
|
||||
@@ -355,7 +364,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
simulation::Region->insert_instance( instance, Scratchpad );
|
||||
}
|
||||
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 {
|
||||
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" ) {
|
||||
// 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" ) {
|
||||
|
||||
@@ -396,7 +418,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
simulation::Region->insert_sound( sound, Scratchpad );
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad scenario: sound node with duplicate name, \"" + sound->m_name + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
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;
|
||||
}
|
||||
|
||||
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 *
|
||||
state_manager::deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "scene.h"
|
||||
#include "event.h"
|
||||
#include "memcell.h"
|
||||
#include "evlaunch.h"
|
||||
#include "track.h"
|
||||
#include "traction.h"
|
||||
#include "tractionpower.h"
|
||||
@@ -60,6 +61,7 @@ private:
|
||||
TTraction * deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TTractionPowerSource * deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
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 );
|
||||
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 );
|
||||
|
||||
Reference in New Issue
Block a user