16
0
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:
tmj-fstate
2017-10-14 03:53:13 +02:00
parent a12b84f50f
commit 09dbb3c639
23 changed files with 921 additions and 484 deletions

View File

@@ -2985,20 +2985,27 @@ void TController::RecognizeCommand()
c->Command = ""; // usunięcie obsłużonej komendy
}
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

View File

@@ -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:

View File

@@ -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;
}
}
}

View File

@@ -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 );
};
//---------------------------------------------------------------------------

View File

@@ -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
};
//---------------------------------------------------------------------------

View File

@@ -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
View File

@@ -727,6 +727,32 @@ event_manager::~event_manager() {
}
}
// adds specified event launcher to the list of global launchers
void
event_manager::queue( TEventLauncher *Launcher ) {
m_launcherqueue.emplace_back( Launcher );
}
// legacy method, updates event queues
void
event_manager::update() {
// process currently queued events
CheckQuery();
// test list of global events for possible new additions to the queue
for( auto *launcher : m_launcherqueue ) {
if( true == launcher->check_conditions() ) {
// NOTE: we're presuming global events aren't going to use event2
WriteLog( "Eventlauncher " + launcher->name() );
if( launcher->Event1 ) {
Global::AddToQuery( launcher->Event1, nullptr );
}
}
}
}
// adds provided event to the collection. returns: true on success
// 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
View File

@@ -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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 &

View File

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

View File

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

36
Timer.h
View File

@@ -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;
};
//---------------------------------------------------------------------------

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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
View File

@@ -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 &section : m_sections ) {
section.center( regioncornercenter + glm::dvec3{ column * EU07_SECTIONSIZE, 0.0, row * EU07_SECTIONSIZE } );
if( ++column >= EU07_REGIONSIDESECTIONCOUNT ) {
++row;
column = 0;
}
}
*/
}
basic_region::~basic_region() {
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 &sectionlist = 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
View File

@@ -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 );

View File

@@ -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

View File

@@ -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 ) {

View File

@@ -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 );