mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 23:19:19 +02:00
tmj merge
This commit is contained in:
103
AnimModel.cpp
103
AnimModel.cpp
@@ -15,15 +15,12 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "stdafx.h"
|
||||
#include "AnimModel.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
#include "usefull.h"
|
||||
#include "McZapkie/mctools.h"
|
||||
#include "Timer.h"
|
||||
#include "MdlMngr.h"
|
||||
// McZapkie:
|
||||
#include "renderer.h"
|
||||
//---------------------------------------------------------------------------
|
||||
#include "simulation.h"
|
||||
#include "Globals.h"
|
||||
#include "Timer.h"
|
||||
#include "Logs.h"
|
||||
|
||||
TAnimContainer *TAnimModel::acAnimList = NULL;
|
||||
|
||||
TAnimAdvanced::TAnimAdvanced(){};
|
||||
@@ -232,9 +229,10 @@ void TAnimContainer::UpdateModel() {
|
||||
fTranslateSpeed = 0.0; // wyłączenie przeliczania wektora
|
||||
if (LengthSquared3(vTranslation) <= 0.0001) // jeśli jest w punkcie początkowym
|
||||
iAnim &= ~2; // wyłączyć zmianę pozycji submodelu
|
||||
if (evDone)
|
||||
Global::AddToQuery(evDone, NULL); // wykonanie eventu informującego o
|
||||
// zakończeniu
|
||||
if( evDone ) {
|
||||
// wykonanie eventu informującego o zakończeniu
|
||||
simulation::Events.AddToQuery( evDone, nullptr );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fRotateSpeed != 0.0)
|
||||
@@ -299,9 +297,10 @@ void TAnimContainer::UpdateModel() {
|
||||
if (!anim)
|
||||
{ // nie potrzeba przeliczać już
|
||||
fRotateSpeed = 0.0;
|
||||
if (evDone)
|
||||
Global::AddToQuery(evDone, NULL); // wykonanie eventu informującego o
|
||||
// zakończeniu
|
||||
if( evDone ) {
|
||||
// wykonanie eventu informującego o zakończeniu
|
||||
simulation::Events.AddToQuery( evDone, nullptr );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( fAngleSpeed != 0.f ) {
|
||||
@@ -330,7 +329,7 @@ void TAnimContainer::PrepareModel()
|
||||
fAngleSpeed = 0.0; // wyłączenie przeliczania wektora
|
||||
if( evDone ) {
|
||||
// wykonanie eventu informującego o zakończeniu
|
||||
Global::AddToQuery( evDone, NULL );
|
||||
simulation::Events.AddToQuery( evDone, nullptr );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -406,23 +405,20 @@ void TAnimContainer::EventAssign(TEvent *ev)
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TAnimModel::TAnimModel()
|
||||
{
|
||||
pRoot = NULL;
|
||||
pModel = NULL;
|
||||
iNumLights = 0;
|
||||
fBlinkTimer = 0;
|
||||
|
||||
for (int i = 0; i < iMaxNumLights; ++i)
|
||||
{
|
||||
LightsOn[i] = LightsOff[i] = nullptr; // normalnie nie ma
|
||||
lsLights[i] = ls_Off; // a jeśli są, to wyłączone
|
||||
TAnimModel::TAnimModel( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {
|
||||
// TODO: wrap these in a tuple and move to underlying model
|
||||
for( int index = 0; index < iMaxNumLights; ++index ) {
|
||||
LightsOn[ index ] = LightsOff[ index ] = nullptr; // normalnie nie ma
|
||||
lsLights[ index ] = ls_Off; // a jeśli są, to wyłączone
|
||||
}
|
||||
}
|
||||
|
||||
TAnimModel::TAnimModel() {
|
||||
// TODO: wrap these in a tuple and move to underlying model
|
||||
for( int index = 0; index < iMaxNumLights; ++index ) {
|
||||
LightsOn[index] = LightsOff[index] = nullptr; // normalnie nie ma
|
||||
lsLights[index] = ls_Off; // a jeśli są, to wyłączone
|
||||
}
|
||||
vAngle.x = vAngle.y = vAngle.z = 0.0; // zerowanie obrotów egzemplarza
|
||||
pAdvanced = NULL; // nie ma zaawansowanej animacji
|
||||
fDark = 0.25f; // standardowy próg zaplania
|
||||
fOnTime = 0.66f;
|
||||
fOffTime = fOnTime + 0.66f;
|
||||
}
|
||||
|
||||
TAnimModel::~TAnimModel()
|
||||
@@ -572,6 +568,15 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
|
||||
m_framestamp = Framestamp;
|
||||
};
|
||||
|
||||
// calculates piece's bounding radius
|
||||
void
|
||||
TAnimModel::radius_() {
|
||||
|
||||
if( pModel != nullptr ) {
|
||||
m_area.radius = pModel->bounding_radius();
|
||||
}
|
||||
}
|
||||
|
||||
void TAnimModel::RaPrepare()
|
||||
{ // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza
|
||||
bool state; // stan światła
|
||||
@@ -762,21 +767,27 @@ void TAnimModel::LightSet(int n, float v)
|
||||
{ // ustawienie światła (n) na wartość (v)
|
||||
if (n >= iMaxNumLights)
|
||||
return; // przekroczony zakres
|
||||
lsLights[n] = TLightState(int(v));
|
||||
switch (lsLights[n])
|
||||
{ // interpretacja ułamka zależnie od typu
|
||||
case 0: // ustalenie czasu migotania, t<1s (f>1Hz), np. 0.1 => t=0.1 (f=10Hz)
|
||||
break;
|
||||
case 1: // ustalenie wypełnienia ułamkiem, np. 1.25 => zapalony przez 1/4 okresu
|
||||
break;
|
||||
case 2: // ustalenie częstotliwości migotania, f<1Hz (t>1s), np. 2.2 => f=0.2Hz (t=5s)
|
||||
break;
|
||||
case 3: // zapalenie świateł zależne od oświetlenia scenerii
|
||||
if (v > 3.0)
|
||||
fDark = v - 3.0; // ustawienie indywidualnego progu zapalania
|
||||
else
|
||||
fDark = 0.25; // standardowy próg zaplania
|
||||
break;
|
||||
lsLights[ n ] = TLightState( static_cast<int>( v ) );
|
||||
switch( lsLights[ n ] ) {
|
||||
// interpretacja ułamka zależnie od typu
|
||||
case ls_Off: {
|
||||
// ustalenie czasu migotania, t<1s (f>1Hz), np. 0.1 => t=0.1 (f=10Hz)
|
||||
break;
|
||||
}
|
||||
case ls_On: {
|
||||
// ustalenie wypełnienia ułamkiem, np. 1.25 => zapalony przez 1/4 okresu
|
||||
break;
|
||||
}
|
||||
case ls_Blink: {
|
||||
// ustalenie częstotliwości migotania, f<1Hz (t>1s), np. 2.2 => f=0.2Hz (t=5s)
|
||||
break;
|
||||
}
|
||||
case ls_Dark: {
|
||||
// zapalenie świateł zależne od oświetlenia scenerii
|
||||
if( v > 3.0 ) { fDark = v - 3.0; } // ustawienie indywidualnego progu zapalania
|
||||
else { fDark = DefaultDarkThresholdLevel; } // standardowy próg zaplania
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
140
AnimModel.h
140
AnimModel.h
@@ -19,15 +19,16 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "DynObj.h"
|
||||
|
||||
const int iMaxNumLights = 8;
|
||||
float const DefaultDarkThresholdLevel { 0.325f };
|
||||
|
||||
// typy stanu świateł
|
||||
typedef enum
|
||||
enum TLightState
|
||||
{
|
||||
ls_Off = 0, // zgaszone
|
||||
ls_On = 1, // zapalone
|
||||
ls_Blink = 2, // migające
|
||||
ls_Dark = 3 // Ra: zapalajce się automatycznie, gdy zrobi się ciemno
|
||||
} TLightState;
|
||||
};
|
||||
|
||||
class TAnimVocaloidFrame
|
||||
{ // ramka animacji typu Vocaloid Motion Data z programu MikuMikuDance
|
||||
@@ -77,16 +78,9 @@ class TAnimContainer
|
||||
TAnimContainer();
|
||||
~TAnimContainer();
|
||||
bool Init(TSubModel *pNewSubModel);
|
||||
// std::string inline GetName() { return
|
||||
// std::string(pSubModel?pSubModel->asName.c_str():""); };
|
||||
// std::string inline GetName() { return std::string(pSubModel?pSubModel->pName:"");
|
||||
// };
|
||||
std::string NameGet()
|
||||
{
|
||||
return (pSubModel ? pSubModel->pName : "");
|
||||
};
|
||||
// void SetRotateAnim(vector3 vNewRotateAxis, double fNewDesiredAngle, double
|
||||
// fNewRotateSpeed, bool bResetAngle=false);
|
||||
inline
|
||||
std::string NameGet() {
|
||||
return (pSubModel ? pSubModel->pName : ""); };
|
||||
void SetRotateAnim(vector3 vNewRotateAngles, double fNewRotateSpeed);
|
||||
void SetTranslateAnim(vector3 vNewTranslate, double fNewSpeed);
|
||||
void AnimSetVMD(double fNewSpeed);
|
||||
@@ -94,24 +88,20 @@ class TAnimContainer
|
||||
void UpdateModel();
|
||||
void UpdateModelIK();
|
||||
bool InMovement(); // czy w trakcie animacji?
|
||||
double AngleGet()
|
||||
{
|
||||
return vRotateAngles.z;
|
||||
}; // jednak ostatnia, T3D ma inny układ
|
||||
vector3 TransGet()
|
||||
{
|
||||
return vector3(-vTranslation.x, vTranslation.z, vTranslation.y);
|
||||
}; // zmiana, bo T3D ma inny układ
|
||||
void WillBeAnimated()
|
||||
{
|
||||
inline
|
||||
double AngleGet() {
|
||||
return vRotateAngles.z; }; // jednak ostatnia, T3D ma inny układ
|
||||
inline
|
||||
vector3 TransGet() {
|
||||
return vector3(-vTranslation.x, vTranslation.z, vTranslation.y); }; // zmiana, bo T3D ma inny układ
|
||||
inline
|
||||
void WillBeAnimated() {
|
||||
if (pSubModel)
|
||||
pSubModel->WillBeAnimated();
|
||||
};
|
||||
pSubModel->WillBeAnimated(); };
|
||||
void EventAssign(TEvent *ev);
|
||||
TEvent * Event()
|
||||
{
|
||||
return evDone;
|
||||
};
|
||||
inline
|
||||
TEvent * Event() {
|
||||
return evDone; };
|
||||
};
|
||||
|
||||
class TAnimAdvanced
|
||||
@@ -129,55 +119,77 @@ class TAnimAdvanced
|
||||
};
|
||||
|
||||
// opakowanie modelu, określające stan egzemplarza
|
||||
class TAnimModel {
|
||||
class TAnimModel : public editor::basic_node {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
private:
|
||||
TAnimContainer *pRoot; // pojemniki sterujące, tylko dla aniomowanych submodeli
|
||||
TModel3d *pModel;
|
||||
double fBlinkTimer;
|
||||
int iNumLights;
|
||||
TSubModel *LightsOn[iMaxNumLights]; // Ra: te wskaźniki powinny być w ramach TModel3d
|
||||
TSubModel *LightsOff[iMaxNumLights];
|
||||
vector3 vAngle; // bazowe obroty egzemplarza względem osi
|
||||
material_data m_materialdata;
|
||||
|
||||
std::string asText; // tekst dla wyświetlacza znakowego
|
||||
TAnimAdvanced *pAdvanced { nullptr };
|
||||
void Advanced();
|
||||
TLightState lsLights[iMaxNumLights];
|
||||
float fDark; // poziom zapalanie światła (powinno być chyba powiązane z danym światłem?)
|
||||
float fOnTime, fOffTime; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza
|
||||
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
|
||||
private:
|
||||
void RaAnimate( unsigned int const Framestamp ); // przeliczenie animacji egzemplarza
|
||||
void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu
|
||||
public:
|
||||
static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania
|
||||
inline
|
||||
material_data const *Material() const { return &m_materialdata; }
|
||||
|
||||
public:
|
||||
// constructors
|
||||
TAnimModel( scene::node_data const &Nodedata );
|
||||
TAnimModel();
|
||||
// destructor
|
||||
~TAnimModel();
|
||||
// methods
|
||||
static void AnimUpdate( double dt );
|
||||
bool Init(TModel3d *pNewModel);
|
||||
bool Init(std::string const &asName, std::string const &asReplacableTexture);
|
||||
bool Load(cParser *parser, bool ter = false);
|
||||
TAnimContainer * AddContainer(std::string const &Name);
|
||||
TAnimContainer * GetContainer(std::string const &Name = "");
|
||||
int Flags();
|
||||
void RaAnglesSet(double a, double b, double c)
|
||||
{
|
||||
vAngle.x = a;
|
||||
vAngle.y = b;
|
||||
vAngle.z = c;
|
||||
};
|
||||
void RaAnglesSet( glm::vec3 Angles ) {
|
||||
vAngle.x = Angles.x;
|
||||
vAngle.y = Angles.y;
|
||||
vAngle.z = Angles.z; };
|
||||
void LightSet( int n, float v );
|
||||
void AnimationVND( void *pData, double a, double b, double c, double d );
|
||||
bool TerrainLoaded();
|
||||
int TerrainCount();
|
||||
TSubModel * TerrainSquare(int n);
|
||||
void AnimationVND(void *pData, double a, double b, double c, double d);
|
||||
void LightSet(int n, float v);
|
||||
static void AnimUpdate(double dt);
|
||||
int Flags();
|
||||
inline
|
||||
material_data const *
|
||||
Material() const {
|
||||
return &m_materialdata; }
|
||||
inline
|
||||
TModel3d *
|
||||
Model() {
|
||||
return pModel; }
|
||||
// members
|
||||
static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania
|
||||
|
||||
protected:
|
||||
// calculates piece's bounding radius
|
||||
void
|
||||
radius_();
|
||||
|
||||
private:
|
||||
// methods
|
||||
void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu
|
||||
void RaAnimate( unsigned int const Framestamp ); // przeliczenie animacji egzemplarza
|
||||
void Advanced();
|
||||
// members
|
||||
TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli
|
||||
TModel3d *pModel { nullptr };
|
||||
double fBlinkTimer { 0.0 };
|
||||
int iNumLights { 0 };
|
||||
TSubModel *LightsOn[ iMaxNumLights ]; // Ra: te wskaźniki powinny być w ramach TModel3d
|
||||
TSubModel *LightsOff[ iMaxNumLights ];
|
||||
vector3 vAngle; // bazowe obroty egzemplarza względem osi
|
||||
material_data m_materialdata;
|
||||
|
||||
std::string asText; // tekst dla wyświetlacza znakowego
|
||||
TAnimAdvanced *pAdvanced { nullptr };
|
||||
TLightState lsLights[ iMaxNumLights ];
|
||||
float fDark { DefaultDarkThresholdLevel }; // poziom zapalanie światła (powinno być chyba powiązane z danym światłem?)
|
||||
float fOnTime { 0.66f };
|
||||
float fOffTime { 0.66f + 0.66f }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza
|
||||
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
|
||||
};
|
||||
|
||||
|
||||
|
||||
class instance_table : public basic_table<TAnimModel> {
|
||||
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -30,7 +30,6 @@ set(SOURCES
|
||||
"Float3d.cpp"
|
||||
"Gauge.cpp"
|
||||
"Globals.cpp"
|
||||
"Ground.cpp"
|
||||
"Logs.cpp"
|
||||
"McZapkie/friction.cpp"
|
||||
"McZapkie/hamulce.cpp"
|
||||
@@ -68,6 +67,11 @@ set(SOURCES
|
||||
"material.cpp"
|
||||
"lua.cpp"
|
||||
"uart.cpp"
|
||||
"messaging.cpp"
|
||||
"scene.cpp"
|
||||
"scenenode.cpp"
|
||||
"simulation.cpp"
|
||||
"vertex.cpp"
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
||||
@@ -18,9 +18,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// TViewPyramid TCamera::OrgViewPyramid;
|
||||
//={vector3(-1,1,1),vector3(1,1,1),vector3(-1,-1,1),vector3(1,-1,1),vector3(0,0,0)};
|
||||
|
||||
void TCamera::Init(vector3 NPos, vector3 NAngle)
|
||||
{
|
||||
|
||||
@@ -37,8 +34,8 @@ void TCamera::Init(vector3 NPos, vector3 NAngle)
|
||||
void TCamera::OnCursorMove(double x, double y)
|
||||
{
|
||||
// McZapkie-170402: zeby mysz dzialala zawsze if (Type==tp_Follow)
|
||||
Pitch += y;
|
||||
Yaw += -x;
|
||||
Yaw -= x;
|
||||
Pitch -= y;
|
||||
if (Yaw > M_PI)
|
||||
Yaw -= 2 * M_PI;
|
||||
else if (Yaw < -M_PI)
|
||||
@@ -62,7 +59,7 @@ TCamera::OnCommand( command_data const &Command ) {
|
||||
|
||||
OnCursorMove(
|
||||
reinterpret_cast<double const &>( Command.param1 ) * 0.005 * Global::fMouseXScale / Global::ZoomFactor,
|
||||
reinterpret_cast<double const &>( Command.param2 ) * -0.01 * Global::fMouseYScale / Global::ZoomFactor );
|
||||
reinterpret_cast<double const &>( Command.param2 ) * 0.01 * Global::fMouseYScale / Global::ZoomFactor );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class TMtableTime; // czas dla danego posterunku
|
||||
|
||||
class TController; // obiekt sterujący pociągiem (AI)
|
||||
|
||||
typedef enum
|
||||
enum TCommandType
|
||||
{ // binarne odpowiedniki komend w komórce pamięci
|
||||
cm_Unknown, // ciąg nierozpoznany (nie jest komendą)
|
||||
cm_Ready, // W4 zezwala na odjazd, ale semafor może zatrzymać
|
||||
@@ -51,6 +51,6 @@ typedef enum
|
||||
cm_OutsideStation,
|
||||
cm_Shunt,
|
||||
cm_Command // komenda pobierana z komórki
|
||||
} TCommandType;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
450
Driver.cpp
450
Driver.cpp
@@ -20,7 +20,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "mtable.h"
|
||||
#include "DynObj.h"
|
||||
#include "Event.h"
|
||||
#include "Ground.h"
|
||||
#include "MemCell.h"
|
||||
#include "World.h"
|
||||
#include "McZapkie/mctools.h"
|
||||
@@ -73,7 +72,17 @@ double GetDistanceToEvent(TTrack const *track, TEvent const *event, double scan_
|
||||
{ // przejście na inny tor
|
||||
track = track->Connected(int(sd), sd);
|
||||
start_dist += (1 == krok) ? 0 : back ? -segment->GetLength() : segment->GetLength();
|
||||
return GetDistanceToEvent(track, event, sd, start_dist, ++iter, 1 == krok ? true : false);
|
||||
if( ( track != nullptr )
|
||||
&& ( track->eType == tt_Cross ) ) {
|
||||
// NOTE: tracing through crossroads currently poses risk of tracing through wrong segment
|
||||
// as it's possible to be performerd before setting a route through the crossroads
|
||||
// as a stop-gap measure we don't trace through crossroads which should be reasonable in most cases
|
||||
// TODO: establish route before the scan, or a way for the function to know which route to pick
|
||||
return start_dist;
|
||||
}
|
||||
else {
|
||||
return GetDistanceToEvent( track, event, sd, start_dist, ++iter, 1 == krok ? true : false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // obliczenie mojego toru
|
||||
@@ -303,7 +312,7 @@ bool TSpeedPos::Update()
|
||||
std::string TSpeedPos::GetName()
|
||||
{
|
||||
if (iFlags & spTrack) // jeśli tor
|
||||
return trTrack->NameGet();
|
||||
return trTrack->name();
|
||||
else if( iFlags & spEvent ) // jeśli event
|
||||
return evEvent->asName;
|
||||
else
|
||||
@@ -517,7 +526,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
|
||||
if (pTrack != tLast) // ostatni zapisany w tabelce nie był jeszcze sprawdzony
|
||||
{ // jeśli tor nie był jeszcze sprawdzany
|
||||
if( Global::iWriteLogEnabled & 8 ) {
|
||||
WriteLog( "Speed table for " + OwnerName() + " tracing through track " + pTrack->NameGet() );
|
||||
WriteLog( "Speed table for " + OwnerName() + " tracing through track " + pTrack->name() );
|
||||
}
|
||||
|
||||
if( ( pEvent = CheckTrackEvent( pTrack, fLastDir ) ) != nullptr ) // jeśli jest semafor na tym torze
|
||||
@@ -580,11 +589,15 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
|
||||
// na skrzyżowaniach trzeba wybrać segment, po którym pojedzie pojazd
|
||||
// dopiero tutaj jest ustalany kierunek segmentu na skrzyżowaniu
|
||||
sSpeedTable[iLast].iFlags |=
|
||||
((pTrack->CrossSegment(
|
||||
(fLastDir < 0 ?
|
||||
tLast->iPrevDirection :
|
||||
tLast->iNextDirection),
|
||||
iRouteWanted) & 0xf) << 28); // ostatnie 4 bity pola flag
|
||||
( ( pTrack->CrossSegment(
|
||||
(fLastDir < 0 ?
|
||||
tLast->iPrevDirection :
|
||||
tLast->iNextDirection),
|
||||
/*
|
||||
iRouteWanted )
|
||||
*/
|
||||
1 + std::floor( Random( static_cast<double>(pTrack->RouteCount()) - 0.001 ) ) )
|
||||
& 0xf ) << 28 ); // ostatnie 4 bity pola flag
|
||||
sSpeedTable[iLast].iFlags &= ~spReverse; // usunięcie flagi kierunku, bo może być błędna
|
||||
if (sSpeedTable[iLast].iFlags < 0) {
|
||||
sSpeedTable[iLast].iFlags |= spReverse; // ustawienie flagi kierunku na podstawie wybranego segmentu
|
||||
@@ -592,10 +605,12 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
|
||||
if (int(fLastDir) * sSpeedTable[iLast].iFlags < 0) {
|
||||
fLastDir = -fLastDir;
|
||||
}
|
||||
/*
|
||||
if (AIControllFlag) {
|
||||
// dla AI na razie losujemy kierunek na kolejnym skrzyżowaniu
|
||||
iRouteWanted = 1 + Random(3);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
else if ( ( pTrack->fRadius != 0.0 ) // odległość na łuku lepiej aproksymować cięciwami
|
||||
@@ -708,7 +723,7 @@ void TController::TableCheck(double fDistance)
|
||||
if (sSpeedTable[i].Update())
|
||||
{
|
||||
if( Global::iWriteLogEnabled & 8 ) {
|
||||
WriteLog( "Speed table for " + OwnerName() + " detected switch change at " + sSpeedTable[ i ].trTrack->NameGet() + " (generating fresh trace)" );
|
||||
WriteLog( "Speed table for " + OwnerName() + " detected switch change at " + sSpeedTable[ i ].trTrack->name() + " (generating fresh trace)" );
|
||||
}
|
||||
// usuwamy wszystko za tym torem
|
||||
while (sSpeedTable.back().trTrack != sSpeedTable[i].trTrack)
|
||||
@@ -812,7 +827,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
WriteLog(
|
||||
pVehicle->asName + " as " + TrainParams->TrainName
|
||||
+ ": at " + std::to_string(simulation::Time.data().wHour) + ":" + std::to_string(simulation::Time.data().wMinute)
|
||||
+ " skipped " + asNextStop); // informacja
|
||||
+ " passed " + asNextStop); // informacja
|
||||
#endif
|
||||
// przy jakim dystansie (stanie licznika) ma przesunąć na następny postój
|
||||
fLastStopExpDist = mvOccupied->DistCounter + 0.250 + 0.001 * fLength;
|
||||
@@ -1252,7 +1267,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
// jeśli ma stać, dostaje komendę od razu
|
||||
go = cm_Command; // komenda z komórki, do wykonania po zatrzymaniu
|
||||
}
|
||||
else if( sSpeedTable[ i ].fDist <= 20.0 ) {
|
||||
else if( sSpeedTable[ i ].fDist <= fMaxProximityDist ) {
|
||||
// jeśli ma dociągnąć, to niech dociąga
|
||||
// (moveStopCloser dotyczy dociągania do W4, nie semafora)
|
||||
go = cm_Command; // komenda z komórki, do wykonania po zatrzymaniu
|
||||
@@ -1782,7 +1797,7 @@ void TController::AutoRewident()
|
||||
}
|
||||
if (mvOccupied->TrainType == dt_EZT)
|
||||
{
|
||||
fAccThreshold = -fBrake_a0[BrakeAccTableSize] - 8 * fBrake_a1[BrakeAccTableSize];
|
||||
fAccThreshold = std::max(-fBrake_a0[BrakeAccTableSize] - 8 * fBrake_a1[BrakeAccTableSize], -0.75);
|
||||
fBrakeReaction = 0.25;
|
||||
}
|
||||
else if (ustaw > 16)
|
||||
@@ -2400,7 +2415,7 @@ bool TController::IncBrake()
|
||||
}
|
||||
case Pneumatic: {
|
||||
// NOTE: can't perform just test whether connected vehicle == nullptr, due to virtual couplers formed with nearby vehicles
|
||||
bool standalone{ true };
|
||||
bool standalone { true };
|
||||
if( ( mvOccupied->TrainType == dt_ET41 )
|
||||
|| ( mvOccupied->TrainType == dt_ET42 ) ) {
|
||||
// NOTE: we're doing simplified checks full of presuptions here.
|
||||
@@ -2415,9 +2430,24 @@ bool TController::IncBrake()
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
standalone =
|
||||
( ( mvOccupied->Couplers[ 0 ].CouplingFlag == 0 )
|
||||
&& ( mvOccupied->Couplers[ 1 ].CouplingFlag == 0 ) );
|
||||
*/
|
||||
if( pVehicles[ 0 ] != pVehicles[ 1 ] ) {
|
||||
// more detailed version, will use manual braking also for coupled sets of controlled vehicles
|
||||
auto *vehicle = pVehicles[ 0 ]; // start from first
|
||||
while( ( true == standalone )
|
||||
&& ( vehicle != nullptr ) ) {
|
||||
// NOTE: we could simplify this by doing only check of the rear coupler, but this can be quite tricky in itself
|
||||
// TODO: add easier ways to access front/rear coupler taking into account vehicle's direction
|
||||
standalone =
|
||||
( ( ( vehicle->MoverParameters->Couplers[ 0 ].CouplingFlag == 0 ) || ( vehicle->MoverParameters->Couplers[ 0 ].CouplingFlag & coupling::control ) )
|
||||
&& ( ( vehicle->MoverParameters->Couplers[ 1 ].CouplingFlag == 0 ) || ( vehicle->MoverParameters->Couplers[ 1 ].CouplingFlag & coupling::control ) ) );
|
||||
vehicle = vehicle->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła)
|
||||
}
|
||||
}
|
||||
}
|
||||
if( true == standalone ) {
|
||||
OK = mvOccupied->IncLocalBrakeLevel(
|
||||
@@ -2973,20 +3003,15 @@ 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)
|
||||
{ // wysłanie komendy przez event PutValues, jak pojazd ma obsadę, to wysyła tutaj, a nie do pojazdu
|
||||
// bezpośrednio
|
||||
vector3 sl;
|
||||
sl.x = -NewLocation.X; // zamiana na współrzędne scenerii
|
||||
sl.z = NewLocation.Y;
|
||||
sl.y = NewLocation.Z;
|
||||
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
|
||||
// zamiana na współrzędne scenerii
|
||||
glm::dvec3 sl { -NewLocation.X, NewLocation.Z, NewLocation.Y };
|
||||
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)
|
||||
bool TController::PutCommand( std::string NewCommand, double NewValue1, double NewValue2, glm::dvec3 const *NewLocation, TStopReason reason )
|
||||
{ // analiza komendy
|
||||
if (NewCommand == "CabSignal")
|
||||
{ // SHP wyzwalane jest przez człon z obsadą, ale obsługiwane przez silnikowy
|
||||
@@ -3639,6 +3664,14 @@ TController::UpdateSituation(double dt) {
|
||||
// dla nastawienia G koniecznie należy wydłużyć drogę na czas reakcji
|
||||
fBrakeDist += 2 * mvOccupied->Vel;
|
||||
}
|
||||
/*
|
||||
// take into account effect of gravity (but to stay on safe side of calculations, only downhill)
|
||||
if( fAccGravity > 0.025 ) {
|
||||
fBrakeDist *= ( 1.0 + fAccGravity );
|
||||
// TBD: use version which shortens route going uphill, too
|
||||
//fBrakeDist = std::max( fBrakeDist, fBrakeDist * ( 1.0 + fAccGravity ) );
|
||||
}
|
||||
*/
|
||||
// route scan
|
||||
double routescanrange = (
|
||||
mvOccupied->Vel > 5.0 ?
|
||||
@@ -3812,8 +3845,11 @@ TController::UpdateSituation(double dt) {
|
||||
CheckVehicles(); // sprawdzić światła nowego składu
|
||||
JumpToNextOrder(); // wykonanie następnej komendy
|
||||
}
|
||||
/*
|
||||
// NOTE: disabled as speed limit is decided in another place based on distance to potential target
|
||||
else
|
||||
SetVelocity(2.0, 0.0); // jazda w ustawionym kierunku z prędkością 2 (18s)
|
||||
*/
|
||||
} // if (AIControllFlag) //koniec zblokowania, bo była zmienna lokalna
|
||||
}
|
||||
else {
|
||||
@@ -4208,13 +4244,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;
|
||||
@@ -4302,7 +4337,12 @@ TController::UpdateSituation(double dt) {
|
||||
if( OrderCurrentGet() & Connect ) {
|
||||
// jeśli spinanie, to jechać dalej
|
||||
AccPreferred = std::min( 0.25, AccPreferred ); // nie hamuj
|
||||
VelDesired = Global::Min0RSpeed( 20.0, VelDesired );
|
||||
VelDesired =
|
||||
Global::Min0RSpeed(
|
||||
VelDesired,
|
||||
( vehicle->fTrackBlock > 150.0 ?
|
||||
20.0:
|
||||
4.0 ) );
|
||||
VelNext = 2.0; // i pakuj się na tamtego
|
||||
}
|
||||
else {
|
||||
@@ -4345,7 +4385,12 @@ TController::UpdateSituation(double dt) {
|
||||
else {
|
||||
if( OrderCurrentGet() & Connect ) {
|
||||
// if there's something nearby in the connect mode don't speed up too much
|
||||
VelDesired = Global::Min0RSpeed( 20.0, VelDesired );
|
||||
VelDesired =
|
||||
Global::Min0RSpeed(
|
||||
VelDesired,
|
||||
( vehicle->fTrackBlock > 150.0 ?
|
||||
20.0 :
|
||||
4.0 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4452,6 +4497,7 @@ TController::UpdateSituation(double dt) {
|
||||
AbsAccS /= fMass;
|
||||
}
|
||||
AbsAccS_pub = AbsAccS;
|
||||
AbsAccS_avg = interpolate( AbsAccS_avg, mvOccupied->AccS * iDirection, 0.25 );
|
||||
|
||||
#if LOGVELOCITY
|
||||
// WriteLog("VelDesired="+AnsiString(VelDesired)+",
|
||||
@@ -4580,26 +4626,53 @@ TController::UpdateSituation(double dt) {
|
||||
|
||||
// decisions based on current speed
|
||||
if( mvOccupied->CategoryFlag == 1 ) {
|
||||
// try to estimate increase of current velocity before engaged brakes start working
|
||||
auto const speedestimate = vel + vel * ( 1.0 - fBrake_a0[ 0 ] ) * AbsAccS;
|
||||
if( speedestimate > VelDesired ) {
|
||||
// jesli jedzie za szybko do AKTUALNEGO
|
||||
if( VelDesired == 0.0 ) {
|
||||
// jesli stoj, to hamuj, ale i tak juz za pozno :)
|
||||
AccDesired = std::min( AccDesired, -0.85 ); // hamuj solidnie
|
||||
}
|
||||
else {
|
||||
if( speedestimate > ( VelDesired + fVelPlus ) ) {
|
||||
// if it looks like we'll exceed maximum allowed speed start thinking about slight slowing down
|
||||
AccDesired = std::min( AccDesired, -0.25 );
|
||||
|
||||
if( fAccGravity < 0.025 ) {
|
||||
// on flats on uphill we can be less careful
|
||||
if( vel > VelDesired ) {
|
||||
// jesli jedzie za szybko do AKTUALNEGO
|
||||
if( VelDesired == 0.0 ) {
|
||||
// jesli stoj, to hamuj, ale i tak juz za pozno :)
|
||||
AccDesired = std::min( AccDesired, -0.85 ); // hamuj solidnie
|
||||
}
|
||||
else {
|
||||
// close enough to target to stop accelerating
|
||||
AccDesired = std::min(
|
||||
AccDesired, // but don't override decceleration for VelNext
|
||||
interpolate( // ease off as you close to the target velocity
|
||||
-0.06, AccPreferred,
|
||||
clamp( speedestimate - vel, 0.0, fVelPlus ) / fVelPlus ) );
|
||||
// slow down, not full stop
|
||||
if( vel > ( VelDesired + fVelPlus ) ) {
|
||||
// hamuj tak średnio
|
||||
AccDesired = std::min( AccDesired, -0.25 );
|
||||
}
|
||||
else {
|
||||
// o 5 km/h to olej (zacznij luzować)
|
||||
AccDesired = std::min(
|
||||
AccDesired, // but don't override decceleration for VelNext
|
||||
std::max( 0.0, AccPreferred ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// going sharply downhill we may need to start braking sooner than usual
|
||||
// try to estimate increase of current velocity before engaged brakes start working
|
||||
auto const speedestimate = vel + ( 1.0 - fBrake_a0[ 0 ] ) * 30.0 * AbsAccS;
|
||||
if( speedestimate > VelDesired ) {
|
||||
// jesli jedzie za szybko do AKTUALNEGO
|
||||
if( VelDesired == 0.0 ) {
|
||||
// jesli stoj, to hamuj, ale i tak juz za pozno :)
|
||||
AccDesired = std::min( AccDesired, -0.85 ); // hamuj solidnie
|
||||
}
|
||||
else {
|
||||
if( speedestimate > ( VelDesired + fVelPlus ) ) {
|
||||
// if it looks like we'll exceed maximum allowed speed start thinking about slight slowing down
|
||||
AccDesired = std::min( AccDesired, -0.25 );
|
||||
}
|
||||
else {
|
||||
// close enough to target to stop accelerating
|
||||
AccDesired = std::min(
|
||||
AccDesired, // but don't override decceleration for VelNext
|
||||
interpolate( // ease off as you close to the target velocity
|
||||
-0.06, AccPreferred,
|
||||
clamp( speedestimate - vel, 0.0, fVelPlus ) / fVelPlus ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4631,8 +4704,10 @@ TController::UpdateSituation(double dt) {
|
||||
|
||||
// last step sanity check, until the whole calculation is straightened out
|
||||
AccDesired = std::min( AccDesired, AccPreferred );
|
||||
if( mvOccupied->CategoryFlag == 1 ) {
|
||||
// also take into account impact of gravity
|
||||
|
||||
if( ( mvOccupied->CategoryFlag == 1 )
|
||||
&& ( fAccGravity > 0.025 ) ) {
|
||||
// going downhill also take into account impact of gravity
|
||||
AccDesired = clamp( AccDesired - fAccGravity, -0.9, 0.9 );
|
||||
}
|
||||
|
||||
@@ -4884,41 +4959,19 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mietek-end1
|
||||
SpeedSet(); // ciągla regulacja prędkości
|
||||
#if LOGVELOCITY
|
||||
WriteLog("BrakePos=" + AnsiString(mvOccupied->BrakeCtrlPos) + ", MainCtrl=" +
|
||||
AnsiString(mvControlling->MainCtrlPos));
|
||||
#endif
|
||||
|
||||
/* //Ra: mamy teraz wskażnik na człon silnikowy, gorzej jak są dwa w
|
||||
ukrotnieniu...
|
||||
//zapobieganie poslizgowi w czlonie silnikowym; Ra: Couplers[1] powinno
|
||||
być
|
||||
if (Controlling->Couplers[0].Connected!=NULL)
|
||||
if (TestFlag(Controlling->Couplers[0].CouplingFlag,ctrain_controll))
|
||||
if (Controlling->Couplers[0].Connected->SlippingWheels)
|
||||
if (Controlling->ScndCtrlPos>0?!Controlling->DecScndCtrl(1):true)
|
||||
{
|
||||
if (!Controlling->DecMainCtrl(1))
|
||||
if (mvOccupied->BrakeCtrlPos==mvOccupied->BrakeCtrlPosNo)
|
||||
mvOccupied->DecBrakeLevel();
|
||||
++iDriverFailCount;
|
||||
}
|
||||
*/
|
||||
// zapobieganie poslizgowi u nas
|
||||
if (mvControlling->SlippingWheels)
|
||||
{
|
||||
if (!mvControlling->DecScndCtrl(2)) // bocznik na zero
|
||||
mvControlling->DecMainCtrl(1);
|
||||
if (mvOccupied->BrakeCtrlPos ==
|
||||
mvOccupied->BrakeCtrlPosNo) // jeśli ostatnia pozycja hamowania
|
||||
//yB: ten warunek wyżej nie ma sensu
|
||||
mvOccupied->DecBrakeLevel(); // to cofnij hamulec
|
||||
else
|
||||
mvControlling->AntiSlippingButton();
|
||||
++iDriverFailCount;
|
||||
//mvControlling->SlippingWheels = false; // flaga już wykorzystana
|
||||
if ((AccDesired < fAccGravity - 0.05) && (AbsAccS < AccDesired - fBrake_a1[0]*0.51)) {
|
||||
// jak hamuje, to nie tykaj kranu za często
|
||||
// yB: luzuje hamulec dopiero przy różnicy opóźnień rzędu 0.2
|
||||
if( OrderList[ OrderPos ] != Disconnect ) {
|
||||
// przy odłączaniu nie zwalniamy tu hamulca
|
||||
DecBrake(); // tutaj zmniejszało o 1 przy odczepianiu
|
||||
}
|
||||
fBrakeTime = (
|
||||
mvOccupied->BrakeDelayFlag > bdelay_G ?
|
||||
mvOccupied->BrakeDelay[ 0 ] :
|
||||
mvOccupied->BrakeDelay[ 2 ] )
|
||||
/ 3.0;
|
||||
fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1
|
||||
}
|
||||
// stop-gap measure to ensure cars actually brake to stop even when above calculactions go awry
|
||||
// instead of releasing the brakes and creeping into obstacle at 1-2 km/h
|
||||
@@ -5177,7 +5230,7 @@ std::string TController::StopReasonText()
|
||||
if (eStopReason != 7) // zawalidroga będzie inaczej
|
||||
return StopReasonTable[eStopReason];
|
||||
else
|
||||
return "Blocked by " + (pVehicles[0]->PrevAny()->GetName());
|
||||
return "Blocked by " + (pVehicles[0]->PrevAny()->name());
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
@@ -5280,7 +5333,7 @@ TTrack * TController::BackwardTraceRoute(double &fDistance, double &fDirection,
|
||||
}
|
||||
|
||||
// sprawdzanie zdarzeń semaforów i ograniczeń szlakowych
|
||||
void TController::SetProximityVelocity(double dist, double vel, const vector3 *pos)
|
||||
void TController::SetProximityVelocity( double dist, double vel, glm::dvec3 const *pos )
|
||||
{ // Ra:przeslanie do AI prędkości
|
||||
/*
|
||||
//!!!! zastąpić prawidłową reakcją AI na SetProximityVelocity !!!!
|
||||
@@ -5292,7 +5345,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
|
||||
@@ -5304,43 +5357,47 @@ void TController::SetProximityVelocity(double dist, double vel, const vector3 *p
|
||||
|
||||
TCommandType TController::BackwardScan()
|
||||
{ // sprawdzanie zdarzeń semaforów z tyłu pojazdu, zwraca komendę
|
||||
// dzięki temu będzie można stawać za wskazanym sygnalizatorem, a zwłaszcza jeśli będzie jazda
|
||||
// na kozioł
|
||||
// ograniczenia prędkości nie są wtedy istotne, również koniec toru jest do niczego nie
|
||||
// przydatny
|
||||
// dzięki temu będzie można stawać za wskazanym sygnalizatorem, a zwłaszcza jeśli będzie jazda na kozioł
|
||||
// ograniczenia prędkości nie są wtedy istotne, również koniec toru jest do niczego nie przydatny
|
||||
// zwraca true, jeśli należy odwrócić kierunek jazdy pojazdu
|
||||
if ((OrderList[OrderPos] & ~(Shunt | Connect)))
|
||||
return cm_Unknown; // skanowanie sygnałów tylko gdy jedzie w trybie manewrowym albo czeka na
|
||||
// rozkazy
|
||||
if( ( OrderList[ OrderPos ] & ~( Shunt | Connect ) ) ) {
|
||||
// skanowanie sygnałów tylko gdy jedzie w trybie manewrowym albo czeka na rozkazy
|
||||
return cm_Unknown;
|
||||
}
|
||||
vector3 sl;
|
||||
int startdir =
|
||||
-pVehicles[0]->DirectionGet(); // kierunek jazdy względem sprzęgów pojazdu na czele
|
||||
if (startdir == 0) // jeśli kabina i kierunek nie jest określony
|
||||
return cm_Unknown; // nie robimy nic
|
||||
double scandir =
|
||||
startdir * pVehicles[0]->RaDirectionGet(); // szukamy od pierwszej osi w wybranym kierunku
|
||||
if (scandir !=
|
||||
0.0) // skanowanie toru w poszukiwaniu eventów GetValues (PutValues nie są przydatne)
|
||||
{ // Ra: przy wstecznym skanowaniu prędkość nie ma znaczenia
|
||||
// scanback=pVehicles[1]->NextDistance(fLength+1000.0); //odległość do następnego pojazdu,
|
||||
// 1000 gdy nic nie ma
|
||||
// kierunek jazdy względem sprzęgów pojazdu na czele
|
||||
int const startdir = -pVehicles[0]->DirectionGet();
|
||||
if( startdir == 0 ) {
|
||||
// jeśli kabina i kierunek nie jest określony nie robimy nic
|
||||
return cm_Unknown;
|
||||
}
|
||||
// szukamy od pierwszej osi w wybranym kierunku
|
||||
double scandir = startdir * pVehicles[0]->RaDirectionGet();
|
||||
if (scandir != 0.0) {
|
||||
// skanowanie toru w poszukiwaniu eventów GetValues (PutValues nie są przydatne)
|
||||
// Ra: przy wstecznym skanowaniu prędkość nie ma znaczenia
|
||||
double scanmax = 1000; // 1000m do tyłu, żeby widział przeciwny koniec stacji
|
||||
double scandist = scanmax; // zmodyfikuje na rzeczywiście przeskanowane
|
||||
TEvent *e = NULL; // event potencjalnie od semafora
|
||||
// opcjonalnie może być skanowanie od "wskaźnika" z przodu, np. W5, Tm=Ms1, koniec toru
|
||||
TTrack *scantrack = BackwardTraceRoute(scandist, scandir, pVehicles[0]->RaTrackGet(),
|
||||
e); // wg drugiej osi w kierunku ruchu
|
||||
vector3 dir = startdir * pVehicles[0]->VectorFront(); // wektor w kierunku jazdy/szukania
|
||||
if (!scantrack) // jeśli wstecz wykryto koniec toru
|
||||
return cm_Unknown; // to raczej nic się nie da w takiej sytuacji zrobić
|
||||
else
|
||||
{ // a jeśli są dalej tory
|
||||
// opcjonalnie może być skanowanie od "wskaźnika" z przodu, np. W5, Tm=Ms1, koniec toru wg drugiej osi w kierunku ruchu
|
||||
TTrack *scantrack = BackwardTraceRoute(scandist, scandir, pVehicles[0]->RaTrackGet(), e);
|
||||
vector3 const dir = startdir * pVehicles[0]->VectorFront(); // wektor w kierunku jazdy/szukania
|
||||
if( !scantrack ) {
|
||||
// jeśli wstecz wykryto koniec toru to raczej nic się nie da w takiej sytuacji zrobić
|
||||
return cm_Unknown;
|
||||
}
|
||||
else {
|
||||
// a jeśli są dalej tory
|
||||
double vmechmax; // prędkość ustawiona semaforem
|
||||
if (e)
|
||||
{ // jeśli jest jakiś sygnał na widoku
|
||||
if( e != nullptr ) {
|
||||
// jeśli jest jakiś sygnał na widoku
|
||||
#if LOGBACKSCAN
|
||||
AnsiString edir =
|
||||
pVehicle->asName + " - " + AnsiString((scandir > 0) ? "Event2 " : "Event1 ");
|
||||
std::string edir {
|
||||
"Backward scan by "
|
||||
+ pVehicle->asName + " - "
|
||||
+ ( ( scandir > 0 ) ?
|
||||
"Event2 " :
|
||||
"Event1 " ) };
|
||||
#endif
|
||||
// najpierw sprawdzamy, czy semafor czy inny znak został przejechany
|
||||
vector3 pos = pVehicles[1]->RearPosition(); // pozycja tyłu
|
||||
@@ -5348,66 +5405,67 @@ TCommandType TController::BackwardScan()
|
||||
if (e->Type == tp_GetValues)
|
||||
{ // przesłać info o zbliżającym się semaforze
|
||||
#if LOGBACKSCAN
|
||||
edir += "(" + (e->Params[8].asGroundNode->asName) + "): ";
|
||||
edir += "(" + ( e->asNodeName ) + ")";
|
||||
#endif
|
||||
sl = e->PositionGet(); // położenie komórki pamięci
|
||||
sem = sl - pos; // wektor do komórki pamięci od końca składu
|
||||
// sem=e->Params[8].asGroundNode->pCenter-pos; //wektor do komórki pamięci
|
||||
if (dir.x * sem.x + dir.z * sem.z < 0) // jeśli został minięty
|
||||
// if ((mvOccupied->CategoryFlag&1)?(VelNext!=0.0):true) //dla pociągu wymagany
|
||||
// sygnał zezwalający
|
||||
{ // iloczyn skalarny jest ujemny, gdy sygnał stoi z tyłu
|
||||
if (dir.x * sem.x + dir.z * sem.z < 0) {
|
||||
// jeśli został minięty
|
||||
// iloczyn skalarny jest ujemny, gdy sygnał stoi z tyłu
|
||||
#if LOGBACKSCAN
|
||||
WriteLog(edir + "- ignored as not passed yet");
|
||||
WriteLog(edir + " - ignored as not passed yet");
|
||||
#endif
|
||||
return cm_Unknown; // nic
|
||||
}
|
||||
vmechmax = e->ValueGet(1); // prędkość przy tym semaforze
|
||||
// przeliczamy odległość od semafora - potrzebne by były współrzędne początku
|
||||
// składu
|
||||
// scandist=(pos-e->Params[8].asGroundNode->pCenter).Length()-0.5*mvOccupied->Dim.L-10;
|
||||
// //10m luzu
|
||||
// przeliczamy odległość od semafora - potrzebne by były współrzędne początku składu
|
||||
scandist = sem.Length() - 2; // 2m luzu przy manewrach wystarczy
|
||||
if (scandist < 0)
|
||||
scandist = 0; // ujemnych nie ma po co wysyłać
|
||||
if( scandist < 0 ) {
|
||||
// ujemnych nie ma po co wysyłać
|
||||
scandist = 0;
|
||||
}
|
||||
bool move = false; // czy AI w trybie manewerowym ma dociągnąć pod S1
|
||||
if (e->Command() == cm_SetVelocity)
|
||||
if ((vmechmax == 0.0) ? (OrderCurrentGet() & (Shunt | Connect)) :
|
||||
(OrderCurrentGet() &
|
||||
Connect)) // przy podczepianiu ignorować wyjazd?
|
||||
if( e->Command() == cm_SetVelocity ) {
|
||||
if( ( vmechmax == 0.0 ) ?
|
||||
( OrderCurrentGet() & ( Shunt | Connect ) ) :
|
||||
( OrderCurrentGet() & Connect ) ) { // przy podczepianiu ignorować wyjazd?
|
||||
move = true; // AI w trybie manewerowym ma dociągnąć pod S1
|
||||
else
|
||||
{ //
|
||||
if ((scandist > fMinProximityDist) ?
|
||||
(mvOccupied->Vel > 0.0) && (OrderCurrentGet() != Shunt) :
|
||||
false)
|
||||
{ // jeśli semafor jest daleko, a pojazd jedzie, to informujemy o
|
||||
// zmianie prędkości
|
||||
// jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył
|
||||
// Mechanik->PutCommand("SetProximityVelocity",scandist,vmechmax,sl);
|
||||
}
|
||||
else {
|
||||
if( ( scandist > fMinProximityDist )
|
||||
&& ( ( mvOccupied->Vel > 0.0 )
|
||||
&& ( OrderCurrentGet() != Shunt ) ) ) {
|
||||
// jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości
|
||||
// jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył
|
||||
#if LOGBACKSCAN
|
||||
// WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+"
|
||||
// "+AnsiString(vmechmax));
|
||||
// WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist) + AnsiString(vmechmax));
|
||||
WriteLog(edir);
|
||||
#endif
|
||||
// SetProximityVelocity(scandist,vmechmax,&sl);
|
||||
return (vmechmax > 0) ? cm_SetVelocity : cm_Unknown;
|
||||
return (
|
||||
vmechmax > 0 ?
|
||||
cm_SetVelocity :
|
||||
cm_Unknown );
|
||||
}
|
||||
else // ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma
|
||||
// stać
|
||||
// if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli stoi lub ma
|
||||
// stanąć/stać
|
||||
{ // semafor na tym torze albo lokomtywa stoi, a ma ruszyć, albo ma
|
||||
// stanąć, albo nie ruszać
|
||||
// stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam
|
||||
// PutCommand("SetVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem);
|
||||
else {
|
||||
// ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma stać
|
||||
// if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli stoi lub ma stanąć/stać
|
||||
// semafor na tym torze albo lokomtywa stoi, a ma ruszyć, albo ma stanąć, albo nie ruszać
|
||||
// stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam
|
||||
// PutCommand("SetVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem);
|
||||
#if LOGBACKSCAN
|
||||
WriteLog(edir + "SetVelocity " + AnsiString(vmechmax) + " " +
|
||||
AnsiString(e->Params[9].asMemCell->Value2()));
|
||||
WriteLog(
|
||||
edir + " - [SetVelocity] ["
|
||||
+ to_string( vmechmax, 2 ) + "] ["
|
||||
+ to_string( e->Params[ 9 ].asMemCell->Value2(), 2 ) + "]" );
|
||||
#endif
|
||||
return (vmechmax > 0) ? cm_SetVelocity : cm_Unknown;
|
||||
return (
|
||||
vmechmax > 0 ?
|
||||
cm_SetVelocity :
|
||||
cm_Unknown );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (OrderCurrentGet() ? OrderCurrentGet() & (Shunt | Connect) :
|
||||
true) // w Wait_for_orders też widzi tarcze
|
||||
{ // reakcja AI w trybie manewrowym dodatkowo na sygnały manewrowe
|
||||
@@ -5434,28 +5492,34 @@ TCommandType TController::BackwardScan()
|
||||
// to można zmienić kierunek
|
||||
}
|
||||
}
|
||||
else // ustawiamy prędkość tylko wtedy, gdy ma ruszyć, albo stanąć albo
|
||||
// ma stać pod tarczą
|
||||
{ // stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam
|
||||
// if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli jedzie
|
||||
// lub ma stanąć/stać
|
||||
else {
|
||||
// ustawiamy prędkość tylko wtedy, gdy ma ruszyć, albo stanąć albo ma stać pod tarczą
|
||||
// stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam
|
||||
// if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli jedzie lub ma stanąć/stać
|
||||
{ // nie dostanie komendy jeśli jedzie i ma jechać
|
||||
// PutCommand("ShuntVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem);
|
||||
// PutCommand("ShuntVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem);
|
||||
#if LOGBACKSCAN
|
||||
WriteLog(edir + "ShuntVelocity " + AnsiString(vmechmax) + " " +
|
||||
AnsiString(e->ValueGet(2)));
|
||||
WriteLog(
|
||||
edir + " - [ShuntVelocity] ["
|
||||
+ to_string( vmechmax, 2 ) + "] ["
|
||||
+ to_string( e->ValueGet( 2 ), 2 ) + "]" );
|
||||
#endif
|
||||
return (vmechmax > 0) ? cm_ShuntVelocity : cm_Unknown;
|
||||
return (
|
||||
vmechmax > 0 ?
|
||||
cm_ShuntVelocity :
|
||||
cm_Unknown );
|
||||
}
|
||||
}
|
||||
if ((vmechmax != 0.0) && (scandist < 100.0))
|
||||
{ // jeśli Tm w odległości do 100m podaje zezwolenie na jazdę, to od
|
||||
// razu ją ignorujemy, aby móc szukać kolejnej
|
||||
// eSignSkip=e; //wtedy uznajemy ignorowaną przy poszukiwaniu nowej
|
||||
if ((vmechmax != 0.0) && (scandist < 100.0)) {
|
||||
// jeśli Tm w odległości do 100m podaje zezwolenie na jazdę, to od razu ją ignorujemy, aby móc szukać kolejnej
|
||||
// eSignSkip=e; //wtedy uznajemy ignorowaną przy poszukiwaniu nowej
|
||||
#if LOGBACKSCAN
|
||||
WriteLog(edir + "- will be ignored due to Ms2");
|
||||
WriteLog(edir + " - will be ignored due to Ms2");
|
||||
#endif
|
||||
return (vmechmax > 0) ? cm_ShuntVelocity : cm_Unknown;
|
||||
return (
|
||||
vmechmax > 0 ?
|
||||
cm_ShuntVelocity :
|
||||
cm_Unknown );
|
||||
}
|
||||
} // if (move?...
|
||||
} // if (OrderCurrentGet()==Shunt)
|
||||
@@ -5644,31 +5708,30 @@ int TController::CrossRoute(TTrack *tr)
|
||||
}
|
||||
return 0; // nic nie znaleziono?
|
||||
};
|
||||
|
||||
/*
|
||||
void TController::RouteSwitch(int d)
|
||||
{ // ustawienie kierunku jazdy z kabiny
|
||||
d &= 3;
|
||||
if( d ) {
|
||||
if( iRouteWanted != d ) { // nowy kierunek
|
||||
iRouteWanted = d; // zapamiętanie
|
||||
if( mvOccupied->CategoryFlag & 2 ) {
|
||||
// jeśli samochód
|
||||
for( std::size_t i = 0; i < sSpeedTable.size(); ++i ) {
|
||||
// szukanie pierwszego skrzyżowania i resetowanie kierunku na nim
|
||||
if( true == TestFlag( sSpeedTable[ i ].iFlags, spEnabled | spTrack ) ) {
|
||||
// jeśli pozycja istotna (1) oraz odcinek (2)
|
||||
if( false == TestFlag( sSpeedTable[ i ].iFlags, spElapsed ) ) {
|
||||
// odcinek nie może być miniętym
|
||||
if( sSpeedTable[ i ].trTrack->eType == tt_Cross ) // jeśli skrzyżowanie
|
||||
{
|
||||
while( sSpeedTable.size() >= i ) {
|
||||
// NOTE: we're ignoring semaphor flags and not resetting them like we do for train route trimming
|
||||
// but what if there's street lights?
|
||||
// TODO: investigate
|
||||
sSpeedTable.pop_back();
|
||||
}
|
||||
iLast = sSpeedTable.size();
|
||||
if( ( d != 0 )
|
||||
&& ( iRouteWanted != d ) ) { // nowy kierunek
|
||||
iRouteWanted = d; // zapamiętanie
|
||||
if( mvOccupied->CategoryFlag & 2 ) {
|
||||
// jeśli samochód
|
||||
for( std::size_t i = 0; i < sSpeedTable.size(); ++i ) {
|
||||
// szukanie pierwszego skrzyżowania i resetowanie kierunku na nim
|
||||
if( true == TestFlag( sSpeedTable[ i ].iFlags, spEnabled | spTrack ) ) {
|
||||
// jeśli pozycja istotna (1) oraz odcinek (2)
|
||||
if( false == TestFlag( sSpeedTable[ i ].iFlags, spElapsed ) ) {
|
||||
// odcinek nie może być miniętym
|
||||
if( sSpeedTable[ i ].trTrack->eType == tt_Cross ) // jeśli skrzyżowanie
|
||||
{
|
||||
while( sSpeedTable.size() >= i ) {
|
||||
// NOTE: we're ignoring semaphor flags and not resetting them like we do for train route trimming
|
||||
// but what if there's street lights?
|
||||
// TODO: investigate
|
||||
sSpeedTable.pop_back();
|
||||
}
|
||||
iLast = sSpeedTable.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5676,6 +5739,7 @@ void TController::RouteSwitch(int d)
|
||||
}
|
||||
}
|
||||
};
|
||||
*/
|
||||
std::string TController::OwnerName() const
|
||||
{
|
||||
return ( pVehicle ? pVehicle->MoverParameters->Name : "none" );
|
||||
|
||||
16
Driver.h
16
Driver.h
@@ -209,6 +209,7 @@ public:
|
||||
double BrakeAccFactor();
|
||||
double fBrakeReaction = 1.0; //opóźnienie zadziałania hamulca - czas w s / (km/h)
|
||||
double fAccThreshold = 0.0; // próg opóźnienia dla zadziałania hamulca
|
||||
double AbsAccS_avg = 0.0; // averaged out directional acceleration
|
||||
double AbsAccS_pub = 0.0; // próg opóźnienia dla zadziałania hamulca
|
||||
double fBrake_a0[BrakeAccTableSize+1] = { 0.0 }; // próg opóźnienia dla zadziałania hamulca
|
||||
double fBrake_a1[BrakeAccTableSize+1] = { 0.0 }; // próg opóźnienia dla zadziałania hamulca
|
||||
@@ -230,8 +231,9 @@ private:
|
||||
TAction GetAction() {
|
||||
return eAction; }
|
||||
bool AIControllFlag = false; // rzeczywisty/wirtualny maszynista
|
||||
int iRouteWanted = 3; // oczekiwany kierunek jazdy (0-stop,1-lewo,2-prawo,3-prosto) np. odpala
|
||||
// migacz lub czeka na stan zwrotnicy
|
||||
/*
|
||||
int iRouteWanted = 3; // oczekiwany kierunek jazdy (0-stop,1-lewo,2-prawo,3-prosto) np. odpala migacz lub czeka na stan zwrotnicy
|
||||
*/
|
||||
private:
|
||||
TDynamicObject *pVehicle = nullptr; // pojazd w którym siedzi sterujący
|
||||
TDynamicObject *pVehicles[2]; // skrajne pojazdy w składzie (niekoniecznie bezpośrednio sterowane)
|
||||
@@ -311,10 +313,8 @@ 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);
|
||||
bool PutCommand( std::string NewCommand, double NewValue1, double NewValue2, glm::dvec3 const *NewLocation, TStopReason reason = stopComm );
|
||||
void UpdateSituation(double dt); // uruchamiac przynajmniej raz na sekundę
|
||||
// procedury dotyczace rozkazow dla maszynisty
|
||||
// uaktualnia informacje o prędkości
|
||||
@@ -374,7 +374,7 @@ private:
|
||||
bool BackwardTrackBusy(TTrack *Track);
|
||||
TEvent *CheckTrackEventBackward(double fDirection, TTrack *Track);
|
||||
TTrack *BackwardTraceRoute(double &fDistance, double &fDirection, TTrack *Track, TEvent *&Event);
|
||||
void SetProximityVelocity(double dist, double vel, const vector3 *pos);
|
||||
void SetProximityVelocity( double dist, double vel, glm::dvec3 const *pos );
|
||||
TCommandType BackwardScan();
|
||||
|
||||
public:
|
||||
@@ -401,7 +401,9 @@ private:
|
||||
void DirectionInitial();
|
||||
std::string TableText(std::size_t const Index);
|
||||
int CrossRoute(TTrack *tr);
|
||||
/*
|
||||
void RouteSwitch(int d);
|
||||
*/
|
||||
std::string OwnerName() const;
|
||||
TMoverParameters const *Controlling() const {
|
||||
return mvControlling; }
|
||||
|
||||
382
DynObj.cpp
382
DynObj.cpp
@@ -15,34 +15,20 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "stdafx.h"
|
||||
#include "DynObj.h"
|
||||
|
||||
#include "Logs.h"
|
||||
#include "MdlMngr.h"
|
||||
#include "Timer.h"
|
||||
#include "usefull.h"
|
||||
// McZapkie-260202
|
||||
#include "simulation.h"
|
||||
#include "Globals.h"
|
||||
#include "renderer.h"
|
||||
#include "AirCoupler.h"
|
||||
|
||||
#include "TractionPower.h"
|
||||
#include "Ground.h" //bo Global::pGround->bDynamicRemove
|
||||
#include "Event.h"
|
||||
#include "Driver.h"
|
||||
#include "Camera.h" //bo likwidujemy trzęsienie
|
||||
#include "Timer.h"
|
||||
#include "Logs.h"
|
||||
#include "Console.h"
|
||||
#include "Traction.h"
|
||||
#include "sound.h"
|
||||
#include "MdlMngr.h"
|
||||
|
||||
// Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny
|
||||
#define vWorldFront Math3D::vector3(0, 0, 1)
|
||||
#define vWorldUp Math3D::vector3(0, 1, 0)
|
||||
#define vWorldLeft CrossProduct(vWorldUp, vWorldFront)
|
||||
|
||||
// Ra: bo te poniżej to się powielały w każdym module odobno
|
||||
// vector3 vWorldFront=vector3(0,0,1);
|
||||
// vector3 vWorldUp=vector3(0,1,0);
|
||||
// vector3 vWorldLeft=CrossProduct(vWorldUp,vWorldFront);
|
||||
|
||||
#define M_2PI 6.283185307179586476925286766559;
|
||||
const float maxrot = (float)(M_PI / 3.0); // 60°
|
||||
|
||||
@@ -50,6 +36,7 @@ std::string const TDynamicObject::MED_labels[] = {
|
||||
"masa: ", "amax: ", "Fzad: ", "FmPN: ", "FmED: ", "FrED: ", "FzPN: ", "nPrF: "
|
||||
};
|
||||
|
||||
bool TDynamicObject::bDynamicRemove { false };
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void TAnimPant::AKP_4E()
|
||||
@@ -416,14 +403,22 @@ void TDynamicObject::UpdateDoorTranslate(TAnim *pAnim)
|
||||
// Ra: te współczynniki są bez sensu, bo modyfikują wektor przesunięcia
|
||||
// w efekcie drzwi otwierane na zewnątrz będą odlatywac dowolnie daleko :)
|
||||
// ograniczyłem zakres ruchu funkcją max
|
||||
if (pAnim->smAnimated)
|
||||
{
|
||||
if (pAnim->iNumber & 1)
|
||||
if (pAnim->smAnimated) {
|
||||
|
||||
if( pAnim->iNumber & 1 ) {
|
||||
pAnim->smAnimated->SetTranslate(
|
||||
vector3(0, 0, Min0R(dDoorMoveR * pAnim->fSpeed, dDoorMoveR)));
|
||||
else
|
||||
vector3{
|
||||
0.0,
|
||||
0.0,
|
||||
dDoorMoveR } );
|
||||
}
|
||||
else {
|
||||
pAnim->smAnimated->SetTranslate(
|
||||
vector3(0, 0, Min0R(dDoorMoveL * pAnim->fSpeed, dDoorMoveL)));
|
||||
vector3{
|
||||
0.0,
|
||||
0.0,
|
||||
dDoorMoveL } );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -494,18 +489,30 @@ void TDynamicObject::UpdatePant(TAnim *pAnim)
|
||||
|
||||
void TDynamicObject::UpdateDoorPlug(TAnim *pAnim)
|
||||
{ // animacja drzwi - odskokprzesuw
|
||||
if (pAnim->smAnimated)
|
||||
{
|
||||
if (pAnim->iNumber & 1)
|
||||
if (pAnim->smAnimated) {
|
||||
|
||||
if( pAnim->iNumber & 1 ) {
|
||||
pAnim->smAnimated->SetTranslate(
|
||||
vector3(Min0R(dDoorMoveR * 2, MoverParameters->DoorMaxPlugShift), 0,
|
||||
Max0R(0, Min0R(dDoorMoveR * pAnim->fSpeed, dDoorMoveR) -
|
||||
MoverParameters->DoorMaxPlugShift * 0.5f)));
|
||||
else
|
||||
vector3 {
|
||||
std::min(
|
||||
dDoorMoveR * 2,
|
||||
MoverParameters->DoorMaxPlugShift ),
|
||||
0.0,
|
||||
std::max(
|
||||
0.0,
|
||||
dDoorMoveR - MoverParameters->DoorMaxPlugShift * 0.5 ) } );
|
||||
}
|
||||
else {
|
||||
pAnim->smAnimated->SetTranslate(
|
||||
vector3(Min0R(dDoorMoveL * 2, MoverParameters->DoorMaxPlugShift), 0,
|
||||
Max0R(0, Min0R(dDoorMoveL * pAnim->fSpeed, dDoorMoveL) -
|
||||
MoverParameters->DoorMaxPlugShift * 0.5f)));
|
||||
vector3 {
|
||||
std::min(
|
||||
dDoorMoveL * 2,
|
||||
MoverParameters->DoorMaxPlugShift ),
|
||||
0.0,
|
||||
std::max(
|
||||
0.0,
|
||||
dDoorMoveL - MoverParameters->DoorMaxPlugShift * 0.5f ) } );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1757,8 +1764,8 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
}
|
||||
if (ActPar.find('0') != std::string::npos) // wylaczanie na sztywno
|
||||
{
|
||||
MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz
|
||||
MoverParameters->Hamulec->ForceEmptiness();
|
||||
MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz
|
||||
}
|
||||
if (ActPar.find('E') != std::string::npos) // oprozniony
|
||||
{
|
||||
@@ -1782,16 +1789,16 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
{
|
||||
if (Random(10) < 1) // losowanie 1/10
|
||||
{
|
||||
MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz
|
||||
MoverParameters->Hamulec->ForceEmptiness();
|
||||
MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz
|
||||
}
|
||||
}
|
||||
if (ActPar.find('X') != std::string::npos) // agonalny wylaczanie 20%, usrednienie przekladni
|
||||
{
|
||||
if (Random(100) < 20) // losowanie 20/100
|
||||
{
|
||||
MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz
|
||||
MoverParameters->Hamulec->ForceEmptiness();
|
||||
MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz
|
||||
}
|
||||
if (MoverParameters->BrakeCylMult[2] * MoverParameters->BrakeCylMult[1] >
|
||||
0.01) // jesli jest nastawiacz mechaniczny PL
|
||||
@@ -2625,77 +2632,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;
|
||||
@@ -2760,9 +2726,9 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
1000; // chwilowy max ED -> do rozdzialu sil
|
||||
FfulED = std::min(p->MoverParameters->eimv[eimv_Fful], 0.0) *
|
||||
1000; // chwilowy max ED -> do rozdzialu sil
|
||||
FrED -= std::min(p->MoverParameters->eimv[eimv_Fr], 0.0) *
|
||||
FrED -= std::min(p->MoverParameters->eimv[eimv_Fmax], 0.0) *
|
||||
1000; // chwilowo realizowane ED -> do pneumatyki
|
||||
Frj += std::max(p->MoverParameters->eimv[eimv_Fr], 0.0) *
|
||||
Frj += std::max(p->MoverParameters->eimv[eimv_Fmax], 0.0) *
|
||||
1000;// chwilowo realizowany napęd -> do utrzymującego
|
||||
masa += p->MoverParameters->TotalMass;
|
||||
osie += p->MoverParameters->NAxles;
|
||||
@@ -2861,10 +2827,10 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
if ((FzEP[i] > 0.01) &&
|
||||
(FzEP[i] >
|
||||
p->MoverParameters->TotalMass * p->MoverParameters->eimc[eimc_p_eped] +
|
||||
Min0R(p->MoverParameters->eimv[eimv_Fr], 0) * 1000) &&
|
||||
Min0R(p->MoverParameters->eimv[eimv_Fmax], 0) * 1000) &&
|
||||
(!PrzekrF[i]))
|
||||
{
|
||||
float przek1 = -Min0R(p->MoverParameters->eimv[eimv_Fr], 0) * 1000 +
|
||||
float przek1 = -Min0R(p->MoverParameters->eimv[eimv_Fmax], 0) * 1000 +
|
||||
FzEP[i] -
|
||||
p->MoverParameters->TotalMass *
|
||||
p->MoverParameters->eimc[eimc_p_eped] * 0.999;
|
||||
@@ -2969,19 +2935,13 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
// McZapkie-260202 - dMoveLen przyda sie przy stukocie kol
|
||||
dDOMoveLen =
|
||||
GetdMoveLen() + MoverParameters->ComputeMovement(dt, dt1, ts, tp, tmpTraction, l, r);
|
||||
// yB: zeby zawsze wrzucalo w jedna strone zakretu
|
||||
/*
|
||||
// this seemed to have opposite effect, if anything -- the sway direction would be affected
|
||||
// by the 'direction' of the track, making the sway go sometimes inward, sometimes outward
|
||||
MoverParameters->AccN *= -ABuGetDirection();
|
||||
*/
|
||||
// if (dDOMoveLen!=0.0) //Ra: nie może być, bo blokuje Event0
|
||||
if( Mechanik )
|
||||
Mechanik->MoveDistanceAdd( dDOMoveLen ); // dodanie aktualnego przemieszczenia
|
||||
Move(dDOMoveLen);
|
||||
if (!bEnabled) // usuwane pojazdy nie mają toru
|
||||
{ // pojazd do usunięcia
|
||||
Global::pGround->bDynamicRemove = true; // sprawdzić
|
||||
bDynamicRemove = true; // sprawdzić
|
||||
return false;
|
||||
}
|
||||
Global::ABuDebug = dDOMoveLen / dt1;
|
||||
@@ -3218,19 +3178,18 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
if ((MoverParameters->PantRearVolt == 0.0) &&
|
||||
(MoverParameters->PantFrontVolt == 0.0) && sPantUp)
|
||||
sPantUp->gain(vol).position(vPosition).play();
|
||||
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 (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 > (
|
||||
@@ -3297,8 +3256,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
|
||||
@@ -4183,7 +4142,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
// Ra 15-01: gałka nastawy hamulca
|
||||
parser.getTokens();
|
||||
parser >> asAnimName;
|
||||
smBrakeMode = mdModel->GetFromName(asAnimName.c_str());
|
||||
smBrakeMode = mdModel->GetFromName(asAnimName);
|
||||
// jeszcze wczytać kąty obrotu dla poszczególnych ustawień
|
||||
}
|
||||
|
||||
@@ -4191,7 +4150,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
// Ra 15-01: gałka nastawy hamulca
|
||||
parser.getTokens();
|
||||
parser >> asAnimName;
|
||||
smLoadMode = mdModel->GetFromName(asAnimName.c_str());
|
||||
smLoadMode = mdModel->GetFromName(asAnimName);
|
||||
// jeszcze wczytać kąty obrotu dla poszczególnych ustawień
|
||||
}
|
||||
|
||||
@@ -4203,7 +4162,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
for (i = 0; i < iAnimType[ANIM_WHEELS]; ++i) // liczba osi
|
||||
{ // McZapkie-050402: wyszukiwanie kol o nazwie str*
|
||||
asAnimName = token + std::to_string(i + 1);
|
||||
pAnimations[i].smAnimated = mdModel->GetFromName(asAnimName.c_str()); // ustalenie submodelu
|
||||
pAnimations[i].smAnimated = mdModel->GetFromName(asAnimName); // ustalenie submodelu
|
||||
if (pAnimations[i].smAnimated)
|
||||
{ //++iAnimatedAxles;
|
||||
pAnimations[i].smAnimated->WillBeAnimated(); // wyłączenie optymalizacji transformu
|
||||
@@ -4344,8 +4303,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
}
|
||||
}
|
||||
else
|
||||
ErrorLog("Bad model: " + asFileName + " - missed submodel " +
|
||||
asAnimName); // brak ramienia
|
||||
ErrorLog("Bad model: " + asFileName + " - missed submodel " + asAnimName); // brak ramienia
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4379,10 +4337,9 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
}
|
||||
}
|
||||
else
|
||||
ErrorLog( "Bad model: " + asFileName + " - missed submodel " +
|
||||
asAnimName ); // brak ramienia
|
||||
ErrorLog( "Bad model: " + asFileName + " - missed submodel " + asAnimName ); // brak ramienia
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if( token == "animpantrg1prefix:" ) {
|
||||
@@ -4473,10 +4430,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4955,7 +4910,9 @@ void TDynamicObject::RadioStop()
|
||||
if( ( MoverParameters->SecuritySystem.RadioStop )
|
||||
&& ( MoverParameters->Radio ) ) {
|
||||
// jeśli pojazd ma RadioStop i jest on aktywny
|
||||
Mechanik->PutCommand( "Emergency_brake", 1.0, 1.0, &vPosition, stopRadio );
|
||||
// HAX cast until math types unification
|
||||
glm::dvec3 pos = static_cast<glm::dvec3>(vPosition);
|
||||
Mechanik->PutCommand( "Emergency_brake", 1.0, 1.0, &pos, stopRadio );
|
||||
// add onscreen notification for human driver
|
||||
// TODO: do it selectively for the 'local' driver once the multiplayer is in
|
||||
if( false == Mechanik->AIControllFlag ) {
|
||||
@@ -5414,3 +5371,166 @@ TDynamicObject::ConnectedEnginePowerSource( TDynamicObject const *Caller ) const
|
||||
// ...if we're still here, report lack of power source
|
||||
return MoverParameters->EnginePowerSource.SourceType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// legacy method, calculates changes in simulation state over specified time
|
||||
void
|
||||
vehicle_table::update( double Deltatime, int Iterationcount ) {
|
||||
// Ra: w zasadzie to trzeba by utworzyć oddzielną listę taboru do liczenia fizyki
|
||||
// na którą by się zapisywały wszystkie pojazdy będące w ruchu
|
||||
// pojazdy stojące nie potrzebują aktualizacji, chyba że np. ktoś im zmieni nastawę hamulca
|
||||
// oddzielną listę można by zrobić na pojazdy z napędem, najlepiej posortowaną wg typu napędu
|
||||
for( auto *vehicle : m_items ) {
|
||||
if( false == vehicle->bEnabled ) { continue; }
|
||||
// Ra: zmienić warunek na sprawdzanie pantografów w jednej zmiennej: czy pantografy i czy podniesione
|
||||
if( vehicle->MoverParameters->EnginePowerSource.SourceType == CurrentCollector ) {
|
||||
update_traction( vehicle );
|
||||
}
|
||||
vehicle->MoverParameters->ComputeConstans();
|
||||
vehicle->CoupleDist();
|
||||
}
|
||||
if( Iterationcount > 1 ) {
|
||||
// ABu: ponizsze wykonujemy tylko jesli wiecej niz jedna iteracja
|
||||
for( int iteration = 0; iteration < ( Iterationcount - 1 ); ++iteration ) {
|
||||
for( auto *vehicle : m_items ) {
|
||||
vehicle->UpdateForce( Deltatime, Deltatime, false );
|
||||
}
|
||||
for( auto *vehicle : m_items ) {
|
||||
vehicle->FastUpdate( Deltatime );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto const totaltime { Deltatime * Iterationcount }; // całkowity czas
|
||||
|
||||
for( auto *vehicle : m_items ) {
|
||||
vehicle->UpdateForce( Deltatime, totaltime, true );
|
||||
}
|
||||
for( auto *vehicle : m_items ) {
|
||||
// Ra 2015-01: tylko tu przelicza sieć trakcyjną
|
||||
vehicle->Update( Deltatime, totaltime );
|
||||
}
|
||||
/*
|
||||
// TODO: re-implement
|
||||
if (TDynamicObject::bDynamicRemove)
|
||||
{ // jeśli jest coś do usunięcia z listy, to trzeba na końcu
|
||||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||||
if ( false == Current->DynamicObject->bEnabled)
|
||||
{
|
||||
DynamicRemove(Current->DynamicObject); // usunięcie tego i podłączonych
|
||||
Current = nRootDynamic; // sprawdzanie listy od początku
|
||||
}
|
||||
TDynamicObject::bDynamicRemove = false; // na razie koniec
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// legacy method, sends list of vehicles over network
|
||||
void
|
||||
vehicle_table::DynamicList( bool const Onlycontrolled ) const {
|
||||
// odesłanie nazw pojazdów dostępnych na scenerii (nazwy, szczególnie wagonów, mogą się powtarzać!)
|
||||
for( auto const *vehicle : m_items ) {
|
||||
if( ( false == Onlycontrolled )
|
||||
|| ( vehicle->Mechanik != nullptr ) ) {
|
||||
// same nazwy pojazdów
|
||||
multiplayer::WyslijString( vehicle->asName, 6 );
|
||||
}
|
||||
}
|
||||
// informacja o końcu listy
|
||||
multiplayer::WyslijString( "none", 6 );
|
||||
}
|
||||
|
||||
196
DynObj.h
196
DynObj.h
@@ -149,6 +149,9 @@ class TDynamicObject { // klasa pojazdu
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
public:
|
||||
static bool bDynamicRemove; // moved from ground
|
||||
|
||||
private: // położenie pojazdu w świecie oraz parametry ruchu
|
||||
Math3D::vector3 vPosition; // Ra: pozycja pojazdu liczona zaraz po przesunięciu
|
||||
Math3D::vector3 vCoulpler[ 2 ]; // współrzędne sprzęgów do liczenia zderzeń czołowych
|
||||
@@ -158,19 +161,17 @@ private: // położenie pojazdu w świecie oraz parametry ruchu
|
||||
TTrackParam tp; // parametry toru przekazywane do fizyki
|
||||
TTrackFollower Axle0; // oś z przodu (od sprzęgu 0)
|
||||
TTrackFollower Axle1; // oś z tyłu (od sprzęgu 1)
|
||||
int iAxleFirst; // numer pierwszej osi w kierunku ruchu (oś wiążąca pojazd z torem i wyzwalająca
|
||||
// eventy)
|
||||
int iAxleFirst; // numer pierwszej osi w kierunku ruchu (oś wiążąca pojazd z torem i wyzwalająca eventy)
|
||||
float fAxleDist; // rozstaw wózków albo osi do liczenia proporcji zacienienia
|
||||
Math3D::vector3 modelRot; // obrot pudła względem świata - do przeanalizowania, czy potrzebne!!!
|
||||
// bool bCameraNear; //blisko kamer są potrzebne dodatkowe obliczenia szczegółów
|
||||
TDynamicObject * ABuFindNearestObject( TTrack *Track, TDynamicObject *MyPointer, int &CouplNr );
|
||||
|
||||
public: // parametry położenia pojazdu dostępne publicznie
|
||||
public:
|
||||
// parametry położenia pojazdu dostępne publicznie
|
||||
std::string asTrack; // nazwa toru początkowego; wywalić?
|
||||
std::string asDestination; // dokąd pojazd ma być kierowany "(stacja):(tor)"
|
||||
Math3D::matrix4x4 mMatrix; // macierz przekształcenia do renderowania modeli
|
||||
TMoverParameters *MoverParameters; // parametry fizyki ruchu oraz przeliczanie
|
||||
// TMoverParameters *pControlled; //wskaźnik do sterowanego członu silnikowego
|
||||
TDynamicObject *NextConnected; // pojazd podłączony od strony sprzęgu 1 (kabina -1)
|
||||
TDynamicObject *PrevConnected; // pojazd podłączony od strony sprzęgu 0 (kabina 1)
|
||||
int NextConnectedNo; // numer sprzęgu podłączonego z tyłu
|
||||
@@ -180,7 +181,7 @@ public: // parametry położenia pojazdu dostępne publicznie
|
||||
|
||||
TPowerSource ConnectedEnginePowerSource( TDynamicObject const *Caller ) const;
|
||||
|
||||
public: // modele składowe pojazdu
|
||||
// modele składowe pojazdu
|
||||
TModel3d *mdModel; // model pudła
|
||||
TModel3d *mdLoad; // model zmiennego ładunku
|
||||
TModel3d *mdKabina; // model kabiny dla użytkownika; McZapkie-030303: to z train.h
|
||||
@@ -199,28 +200,26 @@ public: // modele składowe pojazdu
|
||||
bool SectionLightsActive { false }; // flag indicating whether section lights were set.
|
||||
float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?)
|
||||
|
||||
private: // zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe
|
||||
private:
|
||||
// zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe
|
||||
material_data m_materialdata;
|
||||
|
||||
public:
|
||||
public:
|
||||
inline
|
||||
material_data const
|
||||
*Material() const {
|
||||
return &m_materialdata; }
|
||||
// tymczasowo udostępnione do wyszukiwania drutu
|
||||
int iAnimType[ ANIM_TYPES ]; // 0-osie,1-drzwi,2-obracane,3-zderzaki,4-wózki,5-pantografy,6-tłoki
|
||||
private:
|
||||
private:
|
||||
int iAnimations; // liczba obiektów animujących
|
||||
/*
|
||||
TAnim *pAnimations; // obiekty animujące (zawierają wskaźnik do funkcji wykonującej animację)
|
||||
*/
|
||||
std::vector<TAnim> pAnimations;
|
||||
TSubModel **
|
||||
pAnimated; // lista animowanych submodeli (może być ich więcej niż obiektów animujących)
|
||||
double dWheelAngle[3]; // kąty obrotu kół: 0=przednie toczne, 1=napędzające i wiązary, 2=tylne
|
||||
// toczne
|
||||
void
|
||||
UpdateNone(TAnim *pAnim){}; // animacja pusta (funkcje ustawiania submodeli, gdy blisko kamery)
|
||||
TSubModel ** pAnimated; // lista animowanych submodeli (może być ich więcej niż obiektów animujących)
|
||||
double dWheelAngle[3]; // kąty obrotu kół: 0=przednie toczne, 1=napędzające i wiązary, 2=tylne toczne
|
||||
void UpdateNone(TAnim *pAnim){}; // animacja pusta (funkcje ustawiania submodeli, gdy blisko kamery)
|
||||
void UpdateAxle(TAnim *pAnim); // animacja osi
|
||||
void UpdateBoogie(TAnim *pAnim); // animacja wózka
|
||||
void UpdateDoorTranslate(TAnim *pAnim); // animacja drzwi - przesuw
|
||||
@@ -266,8 +265,7 @@ public: // modele składowe pojazdu
|
||||
|
||||
TButton btCoupler1; // sprzegi
|
||||
TButton btCoupler2;
|
||||
TAirCoupler
|
||||
btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
|
||||
TAirCoupler btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
|
||||
TAirCoupler btCPneumatic2;
|
||||
TAirCoupler btCPneumatic1r; // ABu: to zeby nie bylo problemow przy laczeniu wagonow,
|
||||
TAirCoupler btCPneumatic2r; // jesli beda polaczone sprzegami 1<->1 lub 0<->0
|
||||
@@ -298,8 +296,6 @@ public: // modele składowe pojazdu
|
||||
TButton btHeadSignals23;
|
||||
TButton btMechanik1;
|
||||
TButton btMechanik2;
|
||||
//TSubModel *smMechanik0; // Ra: mechanik wbudowany w model jako submodel?
|
||||
//TSubModel *smMechanik1; // mechanik od strony sprzęgu 1
|
||||
double enginevolume; // MC: pomocnicze zeby gladziej silnik buczal
|
||||
|
||||
int iAxles; // McZapkie: to potem mozna skasowac i zastapic iNumAxles
|
||||
@@ -323,7 +319,6 @@ public: // modele składowe pojazdu
|
||||
sound* sReleaser = nullptr;
|
||||
|
||||
// Winger 010304
|
||||
// sound* rsPanTup; //PSound sPantUp;
|
||||
sound* sPantUp = nullptr;
|
||||
sound* sPantDown = nullptr;
|
||||
sound* rsDoorOpen = nullptr; // Ra: przeniesione z kabiny
|
||||
@@ -350,8 +345,6 @@ public: // modele składowe pojazdu
|
||||
int iHornWarning; // numer syreny do użycia po otrzymaniu sygnału do jazdy
|
||||
bool bEnabled; // Ra: wyjechał na portal i ma być usunięty
|
||||
protected:
|
||||
// TTrackFollower Axle2; //dwie osie z czterech (te są protected)
|
||||
// TTrackFollower Axle3; //Ra: wyłączyłem, bo kąty są liczone w Segment.cpp
|
||||
int iNumAxles; // ilość osi
|
||||
std::string asModel;
|
||||
|
||||
@@ -371,26 +364,18 @@ public: // modele składowe pojazdu
|
||||
TDynamicObject * PrevC(int C);
|
||||
TDynamicObject * NextC(int C);
|
||||
double NextDistance(double d = -1.0);
|
||||
void SetdMoveLen(double dMoveLen)
|
||||
{
|
||||
MoverParameters->dMoveLen = dMoveLen;
|
||||
}
|
||||
void ResetdMoveLen()
|
||||
{
|
||||
MoverParameters->dMoveLen = 0;
|
||||
}
|
||||
double GetdMoveLen()
|
||||
{
|
||||
return MoverParameters->dMoveLen;
|
||||
}
|
||||
void SetdMoveLen(double dMoveLen) {
|
||||
MoverParameters->dMoveLen = dMoveLen; }
|
||||
void ResetdMoveLen() {
|
||||
MoverParameters->dMoveLen = 0; }
|
||||
double GetdMoveLen() {
|
||||
return MoverParameters->dMoveLen; }
|
||||
|
||||
int GetPneumatic(bool front, bool red);
|
||||
void SetPneumatic(bool front, bool red);
|
||||
std::string asName;
|
||||
std::string GetName()
|
||||
{
|
||||
return this ? asName : std::string("");
|
||||
};
|
||||
std::string name() const {
|
||||
return this ? asName : std::string(); };
|
||||
|
||||
sound* rsDiesielInc = nullptr; // youBy
|
||||
sound* rscurve = nullptr; // youBy
|
||||
@@ -403,7 +388,6 @@ public: // modele składowe pojazdu
|
||||
TDynamicObject * ABuScanNearestObject(TTrack *Track, double ScanDir, double ScanDist,
|
||||
int &CouplNr);
|
||||
TDynamicObject * GetFirstDynamic(int cpl_type, int cf = 1);
|
||||
// TDynamicObject* GetFirstCabDynamic(int cpl_type);
|
||||
void ABuSetModelShake( Math3D::vector3 mShake);
|
||||
|
||||
// McZapkie-010302
|
||||
@@ -435,99 +419,65 @@ public: // modele składowe pojazdu
|
||||
void Move(double fDistance);
|
||||
void FastMove(double fDistance);
|
||||
void RenderSounds();
|
||||
inline Math3D::vector3 GetPosition() const
|
||||
{
|
||||
return vPosition;
|
||||
};
|
||||
inline Math3D::vector3 HeadPosition()
|
||||
{
|
||||
return vCoulpler[iDirection ^ 1];
|
||||
}; // pobranie współrzędnych czoła
|
||||
inline Math3D::vector3 RearPosition()
|
||||
{
|
||||
return vCoulpler[iDirection];
|
||||
}; // pobranie współrzędnych tyłu
|
||||
inline Math3D::vector3 AxlePositionGet()
|
||||
{
|
||||
return iAxleFirst ? Axle1.pPosition : Axle0.pPosition;
|
||||
};
|
||||
inline Math3D::vector3 VectorFront() const
|
||||
{
|
||||
return vFront;
|
||||
};
|
||||
inline Math3D::vector3 VectorUp()
|
||||
{
|
||||
return vUp;
|
||||
};
|
||||
inline Math3D::vector3 VectorLeft() const
|
||||
{
|
||||
return vLeft;
|
||||
};
|
||||
inline double * Matrix()
|
||||
{
|
||||
return mMatrix.getArray();
|
||||
};
|
||||
inline double GetVelocity()
|
||||
{
|
||||
return MoverParameters->Vel;
|
||||
};
|
||||
inline double GetLength() const
|
||||
{
|
||||
return MoverParameters->Dim.L;
|
||||
};
|
||||
inline double GetWidth() const
|
||||
{
|
||||
return MoverParameters->Dim.W;
|
||||
};
|
||||
inline TTrack * GetTrack()
|
||||
{
|
||||
return (iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack());
|
||||
};
|
||||
// void UpdatePos();
|
||||
inline Math3D::vector3 GetPosition() const {
|
||||
return vPosition; };
|
||||
// pobranie współrzędnych czoła
|
||||
inline Math3D::vector3 HeadPosition() {
|
||||
return vCoulpler[iDirection ^ 1]; };
|
||||
// pobranie współrzędnych tyłu
|
||||
inline Math3D::vector3 RearPosition() {
|
||||
return vCoulpler[iDirection]; };
|
||||
inline Math3D::vector3 AxlePositionGet() {
|
||||
return iAxleFirst ? Axle1.pPosition : Axle0.pPosition; };
|
||||
inline Math3D::vector3 VectorFront() const {
|
||||
return vFront; };
|
||||
inline Math3D::vector3 VectorUp() {
|
||||
return vUp; };
|
||||
inline Math3D::vector3 VectorLeft() const {
|
||||
return vLeft; };
|
||||
inline double * Matrix() {
|
||||
return mMatrix.getArray(); };
|
||||
inline double GetVelocity() {
|
||||
return MoverParameters->Vel; };
|
||||
inline double GetLength() const {
|
||||
return MoverParameters->Dim.L; };
|
||||
inline double GetWidth() const {
|
||||
return MoverParameters->Dim.W; };
|
||||
inline TTrack * GetTrack() {
|
||||
return (iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack()); };
|
||||
|
||||
// McZapkie-260202
|
||||
void LoadMMediaFile(std::string BaseDir, std::string TypeName, std::string ReplacableSkin);
|
||||
|
||||
inline double ABuGetDirection() const // ABu.
|
||||
{
|
||||
return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection());
|
||||
};
|
||||
// inline double ABuGetTranslation() //ABu.
|
||||
// {//zwraca przesunięcie wózka względem Point1 toru
|
||||
// return (Axle1.GetTrack()==MyTrack?Axle1.GetTranslation():Axle0.GetTranslation());
|
||||
// };
|
||||
inline double RaDirectionGet()
|
||||
{ // zwraca kierunek pojazdu na torze z aktywną osą
|
||||
return iAxleFirst ? Axle1.GetDirection() : Axle0.GetDirection();
|
||||
};
|
||||
inline double RaTranslationGet()
|
||||
{ // zwraca przesunięcie wózka względem Point1 toru z aktywną osią
|
||||
return iAxleFirst ? Axle1.GetTranslation() : Axle0.GetTranslation();
|
||||
};
|
||||
inline TTrack * RaTrackGet()
|
||||
{ // zwraca tor z aktywną osią
|
||||
return iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack();
|
||||
};
|
||||
inline double ABuGetDirection() const { // ABu.
|
||||
return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection()); };
|
||||
// zwraca kierunek pojazdu na torze z aktywną osą
|
||||
inline double RaDirectionGet() {
|
||||
return iAxleFirst ? Axle1.GetDirection() : Axle0.GetDirection(); };
|
||||
// zwraca przesunięcie wózka względem Point1 toru z aktywną osią
|
||||
inline double RaTranslationGet() {
|
||||
return iAxleFirst ? Axle1.GetTranslation() : Axle0.GetTranslation(); };
|
||||
// zwraca tor z aktywną osią
|
||||
inline TTrack * RaTrackGet() {
|
||||
return iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack(); };
|
||||
void CouplersDettach(double MinDist, int MyScanDir);
|
||||
void RadioStop();
|
||||
void Damage(char flag);
|
||||
void RaLightsSet(int head, int rear);
|
||||
// void RaAxleEvent(TEvent *e);
|
||||
TDynamicObject * FirstFind(int &coupler_nr, int cf = 1);
|
||||
float GetEPP(); // wyliczanie sredniego cisnienia w PG
|
||||
int DirectionSet(int d); // ustawienie kierunku w składzie
|
||||
int DirectionGet()
|
||||
{
|
||||
return iDirection + iDirection - 1;
|
||||
}; // odczyt kierunku w składzie
|
||||
// odczyt kierunku w składzie
|
||||
int DirectionGet() {
|
||||
return iDirection + iDirection - 1; };
|
||||
int DettachStatus(int dir);
|
||||
int Dettach(int dir);
|
||||
TDynamicObject * Neightbour(int &dir);
|
||||
void CoupleDist();
|
||||
TDynamicObject * ControlledFind();
|
||||
void ParamSet(int what, int into);
|
||||
int RouteWish(TTrack *tr); // zapytanie do AI, po którym segmencie skrzyżowania
|
||||
// jechać
|
||||
// zapytanie do AI, po którym segmencie skrzyżowania jechać
|
||||
int RouteWish(TTrack *tr);
|
||||
void DestinationSet(std::string to, std::string numer);
|
||||
std::string TextureTest(std::string const &name);
|
||||
void OverheadTrack(float o);
|
||||
@@ -535,4 +485,20 @@ public: // modele składowe pojazdu
|
||||
static std::string const MED_labels[ 8 ];
|
||||
};
|
||||
|
||||
|
||||
|
||||
class vehicle_table : public basic_table<TDynamicObject> {
|
||||
|
||||
public:
|
||||
// legacy method, calculates changes in simulation state over specified time
|
||||
void
|
||||
update( double dt, int iter );
|
||||
// legacy method, checks for presence and height of traction wire for specified vehicle
|
||||
void
|
||||
update_traction( TDynamicObject *Vehicle );
|
||||
// legacy method, sends list of vehicles over network
|
||||
void
|
||||
DynamicList( bool const Onlycontrolled = false ) const;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
17
EU07.cpp
17
EU07.cpp
@@ -20,7 +20,10 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
|
||||
#include <png.h>
|
||||
#include <thread>
|
||||
|
||||
#include "World.h"
|
||||
#include "simulation.h"
|
||||
#include "Globals.h"
|
||||
#include "Timer.h"
|
||||
#include "Logs.h"
|
||||
#include "keyboardinput.h"
|
||||
#include "mouseinput.h"
|
||||
@@ -332,16 +335,6 @@ int main(int argc, char *argv[])
|
||||
BaseWindowProc = (WNDPROC)::SetWindowLongPtr( Hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc );
|
||||
// switch off the topmost flag
|
||||
::SetWindowPos( Hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
|
||||
|
||||
const HANDLE icon = ::LoadImage(
|
||||
::GetModuleHandle( 0 ),
|
||||
MAKEINTRESOURCE( IDI_ICON1 ),
|
||||
IMAGE_ICON,
|
||||
::GetSystemMetrics( SM_CXSMICON ),
|
||||
::GetSystemMetrics( SM_CYSMICON ),
|
||||
0 );
|
||||
if( icon )
|
||||
::SendMessage( Hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>( icon ) );
|
||||
#endif
|
||||
|
||||
try {
|
||||
@@ -419,9 +412,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
#ifdef _WIN32
|
||||
Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej)
|
||||
delete pConsole;
|
||||
SafeDelete( pConsole );
|
||||
#endif
|
||||
|
||||
SafeDelete( simulation::Region );
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
|
||||
|
||||
51
EvLaunch.cpp
51
EvLaunch.cpp
@@ -17,36 +17,14 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "EvLaunch.h"
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
#include "usefull.h"
|
||||
#include "McZapkie/mctools.h"
|
||||
#include "Event.h"
|
||||
#include "MemCell.h"
|
||||
#include "mtable.h"
|
||||
#include "Timer.h"
|
||||
#include "parser.h"
|
||||
#include "Console.h"
|
||||
|
||||
using namespace Mtable;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
TEventLauncher::TEventLauncher()
|
||||
{ // ustawienie początkowych wartości dla wszystkich zmiennych
|
||||
iKey = 0;
|
||||
DeltaTime = -1;
|
||||
UpdatedTime = 0;
|
||||
fVal1 = fVal2 = 0;
|
||||
iHour = iMinute = -1; // takiego czasu nigdy nie będzie
|
||||
dRadius = 0;
|
||||
Event1 = Event2 = NULL;
|
||||
MemCell = NULL;
|
||||
iCheckMask = 0;
|
||||
}
|
||||
|
||||
void TEventLauncher::Init()
|
||||
{
|
||||
}
|
||||
|
||||
// encodes expected key in a short, where low byte represents the actual key,
|
||||
// and the high byte holds modifiers: 0x1 = shift, 0x2 = ctrl, 0x4 = alt
|
||||
int vk_to_glfw_key( int const Keycode ) {
|
||||
@@ -145,9 +123,9 @@ bool TEventLauncher::Load(cParser *parser)
|
||||
*parser >> token;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
bool TEventLauncher::Render()
|
||||
bool TEventLauncher::check_conditions()
|
||||
{ //"renderowanie" wyzwalacza
|
||||
bool bCond = false;
|
||||
if (iKey != 0)
|
||||
@@ -199,13 +177,20 @@ 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
|
||||
}
|
||||
|
||||
// calculates node's bounding radius
|
||||
void
|
||||
TEventLauncher::radius_() {
|
||||
|
||||
m_area.radius = std::sqrt( dRadius );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
60
EvLaunch.h
60
EvLaunch.h
@@ -10,32 +10,48 @@ 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 };
|
||||
|
||||
protected:
|
||||
// calculates node's bounding radius
|
||||
void
|
||||
radius_();
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
81
Event.h
81
Event.h
@@ -12,8 +12,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <string>
|
||||
#include "dumb3d.h"
|
||||
#include "Classes.h"
|
||||
|
||||
using namespace Math3D;
|
||||
#include "Names.h"
|
||||
#include "scenenode.h"
|
||||
#include "EvLaunch.h"
|
||||
|
||||
enum TEventType {
|
||||
tp_Unknown,
|
||||
@@ -32,7 +33,7 @@ enum TEventType {
|
||||
tp_TrackVel,
|
||||
tp_Multiple,
|
||||
tp_AddValues,
|
||||
tp_Ignored,
|
||||
// tp_Ignored, // NOTE: refactored to separate flag
|
||||
tp_CopyValues,
|
||||
tp_WhoIs,
|
||||
tp_LogValues,
|
||||
@@ -63,7 +64,8 @@ union TParam
|
||||
{
|
||||
void *asPointer;
|
||||
TMemCell *asMemCell;
|
||||
TGroundNode *nGroundNode;
|
||||
editor::basic_node *asEditorNode;
|
||||
glm::dvec3 const *asLocation;
|
||||
TTrack *asTrack;
|
||||
TAnimModel *asModel;
|
||||
TAnimContainer *asAnimContainer;
|
||||
@@ -86,11 +88,10 @@ class TEvent // zmienne: ev*
|
||||
|
||||
public:
|
||||
std::string asName;
|
||||
bool m_ignored { false }; // replacement for tp_ignored
|
||||
bool bEnabled = false; // false gdy ma nie być dodawany do kolejki (skanowanie sygnałów)
|
||||
int iQueued = 0; // ile razy dodany do kolejki
|
||||
// bool bIsHistory;
|
||||
TEvent *evNext = nullptr; // następny w kolejce
|
||||
TEvent *evNext2 = nullptr;
|
||||
TEventType Type = tp_Unknown;
|
||||
double fStartTime = 0.0;
|
||||
double fDelay = 0.0;
|
||||
@@ -100,19 +101,79 @@ class TEvent // zmienne: ev*
|
||||
std::string asNodeName; // McZapkie-100302 - dodalem zeby zapamietac nazwe toru
|
||||
TEvent *evJoined = nullptr; // kolejny event z tą samą nazwą - od wersji 378
|
||||
double fRandomDelay = 0.0; // zakres dodatkowego opóźnienia // standardowo nie będzie dodatkowego losowego opóźnienia
|
||||
public: // metody
|
||||
public:
|
||||
// metody
|
||||
TEvent(std::string const &m = "");
|
||||
~TEvent();
|
||||
void Init();
|
||||
void Load(cParser *parser, vector3 *org);
|
||||
void Load(cParser *parser, Math3D::vector3 const &org);
|
||||
static void AddToQuery( TEvent *Event, TEvent *&Start );
|
||||
std::string CommandGet();
|
||||
TCommandType Command();
|
||||
double ValueGet(int n);
|
||||
vector3 PositionGet() const;
|
||||
glm::dvec3 PositionGet() const;
|
||||
bool StopCommand();
|
||||
void StopCommandSent();
|
||||
void Append(TEvent *e);
|
||||
};
|
||||
|
||||
class event_manager {
|
||||
|
||||
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
|
||||
insert( TEvent *Event );
|
||||
bool
|
||||
insert( TEventLauncher *Launcher ) {
|
||||
return m_launchers.insert( Launcher ); }
|
||||
// legacy method, returns pointer to specified event, or null
|
||||
TEvent *
|
||||
FindEvent( std::string const &Name );
|
||||
// legacy method, inserts specified event in the event query
|
||||
bool
|
||||
AddToQuery( TEvent *Event, TDynamicObject *Owner );
|
||||
// legacy method, executes queued events
|
||||
bool
|
||||
CheckQuery();
|
||||
// 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
|
||||
using event_sequence = std::deque<TEvent *>;
|
||||
using event_map = std::unordered_map<std::string, std::size_t>;
|
||||
using eventlauncher_sequence = std::vector<TEventLauncher *>;
|
||||
|
||||
// methods
|
||||
// legacy method, verifies condition for specified event
|
||||
bool
|
||||
EventConditon( TEvent *Event );
|
||||
|
||||
// members
|
||||
event_sequence m_events;
|
||||
/*
|
||||
// NOTE: disabled until event class refactoring
|
||||
event_sequence m_eventqueue;
|
||||
*/
|
||||
// legacy version of the above
|
||||
TEvent *QueryRootEvent { nullptr };
|
||||
TEvent *m_workevent { nullptr };
|
||||
event_map m_eventmap;
|
||||
basic_table<TEventLauncher> m_launchers;
|
||||
eventlauncher_sequence m_launcherqueue;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
9
Gauge.h
9
Gauge.h
@@ -12,15 +12,14 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Classes.h"
|
||||
#include "sound.h"
|
||||
|
||||
typedef enum
|
||||
{ // typ ruchu
|
||||
enum TGaugeType {
|
||||
// typ ruchu
|
||||
gt_Unknown, // na razie nie znany
|
||||
gt_Rotate, // obrót
|
||||
gt_Move, // przesunięcie równoległe
|
||||
gt_Wiper, // obrót trzech kolejnych submodeli o ten sam kąt (np. wycieraczka, drzwi
|
||||
// harmonijkowe)
|
||||
gt_Wiper, // obrót trzech kolejnych submodeli o ten sam kąt (np. wycieraczka, drzwi harmonijkowe)
|
||||
gt_Digital // licznik cyfrowy, np. kilometrów
|
||||
} TGaugeType;
|
||||
};
|
||||
|
||||
// animowany wskaźnik, mogący przyjmować wiele stanów pośrednich
|
||||
class TGauge {
|
||||
|
||||
57
Globals.cpp
57
Globals.cpp
@@ -12,22 +12,17 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "usefull.h"
|
||||
//#include "Mover.h"
|
||||
#include "Console.h"
|
||||
#include "Driver.h"
|
||||
#include "Logs.h"
|
||||
#include "PyInt.h"
|
||||
|
||||
#include "World.h"
|
||||
#include "parser.h"
|
||||
#include "simulation.h"
|
||||
#include "Logs.h"
|
||||
#include "Console.h"
|
||||
#include "PyInt.h"
|
||||
|
||||
// namespace Global {
|
||||
|
||||
// parametry do użytku wewnętrznego
|
||||
// double Global::tSinceStart=0;
|
||||
TGround *Global::pGround = NULL;
|
||||
std::string Global::AppName{ "EU07" };
|
||||
std::string Global::asCurrentSceneryPath = "scenery/";
|
||||
std::string Global::asCurrentTexturePath = std::string(szTexturePath);
|
||||
@@ -74,12 +69,15 @@ std::vector<vector3> Global::FreeCameraInitAngle;
|
||||
GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f};
|
||||
double Global::fFogStart = 1700;
|
||||
double Global::fFogEnd = 2000;
|
||||
float Global::Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
|
||||
int Global::DynamicLightCount = 7;
|
||||
bool Global::ScaleSpecularValues = false;
|
||||
float Global::Overcast { 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
|
||||
std::string Global::Season; // season of the year, based on simulation date
|
||||
|
||||
float Global::BaseDrawRange { 2500.f };
|
||||
bool Global::RenderShadows { false };
|
||||
opengl_light Global::DayLight;
|
||||
int Global::DynamicLightCount { 3 };
|
||||
bool Global::ScaleSpecularValues { true };
|
||||
bool Global::BasicRenderer { false };
|
||||
bool Global::RenderShadows { true };
|
||||
Global::shadowtune_t Global::shadowtune = { 2048, 250.f, 250.f, 500.f };
|
||||
bool Global::bRollFix = true; // czy wykonać przeliczanie przechyłki
|
||||
bool Global::bJoinEvents = false; // czy grupować eventy o tych samych nazwach
|
||||
@@ -118,7 +116,7 @@ bool Global::bLiveTraction = true;
|
||||
float Global::AnisotropicFiltering = 8.0f; // requested level of anisotropic filtering. TODO: move it to renderer object
|
||||
std::string Global::LastGLError;
|
||||
GLint Global::iMaxTextureSize = 4096; // maksymalny rozmiar tekstury
|
||||
bool Global::bSmoothTraction = false; // wygładzanie drutów starym sposobem
|
||||
bool Global::bSmoothTraction { true }; // wygładzanie drutów starym sposobem
|
||||
float Global::SplineFidelity { 1.f }; // determines segment size during conversion of splines to geometry
|
||||
std::string Global::szDefaultExt = Global::szTexturesDDS; // domyślnie od DDS
|
||||
int Global::iMultisampling = 2; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px
|
||||
@@ -172,7 +170,6 @@ Global::uart_conf_t Global::uart_conf;
|
||||
//randomizacja
|
||||
std::mt19937 Global::random_engine = std::mt19937(std::time(NULL));
|
||||
|
||||
opengl_light Global::DayLight;
|
||||
Global::soundmode_t Global::soundpitchmode = Global::linear;
|
||||
Global::soundmode_t Global::soundgainmode = Global::linear;
|
||||
Global::soundstopmode_t Global::soundstopmode = Global::queue;
|
||||
@@ -181,19 +178,6 @@ Global::soundstopmode_t Global::soundstopmode = Global::queue;
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
std::string Global::GetNextSymbol()
|
||||
{ // pobranie tokenu z aktualnego parsera
|
||||
|
||||
std::string token;
|
||||
if (pParser != nullptr)
|
||||
{
|
||||
|
||||
pParser->getTokens();
|
||||
*pParser >> token;
|
||||
};
|
||||
return token;
|
||||
};
|
||||
|
||||
void Global::LoadIniFile(std::string asFileName)
|
||||
{
|
||||
FreeCameraInit.resize( 10 );
|
||||
@@ -449,6 +433,7 @@ void Global::ConfigParse(cParser &Parser)
|
||||
std::tm *localtime = std::localtime(&timenow);
|
||||
Global::fMoveLight = localtime->tm_yday + 1; // numer bieżącego dnia w roku
|
||||
}
|
||||
Global::pWorld->compute_season( Global::fMoveLight );
|
||||
}
|
||||
else if( token == "dynamiclights" ) {
|
||||
// number of dynamic lights in the scene
|
||||
@@ -949,20 +934,6 @@ void Global::TrainDelete(TDynamicObject *d)
|
||||
pWorld->TrainDelete(d);
|
||||
};
|
||||
|
||||
TDynamicObject *Global::DynamicNearest()
|
||||
{ // ustalenie pojazdu najbliższego kamerze
|
||||
return pGround->DynamicNearest(pCamera->Pos);
|
||||
};
|
||||
|
||||
TDynamicObject *Global::CouplerNearest()
|
||||
{ // ustalenie pojazdu najbliższego kamerze
|
||||
return pGround->CouplerNearest(pCamera->Pos);
|
||||
};
|
||||
|
||||
bool Global::AddToQuery(TEvent *event, TDynamicObject *who)
|
||||
{
|
||||
return pGround->AddToQuery(event, who);
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
TTranscripts::TTranscripts()
|
||||
|
||||
56
Globals.h
56
Globals.h
@@ -150,16 +150,27 @@ private:
|
||||
void Update();
|
||||
};
|
||||
|
||||
class Global
|
||||
{
|
||||
private:
|
||||
public:
|
||||
class Global {
|
||||
|
||||
public:
|
||||
// methods
|
||||
static void LoadIniFile(std::string asFileName);
|
||||
static void ConfigParse( cParser &parser );
|
||||
static void InitKeys();
|
||||
inline static Math3D::vector3 GetCameraPosition() { return pCameraPosition; };
|
||||
static void SetCameraPosition(Math3D::vector3 pNewCameraPosition);
|
||||
static void SetCameraRotation(double Yaw);
|
||||
static void TrainDelete(TDynamicObject *d);
|
||||
static bool DoEvents();
|
||||
static std::string Bezogonkow(std::string str, bool _ = false);
|
||||
static double Min0RSpeed(double vel1, double vel2);
|
||||
|
||||
// members
|
||||
static int Keys[MaxKeys];
|
||||
static bool RealisticControlMode; // controls ability to steer the vehicle from outside views
|
||||
static Math3D::vector3 pCameraPosition; // pozycja kamery w świecie
|
||||
static Math3D::vector3 DebugCameraPosition; // pozycja kamery w świecie
|
||||
static double
|
||||
pCameraRotation; // kierunek bezwzględny kamery w świecie: 0=północ, 90°=zachód (-azymut)
|
||||
static double pCameraRotation; // kierunek bezwzględny kamery w świecie: 0=północ, 90°=zachód (-azymut)
|
||||
static double pCameraRotationDeg; // w stopniach, dla animacji billboard
|
||||
static std::vector<Math3D::vector3> FreeCameraInit; // pozycje kamery
|
||||
static std::vector<Math3D::vector3> FreeCameraInitAngle;
|
||||
@@ -179,27 +190,21 @@ class Global
|
||||
static bool bLiveTraction;
|
||||
static float fMouseXScale;
|
||||
static float fMouseYScale;
|
||||
static double fFogStart;
|
||||
static double fFogEnd;
|
||||
static TGround *pGround;
|
||||
static std::string szDefaultExt;
|
||||
static std::string SceneryFile;
|
||||
static std::string AppName;
|
||||
static std::string asCurrentSceneryPath;
|
||||
static std::string asCurrentTexturePath;
|
||||
static std::string asCurrentDynamicPath;
|
||||
// McZapkie-170602: zewnetrzna definicja pojazdu uzytkownika
|
||||
static std::string asHumanCtrlVehicle;
|
||||
static void LoadIniFile(std::string asFileName);
|
||||
static void InitKeys();
|
||||
inline static Math3D::vector3 GetCameraPosition() { return pCameraPosition; };
|
||||
static void SetCameraPosition(Math3D::vector3 pNewCameraPosition);
|
||||
static void SetCameraRotation(double Yaw);
|
||||
static int iWriteLogEnabled; // maska bitowa: 1-zapis do pliku, 2-okienko
|
||||
static bool MultipleLogs;
|
||||
// McZapkie-221002: definicja swiatla dziennego
|
||||
static GLfloat FogColor[];
|
||||
// McZapkie-170602: zewnetrzna definicja pojazdu uzytkownika
|
||||
static std::string asHumanCtrlVehicle;
|
||||
// world environment
|
||||
static float Overcast;
|
||||
static double fFogStart;
|
||||
static double fFogEnd;
|
||||
static std::string Season; // season of the year, based on simulation date
|
||||
|
||||
// TODO: put these things in the renderer
|
||||
static float BaseDrawRange;
|
||||
@@ -221,6 +226,9 @@ class Global
|
||||
static float FieldOfView; // vertical field of view for the camera. TODO: move it to the renderer
|
||||
static GLint iMaxTextureSize; // maksymalny rozmiar tekstury
|
||||
static int iMultisampling; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px
|
||||
static bool bSmoothTraction; // wygładzanie drutów
|
||||
static float SplineFidelity; // determines segment size during conversion of splines to geometry
|
||||
static GLfloat FogColor[];
|
||||
|
||||
static bool FullPhysics; // full calculations performed for each simulation step
|
||||
static int iSlowMotion;
|
||||
@@ -247,8 +255,6 @@ class Global
|
||||
static int iScreenMode[12]; // numer ekranu wyświetlacza tekstowego
|
||||
static double fMoveLight; // numer dnia w roku albo -1
|
||||
static bool FakeLight; // toggle between fixed and dynamic daylight
|
||||
static bool bSmoothTraction; // wygładzanie drutów
|
||||
static float SplineFidelity; // determines segment size during conversion of splines to geometry
|
||||
static double fTimeSpeed; // przyspieszenie czasu, zmienna do testów
|
||||
static double fTimeAngleDeg; // godzina w postaci kąta
|
||||
static float fClockAngleDeg[6]; // kąty obrotu cylindrów dla zegara cyfrowego
|
||||
@@ -324,16 +330,6 @@ class Global
|
||||
};
|
||||
static uart_conf_t uart_conf;
|
||||
|
||||
// metody
|
||||
static void TrainDelete(TDynamicObject *d);
|
||||
static void ConfigParse(cParser &parser);
|
||||
static std::string GetNextSymbol();
|
||||
static TDynamicObject * DynamicNearest();
|
||||
static TDynamicObject * CouplerNearest();
|
||||
static bool AddToQuery(TEvent *event, TDynamicObject *who);
|
||||
static std::string Bezogonkow(std::string str, bool _ = false);
|
||||
static double Min0RSpeed(double vel1, double vel2);
|
||||
|
||||
static opengl_light DayLight;
|
||||
|
||||
enum soundmode_t
|
||||
|
||||
4360
Ground.cpp
4360
Ground.cpp
File diff suppressed because it is too large
Load Diff
352
Ground.h
352
Ground.h
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "GL/glew.h"
|
||||
#include "openglgeometrybank.h"
|
||||
#include "VBO.h"
|
||||
#include "Classes.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "material.h"
|
||||
#include "dumb3d.h"
|
||||
#include "Float3d.h"
|
||||
#include "Names.h"
|
||||
#include "lightarray.h"
|
||||
#include "lua.h"
|
||||
|
||||
typedef int TGroundNodeType;
|
||||
// Ra: zmniejszone liczby, aby zrobić tabelkę i zoptymalizować wyszukiwanie
|
||||
const int TP_MODEL = 10;
|
||||
/*
|
||||
const int TP_MESH = 11; // Ra: specjalny obiekt grupujący siatki dla tekstury
|
||||
const int TP_DUMMYTRACK = 12; // Ra: zdublowanie obiektu toru dla rozdzielenia tekstur
|
||||
*/
|
||||
const int TP_TERRAIN = 13; // Ra: specjalny model dla terenu
|
||||
const int TP_DYNAMIC = 14;
|
||||
const int TP_SOUND = 15;
|
||||
const int TP_TRACK = 16;
|
||||
/*
|
||||
const int TP_GEOMETRY=17;
|
||||
*/
|
||||
const int TP_MEMCELL = 18;
|
||||
const int TP_EVLAUNCH = 19; // MC
|
||||
const int TP_TRACTION = 20;
|
||||
const int TP_TRACTIONPOWERSOURCE = 21; // MC
|
||||
/*
|
||||
const int TP_ISOLATED=22; //Ra
|
||||
*/
|
||||
const int TP_SUBMODEL = 22; // Ra: submodele terenu
|
||||
const int TP_LAST = 25; // rozmiar tablicy
|
||||
|
||||
struct DaneRozkaz
|
||||
{ // struktura komunikacji z EU07.EXE
|
||||
int iSygn; // sygnatura 'EU07'
|
||||
int iComm; // rozkaz/status (kod ramki)
|
||||
union
|
||||
{
|
||||
float fPar[62];
|
||||
int iPar[62];
|
||||
char cString[248]; // upakowane stringi
|
||||
};
|
||||
};
|
||||
|
||||
struct DaneRozkaz2
|
||||
{ // struktura komunikacji z EU07.EXE
|
||||
int iSygn; // sygnatura 'EU07'
|
||||
int iComm; // rozkaz/status (kod ramki)
|
||||
union
|
||||
{
|
||||
float fPar[496];
|
||||
int iPar[496];
|
||||
char cString[1984]; // upakowane stringi
|
||||
};
|
||||
};
|
||||
|
||||
struct TGroundVertex
|
||||
{
|
||||
glm::dvec3 position;
|
||||
glm::vec3 normal;
|
||||
glm::vec2 texture;
|
||||
|
||||
void HalfSet(const TGroundVertex &v1, const TGroundVertex &v2)
|
||||
{ // wyliczenie współrzędnych i mapowania punktu na środku odcinka v1<->v2
|
||||
interpolate_( v1, v2, 0.5 );
|
||||
}
|
||||
void SetByX(const TGroundVertex &v1, const TGroundVertex &v2, double x)
|
||||
{ // wyliczenie współrzędnych i mapowania punktu na odcinku v1<->v2
|
||||
interpolate_( v1, v2, ( x - v1.position.x ) / ( v2.position.x - v1.position.x ) );
|
||||
}
|
||||
void SetByZ(const TGroundVertex &v1, const TGroundVertex &v2, double z)
|
||||
{ // wyliczenie współrzędnych i mapowania punktu na odcinku v1<->v2
|
||||
interpolate_( v1, v2, ( z - v1.position.z ) / ( v2.position.z - v1.position.z ) );
|
||||
}
|
||||
void interpolate_( const TGroundVertex &v1, const TGroundVertex &v2, double factor ) {
|
||||
position = interpolate( v1.position, v2.position, factor );
|
||||
normal = interpolate( v1.normal, v2.normal, static_cast<float>( factor ) );
|
||||
texture = interpolate( v1.texture, v2.texture, static_cast<float>( factor ) );
|
||||
}
|
||||
};
|
||||
|
||||
// ground node holding single, unique piece of 3d geometry. TBD, TODO: unify this with basic 3d model node
|
||||
struct piece_node {
|
||||
std::vector<TGroundVertex> vertices;
|
||||
geometry_handle geometry { 0,0 }; // geometry prepared for drawing
|
||||
};
|
||||
|
||||
// obiekt scenerii
|
||||
class TGroundNode {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
public:
|
||||
TGroundNode *nNext; // lista wszystkich w scenerii, ostatni na początku
|
||||
TGroundNode *nNext2; // lista obiektów w sektorze
|
||||
TGroundNode *nNext3; // lista obiektów renderowanych we wspólnym cyklu
|
||||
std::string asName; // nazwa (nie zawsze ma znaczenie)
|
||||
TGroundNodeType iType; // typ obiektu
|
||||
union
|
||||
{ // Ra: wskażniki zależne od typu - zrobić klasy dziedziczone zamiast
|
||||
void *Pointer; // do przypisywania NULL
|
||||
TSubModel *smTerrain; // modele terenu (kwadratow kilometrowych)
|
||||
TAnimModel *Model; // model z animacjami
|
||||
TDynamicObject *DynamicObject; // pojazd
|
||||
piece_node *Piece; // non-instanced piece of geometry
|
||||
TTrack *pTrack; // trajektoria ruchu
|
||||
TMemCell *MemCell; // komórka pamięci
|
||||
TEventLauncher *EvLaunch; // wyzwalacz zdarzeń
|
||||
TTraction *hvTraction; // drut zasilający
|
||||
TTractionPowerSource *psTractionPowerSource; // zasilanie drutu (zaniedbane w sceneriach)
|
||||
sound *tsStaticSound; // dźwięk przestrzenny
|
||||
TGroundNode *nNode; // obiekt renderujący grupowo ma tu wskaźnik na listę obiektów
|
||||
};
|
||||
Math3D::vector3 pCenter; // współrzędne środka do przydzielenia sektora
|
||||
float m_radius { 0.0f }; // bounding radius of geometry stored in the node. TODO: reuse bounding_area struct for radius and center
|
||||
glm::dvec3 m_rootposition; // position of the ground (sub)rectangle holding the node, in the 3d world
|
||||
// visualization-related data
|
||||
// TODO: wrap these in a struct, when cleaning objects up
|
||||
double fSquareMinRadius; // kwadrat widoczności od
|
||||
double fSquareRadius; // kwadrat widoczności do
|
||||
union
|
||||
{
|
||||
int iNumVerts; // dla trójkątów
|
||||
int iNumPts; // dla linii
|
||||
int iCount; // dla terenu
|
||||
};
|
||||
int iFlags; // tryb przezroczystości: 0x10-nieprz.,0x20-przezroczysty,0x30-mieszany
|
||||
material_handle m_material; // główna (jedna) tekstura obiektu
|
||||
glm::vec3
|
||||
Ambient{ 1.0f, 1.0f, 1.0f },
|
||||
Diffuse{ 1.0f, 1.0f, 1.0f },
|
||||
Specular{ 1.0f, 1.0f, 1.0f }; // oświetlenie
|
||||
double fLineThickness; // McZapkie-120702: grubosc linii
|
||||
bool bVisible;
|
||||
|
||||
TGroundNode();
|
||||
TGroundNode(TGroundNodeType t);
|
||||
~TGroundNode();
|
||||
|
||||
void InitNormals();
|
||||
void RenderHidden(); // obsługa dźwięków i wyzwalaczy zdarzeń
|
||||
};
|
||||
|
||||
struct bounding_area {
|
||||
|
||||
glm::vec3 center; // mid point of the rectangle
|
||||
float radius { 0.0f }; // radius of the bounding sphere
|
||||
};
|
||||
|
||||
class TSubRect : /*public Resource,*/ public CMesh
|
||||
{ // sektor składowy kwadratu kilometrowego
|
||||
public:
|
||||
bounding_area m_area;
|
||||
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
|
||||
int iTracks = 0; // ilość torów w (tTracks)
|
||||
TTrack **tTracks = nullptr; // tory do renderowania pojazdów
|
||||
protected:
|
||||
TTrack *tTrackAnim = nullptr; // obiekty do przeliczenia animacji
|
||||
public:
|
||||
TGroundNode *nRootNode = nullptr; // wszystkie obiekty w sektorze, z wyjątkiem renderujących i pojazdów (nNext2)
|
||||
TGroundNode *nRenderHidden = nullptr; // lista obiektów niewidocznych, "renderowanych" również z tyłu (nNext3)
|
||||
TGroundNode *nRenderRect = nullptr; // z poziomu sektora - nieprzezroczyste (nNext3)
|
||||
TGroundNode *nRenderRectAlpha = nullptr; // z poziomu sektora - przezroczyste (nNext3)
|
||||
TGroundNode *nRenderWires = nullptr; // z poziomu sektora - druty i inne linie (nNext3)
|
||||
TGroundNode *nRender = nullptr; // indywidualnie - nieprzezroczyste (nNext3)
|
||||
TGroundNode *nRenderMixed = nullptr; // indywidualnie - nieprzezroczyste i przezroczyste (nNext3)
|
||||
TGroundNode *nRenderAlpha = nullptr; // indywidualnie - przezroczyste (nNext3)
|
||||
#ifdef EU07_SCENERY_EDITOR
|
||||
std::deque< TGroundNode* > m_memcells; // collection of memcells present in the sector
|
||||
#endif
|
||||
int iNodeCount = 0; // licznik obiektów, do pomijania pustych sektorów
|
||||
public:
|
||||
void LoadNodes(); // utworzenie VBO sektora
|
||||
public:
|
||||
virtual ~TSubRect();
|
||||
virtual void NodeAdd(TGroundNode *Node); // dodanie obiektu do sektora na etapie rozdzielania na sektory
|
||||
void Sort(); // optymalizacja obiektów w sektorze (sortowanie wg tekstur)
|
||||
TTrack * FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude);
|
||||
TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude);
|
||||
bool RaTrackAnimAdd(TTrack *t); // zgłoszenie toru do animacji
|
||||
void RaAnimate( unsigned int const Framestamp ); // przeliczenie animacji torów
|
||||
void RenderSounds(); // dźwięki pojazdów z niewidocznych sektorów
|
||||
};
|
||||
|
||||
// Ra: trzeba sprawdzić wydajność siatki
|
||||
const int iNumSubRects = 5; // na ile dzielimy kilometr
|
||||
const int iNumRects = 500;
|
||||
const int iTotalNumSubRects = iNumRects * iNumSubRects;
|
||||
const double fHalfTotalNumSubRects = iTotalNumSubRects / 2.0;
|
||||
const double fSubRectSize = 1000.0 / iNumSubRects;
|
||||
const double fRectSize = fSubRectSize * iNumSubRects;
|
||||
|
||||
class TGroundRect : public TSubRect
|
||||
{ // kwadrat kilometrowy
|
||||
// obiekty o niewielkiej ilości wierzchołków będą renderowane stąd
|
||||
// Ra: 2012-02 doszły submodele terenu
|
||||
friend class opengl_renderer;
|
||||
|
||||
private:
|
||||
TSubRect *pSubRects { nullptr };
|
||||
|
||||
void Init();
|
||||
|
||||
public:
|
||||
virtual ~TGroundRect();
|
||||
// pobranie wskaźnika do małego kwadratu, utworzenie jeśli trzeba
|
||||
TSubRect * SafeGetSubRect(int iCol, int iRow) {
|
||||
if( !pSubRects ) {
|
||||
// utworzenie małych kwadratów
|
||||
Init();
|
||||
}
|
||||
return pSubRects + iRow * iNumSubRects + iCol; // zwrócenie właściwego
|
||||
};
|
||||
// pobranie wskaźnika do małego kwadratu, bez tworzenia jeśli nie ma
|
||||
TSubRect *FastGetSubRect(int iCol, int iRow) const {
|
||||
return (
|
||||
pSubRects ?
|
||||
pSubRects + iRow * iNumSubRects + iCol :
|
||||
nullptr); };
|
||||
void NodeAdd( TGroundNode *Node ); // dodanie obiektu do sektora na etapie rozdzielania na sektory
|
||||
// compares two provided nodes, returns true if their content can be merged
|
||||
bool mergeable( TGroundNode const &Left, TGroundNode const &Right );
|
||||
// optymalizacja obiektów w sektorach
|
||||
void Optimize() {
|
||||
if( pSubRects ) {
|
||||
for( int i = iNumSubRects * iNumSubRects - 1; i >= 0; --i ) {
|
||||
// optymalizacja obiektów w sektorach
|
||||
pSubRects[ i ].Sort(); } } };
|
||||
|
||||
TGroundNode *nTerrain { nullptr }; // model terenu z E3D - użyć nRootMesh?
|
||||
};
|
||||
|
||||
class TGround
|
||||
{
|
||||
friend class opengl_renderer;
|
||||
|
||||
TGroundRect Rects[ iNumRects ][ iNumRects ]; // mapa kwadratów kilometrowych
|
||||
TSubRect srGlobal; // zawiera obiekty globalne (na razie wyzwalacze czasowe)
|
||||
TGroundNode *nRootDynamic = nullptr; // lista pojazdów
|
||||
TGroundNode *nRootOfType[ TP_LAST ]; // tablica grupująca obiekty, przyspiesza szukanie
|
||||
TEvent *RootEvent = nullptr; // lista zdarzeń
|
||||
TEvent *QueryRootEvent = nullptr,
|
||||
*tmpEvent = nullptr;
|
||||
typedef std::unordered_map<std::string, TEvent *> event_map;
|
||||
event_map m_eventmap;
|
||||
TNames<TGroundNode *> m_trackmap;
|
||||
light_array m_lights; // collection of dynamic light sources present in the scene
|
||||
lua m_lua;
|
||||
|
||||
vector3 pOrigin;
|
||||
vector3 aRotate;
|
||||
bool bInitDone = false;
|
||||
|
||||
private: // metody prywatne
|
||||
bool EventConditon(TEvent *e);
|
||||
|
||||
public:
|
||||
bool bDynamicRemove = false; // czy uruchomić procedurę usuwania pojazdów
|
||||
|
||||
TGround();
|
||||
~TGround();
|
||||
void Free();
|
||||
bool Init( std::string File );
|
||||
void FirstInit();
|
||||
void InitTracks();
|
||||
void InitTraction();
|
||||
bool InitEvents();
|
||||
bool InitLaunchers();
|
||||
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);
|
||||
TGroundNode * AddGroundNode(cParser *parser);
|
||||
void UpdatePhys(double dt, int iter); // aktualizacja fizyki stałym krokiem
|
||||
bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS
|
||||
void Update_Lights(); // updates scene lights array
|
||||
void Update_Hidden(); // updates invisible elements of the scene
|
||||
bool AddToQuery(TEvent *Event, TDynamicObject *Node);
|
||||
bool GetTraction(TDynamicObject *model);
|
||||
bool CheckQuery();
|
||||
TGroundNode * DynamicFindAny(std::string const &Name);
|
||||
TGroundNode * DynamicFind(std::string const &Name);
|
||||
void DynamicList(bool all = false);
|
||||
TGroundNode * FindGroundNode(std::string asNameToFind, TGroundNodeType iNodeType);
|
||||
TGroundRect * GetRect( double x, double z );
|
||||
TSubRect * GetSubRect( int iCol, int iRow );
|
||||
inline
|
||||
TSubRect * GetSubRect(double x, double z) {
|
||||
return GetSubRect(GetColFromX(x), GetRowFromZ(z)); };
|
||||
TSubRect * FastGetSubRect( int iCol, int iRow );
|
||||
inline
|
||||
TSubRect * FastGetSubRect( double x, double z ) {
|
||||
return FastGetSubRect( GetColFromX( x ), GetRowFromZ( z ) ); };
|
||||
inline
|
||||
int GetRowFromZ(double z) {
|
||||
return (int)(z / fSubRectSize + fHalfTotalNumSubRects); };
|
||||
inline
|
||||
int GetColFromX(double x) {
|
||||
return (int)(x / fSubRectSize + fHalfTotalNumSubRects); };
|
||||
TEvent * FindEvent(const std::string &asEventName);
|
||||
TEvent * FindEventScan(const std::string &asEventName);
|
||||
void TrackJoin(TGroundNode *Current);
|
||||
|
||||
private:
|
||||
// convert tp_terrain model to a series of triangle nodes
|
||||
void convert_terrain( TGroundNode const *Terrain );
|
||||
void convert_terrain( TSubModel const *Submodel );
|
||||
void RaTriangleDivider(TGroundNode *node);
|
||||
#ifdef _WIN32
|
||||
void Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
||||
|
||||
public:
|
||||
void WyslijEvent(const std::string &e, const std::string &d);
|
||||
void WyslijString(const std::string &t, int n);
|
||||
void WyslijWolny(const std::string &t);
|
||||
void WyslijNamiary(TGroundNode *t);
|
||||
void WyslijParam(int nr, int fl);
|
||||
void WyslijUszkodzenia(const std::string &t, char fl);
|
||||
void WyslijObsadzone(); // -> skladanie wielu pojazdow
|
||||
void RadioStop(vector3 pPosition);
|
||||
TDynamicObject * DynamicNearest(vector3 pPosition, double distance = 20.0,
|
||||
bool mech = false);
|
||||
TDynamicObject * CouplerNearest(vector3 pPosition, double distance = 20.0,
|
||||
bool mech = false);
|
||||
void DynamicRemove(TDynamicObject *dyn);
|
||||
void TerrainRead(std::string const &f);
|
||||
void TerrainWrite();
|
||||
void TrackBusyList();
|
||||
void IsolatedBusyList();
|
||||
void IsolatedBusy(const std::string t);
|
||||
void Silence(vector3 gdzie);
|
||||
|
||||
void add_event(TEvent *event);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -706,6 +706,7 @@ public:
|
||||
headlight_upper = 0x04,
|
||||
headlight_right = 0x10,
|
||||
redmarker_right = 0x20,
|
||||
rearendsignals = 0x40
|
||||
};
|
||||
int ScndInMain{ 0 }; /*zaleznosc bocznika od nastawnika*/
|
||||
bool MBrake = false; /*Czy jest hamulec reczny*/
|
||||
@@ -778,6 +779,7 @@ public:
|
||||
double Ftmax = 0.0;
|
||||
/*- dla lokomotyw z silnikami indukcyjnymi -*/
|
||||
double eimc[26];
|
||||
bool EIMCLogForce; //
|
||||
static std::vector<std::string> const eimc_labels;
|
||||
/*-dla wagonow*/
|
||||
double MaxLoad = 0.0; /*masa w T lub ilosc w sztukach - ladownosc*/
|
||||
@@ -820,6 +822,7 @@ public:
|
||||
double AccN = 0.0; //przyspieszenie normalne w [m/s^2]
|
||||
double AccV = 0.0;
|
||||
double nrot = 0.0;
|
||||
double WheelFlat = 0.0;
|
||||
/*! rotacja kol [obr/s]*/
|
||||
double EnginePower = 0.0; /*! chwilowa moc silnikow*/
|
||||
double dL = 0.0; double Fb = 0.0; double Ff = 0.0; /*przesuniecie, sila hamowania i tarcia*/
|
||||
|
||||
@@ -3455,7 +3455,7 @@ void TMoverParameters::UpdatePipePressure(double dt)
|
||||
temp = 0.0; // odetnij
|
||||
else
|
||||
temp = 1.0; // połącz
|
||||
Pipe->Flow(temp * Hamulec->GetPF(temp * PipePress, dt, Vel) + GetDVc(dt));
|
||||
Pipe->Flow( temp * Hamulec->GetPF( temp * PipePress, dt, Vel ) + GetDVc( dt ) );
|
||||
|
||||
if (ASBType == 128)
|
||||
Hamulec->ASB(int(SlippingWheels));
|
||||
@@ -3751,14 +3751,23 @@ void TMoverParameters::ComputeTotalForce(double dt, double dt1, bool FullVer)
|
||||
Sign(nrot * M_PI * WheelDiameter - V) *
|
||||
Adhesive(RunningTrack.friction) * TotalMassxg,
|
||||
dt, nrot);
|
||||
Fwheels = Sign(nrot * M_PI * WheelDiameter - V) * TotalMassxg * Adhesive(RunningTrack.friction);
|
||||
Fwheels = Sign(temp_nrot * M_PI * WheelDiameter - V) * TotalMassxg * Adhesive(RunningTrack.friction);
|
||||
if (Fwheels*Sign(V)>0)
|
||||
{
|
||||
FTrain = Fwheels - Fb;
|
||||
FTrain = Fwheels + Fb*Sign(V);
|
||||
}
|
||||
else if (FTrain*Sign(V)>0)
|
||||
{
|
||||
Fb = FTrain*Sign(V) - Fwheels*Sign(V);
|
||||
}
|
||||
else
|
||||
{
|
||||
Fb = FTrain - Fwheels;
|
||||
Fb = -Fwheels*Sign(V);
|
||||
FTrain = 0;
|
||||
}
|
||||
if (nrot < 0.1)
|
||||
{
|
||||
WheelFlat = sqrt(sqr(WheelFlat) + abs(Fwheels) / NAxles*Vel*0.000002);
|
||||
}
|
||||
if (Sign(nrot * M_PI * WheelDiameter - V)*Sign(temp_nrot * M_PI * WheelDiameter - V) < 0)
|
||||
{
|
||||
@@ -4648,7 +4657,7 @@ double TMoverParameters::TractionForce(double dt)
|
||||
{
|
||||
PosRatio = -Sign(V) * DirAbsolute * eimv[eimv_Fr] /
|
||||
(eimc[eimc_p_Fh] *
|
||||
Max0R(dtrans / MaxBrakePress[0], AnPos) /*dizel_fill*/);
|
||||
Max0R(Max0R(dtrans,0.01) / MaxBrakePress[0], AnPos) /*dizel_fill*/);
|
||||
}
|
||||
else
|
||||
PosRatio = 0;
|
||||
@@ -4699,11 +4708,11 @@ double TMoverParameters::TractionForce(double dt)
|
||||
if( ( SlippingWheels ) ) {
|
||||
PosRatio = 0;
|
||||
tmp = 9;
|
||||
Sandbox( true, range::local );
|
||||
Sandbox( true, range::unit );
|
||||
} // przeciwposlizg
|
||||
else {
|
||||
// switch sandbox off
|
||||
Sandbox( false, range::local );
|
||||
Sandbox( false, range::unit );
|
||||
}
|
||||
|
||||
dizel_fill += Max0R(Min0R(PosRatio - dizel_fill, 0.1), -0.1) * 2 *
|
||||
@@ -4740,6 +4749,13 @@ double TMoverParameters::TractionForce(double dt)
|
||||
-Sign(V) * (DirAbsolute)*std::min(
|
||||
eimc[eimc_p_Ph] * 3.6 / (Vel != 0.0 ? Vel : 0.001),
|
||||
std::min(-eimc[eimc_p_Fh] * dizel_fill, eimv[eimv_FMAXMAX]));
|
||||
double pr = dizel_fill;
|
||||
if (EIMCLogForce)
|
||||
pr = -log(1 - 4 * pr) / log(5);
|
||||
eimv[eimv_Fr] =
|
||||
-Sign(V) * (DirAbsolute)*std::min(
|
||||
eimc[eimc_p_Ph] * 3.6 / (Vel != 0.0 ? Vel : 0.001),
|
||||
std::min(-eimc[eimc_p_Fh] * pr, eimv[eimv_FMAXMAX]));
|
||||
//*Min0R(1,(Vel-eimc[eimc_p_Vh0])/(eimc[eimc_p_Vh1]-eimc[eimc_p_Vh0]))
|
||||
}
|
||||
else
|
||||
@@ -4751,9 +4767,13 @@ double TMoverParameters::TractionForce(double dt)
|
||||
eimv[eimv_Fmax] = eimv[eimv_Fful] * dizel_fill;
|
||||
// else
|
||||
// eimv[eimv_Fmax]:=Min0R(eimc[eimc_p_F0]*dizel_fill,eimv[eimv_Fful]);
|
||||
double pr = dizel_fill;
|
||||
if (EIMCLogForce)
|
||||
pr = log(1 + 4 * pr) / log(5);
|
||||
eimv[eimv_Fr] = eimv[eimv_Fful] * pr;
|
||||
}
|
||||
|
||||
eimv[eimv_ks] = eimv[eimv_Fmax] / eimv[eimv_FMAXMAX];
|
||||
eimv[eimv_ks] = eimv[eimv_Fr] / eimv[eimv_FMAXMAX];
|
||||
eimv[eimv_df] = eimv[eimv_ks] * eimc[eimc_s_dfmax];
|
||||
eimv[eimv_fp] = DirAbsolute * enrot * eimc[eimc_s_p] +
|
||||
eimv[eimv_df]; // do przemyslenia dzialanie pp z tmpV
|
||||
@@ -4924,7 +4944,7 @@ double TMoverParameters::v2n(void)
|
||||
n = V / (M_PI * WheelDiameter); // predkosc obrotowa wynikajaca z liniowej [obr/s]
|
||||
deltan = n - nrot; //"pochodna" prędkości obrotowej
|
||||
if (SlippingWheels)
|
||||
if (std::abs(deltan) < 0.01)
|
||||
if (std::abs(deltan) < 0.001)
|
||||
SlippingWheels = false; // wygaszenie poslizgu
|
||||
if (SlippingWheels) // nie ma zwiazku z predkoscia liniowa V
|
||||
{ // McZapkie-221103: uszkodzenia kol podczas poslizgu
|
||||
@@ -6923,7 +6943,7 @@ void TMoverParameters::LoadFIZ_Brake( std::string const &line ) {
|
||||
}
|
||||
|
||||
if( true == extract_value( AirLeakRate, "AirLeakRate", line, "" ) ) {
|
||||
// the parameter is provided in form of a multiplier, where 1.0 means the default rate of 0.001
|
||||
// the parameter is provided in form of a multiplier, where 1.0 means the default rate of 0.01
|
||||
AirLeakRate *= 0.01;
|
||||
}
|
||||
}
|
||||
@@ -7149,6 +7169,7 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) {
|
||||
|
||||
if( asb == "Manual" ) { ASBType = 1; }
|
||||
else if( asb == "Automatic" ) { ASBType = 2; }
|
||||
else if (asb == "Yes") { ASBType = 128; }
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -7397,6 +7418,7 @@ void TMoverParameters::LoadFIZ_Engine( std::string const &Input ) {
|
||||
extract_value( eimc[ eimc_p_Imax ], "Imax", Input, "" );
|
||||
extract_value( eimc[ eimc_p_abed ], "abed", Input, "" );
|
||||
extract_value( eimc[ eimc_p_eped ], "edep", Input, "" );
|
||||
EIMCLogForce = ( extract_value( "eimclf", Input ) == "Yes" );
|
||||
|
||||
Flat = ( extract_value( "Flat", Input ) == "1" );
|
||||
|
||||
@@ -7826,10 +7848,13 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir)
|
||||
BrakeCtrlPos = static_cast<int>( Handle->GetPos( bh_NP ) );
|
||||
else
|
||||
BrakeCtrlPos = static_cast<int>( Handle->GetPos( bh_RP ) );
|
||||
/*
|
||||
// NOTE: disabled and left up to the driver, if there's any
|
||||
MainSwitch( false );
|
||||
PantFront( true );
|
||||
PantRear( true );
|
||||
MainSwitch( true );
|
||||
*/
|
||||
ActiveDir = 0; // Dir; //nastawnik kierunkowy - musi być ustawiane osobno!
|
||||
DirAbsolute = ActiveDir * CabNo; // kierunek jazdy względem sprzęgów
|
||||
LimPipePress = CntrlPipePress;
|
||||
|
||||
@@ -435,8 +435,6 @@ void TNESt3::ForceEmptiness()
|
||||
Miedzypoj->CreatePress(0);
|
||||
CntrlRes->CreatePress(0);
|
||||
|
||||
BrakeStatus = 0;
|
||||
|
||||
ValveRes->Act();
|
||||
BrakeRes->Act();
|
||||
Miedzypoj->Act();
|
||||
|
||||
@@ -413,6 +413,7 @@ void TBrake::ForceEmptiness()
|
||||
{
|
||||
ValveRes->CreatePress(0);
|
||||
BrakeRes->CreatePress(0);
|
||||
|
||||
ValveRes->Act();
|
||||
BrakeRes->Act();
|
||||
}
|
||||
@@ -757,6 +758,17 @@ double TESt::GetCRP()
|
||||
return CntrlRes->P();
|
||||
}
|
||||
|
||||
void TESt::ForceEmptiness() {
|
||||
|
||||
ValveRes->CreatePress( 0 );
|
||||
BrakeRes->CreatePress( 0 );
|
||||
CntrlRes->CreatePress( 0 );
|
||||
|
||||
ValveRes->Act();
|
||||
BrakeRes->Act();
|
||||
CntrlRes->Act();
|
||||
}
|
||||
|
||||
//---EP2---
|
||||
|
||||
void TEStEP2::Init( double const PP, double const HPP, double const LPP, double const BP, int const BDF )
|
||||
@@ -1462,9 +1474,15 @@ double TEStED::GetPF( double const PP, double const dt, double const Vel )
|
||||
|
||||
// powtarzacz — podwojny zawor zwrotny
|
||||
temp = Max0R(LoadC * BCP / temp * Min0R(Max0R(1 - EDFlag, 0), 1), LBP);
|
||||
double speed = 1;
|
||||
if ((ASBP < 0.1) && ((BrakeStatus & b_asb) == b_asb))
|
||||
{
|
||||
temp = 0;
|
||||
speed = 3;
|
||||
}
|
||||
|
||||
if ((BrakeCyl->P() > temp))
|
||||
dv = -PFVd(BrakeCyl->P(), 0, 0.02 * SizeBC, temp) * dt;
|
||||
dv = -PFVd(BrakeCyl->P(), 0, 0.02 * SizeBC * speed, temp) * dt;
|
||||
else if ((BrakeCyl->P() < temp))
|
||||
dv = PFVa(BVP, BrakeCyl->P(), 0.02 * SizeBC, temp) * dt;
|
||||
else
|
||||
@@ -1721,6 +1739,17 @@ double TCV1::GetCRP()
|
||||
return CntrlRes->P();
|
||||
}
|
||||
|
||||
void TCV1::ForceEmptiness() {
|
||||
|
||||
ValveRes->CreatePress( 0 );
|
||||
BrakeRes->CreatePress( 0 );
|
||||
CntrlRes->CreatePress( 0 );
|
||||
|
||||
ValveRes->Act();
|
||||
BrakeRes->Act();
|
||||
CntrlRes->Act();
|
||||
}
|
||||
|
||||
//---CV1-L-TR---
|
||||
|
||||
void TCV1L_TR::SetLBP( double const P )
|
||||
@@ -1995,7 +2024,8 @@ double TKE::GetPF( double const PP, double const dt, double const Vel )
|
||||
// luzowanie CH
|
||||
// temp:=Max0R(BCP,LBP);
|
||||
IMP = Max0R(IMP / temp, Max0R(LBP, ASBP * int((BrakeStatus & b_asb) == b_asb)));
|
||||
|
||||
if ((ASBP < 0.1) && ((BrakeStatus & b_asb) == b_asb))
|
||||
IMP = 0;
|
||||
// luzowanie CH
|
||||
if ((BCP > IMP + 0.005) || (Max0R(ImplsRes->P(), 8 * LBP) < 0.25))
|
||||
dv = PFVd(BCP, 0, 0.05, IMP) * dt;
|
||||
@@ -2090,6 +2120,21 @@ void TKE::SetLBP( double const P )
|
||||
LBP = P;
|
||||
}
|
||||
|
||||
void TKE::ForceEmptiness() {
|
||||
|
||||
ValveRes->CreatePress( 0 );
|
||||
BrakeRes->CreatePress( 0 );
|
||||
CntrlRes->CreatePress( 0 );
|
||||
ImplsRes->CreatePress( 0 );
|
||||
Brak2Res->CreatePress( 0 );
|
||||
|
||||
ValveRes->Act();
|
||||
BrakeRes->Act();
|
||||
CntrlRes->Act();
|
||||
ImplsRes->Act();
|
||||
Brak2Res->Act();
|
||||
}
|
||||
|
||||
//---KRANY---
|
||||
|
||||
double TDriverHandle::GetPF(double const i_bcp, double PP, double HP, double dt, double ep)
|
||||
|
||||
@@ -260,6 +260,7 @@ class TESt : public TBrake {
|
||||
void CheckReleaser(double dt); //odluzniacz
|
||||
double CVs(double BP); //napelniacz sterujacego
|
||||
double BVs(double BCP); //napelniacz pomocniczego
|
||||
void ForceEmptiness() /*override*/; // wymuszenie bycia pustym
|
||||
|
||||
inline TESt(double i_mbp, double i_bcr, double i_bcd, double i_brc, int i_bcn, int i_BD, int i_mat, int i_ba, int i_nbpa) :
|
||||
TBrake( i_mbp, i_bcr, i_bcd, i_brc, i_bcn, i_BD, i_mat, i_ba, i_nbpa)
|
||||
@@ -410,6 +411,7 @@ public:
|
||||
void CheckState( double const BCP, double &dV1 );
|
||||
double CVs( double const BP );
|
||||
double BVs( double const BCP );
|
||||
void ForceEmptiness() /*override*/; // wymuszenie bycia pustym
|
||||
|
||||
inline TCV1(double i_mbp, double i_bcr, double i_bcd, double i_brc, int i_bcn, int i_BD, int i_mat, int i_ba, int i_nbpa) :
|
||||
TBrake( i_mbp, i_bcr, i_bcd, i_brc, i_bcn, i_BD, i_mat, i_ba, i_nbpa)
|
||||
@@ -482,6 +484,7 @@ class TKE : public TBrake { //Knorr Einheitsbauart — jeden do wszystkiego
|
||||
void PLC( double const mass ); //wspolczynnik cisnienia przystawki wazacej
|
||||
void SetLP( double const TM, double const LM, double const TBP ); //parametry przystawki wazacej
|
||||
void SetLBP( double const P ); //cisnienie z hamulca pomocniczego
|
||||
void ForceEmptiness() /*override*/; // wymuszenie bycia pustym
|
||||
|
||||
inline TKE(double i_mbp, double i_bcr, double i_bcd, double i_brc, int i_bcn, int i_BD, int i_mat, int i_ba, int i_nbpa) :
|
||||
TBrake( i_mbp, i_bcr, i_bcd, i_brc, i_bcn, i_BD, i_mat, i_ba, i_nbpa)
|
||||
|
||||
63
MemCell.cpp
63
MemCell.cpp
@@ -16,26 +16,23 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "stdafx.h"
|
||||
#include "MemCell.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "simulation.h"
|
||||
#include "Logs.h"
|
||||
#include "usefull.h"
|
||||
#include "Driver.h"
|
||||
#include "Event.h"
|
||||
#include "parser.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// legacy constructor
|
||||
TMemCell::TMemCell(vector3 *p)
|
||||
{
|
||||
fValue1 = fValue2 = 0;
|
||||
vPosition =
|
||||
p ? *p : vector3(0, 0, 0); // ustawienie współrzędnych, bo do TGroundNode nie ma dostępu
|
||||
location(
|
||||
p ? *p : vector3() ); // ustawienie współrzędnych, bo do TGroundNode nie ma dostępu
|
||||
bCommand = false; // komenda wysłana
|
||||
OnSent = NULL;
|
||||
}
|
||||
void TMemCell::Init()
|
||||
{
|
||||
}
|
||||
|
||||
TMemCell::TMemCell( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {}
|
||||
|
||||
void TMemCell::UpdateValues( std::string const &szNewText, double const fNewValue1, double const fNewValue2, int const CheckMask )
|
||||
{
|
||||
if (CheckMask & update_memadd)
|
||||
@@ -103,10 +100,12 @@ TCommandType TMemCell::CommandCheck()
|
||||
bool TMemCell::Load(cParser *parser)
|
||||
{
|
||||
std::string token;
|
||||
parser->getTokens(1, false); // case sensitive
|
||||
*parser >> szText;
|
||||
parser->getTokens( 2, false );
|
||||
parser->getTokens( 6, false );
|
||||
*parser
|
||||
>> m_area.center.x
|
||||
>> m_area.center.y
|
||||
>> m_area.center.z
|
||||
>> szText
|
||||
>> fValue1
|
||||
>> fValue2;
|
||||
parser->getTokens();
|
||||
@@ -121,7 +120,7 @@ bool TMemCell::Load(cParser *parser)
|
||||
return true;
|
||||
}
|
||||
|
||||
void TMemCell::PutCommand(TController *Mech, vector3 *Loc)
|
||||
void TMemCell::PutCommand( TController *Mech, glm::dvec3 const *Loc )
|
||||
{ // wysłanie zawartości komórki do AI
|
||||
if (Mech)
|
||||
Mech->PutCommand(szText, fValue1, fValue2, Loc);
|
||||
@@ -150,11 +149,6 @@ bool TMemCell::Compare( std::string const &szTestText, double const fTestValue1,
|
||||
&& ( !TestFlag( CheckMask, conditional_memval2 ) || ( fValue2 == fTestValue2 ) ) );
|
||||
};
|
||||
|
||||
bool TMemCell::Render()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TMemCell::IsVelocity()
|
||||
{ // sprawdzenie, czy event odczytu tej komórki ma być do skanowania, czy do kolejkowania
|
||||
if (eCommand == cm_SetVelocity)
|
||||
@@ -169,11 +163,38 @@ void TMemCell::StopCommandSent()
|
||||
if (!bCommand)
|
||||
return;
|
||||
bCommand = false;
|
||||
if (OnSent) // jeśli jest event
|
||||
Global::AddToQuery(OnSent, NULL);
|
||||
if( OnSent ) {
|
||||
// jeśli jest event
|
||||
simulation::Events.AddToQuery( OnSent, nullptr );
|
||||
}
|
||||
};
|
||||
|
||||
void TMemCell::AssignEvents(TEvent *e)
|
||||
{ // powiązanie eventu
|
||||
OnSent = e;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// legacy method, initializes traction after deserialization from scenario file
|
||||
void
|
||||
memory_table::InitCells() {
|
||||
|
||||
for( auto *cell : m_items ) {
|
||||
// Ra: eventy komórek pamięci, wykonywane po wysłaniu komendy do zatrzymanego pojazdu
|
||||
cell->AssignEvents( simulation::Events.FindEvent( cell->name() + ":sent" ) );
|
||||
}
|
||||
}
|
||||
|
||||
// legacy method, sends content of all cells to the log
|
||||
void
|
||||
memory_table::log_all() {
|
||||
|
||||
for( auto *cell : m_items ) {
|
||||
|
||||
WriteLog( "Memcell \"" + cell->name() + "\": ["
|
||||
+ cell->Text() + "] ["
|
||||
+ to_string( cell->Value1(), 2 ) + "] ["
|
||||
+ to_string( cell->Value2(), 2 ) + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
93
MemCell.h
93
MemCell.h
@@ -10,52 +10,69 @@ http://mozilla.org/MPL/2.0/.
|
||||
#pragma once
|
||||
|
||||
#include "Classes.h"
|
||||
#include "scenenode.h"
|
||||
#include "dumb3d.h"
|
||||
#include "Names.h"
|
||||
|
||||
class TMemCell
|
||||
{
|
||||
private:
|
||||
Math3D::vector3 vPosition;
|
||||
std::string szText;
|
||||
double fValue1;
|
||||
double fValue2;
|
||||
TCommandType eCommand;
|
||||
bool bCommand; // czy zawiera komendę dla zatrzymanego AI
|
||||
TEvent *OnSent; // event dodawany do kolejki po wysłaniu komendy zatrzymującej skład
|
||||
public:
|
||||
class TMemCell : public editor::basic_node {
|
||||
|
||||
public:
|
||||
std::string asTrackName; // McZapkie-100302 - zeby nazwe toru na ktory jest Putcommand wysylane pamietac
|
||||
|
||||
TMemCell( scene::node_data const &Nodedata );
|
||||
// legacy constructor
|
||||
TMemCell( Math3D::vector3 *p );
|
||||
void Init();
|
||||
void UpdateValues( std::string const &szNewText, double const fNewValue1, double const fNewValue2, int const CheckMask );
|
||||
bool Load(cParser *parser);
|
||||
void PutCommand( TController *Mech, Math3D::vector3 *Loc );
|
||||
bool Compare( std::string const &szTestText, double const fTestValue1, double const fTestValue2, int const CheckMask );
|
||||
bool Render();
|
||||
inline std::string const &Text() { return szText; }
|
||||
inline double Value1()
|
||||
{
|
||||
return fValue1;
|
||||
};
|
||||
inline double Value2()
|
||||
{
|
||||
return fValue2;
|
||||
};
|
||||
inline Math3D::vector3 Position()
|
||||
{
|
||||
return vPosition;
|
||||
};
|
||||
inline TCommandType Command()
|
||||
{
|
||||
return eCommand;
|
||||
};
|
||||
inline bool StopCommand()
|
||||
{
|
||||
return bCommand;
|
||||
};
|
||||
|
||||
void
|
||||
UpdateValues( std::string const &szNewText, double const fNewValue1, double const fNewValue2, int const CheckMask );
|
||||
bool
|
||||
Load(cParser *parser);
|
||||
void
|
||||
PutCommand( TController *Mech, glm::dvec3 const *Loc );
|
||||
bool
|
||||
Compare( std::string const &szTestText, double const fTestValue1, double const fTestValue2, int const CheckMask );
|
||||
std::string const &
|
||||
Text() const {
|
||||
return szText; }
|
||||
double
|
||||
Value1() const {
|
||||
return fValue1; };
|
||||
double
|
||||
Value2() const {
|
||||
return fValue2; };
|
||||
TCommandType
|
||||
Command() const {
|
||||
return eCommand; };
|
||||
bool
|
||||
StopCommand() const {
|
||||
return bCommand; };
|
||||
void StopCommandSent();
|
||||
TCommandType CommandCheck();
|
||||
bool IsVelocity();
|
||||
void AssignEvents(TEvent *e);
|
||||
|
||||
private:
|
||||
// content
|
||||
std::string szText;
|
||||
double fValue1 { 0.0 };
|
||||
double fValue2 { 0.0 };
|
||||
// other
|
||||
TCommandType eCommand { cm_Unknown };
|
||||
bool bCommand { false }; // czy zawiera komendę dla zatrzymanego AI
|
||||
TEvent *OnSent { nullptr }; // event dodawany do kolejki po wysłaniu komendy zatrzymującej skład
|
||||
};
|
||||
|
||||
|
||||
|
||||
class memory_table : public basic_table<TMemCell> {
|
||||
|
||||
public:
|
||||
// legacy method, initializes traction after deserialization from scenario file
|
||||
void
|
||||
InitCells();
|
||||
// legacy method, sends content of all cells to the log
|
||||
void
|
||||
log_all();
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
109
Model3d.cpp
109
Model3d.cpp
@@ -988,11 +988,11 @@ TSubModel::create_geometry( std::size_t &Dataoffset, geometrybank_handle const &
|
||||
|
||||
// data offset is used to determine data offset of each submodel into single shared geometry bank
|
||||
// (the offsets are part of legacy system which we now need to work around for backward compatibility)
|
||||
|
||||
if( Child )
|
||||
Child->create_geometry( Dataoffset, Bank );
|
||||
|
||||
if( false == Vertices.empty() ) {
|
||||
|
||||
tVboPtr = static_cast<int>( Dataoffset );
|
||||
Dataoffset += Vertices.size();
|
||||
// conveniently all relevant custom node types use GL_POINTS, or we'd have to determine the type on individual basis
|
||||
@@ -1003,67 +1003,33 @@ TSubModel::create_geometry( std::size_t &Dataoffset, geometrybank_handle const &
|
||||
m_geometry = GfxRenderer.Insert( Vertices, Bank, type );
|
||||
}
|
||||
|
||||
if( Next )
|
||||
Next->create_geometry( Dataoffset, Bank );
|
||||
}
|
||||
|
||||
// places contained geometry in provided ground node
|
||||
void
|
||||
TSubModel::convert( TGroundNode &Groundnode ) const {
|
||||
|
||||
Groundnode.asName = pName;
|
||||
Groundnode.Ambient = f4Ambient;
|
||||
Groundnode.Diffuse = f4Diffuse;
|
||||
Groundnode.Specular = f4Specular;
|
||||
Groundnode.m_material = m_material;
|
||||
Groundnode.iFlags = (
|
||||
( true == GfxRenderer.Material( m_material ).has_alpha ) ?
|
||||
0x20 :
|
||||
0x10 );
|
||||
|
||||
if( m_geometry == null_handle ) { return; }
|
||||
|
||||
std::size_t vertexcount { 0 };
|
||||
std::vector<TGroundVertex> importedvertices;
|
||||
TGroundVertex vertex, vertex1, vertex2;
|
||||
for( auto const &sourcevertex : GfxRenderer.Vertices( m_geometry ) ) {
|
||||
vertex.position = sourcevertex.position;
|
||||
vertex.normal = sourcevertex.normal;
|
||||
vertex.texture = sourcevertex.texture;
|
||||
if( vertexcount == 0 ) { vertex1 = vertex; }
|
||||
else if( vertexcount == 1 ) { vertex2 = vertex; }
|
||||
else if( vertexcount >= 2 ) {
|
||||
if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) {
|
||||
importedvertices.emplace_back( vertex1 );
|
||||
importedvertices.emplace_back( vertex2 );
|
||||
importedvertices.emplace_back( vertex );
|
||||
if( m_geometry != 0 ) {
|
||||
// calculate bounding radius while we're at it
|
||||
// NOTE: doesn't take into account transformation hierarchy TODO: implement it
|
||||
float squaredradius { 0.f };
|
||||
// if this happens to be root node it may already have non-squared radius of the largest child
|
||||
// since we're comparing squared radii, we need to square it back for correct results
|
||||
m_boundingradius *= m_boundingradius;
|
||||
for( auto const &vertex : GfxRenderer.Vertices( m_geometry ) ) {
|
||||
squaredradius = static_cast<float>( glm::length2( vertex.position ) );
|
||||
if( squaredradius > m_boundingradius ) {
|
||||
m_boundingradius = squaredradius;
|
||||
}
|
||||
}
|
||||
++vertexcount;
|
||||
if( vertexcount > 2 ) { vertexcount = 0; } // start new triangle if needed
|
||||
}
|
||||
if( Groundnode.Piece == nullptr ) {
|
||||
Groundnode.Piece = new piece_node();
|
||||
}
|
||||
Groundnode.iNumVerts = importedvertices.size();
|
||||
if( Groundnode.iNumVerts > 0 ) {
|
||||
|
||||
Groundnode.Piece->vertices.swap( importedvertices );
|
||||
|
||||
for( auto const &vertex : Groundnode.Piece->vertices ) {
|
||||
Groundnode.pCenter += vertex.position;
|
||||
if( m_boundingradius > 0.f ) { m_boundingradius = std::sqrt( m_boundingradius ); }
|
||||
// adjust overall radius if needed
|
||||
// NOTE: the method to access root submodel is... less than ideal
|
||||
auto *root { this };
|
||||
while( root->Parent != nullptr ) {
|
||||
root = root->Parent;
|
||||
}
|
||||
Groundnode.pCenter /= Groundnode.iNumVerts;
|
||||
|
||||
double r { 0.0 };
|
||||
double tf;
|
||||
for( auto const &vertex : Groundnode.Piece->vertices ) {
|
||||
tf = glm::length2( vertex.position - glm::dvec3{ Groundnode.pCenter } );
|
||||
if( tf > r )
|
||||
r = tf;
|
||||
}
|
||||
Groundnode.fSquareRadius += r;
|
||||
root->m_boundingradius = std::max(
|
||||
root->m_boundingradius,
|
||||
m_boundingradius );
|
||||
}
|
||||
|
||||
if( Next )
|
||||
Next->create_geometry( Dataoffset, Bank );
|
||||
}
|
||||
|
||||
void TSubModel::ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular )
|
||||
@@ -1151,7 +1117,8 @@ TModel3d::~TModel3d() {
|
||||
|
||||
if (iFlags & 0x0200) {
|
||||
// wczytany z pliku tekstowego, submodele sprzątają same
|
||||
Root = nullptr;
|
||||
SafeDelete( Root );
|
||||
// Root = nullptr;
|
||||
}
|
||||
else {
|
||||
// wczytano z pliku binarnego (jest właścicielem tablic)
|
||||
@@ -1639,7 +1606,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector<std::string> *t,
|
||||
}
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad model: reference to non-existent texture index in sub-model" + ( pName.empty() ? "" : " \"" + pName + "\"" ) );
|
||||
ErrorLog( "Bad model: reference to nonexistent texture index in sub-model" + ( pName.empty() ? "" : " \"" + pName + "\"" ) );
|
||||
m_material = null_handle;
|
||||
}
|
||||
}
|
||||
@@ -1750,18 +1717,11 @@ void TModel3d::Init()
|
||||
return; // operacje zostały już wykonane
|
||||
if (Root)
|
||||
{
|
||||
if (iFlags & 0x0200) // jeśli wczytano z pliku tekstowego
|
||||
{ // jest jakiś dziwny błąd, że obkręcany ma być tylko ostatni submodel
|
||||
// głównego łańcucha
|
||||
// TSubModel *p=Root;
|
||||
// do
|
||||
//{p->InitialRotate(true); //ostatniemu należy się konwersja układu
|
||||
// współrzędnych
|
||||
// p=p->NextGet();
|
||||
//}
|
||||
// while (p->NextGet())
|
||||
// Root->InitialRotate(false); //a poprzednim tylko optymalizacja
|
||||
Root->InitialRotate(true); // argumet określa, czy wykonać pierwotny obrót
|
||||
if (iFlags & 0x0200) {
|
||||
// jeśli wczytano z pliku tekstowego jest jakiś dziwny błąd,
|
||||
// że obkręcany ma być tylko ostatni submodel głównego łańcucha
|
||||
// argumet określa, czy wykonać pierwotny obrót
|
||||
Root->InitialRotate(true);
|
||||
}
|
||||
iFlags |= Root->FlagsCheck() | 0x8000; // flagi całego modelu
|
||||
if (iNumVerts) {
|
||||
@@ -1779,11 +1739,6 @@ void TModel3d::Init()
|
||||
}
|
||||
};
|
||||
|
||||
void TModel3d::BreakHierarhy()
|
||||
{
|
||||
Error("Not implemented yet :(");
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 2012-02 funkcje do tworzenia terenu z E3D
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
21
Model3d.h
21
Model3d.h
@@ -50,14 +50,18 @@ enum TAnimType // rodzaj animacji
|
||||
at_Undefined = 0x800000FF // animacja chwilowo nieokreślona
|
||||
};
|
||||
|
||||
namespace scene {
|
||||
class shape_node;
|
||||
}
|
||||
|
||||
class TModel3d;
|
||||
class TGroundNode;
|
||||
|
||||
class TSubModel
|
||||
{ // klasa submodelu - pojedyncza siatka, punkt świetlny albo grupa punktów
|
||||
friend class opengl_renderer;
|
||||
friend class TModel3d; // temporary workaround. TODO: clean up class content/hierarchy
|
||||
friend class TDynamicObject; // temporary etc
|
||||
friend class scene::shape_node; // temporary etc
|
||||
|
||||
public:
|
||||
enum normalization {
|
||||
@@ -130,10 +134,8 @@ private:
|
||||
|
||||
public: // chwilowo
|
||||
float3 v_TransVector { 0.0f, 0.0f, 0.0f };
|
||||
/*
|
||||
basic_vertex *Vertices; // roboczy wskaźnik - wczytanie T3D do VBO
|
||||
*/
|
||||
vertex_array Vertices;
|
||||
float m_boundingradius { 0 };
|
||||
size_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawił animację
|
||||
TAnimType b_aAnim{ at_None }; // kody animacji oddzielnie, bo zerowane
|
||||
public:
|
||||
@@ -163,9 +165,6 @@ public:
|
||||
TSubModel * NextGet() { return Next; };
|
||||
TSubModel * ChildGet() { return Child; };
|
||||
int TriangleAdd(TModel3d *m, material_handle tex, int tri);
|
||||
/*
|
||||
basic_vertex * TrianglePtr(int tex, int pos, glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular );
|
||||
*/
|
||||
void SetRotate(float3 vNewRotateAxis, float fNewAngle);
|
||||
void SetRotateXYZ(vector3 vNewAngles);
|
||||
void SetRotateXYZ(float3 vNewAngles);
|
||||
@@ -215,8 +214,6 @@ public:
|
||||
std::vector<float4x4>&);
|
||||
void serialize_geometry( std::ostream &Output ) const;
|
||||
// places contained geometry in provided ground node
|
||||
void convert( TGroundNode &Groundnode ) const;
|
||||
|
||||
};
|
||||
|
||||
class TModel3d : public CMesh
|
||||
@@ -236,6 +233,11 @@ private:
|
||||
std::string asBinary; // nazwa pod którą zapisać model binarny
|
||||
std::string m_filename;
|
||||
public:
|
||||
float bounding_radius() const {
|
||||
return (
|
||||
Root ?
|
||||
Root->m_boundingradius :
|
||||
0.f ); }
|
||||
inline TSubModel * GetSMRoot() { return (Root); };
|
||||
TModel3d();
|
||||
~TModel3d();
|
||||
@@ -246,7 +248,6 @@ public:
|
||||
void LoadFromBinFile(std::string const &FileName, bool dynamic);
|
||||
bool LoadFromFile(std::string const &FileName, bool dynamic);
|
||||
void SaveToBinFile(std::string const &FileName);
|
||||
void BreakHierarhy();
|
||||
int Flags() const { return iFlags; };
|
||||
void Init();
|
||||
std::string NameGet() { return m_filename; };
|
||||
|
||||
83
Names.h
83
Names.h
@@ -13,55 +13,52 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <string>
|
||||
|
||||
template <typename Type_>
|
||||
class TNames {
|
||||
class basic_table {
|
||||
|
||||
public:
|
||||
// types:
|
||||
|
||||
// constructors:
|
||||
TNames() = default;
|
||||
|
||||
// destructor:
|
||||
|
||||
// methods:
|
||||
// dodanie obiektu z wskaźnikiem. updates data field if the object already exists. returns true for insertion, false for update
|
||||
// destructor
|
||||
~basic_table() {
|
||||
for( auto *item : m_items ) {
|
||||
delete item; } }
|
||||
// methods
|
||||
// adds provided item to the collection. returns: true if there's no duplicate with the same name, false otherwise
|
||||
bool
|
||||
Add( int const Type, std::string const &Name, Type_ Data ) {
|
||||
|
||||
auto lookup = find_map( Type ).emplace( Name, Data );
|
||||
if( lookup.second == false ) {
|
||||
// record already exists, update it
|
||||
lookup.first->second = Data;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// new record inserted, bail out
|
||||
insert( Type_ *Item ) {
|
||||
m_items.emplace_back( Item );
|
||||
auto const itemname = Item->name();
|
||||
if( ( true == itemname.empty() ) || ( itemname == "none" ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// returns pointer associated with provided label, or nullptr if there's no match
|
||||
Type_
|
||||
Find( int const Type, std::string const &Name ) {
|
||||
auto const itemhandle { m_items.size() - 1 };
|
||||
// add item name to the map
|
||||
auto mapping = m_itemmap.emplace( itemname, itemhandle );
|
||||
if( true == mapping.second ) {
|
||||
return true;
|
||||
}
|
||||
// cell with this name already exists; update mapping to point to the new one, for backward compatibility
|
||||
mapping.first->second = itemhandle;
|
||||
return false; }
|
||||
// locates item with specified name. returns pointer to the item, or nullptr
|
||||
Type_ *
|
||||
find( std::string const &Name ) {
|
||||
auto lookup = m_itemmap.find( Name );
|
||||
return (
|
||||
lookup != m_itemmap.end() ?
|
||||
m_items[ lookup->second ] :
|
||||
nullptr ); }
|
||||
|
||||
auto const &map = find_map( Type );
|
||||
auto const lookup = map.find( Name );
|
||||
if( lookup != map.end() ) { return lookup->second; }
|
||||
else { return nullptr; }
|
||||
}
|
||||
protected:
|
||||
// types
|
||||
using type_sequence = std::deque<Type_ *>;
|
||||
using type_map = std::unordered_map<std::string, std::size_t>;
|
||||
// members
|
||||
type_sequence m_items;
|
||||
type_map m_itemmap;
|
||||
|
||||
private:
|
||||
// types:
|
||||
typedef std::unordered_map<std::string, Type_> type_map;
|
||||
typedef std::unordered_map<int, type_map> typemap_map;
|
||||
public:
|
||||
// data access
|
||||
type_sequence &
|
||||
sequence() {
|
||||
return m_items; }
|
||||
|
||||
// methods:
|
||||
// returns database stored with specified type key; creates new database if needed.
|
||||
type_map &
|
||||
find_map( int const Type ) {
|
||||
|
||||
return m_maps.emplace( Type, type_map() ).first->second;
|
||||
}
|
||||
|
||||
// members:
|
||||
typemap_map m_maps; // list of object maps of types specified so far
|
||||
};
|
||||
|
||||
153
Segment.cpp
153
Segment.cpp
@@ -59,8 +59,8 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
|
||||
CPointIn = NewCPointIn;
|
||||
Point2 = NewPoint2;
|
||||
// poprawienie przechyłki
|
||||
fRoll1 = DegToRad(fNewRoll1); // Ra: przeliczone jest bardziej przydatne do obliczeń
|
||||
fRoll2 = DegToRad(fNewRoll2);
|
||||
fRoll1 = glm::radians(fNewRoll1); // Ra: przeliczone jest bardziej przydatne do obliczeń
|
||||
fRoll2 = glm::radians(fNewRoll2);
|
||||
if (Global::bRollFix)
|
||||
{ // Ra: poprawianie przechyłki
|
||||
// Przechyłka powinna być na środku wewnętrznej szyny, a standardowo jest w osi
|
||||
@@ -78,7 +78,7 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
|
||||
CPointOut.y += w1; // prosty ma wektory jednostkowe
|
||||
pOwner->MovedUp1(w1); // zwrócić trzeba informację o podwyższeniu podsypki
|
||||
}
|
||||
if (fRoll2 != 0.0)
|
||||
if (fRoll2 != 0.f)
|
||||
{
|
||||
double w2 = std::abs(std::sin(fRoll2) * 0.75); // 0.5*w2+0.0325; //0.75m dla 1.435
|
||||
Point2.y += w2; // modyfikacja musi być przed policzeniem dalszych parametrów
|
||||
@@ -87,9 +87,9 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
|
||||
// zwrócić trzeba informację o podwyższeniu podsypki
|
||||
}
|
||||
}
|
||||
// kąt w planie, żeby nie liczyć wielokrotnie
|
||||
// Ra: ten kąt jeszcze do przemyślenia jest
|
||||
fDirection = -atan2(Point2.x - Point1.x,
|
||||
Point2.z - Point1.z); // kąt w planie, żeby nie liczyć wielokrotnie
|
||||
fDirection = -std::atan2(Point2.x - Point1.x, Point2.z - Point1.z);
|
||||
bCurve = bIsCurve;
|
||||
if (bCurve)
|
||||
{ // przeliczenie współczynników wielomianu, będzie mniej mnożeń i można policzyć pochodne
|
||||
@@ -101,10 +101,9 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
|
||||
else
|
||||
fLength = (Point1 - Point2).Length();
|
||||
fStep = fNewStep;
|
||||
if (fLength <= 0)
|
||||
{
|
||||
ErrorLog( "Bad geometry: zero length spline \"" + pOwner->NameGet() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
|
||||
// MessageBox(0,"Length<=0","TSegment::Init",MB_OK);
|
||||
if (fLength <= 0) {
|
||||
|
||||
ErrorLog( "Bad track: zero length spline \"" + pOwner->name() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
|
||||
fLength = 0.01; // crude workaround TODO: fix this properly
|
||||
/*
|
||||
return false; // zerowe nie mogą być
|
||||
@@ -206,7 +205,7 @@ double TSegment::GetTFromS(double const s) const
|
||||
// Newton's method failed. If this happens, increase iterations or
|
||||
// tolerance or integration accuracy.
|
||||
// return -1; //Ra: tu nigdy nie dojdzie
|
||||
ErrorLog( "Bad geometry: shape estimation failed for spline \"" + pOwner->NameGet() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
|
||||
ErrorLog( "Bad track: shape estimation failed for spline \"" + pOwner->name() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
|
||||
// MessageBox(0,"Too many iterations","GetTFromS",MB_OK);
|
||||
return fTime;
|
||||
};
|
||||
@@ -324,23 +323,28 @@ Math3D::vector3 TSegment::GetPoint(double const fDistance) const
|
||||
}
|
||||
};
|
||||
|
||||
void TSegment::RaPositionGet(double const fDistance, Math3D::vector3 &p, Math3D::vector3 &a) const
|
||||
{ // ustalenie pozycji osi na torze, przechyłki, pochylenia i kierunku jazdy
|
||||
if (bCurve)
|
||||
{ // można by wprowadzić uproszczony wzór dla okręgów płaskich
|
||||
double t = GetTFromS(fDistance); // aproksymacja dystansu na krzywej Beziera na parametr (t)
|
||||
p = RaInterpolate(t);
|
||||
a.x = (1.0 - t) * fRoll1 + (t)*fRoll2; // przechyłka w danym miejscu (zmienia się liniowo)
|
||||
// ustalenie pozycji osi na torze, przechyłki, pochylenia i kierunku jazdy
|
||||
void TSegment::RaPositionGet(double const fDistance, Math3D::vector3 &p, Math3D::vector3 &a) const {
|
||||
|
||||
if (bCurve) {
|
||||
// można by wprowadzić uproszczony wzór dla okręgów płaskich
|
||||
auto const t = GetTFromS(fDistance); // aproksymacja dystansu na krzywej Beziera na parametr (t)
|
||||
p = FastGetPoint( t );
|
||||
// przechyłka w danym miejscu (zmienia się liniowo)
|
||||
a.x = interpolate<double>( fRoll1, fRoll2, t );
|
||||
// pochodna jest 3*A*t^2+2*B*t+C
|
||||
a.y = atan(t * (t * 3.0 * vA.y + vB.y + vB.y) + vC.y); // pochylenie krzywej (w pionie)
|
||||
a.z = -atan2(t * (t * 3.0 * vA.x + vB.x + vB.x) + vC.x,
|
||||
t * (t * 3.0 * vA.z + vB.z + vB.z) + vC.z); // kierunek krzywej w planie
|
||||
auto const tangent = t * ( t * 3.0 * vA + vB + vB ) + vC;
|
||||
// pochylenie krzywej (w pionie)
|
||||
a.y = std::atan( tangent.y );
|
||||
// kierunek krzywej w planie
|
||||
a.z = -std::atan2( tangent.x, tangent.z );
|
||||
}
|
||||
else
|
||||
{ // wyliczenie dla odcinka prostego jest prostsze
|
||||
double t = fDistance / fLength; // zerowych torów nie ma
|
||||
p = ((1.0 - t) * Point1 + (t)*Point2);
|
||||
a.x = (1.0 - t) * fRoll1 + (t)*fRoll2; // przechyłka w danym miejscu (zmienia się liniowo)
|
||||
else {
|
||||
// wyliczenie dla odcinka prostego jest prostsze
|
||||
auto const t = fDistance / fLength; // zerowych torów nie ma
|
||||
p = FastGetPoint( t );
|
||||
// przechyłka w danym miejscu (zmienia się liniowo)
|
||||
a.x = interpolate<double>( fRoll1, fRoll2, t );
|
||||
a.y = fStoop; // pochylenie toru prostego
|
||||
a.z = fDirection; // kierunek toru w planie
|
||||
}
|
||||
@@ -355,7 +359,7 @@ Math3D::vector3 TSegment::FastGetPoint(double const t) const
|
||||
interpolate( Point1, Point2, t ) );
|
||||
}
|
||||
|
||||
bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, Math3D::vector3 **p, bool bRender)
|
||||
bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, const basic_vertex *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, float fOffsetX, glm::vec3 **p, bool bRender)
|
||||
{ // generowanie trójkątów dla odcinka trajektorii ruchu
|
||||
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
|
||||
// po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli
|
||||
@@ -365,13 +369,14 @@ bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin,
|
||||
if( !fTsBuffer )
|
||||
return false; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę
|
||||
|
||||
Math3D::vector3 pos1, pos2, dir, parallel1, parallel2, pt, norm;
|
||||
double s, step, fOffset, tv1, tv2, t, fEnd;
|
||||
glm::vec3 pos1, pos2, dir, parallel1, parallel2, pt, norm;
|
||||
float s, step, fOffset, tv1, tv2, t, fEnd;
|
||||
bool const trapez = iNumShapePoints < 0; // sygnalizacja trapezowatości
|
||||
iNumShapePoints = std::abs( iNumShapePoints );
|
||||
fTextureLength *= Texturescale;
|
||||
float const texturelength = fTextureLength * Texturescale;
|
||||
float const texturescale = Texturescale;
|
||||
|
||||
double m1, jmm1, m2, jmm2; // pozycje względne na odcinku 0...1 (ale nie parametr Beziera)
|
||||
float m1, jmm1, m2, jmm2; // pozycje względne na odcinku 0...1 (ale nie parametr Beziera)
|
||||
step = fStep;
|
||||
tv1 = 1.0; // Ra: to by można było wyliczać dla odcinka, wyglądało by lepiej
|
||||
s = fStep * iSkip; // iSkip - ile odcinków z początku pominąć
|
||||
@@ -379,9 +384,14 @@ bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin,
|
||||
t = fTsBuffer[ i ]; // tabela wattości t dla segmentów
|
||||
// BUG: length of spline can be 0, we should skip geometry generation for such cases
|
||||
fOffset = 0.1 / fLength; // pierwsze 10cm
|
||||
pos1 = FastGetPoint( t ); // wektor początku segmentu
|
||||
dir = FastGetDirection( t, fOffset ); // wektor kierunku
|
||||
parallel1 = Normalize( Math3D::vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny
|
||||
pos1 = glm::dvec3{ FastGetPoint( t ) - Origin }; // wektor początku segmentu
|
||||
dir = glm::dvec3{ FastGetDirection( t, fOffset ) }; // wektor kierunku
|
||||
parallel1 = glm::vec3{ -dir.z, 0.f, dir.x }; // wektor poprzeczny
|
||||
if( glm::length2( parallel1 ) == 0.f ) {
|
||||
// temporary workaround for malformed situations with control points placed above endpoints
|
||||
parallel1 = glm::vec3{ glm::dvec3{ FastGetPoint_1() - FastGetPoint_0() } };
|
||||
}
|
||||
parallel1 = glm::normalize( parallel1 );
|
||||
if( iEnd == 0 )
|
||||
iEnd = iSegCount;
|
||||
fEnd = fLength * double( iEnd ) / double( iSegCount );
|
||||
@@ -406,26 +416,31 @@ bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin,
|
||||
while( tv1 < 0.0 ) {
|
||||
tv1 += 1.0;
|
||||
}
|
||||
tv2 = tv1 - step / fTextureLength; // mapowanie na końcu segmentu
|
||||
tv2 = tv1 - step / texturelength; // mapowanie na końcu segmentu
|
||||
|
||||
t = fTsBuffer[ i ]; // szybsze od GetTFromS(s);
|
||||
pos2 = FastGetPoint( t );
|
||||
dir = FastGetDirection( t, fOffset ); // nowy wektor kierunku
|
||||
parallel2 = Normalize( Math3D::vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny
|
||||
pos2 = glm::dvec3{ FastGetPoint( t ) - Origin };
|
||||
dir = glm::dvec3{ FastGetDirection( t, fOffset ) }; // nowy wektor kierunku
|
||||
parallel2 = glm::vec3{ -dir.z, 0.f, dir.x }; // wektor poprzeczny
|
||||
if( glm::length2( parallel2 ) == 0.f ) {
|
||||
// temporary workaround for malformed situations with control points placed above endpoints
|
||||
parallel2 = glm::vec3{ glm::dvec3{ FastGetPoint_1() - FastGetPoint_0() } };
|
||||
}
|
||||
parallel2 = glm::normalize( parallel2 );
|
||||
|
||||
if( trapez ) {
|
||||
for( int j = 0; j < iNumShapePoints; ++j ) {
|
||||
pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].x - fOffsetX ) + m1 * ShapePoints[ j + iNumShapePoints ].x ) + pos1;
|
||||
pt.y += jmm1 * ShapePoints[ j ].y + m1 * ShapePoints[ j + iNumShapePoints ].y;
|
||||
pt -= Origin;
|
||||
norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel1;
|
||||
norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y;
|
||||
pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].position.x - fOffsetX ) + m1 * ShapePoints[ j + iNumShapePoints ].position.x ) + pos1;
|
||||
pt.y += jmm1 * ShapePoints[ j ].position.y + m1 * ShapePoints[ j + iNumShapePoints ].position.y;
|
||||
// pt -= Origin;
|
||||
norm = ( jmm1 * ShapePoints[ j ].normal.x + m1 * ShapePoints[ j + iNumShapePoints ].normal.x ) * parallel1;
|
||||
norm.y += jmm1 * ShapePoints[ j ].normal.y + m1 * ShapePoints[ j + iNumShapePoints ].normal.y;
|
||||
if( bRender ) {
|
||||
// skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów
|
||||
Output.emplace_back(
|
||||
glm::vec3 { pt.x, pt.y, pt.z },
|
||||
glm::vec3 { norm.x, norm.y, norm.z },
|
||||
glm::vec2 { ( jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z ) / Texturescale, tv1 } );
|
||||
pt,
|
||||
glm::normalize( norm ),
|
||||
glm::vec2 { ( jmm1 * ShapePoints[ j ].texture.x + m1 * ShapePoints[ j + iNumShapePoints ].texture.x ) / texturescale, tv1 } );
|
||||
}
|
||||
if( p ) // jeśli jest wskaźnik do tablicy
|
||||
if( *p )
|
||||
@@ -435,17 +450,17 @@ bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin,
|
||||
( *p )++;
|
||||
} // zapamiętanie brzegu jezdni
|
||||
// dla trapezu drugi koniec ma inne współrzędne
|
||||
pt = parallel2 * ( jmm2 * ( ShapePoints[ j ].x - fOffsetX ) + m2 * ShapePoints[ j + iNumShapePoints ].x ) + pos2;
|
||||
pt.y += jmm2 * ShapePoints[ j ].y + m2 * ShapePoints[ j + iNumShapePoints ].y;
|
||||
pt -= Origin;
|
||||
norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel2;
|
||||
norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y;
|
||||
pt = parallel2 * ( jmm2 * ( ShapePoints[ j ].position.x - fOffsetX ) + m2 * ShapePoints[ j + iNumShapePoints ].position.x ) + pos2;
|
||||
pt.y += jmm2 * ShapePoints[ j ].position.y + m2 * ShapePoints[ j + iNumShapePoints ].position.y;
|
||||
// pt -= Origin;
|
||||
norm = ( jmm1 * ShapePoints[ j ].normal.x + m1 * ShapePoints[ j + iNumShapePoints ].normal.x ) * parallel2;
|
||||
norm.y += jmm1 * ShapePoints[ j ].normal.y + m1 * ShapePoints[ j + iNumShapePoints ].normal.y;
|
||||
if( bRender ) {
|
||||
// skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów
|
||||
Output.emplace_back(
|
||||
glm::vec3 { pt.x, pt.y, pt.z },
|
||||
glm::vec3 { norm.x, norm.y, norm.z },
|
||||
glm::vec2 { ( jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z ) / Texturescale, tv2 } );
|
||||
pt,
|
||||
glm::normalize( norm ),
|
||||
glm::vec2 { ( jmm2 * ShapePoints[ j ].texture.x + m2 * ShapePoints[ j + iNumShapePoints ].texture.x ) / texturescale, tv2 } );
|
||||
}
|
||||
if( p ) // jeśli jest wskaźnik do tablicy
|
||||
if( *p )
|
||||
@@ -460,27 +475,27 @@ bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin,
|
||||
if( bRender ) {
|
||||
for( int j = 0; j < iNumShapePoints; ++j ) {
|
||||
//łuk z jednym profilem
|
||||
pt = parallel1 * ( ShapePoints[ j ].x - fOffsetX ) + pos1;
|
||||
pt.y += ShapePoints[ j ].y;
|
||||
pt -= Origin;
|
||||
norm = ShapePoints[ j ].n.x * parallel1;
|
||||
norm.y += ShapePoints[ j ].n.y;
|
||||
pt = parallel1 * ( ShapePoints[ j ].position.x - fOffsetX ) + pos1;
|
||||
pt.y += ShapePoints[ j ].position.y;
|
||||
// pt -= Origin;
|
||||
norm = ShapePoints[ j ].normal.x * parallel1;
|
||||
norm.y += ShapePoints[ j ].normal.y;
|
||||
|
||||
Output.emplace_back(
|
||||
glm::vec3 { pt.x, pt.y, pt.z },
|
||||
glm::vec3 { norm.x, norm.y, norm.z },
|
||||
glm::vec2 { ShapePoints[ j ].z / Texturescale, tv1 } );
|
||||
pt,
|
||||
glm::normalize( norm ),
|
||||
glm::vec2 { ShapePoints[ j ].texture.x / texturescale, tv1 } );
|
||||
|
||||
pt = parallel2 * ShapePoints[ j ].x + pos2;
|
||||
pt.y += ShapePoints[ j ].y;
|
||||
pt -= Origin;
|
||||
norm = ShapePoints[ j ].n.x * parallel2;
|
||||
norm.y += ShapePoints[ j ].n.y;
|
||||
pt = parallel2 * ShapePoints[ j ].position.x + pos2;
|
||||
pt.y += ShapePoints[ j ].position.y;
|
||||
// pt -= Origin;
|
||||
norm = ShapePoints[ j ].normal.x * parallel2;
|
||||
norm.y += ShapePoints[ j ].normal.y;
|
||||
|
||||
Output.emplace_back(
|
||||
glm::vec3 { pt.x, pt.y, pt.z },
|
||||
glm::vec3 { norm.x, norm.y, norm.z },
|
||||
glm::vec2 { ShapePoints[ j ].z / Texturescale, tv2 } );
|
||||
pt,
|
||||
glm::normalize( norm ),
|
||||
glm::vec2 { ShapePoints[ j ].texture.x / texturescale, tv2 } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
50
Segment.h
50
Segment.h
@@ -14,44 +14,13 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Classes.h"
|
||||
#include "usefull.h"
|
||||
|
||||
// 110405 Ra: klasa punktów przekroju z normalnymi
|
||||
|
||||
class vector6 : public Math3D::vector3
|
||||
{ // punkt przekroju wraz z wektorem normalnym
|
||||
public:
|
||||
Math3D::vector3 n;
|
||||
vector6()
|
||||
{
|
||||
x = y = z = n.x = n.z = 0.0;
|
||||
n.y = 1.0;
|
||||
};
|
||||
vector6(double a, double b, double c, double d, double e, double f)
|
||||
//{x=a; y=b; z=c; n.x=d; n.y=e; n.z=f;};
|
||||
{
|
||||
x = a;
|
||||
y = b;
|
||||
z = c;
|
||||
n.x = 0.0;
|
||||
n.y = 1.0;
|
||||
n.z = 0.0;
|
||||
}; // Ra: bo na razie są z tym problemy
|
||||
vector6(double a, double b, double c)
|
||||
{
|
||||
x = a;
|
||||
y = b;
|
||||
z = c;
|
||||
n.x = 0.0;
|
||||
n.y = 1.0;
|
||||
n.z = 0.0;
|
||||
};
|
||||
};
|
||||
|
||||
class TSegment
|
||||
{ // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny)
|
||||
private:
|
||||
Math3D::vector3 Point1, CPointOut, CPointIn, Point2;
|
||||
double fRoll1 = 0.0,
|
||||
fRoll2 = 0.0; // przechyłka na końcach
|
||||
float
|
||||
fRoll1{ 0.f },
|
||||
fRoll2{ 0.f }; // przechyłka na końcach
|
||||
double fLength = 0.0; // długość policzona
|
||||
double *fTsBuffer = nullptr; // wartości parametru krzywej dla równych odcinków
|
||||
double fStep = 0.0;
|
||||
@@ -60,7 +29,6 @@ class TSegment
|
||||
double fStoop = 0.0; // Ra: kąt wzniesienia; dla łuku od Point1
|
||||
Math3D::vector3 vA, vB, vC; // współczynniki wielomianów trzeciego stopnia vD==Point1
|
||||
TTrack *pOwner = nullptr; // wskaźnik na właściciela
|
||||
double fAngle[ 2 ] = { 0.0, 0.0 }; // kąty zakończenia drogi na przejazdach
|
||||
|
||||
Math3D::vector3
|
||||
GetFirstDerivative(double const fTime) const;
|
||||
@@ -118,18 +86,18 @@ public:
|
||||
FastGetPoint_1() const {
|
||||
return Point2; };
|
||||
inline
|
||||
double
|
||||
float
|
||||
GetRoll(double const Distance) const {
|
||||
return interpolate( fRoll1, fRoll2, Distance / fLength ); }
|
||||
return interpolate( fRoll1, fRoll2, static_cast<float>(Distance / fLength) ); }
|
||||
inline
|
||||
void
|
||||
GetRolls(double &r1, double &r2) const {
|
||||
GetRolls(float &r1, float &r2) const {
|
||||
// pobranie przechyłek (do generowania trójkątów)
|
||||
r1 = fRoll1;
|
||||
r2 = fRoll2; }
|
||||
|
||||
bool
|
||||
RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, vector6 const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, Math3D::vector3 **p = nullptr, bool bRender = true);
|
||||
RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, basic_vertex const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, float fOffsetX = 0.f, glm::vec3 **p = nullptr, bool bRender = true);
|
||||
void
|
||||
Render();
|
||||
inline
|
||||
@@ -140,10 +108,6 @@ public:
|
||||
int
|
||||
RaSegCount() const {
|
||||
return fTsBuffer ? iSegCount : 1; };
|
||||
inline
|
||||
void
|
||||
AngleSet(int const i, double const a) {
|
||||
fAngle[i] = a; };
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -765,8 +765,11 @@ texture_manager::create( std::string Filename, bool const Loadnow ) {
|
||||
Filename.erase( traitpos );
|
||||
}
|
||||
|
||||
if( Filename.rfind( '.' ) != std::string::npos )
|
||||
Filename.erase( Filename.rfind( '.' ) ); // trim extension if there's one
|
||||
if( ( Filename.rfind( '.' ) != std::string::npos )
|
||||
&& ( Filename.rfind( '.' ) != Filename.rfind( ".." ) + 1 ) ) {
|
||||
// trim extension if there's one, but don't mistake folder traverse for extension
|
||||
Filename.erase( Filename.rfind( '.' ) );
|
||||
}
|
||||
|
||||
std::replace(Filename.begin(), Filename.end(), '\\', '/'); // fix slashes
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Timer.h"
|
||||
#include "Globals.h"
|
||||
|
||||
namespace Timer
|
||||
{
|
||||
namespace Timer {
|
||||
|
||||
subsystem_stopwatches subsystem;
|
||||
|
||||
double DeltaTime, DeltaRenderTime;
|
||||
double fFPS{ 0.0f };
|
||||
|
||||
36
Timer.h
36
Timer.h
@@ -9,8 +9,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Timer
|
||||
{
|
||||
namespace Timer {
|
||||
|
||||
double GetTime();
|
||||
|
||||
@@ -28,6 +27,39 @@ double GetFPS();
|
||||
void ResetTimers();
|
||||
|
||||
void UpdateTimers(bool pause);
|
||||
|
||||
class stopwatch {
|
||||
|
||||
public:
|
||||
void
|
||||
start() {
|
||||
m_start = std::chrono::steady_clock::now(); }
|
||||
void
|
||||
stop() {
|
||||
m_accumulator = 0.95f * m_accumulator + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - m_start ) ).count() / 1000.f; }
|
||||
float
|
||||
average() const {
|
||||
return m_accumulator / 20.f;}
|
||||
|
||||
private:
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_start { std::chrono::steady_clock::now() };
|
||||
float m_accumulator { 1000.f / 30.f * 20.f }; // 20 last samples, initial 'neutral' rate of 30 fps
|
||||
};
|
||||
|
||||
struct subsystem_stopwatches {
|
||||
stopwatch gfx_total;
|
||||
stopwatch gfx_color;
|
||||
stopwatch gfx_shadows;
|
||||
stopwatch gfx_reflections;
|
||||
stopwatch gfx_swap;
|
||||
stopwatch sim_total;
|
||||
stopwatch sim_dynamics;
|
||||
stopwatch sim_events;
|
||||
stopwatch sim_ai;
|
||||
};
|
||||
|
||||
extern subsystem_stopwatches subsystem;
|
||||
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
138
Track.h
138
Track.h
@@ -10,23 +10,29 @@ http://mozilla.org/MPL/2.0/.
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "GL/glew.h"
|
||||
#include "ResourceManager.h"
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
#include "Segment.h"
|
||||
#include "material.h"
|
||||
#include "scenenode.h"
|
||||
#include "Names.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
namespace scene {
|
||||
class basic_cell;
|
||||
}
|
||||
|
||||
enum TTrackType {
|
||||
tt_Unknown,
|
||||
tt_Normal,
|
||||
tt_Switch,
|
||||
tt_Table,
|
||||
tt_Cross,
|
||||
tt_Tributary
|
||||
} TTrackType;
|
||||
};
|
||||
// McZapkie-100502
|
||||
typedef enum
|
||||
{
|
||||
|
||||
enum TEnvironmentType {
|
||||
e_unknown = -1,
|
||||
e_flat = 0,
|
||||
e_mountains,
|
||||
@@ -34,7 +40,7 @@ typedef enum
|
||||
e_tunnel,
|
||||
e_bridge,
|
||||
e_bank
|
||||
} TEnvironmentType;
|
||||
};
|
||||
// Ra: opracować alternatywny system cieni/świateł z definiowaniem koloru oświetlenia w halach
|
||||
|
||||
class TEvent;
|
||||
@@ -49,49 +55,43 @@ class TSwitchExtension
|
||||
TSwitchExtension(TTrack *owner, int const what);
|
||||
~TSwitchExtension();
|
||||
std::shared_ptr<TSegment> Segments[6]; // dwa tory od punktu 1, pozosta³e dwa od 2? Ra 140101: 6 po³¹czeñ dla skrzy¿owañ
|
||||
// TTrack *trNear[4]; //tory do³¹czone do punktów 1, 2, 3 i 4
|
||||
// dotychczasowe [2]+[2] wskaŸniki zamieniæ na nowe [4]
|
||||
TTrack *pNexts[2]; // tory do³¹czone do punktów 2 i 4
|
||||
TTrack *pPrevs[2]; // tory do³¹czone do punktów 1 i 3
|
||||
int iNextDirection[2]; // to te¿ z [2]+[2] przerobiæ na [4]
|
||||
int iPrevDirection[2];
|
||||
int CurrentIndex = 0; // dla zwrotnicy
|
||||
double fOffset = 0.0,
|
||||
fDesiredOffset = 0.0; // aktualne i docelowe położenie napędu iglic
|
||||
double fOffsetSpeed = 0.1; // prędkość liniowa ruchu iglic
|
||||
double fOffsetDelay = 0.05; // opóźnienie ruchu drugiej iglicy względem pierwszej // dodatkowy ruch drugiej iglicy po zablokowaniu pierwszej na opornicy
|
||||
float
|
||||
fOffset{ 0.f },
|
||||
fDesiredOffset{ 0.f }; // aktualne i docelowe położenie napędu iglic
|
||||
float fOffsetSpeed = 0.1f; // prędkość liniowa ruchu iglic
|
||||
float fOffsetDelay = 0.05f; // opóźnienie ruchu drugiej iglicy względem pierwszej // dodatkowy ruch drugiej iglicy po zablokowaniu pierwszej na opornicy
|
||||
union
|
||||
{
|
||||
struct
|
||||
{ // zmienne potrzebne tylko dla zwrotnicy
|
||||
double fOffset1,
|
||||
fOffset2; // przesunięcia iglic - 0=na wprost
|
||||
float fOffset1,
|
||||
fOffset2; // przesunięcia iglic - 0=na wprost
|
||||
bool RightSwitch; // czy zwrotnica w prawo
|
||||
};
|
||||
struct
|
||||
{ // zmienne potrzebne tylko dla obrotnicy/przesuwnicy
|
||||
TGroundNode *pMyNode; // dla obrotnicy do wtórnego podłączania torów
|
||||
// TAnimContainer *pAnim; //animator modelu dla obrotnicy
|
||||
// TAnimContainer *pAnim; //animator modelu dla obrotnicy
|
||||
TAnimModel *pModel; // na razie model
|
||||
};
|
||||
struct
|
||||
{ // zmienne dla skrzyżowania
|
||||
int iRoads; // ile dróg się spotyka?
|
||||
Math3D::vector3 *vPoints; // tablica wierzchołków nawierzchni, generowana przez pobocze
|
||||
// int iPoints; // liczba faktycznie użytych wierzchołków nawierzchni
|
||||
glm::vec3 *vPoints; // tablica wierzchołków nawierzchni, generowana przez pobocze
|
||||
bool bPoints; // czy utworzone?
|
||||
};
|
||||
};
|
||||
bool bMovement = false; // czy w trakcie animacji
|
||||
int iLeftVBO = 0,
|
||||
iRightVBO = 0; // indeksy iglic w VBO
|
||||
TSubRect *pOwner = nullptr; // sektor, któremu trzeba zgłosić animację
|
||||
scene::basic_cell *pOwner = nullptr; // TODO: convert this to observer pattern
|
||||
TTrack *pNextAnim = nullptr; // następny tor do animowania
|
||||
TEvent *evPlus = nullptr,
|
||||
*evMinus = nullptr; // zdarzenia sygnalizacji rozprucia
|
||||
float fVelocity = -1.0; // maksymalne ograniczenie prędkości (ustawianej eventem)
|
||||
Math3D::vector3 vTrans; // docelowa translacja przesuwnicy
|
||||
private:
|
||||
};
|
||||
|
||||
class TIsolated
|
||||
@@ -106,7 +106,7 @@ class TIsolated
|
||||
TMemCell *pMemCell = nullptr; // automatyczna komórka pamięci, która współpracuje z odcinkiem izolowanym
|
||||
TIsolated();
|
||||
TIsolated(const std::string &n, TIsolated *i);
|
||||
~TIsolated();
|
||||
static void DeleteAll();
|
||||
static TIsolated * Find(const std::string &n); // znalezienie obiektu albo utworzenie nowego
|
||||
void Modify(int i, TDynamicObject *o); // dodanie lub odjęcie osi
|
||||
bool Busy() {
|
||||
@@ -118,12 +118,11 @@ class TIsolated
|
||||
};
|
||||
|
||||
// trajektoria ruchu - opakowanie
|
||||
class TTrack /*: public Resource*/ {
|
||||
class TTrack : public editor::basic_node {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
private:
|
||||
TGroundNode * pMyNode = nullptr; // Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode
|
||||
TIsolated * pIsolated = nullptr; // obwód izolowany obsługujący zajęcia/zwolnienia grupy torów
|
||||
std::shared_ptr<TSwitchExtension> SwitchExtension; // dodatkowe dane do toru, który jest zwrotnicą
|
||||
std::shared_ptr<TSegment> Segment;
|
||||
@@ -132,7 +131,7 @@ private:
|
||||
|
||||
// McZapkie-070402: dodalem zmienne opisujace rozmiary tekstur
|
||||
int iTrapezoid = 0; // 0-standard, 1-przechyłka, 2-trapez, 3-oba
|
||||
double fRadiusTable[ 2 ]; // dwa promienie, drugi dla zwrotnicy
|
||||
double fRadiusTable[ 2 ] = { 0.0, 0.0 }; // dwa promienie, drugi dla zwrotnicy
|
||||
float fTexLength = 4.0f; // długość powtarzania tekstury w metrach
|
||||
float fTexRatio1 = 1.0f; // proporcja boków tekstury nawierzchni (żeby zaoszczędzić na rozmiarach tekstur...)
|
||||
float fTexRatio2 = 1.0f; // proporcja boków tekstury chodnika (żeby zaoszczędzić na rozmiarach tekstur...)
|
||||
@@ -140,6 +139,7 @@ private:
|
||||
float fTexWidth = 0.9f; // szerokość boku
|
||||
float fTexSlope = 0.9f;
|
||||
|
||||
glm::dvec3 m_origin;
|
||||
material_handle m_material1 = 0; // tekstura szyn albo nawierzchni
|
||||
material_handle m_material2 = 0; // tekstura automatycznej podsypki albo pobocza
|
||||
typedef std::vector<geometry_handle> geometryhandle_sequence;
|
||||
@@ -173,22 +173,24 @@ public:
|
||||
int iQualityFlag = 20;
|
||||
int iDamageFlag = 0;
|
||||
TEnvironmentType eEnvironment = e_flat; // dźwięk i oświetlenie
|
||||
bool bVisible = true; // czy rysowany
|
||||
int iAction = 0; // czy modyfikowany eventami (specjalna obsługa przy skanowaniu)
|
||||
float fOverhead = -1.0; // można normalnie pobierać prąd (0 dla jazdy bezprądowej po danym odcinku, >0-z opuszczonym i ograniczeniem prędkości)
|
||||
private:
|
||||
private:
|
||||
double fVelocity = -1.0; // ograniczenie prędkości // prędkość dla AI (powyżej rośnie prawdopowobieństwo wykolejenia)
|
||||
public:
|
||||
public:
|
||||
// McZapkie-100502:
|
||||
double fTrackLength = 100.0; // długość z wpisu, nigdzie nie używana
|
||||
double fRadius = 0.0; // promień, dla zwrotnicy kopiowany z tabeli
|
||||
bool ScannedFlag = false; // McZapkie: do zaznaczania kolorem torów skanowanych przez AI
|
||||
TTraction *hvOverhead = nullptr; // drut zasilający do szybkiego znalezienia (nie używany)
|
||||
TGroundNode *nFouling[ 2 ]; // współrzędne ukresu albo oporu kozła
|
||||
TGroundNode *nFouling[ 2 ] = { nullptr, nullptr }; // współrzędne ukresu albo oporu kozła
|
||||
|
||||
TTrack( scene::node_data const &Nodedata );
|
||||
// legacy constructor
|
||||
TTrack( std::string Name );
|
||||
virtual ~TTrack();
|
||||
|
||||
TTrack(TGroundNode *g);
|
||||
~TTrack();
|
||||
void Init();
|
||||
static bool sort_by_material( TTrack const *Left, TTrack const *Right );
|
||||
static TTrack * Create400m(int what, double dx);
|
||||
TTrack * NullCreate(int dir);
|
||||
inline bool IsEmpty() {
|
||||
@@ -207,7 +209,7 @@ public:
|
||||
return trPrev; };
|
||||
TTrack *Connected(int s, double &d) const;
|
||||
bool SetConnections(int i);
|
||||
bool Switch(int i, double t = -1.0, double d = -1.0);
|
||||
bool Switch(int i, float const t = -1.f, float const d = -1.f);
|
||||
bool SwitchForced(int i, TDynamicObject *o);
|
||||
int CrossSegment(int from, int into);
|
||||
inline int GetSwitchState() {
|
||||
@@ -215,7 +217,16 @@ public:
|
||||
SwitchExtension ?
|
||||
SwitchExtension->CurrentIndex :
|
||||
-1); };
|
||||
void Load(cParser *parser, Math3D::vector3 pOrigin, std::string name);
|
||||
// returns number of different routes possible to take from given point
|
||||
// TODO: specify entry point, number of routes for switches can vary
|
||||
inline
|
||||
int
|
||||
RouteCount() const {
|
||||
return (
|
||||
SwitchExtension != nullptr ?
|
||||
SwitchExtension->iRoads - 1 :
|
||||
1 ); }
|
||||
void Load(cParser *parser, Math3D::vector3 pOrigin);
|
||||
bool AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2);
|
||||
bool AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2);
|
||||
bool AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus);
|
||||
@@ -223,14 +234,21 @@ public:
|
||||
bool AddDynamicObject(TDynamicObject *Dynamic);
|
||||
bool RemoveDynamicObject(TDynamicObject *Dynamic);
|
||||
|
||||
void create_geometry(geometrybank_handle const &Bank); // wypełnianie VBO
|
||||
// set origin point
|
||||
void
|
||||
origin( glm::dvec3 Origin ) {
|
||||
m_origin = Origin; }
|
||||
// retrieves list of the track's end points
|
||||
std::vector<glm::dvec3>
|
||||
endpoints() const;
|
||||
|
||||
void create_geometry( geometrybank_handle const &Bank ); // wypełnianie VBO
|
||||
void RenderDynSounds(); // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania
|
||||
|
||||
void RaOwnerSet(TSubRect *o) {
|
||||
if (SwitchExtension)
|
||||
SwitchExtension->pOwner = o; };
|
||||
void RaOwnerSet( scene::basic_cell *o ) {
|
||||
if( SwitchExtension ) { SwitchExtension->pOwner = o; } };
|
||||
bool InMovement(); // czy w trakcie animacji?
|
||||
void RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joined);
|
||||
void RaAssign( TAnimModel *am, TEvent *done, TEvent *joined );
|
||||
void RaAnimListAdd(TTrack *t);
|
||||
TTrack * RaAnimate();
|
||||
|
||||
@@ -241,22 +259,42 @@ public:
|
||||
std::string IsolatedName();
|
||||
bool IsolatedEventsAssign(TEvent *busy, TEvent *free);
|
||||
double WidthTotal();
|
||||
GLuint TextureGet(int i) {
|
||||
return (
|
||||
i ?
|
||||
m_material1 :
|
||||
m_material2 ); };
|
||||
bool IsGroupable();
|
||||
int TestPoint( Math3D::vector3 *Point);
|
||||
void MovedUp1(float const dh);
|
||||
std::string NameGet();
|
||||
void VelocitySet(float v);
|
||||
float VelocityGet();
|
||||
double VelocityGet();
|
||||
void ConnectionsLog();
|
||||
|
||||
private:
|
||||
protected:
|
||||
// calculates path's bounding radius
|
||||
void
|
||||
radius_();
|
||||
|
||||
private:
|
||||
void EnvironmentSet();
|
||||
void EnvironmentReset();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// collection of virtual tracks and roads present in the scene
|
||||
class path_table : public basic_table<TTrack> {
|
||||
|
||||
public:
|
||||
~path_table();
|
||||
// legacy method, initializes tracks after deserialization from scenario file
|
||||
void
|
||||
InitTracks();
|
||||
// legacy method, sends list of occupied paths over network
|
||||
void
|
||||
TrackBusyList() const;
|
||||
// legacy method, sends list of occupied path sections over network
|
||||
void
|
||||
IsolatedBusyList() const;
|
||||
// legacy method, sends state of specified path section over network
|
||||
void
|
||||
IsolatedBusy( std::string const &Name ) const;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
589
Traction.cpp
589
Traction.cpp
@@ -14,10 +14,10 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Traction.h"
|
||||
|
||||
#include "simulation.h"
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
#include "mctools.h"
|
||||
#include "TractionPower.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
/*
|
||||
@@ -90,9 +90,97 @@ jawnie nazwę sekcji, ewentualnie nazwę zasilacza (zostanie zastąpiona wskazan
|
||||
sekcji z sąsiedniego przęsła).
|
||||
*/
|
||||
|
||||
std::size_t
|
||||
TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ) {
|
||||
TTraction::TTraction( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {}
|
||||
// legacy constructor
|
||||
TTraction::TTraction( std::string Name ) {
|
||||
|
||||
m_name = Name;
|
||||
}
|
||||
|
||||
glm::dvec3 LoadPoint( cParser &Input ) {
|
||||
// pobranie współrzędnych punktu
|
||||
glm::dvec3 point;
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> point.x
|
||||
>> point.y
|
||||
>> point.z;
|
||||
return point;
|
||||
}
|
||||
|
||||
void
|
||||
TTraction::Load( cParser *parser, glm::dvec3 const &pOrigin ) {
|
||||
|
||||
parser->getTokens( 4 );
|
||||
*parser
|
||||
>> asPowerSupplyName
|
||||
>> NominalVoltage
|
||||
>> MaxCurrent
|
||||
>> fResistivity;
|
||||
if( fResistivity == 0.01f ) {
|
||||
// tyle jest w sceneriach [om/km]
|
||||
// taka sensowniejsza wartość za http://www.ikolej.pl/fileadmin/user_upload/Seminaria_IK/13_05_07_Prezentacja_Kruczek.pdf
|
||||
fResistivity = 0.075f;
|
||||
}
|
||||
fResistivity *= 0.001f; // teraz [om/m]
|
||||
// Ra 2014-02: a tutaj damy symbol sieci i jej budowę, np.:
|
||||
// SKB70-C, CuCd70-2C, KB95-2C, C95-C, C95-2C, YC95-2C, YpC95-2C, YC120-2C
|
||||
// YpC120-2C, YzC120-2C, YwsC120-2C, YC150-C150, YC150-2C150, C150-C150
|
||||
// C120-2C, 2C120-2C, 2C120-2C-1, 2C120-2C-2, 2C120-2C-3, 2C120-2C-4
|
||||
auto const material = parser->getToken<std::string>();
|
||||
// 1=miedziana, rysuje się na zielono albo czerwono
|
||||
// 2=aluminiowa, rysuje się na czarno
|
||||
if( material == "none" ) { Material = 0; }
|
||||
else if( material == "al" ) { Material = 2; }
|
||||
else { Material = 1; }
|
||||
parser->getTokens( 2 );
|
||||
*parser
|
||||
>> WireThickness
|
||||
>> DamageFlag;
|
||||
pPoint1 = LoadPoint( *parser ) + pOrigin;
|
||||
pPoint2 = LoadPoint( *parser ) + pOrigin;
|
||||
pPoint3 = LoadPoint( *parser ) + pOrigin;
|
||||
pPoint4 = LoadPoint( *parser ) + pOrigin;
|
||||
auto const minheight { parser->getToken<double>() };
|
||||
fHeightDifference = ( pPoint3.y - pPoint1.y + pPoint4.y - pPoint2.y ) * 0.5 - minheight;
|
||||
auto const segmentlength { parser->getToken<double>() };
|
||||
iNumSections = (
|
||||
segmentlength ?
|
||||
glm::length( ( pPoint1 - pPoint2 ) ) / segmentlength :
|
||||
0 );
|
||||
parser->getTokens( 2 );
|
||||
*parser
|
||||
>> Wires
|
||||
>> WireOffset;
|
||||
m_visible = ( parser->getToken<std::string>() == "vis" );
|
||||
|
||||
std::string token { parser->getToken<std::string>() };
|
||||
if( token == "parallel" ) {
|
||||
// jawne wskazanie innego przęsła, na które może przestawić się pantograf
|
||||
parser->getTokens();
|
||||
*parser >> asParallel;
|
||||
}
|
||||
while( ( false == token.empty() )
|
||||
&& ( token != "endtraction" ) ) {
|
||||
|
||||
token = parser->getToken<std::string>();
|
||||
}
|
||||
|
||||
Init(); // przeliczenie parametrów
|
||||
|
||||
// calculate traction location
|
||||
location( interpolate( pPoint2, pPoint1, 0.5 ) );
|
||||
}
|
||||
|
||||
// retrieves list of the track's end points
|
||||
std::vector<glm::dvec3>
|
||||
TTraction::endpoints() const {
|
||||
|
||||
return { pPoint1, pPoint2 };
|
||||
}
|
||||
|
||||
std::size_t
|
||||
TTraction::create_geometry( geometrybank_handle const &Bank ) {
|
||||
if( m_geometry != null_handle ) {
|
||||
return GfxRenderer.Vertices( m_geometry ).size() / 2;
|
||||
}
|
||||
@@ -106,14 +194,14 @@ TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &O
|
||||
basic_vertex startvertex, endvertex;
|
||||
startvertex.position =
|
||||
glm::vec3(
|
||||
pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x,
|
||||
pPoint1.y - Origin.y,
|
||||
pPoint1.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z );
|
||||
pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - m_origin.x,
|
||||
pPoint1.y - m_origin.y,
|
||||
pPoint1.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - m_origin.z );
|
||||
endvertex.position =
|
||||
glm::vec3(
|
||||
pPoint2.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x,
|
||||
pPoint2.y - Origin.y,
|
||||
pPoint2.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z );
|
||||
pPoint2.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - m_origin.x,
|
||||
pPoint2.y - m_origin.y,
|
||||
pPoint2.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - m_origin.z );
|
||||
vertices.emplace_back( startvertex );
|
||||
vertices.emplace_back( endvertex );
|
||||
// Nie wiem co 'Marcin
|
||||
@@ -130,9 +218,9 @@ TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &O
|
||||
if( Wires > 1 ) { // lina nośna w kawałkach
|
||||
startvertex.position =
|
||||
glm::vec3(
|
||||
pPoint3.x - Origin.x,
|
||||
pPoint3.y - Origin.y,
|
||||
pPoint3.z - Origin.z );
|
||||
pPoint3.x - m_origin.x,
|
||||
pPoint3.y - m_origin.y,
|
||||
pPoint3.z - m_origin.z );
|
||||
for( int i = 0; i < iNumSections - 1; ++i ) {
|
||||
pt3 = pPoint3 + v1 * f;
|
||||
t = ( 1 - std::fabs( f - mid ) * 2 );
|
||||
@@ -141,9 +229,9 @@ TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &O
|
||||
&& ( i != iNumSections - 2 ) ) ) {
|
||||
endvertex.position =
|
||||
glm::vec3(
|
||||
pt3.x - Origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - Origin.y,
|
||||
pt3.z - Origin.z );
|
||||
pt3.x - m_origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - m_origin.y,
|
||||
pt3.z - m_origin.z );
|
||||
vertices.emplace_back( startvertex );
|
||||
vertices.emplace_back( endvertex );
|
||||
startvertex = endvertex;
|
||||
@@ -152,9 +240,9 @@ TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &O
|
||||
}
|
||||
endvertex.position =
|
||||
glm::vec3(
|
||||
pPoint4.x - Origin.x,
|
||||
pPoint4.y - Origin.y,
|
||||
pPoint4.z - Origin.z );
|
||||
pPoint4.x - m_origin.x,
|
||||
pPoint4.y - m_origin.y,
|
||||
pPoint4.z - m_origin.z );
|
||||
vertices.emplace_back( startvertex );
|
||||
vertices.emplace_back( endvertex );
|
||||
}
|
||||
@@ -162,14 +250,14 @@ TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &O
|
||||
if( Wires > 2 ) {
|
||||
startvertex.position =
|
||||
glm::vec3(
|
||||
pPoint1.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x,
|
||||
pPoint1.y - Origin.y,
|
||||
pPoint1.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z );
|
||||
pPoint1.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - m_origin.x,
|
||||
pPoint1.y - m_origin.y,
|
||||
pPoint1.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - m_origin.z );
|
||||
endvertex.position =
|
||||
glm::vec3(
|
||||
pPoint2.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x,
|
||||
pPoint2.y - Origin.y,
|
||||
pPoint2.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z );
|
||||
pPoint2.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - m_origin.x,
|
||||
pPoint2.y - m_origin.y,
|
||||
pPoint2.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - m_origin.z );
|
||||
vertices.emplace_back( startvertex );
|
||||
vertices.emplace_back( endvertex );
|
||||
}
|
||||
@@ -179,22 +267,22 @@ TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &O
|
||||
if( Wires == 4 ) {
|
||||
startvertex.position =
|
||||
glm::vec3(
|
||||
pPoint3.x - Origin.x,
|
||||
pPoint3.y - 0.65f * fHeightDifference - Origin.y,
|
||||
pPoint3.z - Origin.z );
|
||||
pPoint3.x - m_origin.x,
|
||||
pPoint3.y - 0.65f * fHeightDifference - m_origin.y,
|
||||
pPoint3.z - m_origin.z );
|
||||
for( int i = 0; i < iNumSections - 1; ++i ) {
|
||||
pt3 = pPoint3 + v1 * f;
|
||||
t = ( 1 - std::fabs( f - mid ) * 2 );
|
||||
endvertex.position =
|
||||
glm::vec3(
|
||||
pt3.x - Origin.x,
|
||||
pt3.x - m_origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - (
|
||||
( ( i == 0 )
|
||||
|| ( i == iNumSections - 2 ) ) ?
|
||||
0.25f * fHeightDifference :
|
||||
0.05 )
|
||||
- Origin.y,
|
||||
pt3.z - Origin.z );
|
||||
- m_origin.y,
|
||||
pt3.z - m_origin.z );
|
||||
vertices.emplace_back( startvertex );
|
||||
vertices.emplace_back( endvertex );
|
||||
startvertex = endvertex;
|
||||
@@ -202,9 +290,9 @@ TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &O
|
||||
}
|
||||
endvertex.position =
|
||||
glm::vec3(
|
||||
pPoint4.x - Origin.x,
|
||||
pPoint4.y - 0.65f * fHeightDifference - Origin.y,
|
||||
pPoint4.z - Origin.z );
|
||||
pPoint4.x - m_origin.x,
|
||||
pPoint4.y - 0.65f * fHeightDifference - m_origin.y,
|
||||
pPoint4.z - m_origin.z );
|
||||
vertices.emplace_back( startvertex );
|
||||
vertices.emplace_back( endvertex );
|
||||
}
|
||||
@@ -223,28 +311,28 @@ TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &O
|
||||
if( ( i % 2 ) == 0 ) {
|
||||
startvertex.position =
|
||||
glm::vec3(
|
||||
pt3.x - Origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - Origin.y,
|
||||
pt3.z - Origin.z );
|
||||
pt3.x - m_origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - m_origin.y,
|
||||
pt3.z - m_origin.z );
|
||||
endvertex.position =
|
||||
glm::vec3(
|
||||
pt4.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x,
|
||||
pt4.y - Origin.y,
|
||||
pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z );
|
||||
pt4.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - m_origin.x,
|
||||
pt4.y - m_origin.y,
|
||||
pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - m_origin.z );
|
||||
vertices.emplace_back( startvertex );
|
||||
vertices.emplace_back( endvertex );
|
||||
}
|
||||
else {
|
||||
startvertex.position =
|
||||
glm::vec3(
|
||||
pt3.x - Origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - Origin.y,
|
||||
pt3.z - Origin.z );
|
||||
pt3.x - m_origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - m_origin.y,
|
||||
pt3.z - m_origin.z );
|
||||
endvertex.position =
|
||||
glm::vec3(
|
||||
pt4.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x,
|
||||
pt4.y - Origin.y,
|
||||
pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z );
|
||||
pt4.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - m_origin.x,
|
||||
pt4.y - m_origin.y,
|
||||
pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - m_origin.z );
|
||||
vertices.emplace_back( startvertex );
|
||||
vertices.emplace_back( endvertex );
|
||||
}
|
||||
@@ -253,14 +341,14 @@ TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &O
|
||||
|| ( i == iNumSections - 3 ) ) ) ) {
|
||||
startvertex.position =
|
||||
glm::vec3(
|
||||
pt3.x - Origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - 0.05 - Origin.y,
|
||||
pt3.z - Origin.z );
|
||||
pt3.x - m_origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - 0.05 - m_origin.y,
|
||||
pt3.z - m_origin.z );
|
||||
endvertex.position =
|
||||
glm::vec3(
|
||||
pt3.x - Origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - Origin.y,
|
||||
pt3.z - Origin.z );
|
||||
pt3.x - m_origin.x,
|
||||
pt3.y - std::sqrt( t ) * fHeightDifference - m_origin.y,
|
||||
pt3.z - m_origin.z );
|
||||
vertices.emplace_back( startvertex );
|
||||
vertices.emplace_back( endvertex );
|
||||
}
|
||||
@@ -276,55 +364,59 @@ TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &O
|
||||
|
||||
int TTraction::TestPoint(glm::dvec3 const &Point)
|
||||
{ // sprawdzanie, czy przęsła można połączyć
|
||||
if (!hvNext[0])
|
||||
if( glm::all( glm::epsilonEqual( Point, pPoint1, 0.025 ) ) )
|
||||
return 0;
|
||||
if (!hvNext[1])
|
||||
if( glm::all( glm::epsilonEqual( Point, pPoint2, 0.025 ) ) )
|
||||
return 1;
|
||||
if( ( hvNext[ 0 ] == nullptr )
|
||||
&& ( glm::all( glm::epsilonEqual( Point, pPoint1, 0.025 ) ) ) ) {
|
||||
return 0;
|
||||
}
|
||||
if( ( hvNext[ 1 ] == nullptr )
|
||||
&& ( glm::all( glm::epsilonEqual( Point, pPoint2, 0.025 ) ) ) ) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
void TTraction::Connect(int my, TTraction *with, int to)
|
||||
{ //łączenie segmentu (with) od strony (my) do jego (to)
|
||||
if (my)
|
||||
{ // do mojego Point2
|
||||
hvNext[1] = with;
|
||||
iNext[1] = to;
|
||||
}
|
||||
else
|
||||
{ // do mojego Point1
|
||||
hvNext[0] = with;
|
||||
iNext[0] = to;
|
||||
}
|
||||
if (to)
|
||||
{ // do jego Point2
|
||||
with->hvNext[1] = this;
|
||||
with->iNext[1] = my;
|
||||
}
|
||||
else
|
||||
{ // do jego Point1
|
||||
with->hvNext[0] = this;
|
||||
with->iNext[0] = my;
|
||||
}
|
||||
if (hvNext[0]) // jeśli z obu stron podłączony
|
||||
if (hvNext[1])
|
||||
iLast = 0; // to nie jest ostatnim
|
||||
if (with->hvNext[0]) // temu też, bo drugi raz łączenie się nie nie wykona
|
||||
if (with->hvNext[1])
|
||||
with->iLast = 0; // to nie jest ostatnim
|
||||
};
|
||||
//łączenie segmentu (with) od strony (my) do jego (to)
|
||||
void
|
||||
TTraction::Connect(int my, TTraction *with, int to) {
|
||||
|
||||
bool TTraction::WhereIs()
|
||||
{ // ustalenie przedostatnich przęseł
|
||||
if (iLast)
|
||||
return (iLast == 1); // ma już ustaloną informację o położeniu
|
||||
if (hvNext[0] ? hvNext[0]->iLast == 1 : false) // jeśli poprzedni jest ostatnim
|
||||
iLast = 2; // jest przedostatnim
|
||||
else if (hvNext[1] ? hvNext[1]->iLast == 1 : false) // jeśli następny jest ostatnim
|
||||
iLast = 2; // jest przedostatnim
|
||||
return (iLast == 1); // ostatnie będą dostawać zasilanie
|
||||
};
|
||||
hvNext[ my ] = with;
|
||||
iNext[ my ] = to;
|
||||
|
||||
if( ( hvNext[ 0 ] != nullptr )
|
||||
&& ( hvNext[ 1 ] != nullptr ) ) {
|
||||
// jeśli z obu stron podłączony to nie jest ostatnim
|
||||
iLast = 0;
|
||||
}
|
||||
|
||||
with->hvNext[ to ] = this;
|
||||
with->iNext[ to ] = my;
|
||||
|
||||
if( ( with->hvNext[ 0 ] != nullptr )
|
||||
&& ( with->hvNext[ 1 ] != nullptr ) ) {
|
||||
// temu też, bo drugi raz łączenie się nie nie wykona
|
||||
with->iLast = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ustalenie przedostatnich przęseł
|
||||
bool TTraction::WhereIs() {
|
||||
|
||||
if( iLast ) {
|
||||
// ma już ustaloną informację o położeniu
|
||||
return ( iLast & 1 );
|
||||
}
|
||||
for( int endindex = 0; endindex < 2; ++endindex ) {
|
||||
if( hvNext[ endindex ] == nullptr ) {
|
||||
// no neighbour piece means this one is last
|
||||
iLast |= 1;
|
||||
}
|
||||
else if( hvNext[ endindex ]->hvNext[ 1 - iNext[ endindex ] ] == nullptr ) {
|
||||
// otherwise if that neighbour has no further connection on the opposite end then this piece is second-last
|
||||
iLast |= 2;
|
||||
}
|
||||
}
|
||||
return (iLast & 1); // ostatnie będą dostawać zasilanie
|
||||
}
|
||||
|
||||
void TTraction::Init()
|
||||
{ // przeliczenie parametrów
|
||||
@@ -441,6 +533,18 @@ double TTraction::VoltageGet(double u, double i)
|
||||
return 0.0; // gdy nie podłączony wcale?
|
||||
};
|
||||
|
||||
// calculates path's bounding radius
|
||||
void
|
||||
TTraction::radius_() {
|
||||
|
||||
auto const points = endpoints();
|
||||
for( auto &point : points ) {
|
||||
m_area.radius = std::max(
|
||||
m_area.radius,
|
||||
static_cast<float>( glm::length( m_area.center - point ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3
|
||||
TTraction::wire_color() const {
|
||||
|
||||
@@ -488,30 +592,41 @@ TTraction::wire_color() const {
|
||||
|
||||
case 1: {
|
||||
// czerwone z podłączonym zasilaniem 1
|
||||
color.r = 1.0f;
|
||||
color.g = 0.0f;
|
||||
color.b = 0.0f;
|
||||
// color.r = 1.0f;
|
||||
// color.g = 0.0f;
|
||||
// color.b = 0.0f;
|
||||
// cyan
|
||||
color = glm::vec3 { 0.f, 174.f / 255.f, 239.f / 255.f };
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// zielone z podłączonym zasilaniem 2
|
||||
color.r = 0.0f;
|
||||
color.g = 1.0f;
|
||||
color.b = 0.0f;
|
||||
// color.r = 0.0f;
|
||||
// color.g = 1.0f;
|
||||
// color.b = 0.0f;
|
||||
// yellow
|
||||
color = glm::vec3 { 240.f / 255.f, 228.f / 255.f, 0.f };
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
//żółte z podłączonym zasilaniem z obu stron
|
||||
color.r = 1.0f;
|
||||
color.g = 1.0f;
|
||||
color.b = 0.0f;
|
||||
// color.r = 1.0f;
|
||||
// color.g = 1.0f;
|
||||
// color.b = 0.0f;
|
||||
// green
|
||||
color = glm::vec3 { 0.f, 239.f / 255.f, 118.f / 255.f };
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
// niebieskie z podłączonym zasilaniem
|
||||
color.r = 0.5f;
|
||||
color.g = 0.5f;
|
||||
color.b = 1.0f;
|
||||
// color.r = 0.5f;
|
||||
// color.g = 0.5f;
|
||||
// color.b = 1.0f;
|
||||
// white for powered, red for ends
|
||||
color = (
|
||||
psPowered != nullptr ?
|
||||
glm::vec3{ 239.f / 255.f, 239.f / 255.f, 239.f / 255.f } :
|
||||
glm::vec3{ 239.f / 255.f, 128.f / 255.f, 128.f / 255.f } );
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
@@ -521,6 +636,262 @@ TTraction::wire_color() const {
|
||||
color.g *= 0.6f;
|
||||
color.b *= 0.6f;
|
||||
}
|
||||
/*
|
||||
switch( iTries ) {
|
||||
case 0: {
|
||||
color = glm::vec3{ 239.f / 255.f, 128.f / 255.f, 128.f / 255.f }; // red
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
color = glm::vec3{ 240.f / 255.f, 228.f / 255.f, 0.f }; // yellow
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
color = glm::vec3{ 0.f / 255.f, 239.f / 255.f, 118.f / 255.f }; // green
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
color = glm::vec3{ 239.f / 255.f, 239.f / 255.f, 239.f / 255.f };
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
switch( iLast ) {
|
||||
case 0: {
|
||||
color = glm::vec3{ 240.f / 255.f, 228.f / 255.f, 0.f }; // yellow
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
color = glm::vec3{ 239.f / 255.f, 128.f / 255.f, 128.f / 255.f }; // red
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
color = glm::vec3{ 0.f / 255.f, 239.f / 255.f, 118.f / 255.f }; // green
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
color = glm::vec3{ 239.f / 255.f, 239.f / 255.f, 239.f / 255.f };
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// legacy method, initializes traction after deserialization from scenario file
|
||||
void
|
||||
traction_table::InitTraction() {
|
||||
|
||||
//łączenie drutów ze sobą oraz z torami i eventami
|
||||
// TGroundNode *nCurrent, *nTemp;
|
||||
// TTraction *tmp; // znalezione przęsło
|
||||
|
||||
int connection { -1 };
|
||||
TTraction *matchingtraction { nullptr };
|
||||
|
||||
for( auto *traction : m_items ) {
|
||||
// podłączenie do zasilacza, żeby można było sumować prąd kilku pojazdów
|
||||
// a jednocześnie z jednego miejsca zmieniać napięcie eventem
|
||||
// wykonywane najpierw, żeby można było logować podłączenie 2 zasilaczy do jednego drutu
|
||||
// izolator zawieszony na przęśle jest ma być osobnym odcinkiem drutu o długości ok. 1m,
|
||||
// podłączonym do zasilacza o nazwie "*" (gwiazka); "none" nie będzie odpowiednie
|
||||
auto *powersource = simulation::Powergrid.find( traction->asPowerSupplyName );
|
||||
if( powersource ) {
|
||||
// jak zasilacz znaleziony to podłączyć do przęsła
|
||||
traction->PowerSet( powersource );
|
||||
}
|
||||
else {
|
||||
if( ( traction->asPowerSupplyName != "*" ) // gwiazdka dla przęsła z izolatorem
|
||||
&& ( traction->asPowerSupplyName != "none" ) ) { // dopuszczamy na razie brak podłączenia?
|
||||
// logowanie błędu i utworzenie zasilacza o domyślnej zawartości
|
||||
ErrorLog( "Bad scenario: traction piece connected to nonexistent power source \"" + traction->asPowerSupplyName + "\"" );
|
||||
scene::node_data nodedata;
|
||||
nodedata.name = traction->asPowerSupplyName;
|
||||
powersource = new TTractionPowerSource( nodedata );
|
||||
powersource->Init( traction->NominalVoltage, traction->MaxCurrent );
|
||||
simulation::Powergrid.insert( powersource );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EU07_IGNORE_LEGACYPROCESSINGORDER
|
||||
for( auto *traction : m_items ) {
|
||||
#else
|
||||
// NOTE: legacy code peformed item operations last-to-first due to way the items were added to the list
|
||||
// this had impact in situations like two possible connection candidates, where only the first one would be used
|
||||
for( auto first = std::rbegin(m_items); first != std::rend(m_items); ++first ) {
|
||||
auto *traction = *first;
|
||||
#endif
|
||||
if( traction->hvNext[ 0 ] == nullptr ) {
|
||||
// tylko jeśli jeszcze nie podłączony
|
||||
std::tie( matchingtraction, connection ) = simulation::Region->find_traction( traction->pPoint1, traction );
|
||||
switch (connection) {
|
||||
case 0:
|
||||
case 1: {
|
||||
traction->Connect( 0, matchingtraction, connection );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( traction->hvNext[ 0 ] ) {
|
||||
// jeśli został podłączony
|
||||
if( ( traction->psSection != nullptr )
|
||||
&& ( matchingtraction->psSection != nullptr ) ) {
|
||||
// tylko przęsło z izolatorem może nie mieć zasilania, bo ma 2, trzeba sprawdzać sąsiednie
|
||||
if( traction->psSection != matchingtraction->psSection ) {
|
||||
// połączone odcinki mają różne zasilacze
|
||||
// to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo błąd
|
||||
if( ( true == traction->psSection->bSection )
|
||||
&& ( false == matchingtraction->psSection->bSection ) ) {
|
||||
//(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji
|
||||
matchingtraction->PowerSet( traction->psSection ); // zastąpienie wskazaniem sekcji
|
||||
}
|
||||
else if( ( false == traction->psSection->bSection )
|
||||
&& ( true == matchingtraction->psSection->bSection ) ) {
|
||||
//(Traction->psSection) jest podstacją, a (tmp->psSection) nazwą sekcji
|
||||
traction->PowerSet( matchingtraction->psSection ); // zastąpienie wskazaniem sekcji
|
||||
}
|
||||
else {
|
||||
// jeśli obie to sekcje albo obie podstacje, to będzie błąd
|
||||
ErrorLog( "Bad scenario: faulty traction power connection at location " + to_string( traction->pPoint1 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( traction->hvNext[ 1 ] == nullptr ) {
|
||||
// tylko jeśli jeszcze nie podłączony
|
||||
std::tie( matchingtraction, connection ) = simulation::Region->find_traction( traction->pPoint2, traction );
|
||||
switch (connection) {
|
||||
case 0:
|
||||
case 1: {
|
||||
traction->Connect( 1, matchingtraction, connection );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( traction->hvNext[ 1 ] ) {
|
||||
// jeśli został podłączony
|
||||
if( ( traction->psSection != nullptr )
|
||||
&& ( matchingtraction->psSection != nullptr ) ) {
|
||||
// tylko przęsło z izolatorem może nie mieć zasilania, bo ma 2, trzeba sprawdzać sąsiednie
|
||||
if( traction->psSection != matchingtraction->psSection ) {
|
||||
// to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo błąd
|
||||
if( ( true == traction->psSection->bSection )
|
||||
&& ( false == matchingtraction->psSection->bSection ) ) {
|
||||
//(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji
|
||||
matchingtraction->PowerSet( traction->psSection ); // zastąpienie wskazaniem sekcji
|
||||
}
|
||||
else if( ( false == traction->psSection->bSection )
|
||||
&& ( true == matchingtraction->psSection->bSection ) ) {
|
||||
//(Traction->psSection) jest podstacją, a (tmp->psSection) nazwą sekcji
|
||||
traction->PowerSet( matchingtraction->psSection ); // zastąpienie wskazaniem sekcji
|
||||
}
|
||||
else {
|
||||
// jeśli obie to sekcje albo obie podstacje, to będzie błąd
|
||||
ErrorLog( "Bad scenario: faulty traction power connection at location " + to_string( traction->pPoint2 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto endcount { 0 };
|
||||
for( auto *traction : m_items ) {
|
||||
// operacje mające na celu wykrywanie bieżni wspólnych i łączenie przęseł naprążania
|
||||
if( traction->WhereIs() ) {
|
||||
// true for outer pieces of the traction section
|
||||
traction->iTries = 5; // oznaczanie końcowych
|
||||
++endcount;
|
||||
}
|
||||
if (traction->fResistance[0] == 0.0) {
|
||||
// obliczanie przęseł w segmencie z bezpośrednim zasilaniem
|
||||
traction->ResistanceCalc();
|
||||
traction->iTries = 0; // nie potrzeba mu szukać zasilania
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TTraction *> ends; ends.reserve( endcount );
|
||||
for( auto *traction : m_items ) {
|
||||
//łączenie bieżni wspólnych, w tym oznaczanie niepodanych jawnie
|
||||
if( false == traction->asParallel.empty() ) {
|
||||
// będzie wskaźnik na inne przęsło
|
||||
if( ( traction->asParallel == "none" )
|
||||
|| ( traction->asParallel == "*" ) ) {
|
||||
// jeśli nieokreślone
|
||||
traction->iLast |= 2; // jakby przedostatni - niech po prostu szuka (iLast już przeliczone)
|
||||
}
|
||||
else if( traction->hvParallel == nullptr ) {
|
||||
// jeśli jeszcze nie został włączony w kółko
|
||||
auto *nTemp = find( traction->asParallel );
|
||||
if( nTemp != nullptr ) {
|
||||
// o ile zostanie znalezione przęsło o takiej nazwie
|
||||
if( nTemp->hvParallel == nullptr ) {
|
||||
// jeśli tamten jeszcze nie ma wskaźnika bieżni wspólnej
|
||||
traction->hvParallel = nTemp; // wpisać siebie i dalej dać mu wskaźnik zwrotny
|
||||
}
|
||||
else {
|
||||
// a jak ma, to albo dołączyć się do kółeczka
|
||||
traction->hvParallel = nTemp->hvParallel; // przjąć dotychczasowy wskaźnik od niego
|
||||
}
|
||||
nTemp->hvParallel = traction; // i na koniec ustawienie wskaźnika zwrotnego
|
||||
}
|
||||
if( traction->hvParallel == nullptr ) {
|
||||
ErrorLog( "Missed overhead: " + traction->asParallel ); // logowanie braku
|
||||
}
|
||||
}
|
||||
}
|
||||
if( traction->iTries == 5 ) {
|
||||
// jeśli zaznaczony do podłączenia
|
||||
// wypełnianie tabeli końców w celu szukania im połączeń
|
||||
ends.emplace_back( traction );
|
||||
}
|
||||
}
|
||||
|
||||
bool connected; // nieefektywny przebieg kończy łączenie
|
||||
do {
|
||||
// ustalenie zastępczej rezystancji dla każdego przęsła
|
||||
// flaga podłączonych przęseł końcowych: -1=puste wskaźniki, 0=coś zostało, 1=wykonano łączenie
|
||||
connected = false;
|
||||
for( auto &end : ends ) {
|
||||
// załatwione będziemy zerować
|
||||
if( end == nullptr ) { continue; }
|
||||
// każdy przebieg to próba podłączenia końca segmentu naprężania do innego zasilanego przęsła
|
||||
if( end->hvNext[ 0 ] != nullptr ) {
|
||||
// jeśli końcowy ma ciąg dalszy od strony 0 (Point1), szukamy odcinka najbliższego do Point2
|
||||
std::tie( matchingtraction, connection ) = simulation::Region->find_traction( end->pPoint2, end, 0 );
|
||||
if( matchingtraction != nullptr ) {
|
||||
// jak znalezione przęsło z zasilaniem, to podłączenie "równoległe"
|
||||
end->ResistanceCalc( 0, matchingtraction->fResistance[ connection ], matchingtraction->psPower[ connection ] );
|
||||
// jak coś zostało podłączone, to może zasilanie gdzieś dodatkowo dotrze
|
||||
connected = true;
|
||||
end = nullptr;
|
||||
}
|
||||
}
|
||||
else if( end->hvNext[ 1 ] != nullptr ) {
|
||||
// jeśli końcowy ma ciąg dalszy od strony 1 (Point2), szukamy odcinka najbliższego do Point1
|
||||
std::tie( matchingtraction, connection ) = simulation::Region->find_traction( end->pPoint1, end, 1 );
|
||||
if( matchingtraction != nullptr ) {
|
||||
// jak znalezione przęsło z zasilaniem, to podłączenie "równoległe"
|
||||
end->ResistanceCalc( 1, matchingtraction->fResistance[ connection ], matchingtraction->psPower[ connection ] );
|
||||
// jak coś zostało podłączone, to może zasilanie gdzieś dodatkowo dotrze
|
||||
connected = true;
|
||||
end = nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// gdy koniec jest samotny, to na razie nie zostanie podłączony (nie powinno takich być)
|
||||
end = nullptr;
|
||||
}
|
||||
}
|
||||
} while( true == connected );
|
||||
}
|
||||
|
||||
51
Traction.h
51
Traction.h
@@ -10,14 +10,17 @@ http://mozilla.org/MPL/2.0/.
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "GL/glew.h"
|
||||
#include "dumb3d.h"
|
||||
#include "openglgeometrybank.h"
|
||||
|
||||
#include "scenenode.h"
|
||||
#include "Segment.h"
|
||||
#include "material.h"
|
||||
#include "Names.h"
|
||||
#include "Model3d.h"
|
||||
|
||||
class TTractionPowerSource;
|
||||
|
||||
class TTraction
|
||||
{ // drut zasilający, dla wskaźników używać przedrostka "hv"
|
||||
class TTraction : public editor::basic_node {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
public: // na razie
|
||||
@@ -25,11 +28,11 @@ class TTraction
|
||||
TTractionPowerSource *psPowered { nullptr }; // ustawione tylko dla bezpośrednio zasilanego przęsła
|
||||
TTraction *hvNext[ 2 ] { nullptr, nullptr }; //łączenie drutów w sieć
|
||||
int iNext[ 2 ] { 0, 0 }; // do którego końca się łączy
|
||||
int iLast { 1 }; //że niby ostatni drut // ustawiony bit 0, jeśli jest ostatnim drutem w sekcji; bit1 - przedostatni
|
||||
int iLast { 0 }; //że niby ostatni drut // ustawiony bit 0, jeśli jest ostatnim drutem w sekcji; bit1 - przedostatni
|
||||
public:
|
||||
glm::dvec3 pPoint1, pPoint2, pPoint3, pPoint4;
|
||||
glm::dvec3 vParametric; // współczynniki równania parametrycznego odcinka
|
||||
double fHeightDifference { 0.0 }; //,fMiddleHeight;
|
||||
double fHeightDifference { 0.0 };
|
||||
int iNumSections { 0 };
|
||||
float NominalVoltage { 0.0f };
|
||||
float MaxCurrent { 0.0f };
|
||||
@@ -44,14 +47,27 @@ class TTraction
|
||||
std::string asParallel; // nazwa przęsła, z którym może być bieżnia wspólna
|
||||
TTraction *hvParallel { nullptr }; // jednokierunkowa i zapętlona lista przęseł ewentualnej bieżni wspólnej
|
||||
float fResistance[ 2 ] { -1.0f, -1.0f }; // rezystancja zastępcza do punktu zasilania (0: przęsło zasilane, <0: do policzenia)
|
||||
int iTries { 0 };
|
||||
int iTries { 1 }; // 0 is used later down the road to mark directly powered pieces
|
||||
int PowerState { 0 }; // type of incoming power, if any
|
||||
// visualization data
|
||||
glm::dvec3 m_origin;
|
||||
geometry_handle m_geometry;
|
||||
|
||||
TTraction( scene::node_data const &Nodedata );
|
||||
// legacy constructor
|
||||
TTraction( std::string Name );
|
||||
|
||||
void Load( cParser *parser, glm::dvec3 const &pOrigin );
|
||||
// set origin point
|
||||
void
|
||||
origin( glm::dvec3 Origin ) {
|
||||
m_origin = Origin; }
|
||||
// retrieves list of the track's end points
|
||||
std::vector<glm::dvec3>
|
||||
endpoints() const;
|
||||
// creates geometry data in specified geometry bank. returns: number of created elements, or NULL
|
||||
// NOTE: deleting nodes doesn't currently release geometry data owned by the node. TODO: implement erasing individual geometry chunks and banks
|
||||
std::size_t create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin );
|
||||
std::size_t create_geometry( geometrybank_handle const &Bank );
|
||||
int TestPoint(glm::dvec3 const &Point);
|
||||
void Connect(int my, TTraction *with, int to);
|
||||
void Init();
|
||||
@@ -59,8 +75,25 @@ class TTraction
|
||||
void ResistanceCalc(int d = -1, double r = 0, TTractionPowerSource *ps = nullptr);
|
||||
void PowerSet(TTractionPowerSource *ps);
|
||||
double VoltageGet(double u, double i);
|
||||
|
||||
protected:
|
||||
// calculates piece's bounding radius
|
||||
void
|
||||
radius_();
|
||||
|
||||
private:
|
||||
glm::vec3 wire_color() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// collection of virtual tracks and roads present in the scene
|
||||
class traction_table : public basic_table<TTraction> {
|
||||
|
||||
public:
|
||||
// legacy method, initializes traction after deserialization from scenario file
|
||||
void
|
||||
InitTraction();
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -15,19 +15,17 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "TractionPower.h"
|
||||
|
||||
#include "Logs.h"
|
||||
#include "Ground.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
TTractionPowerSource::TTractionPowerSource(TGroundNode const *node) :
|
||||
gMyNode( node )
|
||||
{
|
||||
psNode[0] = nullptr; // sekcje zostaną podłączone do zasilaczy
|
||||
psNode[1] = nullptr;
|
||||
};
|
||||
TTractionPowerSource::TTractionPowerSource( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {}
|
||||
// legacy constructor
|
||||
TTractionPowerSource::TTractionPowerSource( std::string Name ) {
|
||||
|
||||
TTractionPowerSource::~TTractionPowerSource(){};
|
||||
m_name = Name;
|
||||
}
|
||||
|
||||
void TTractionPowerSource::Init(double const u, double const i)
|
||||
{ // ustawianie zasilacza przy braku w scenerii
|
||||
@@ -36,61 +34,62 @@ void TTractionPowerSource::Init(double const u, double const i)
|
||||
MaxOutputCurrent = i;
|
||||
};
|
||||
|
||||
bool TTractionPowerSource::Load(cParser *parser)
|
||||
{
|
||||
std::string token;
|
||||
// AnsiString str;
|
||||
// str= Parser->GetNextSymbol()LowerCase();
|
||||
// asName= str;
|
||||
parser->getTokens(5);
|
||||
*parser >> NominalVoltage >> VoltageFrequency >> InternalRes >> MaxOutputCurrent >>
|
||||
FastFuseTimeOut;
|
||||
parser->getTokens();
|
||||
*parser >> FastFuseRepetition;
|
||||
parser->getTokens();
|
||||
*parser >> SlowFuseTimeOut;
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
if (token.compare("recuperation") == 0)
|
||||
Recuperation = true;
|
||||
else if (token.compare("section") == 0) // odłącznik sekcyjny
|
||||
bSection = true; // nie jest źródłem zasilania, a jedynie informuje o prądzie odłączenia
|
||||
// sekcji z obwodu
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
if (token.compare("end") != 0)
|
||||
Error("tractionpowersource end statement missing");
|
||||
// if (!bSection) //odłącznik sekcji zasadniczo nie ma impedancji (0.01 jest OK)
|
||||
if (InternalRes < 0.1) // coś mała ta rezystancja była...
|
||||
InternalRes = 0.2; // tak około 0.2, wg
|
||||
// http://www.ikolej.pl/fileadmin/user_upload/Seminaria_IK/13_05_07_Prezentacja_Kruczek.pdf
|
||||
return true;
|
||||
};
|
||||
bool TTractionPowerSource::Load(cParser *parser) {
|
||||
|
||||
bool TTractionPowerSource::Render()
|
||||
{
|
||||
parser->getTokens( 10, false );
|
||||
*parser
|
||||
>> m_area.center.x
|
||||
>> m_area.center.y
|
||||
>> m_area.center.z
|
||||
>> NominalVoltage
|
||||
>> VoltageFrequency
|
||||
>> InternalRes
|
||||
>> MaxOutputCurrent
|
||||
>> FastFuseTimeOut
|
||||
>> FastFuseRepetition
|
||||
>> SlowFuseTimeOut;
|
||||
|
||||
std::string token { parser->getToken<std::string>() };
|
||||
if( token == "recuperation" ) {
|
||||
Recuperation = true;
|
||||
}
|
||||
else if( token == "section" ) {
|
||||
// odłącznik sekcyjny
|
||||
// nie jest źródłem zasilania, a jedynie informuje o prądzie odłączenia sekcji z obwodu
|
||||
bSection = true;
|
||||
}
|
||||
// skip rest of the section
|
||||
while( ( false == token.empty() )
|
||||
&& ( token != "end" ) ) {
|
||||
|
||||
token = parser->getToken<std::string>();
|
||||
}
|
||||
|
||||
if( InternalRes < 0.1 ) {
|
||||
// coś mała ta rezystancja była...
|
||||
// tak około 0.2, wg
|
||||
// http://www.ikolej.pl/fileadmin/user_upload/Seminaria_IK/13_05_07_Prezentacja_Kruczek.pdf
|
||||
InternalRes = 0.2;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
bool TTractionPowerSource::Update(double dt)
|
||||
{ // powinno być wykonane raz na krok fizyki
|
||||
// if (NominalVoltage * TotalPreviousAdmitance >
|
||||
// MaxOutputCurrent * 0.00000005) // iloczyn napięcia i admitancji daje prąd
|
||||
// ErrorLog("Power overload: \"" + gMyNode->asName + "\" with current " + AnsiString(NominalVoltage * TotalPreviousAdmitance) + "A");
|
||||
if (NominalVoltage * TotalPreviousAdmitance >
|
||||
MaxOutputCurrent) // iloczyn napięcia i admitancji daje prąd
|
||||
{
|
||||
// iloczyn napięcia i admitancji daje prąd
|
||||
if (NominalVoltage * TotalPreviousAdmitance > MaxOutputCurrent) {
|
||||
|
||||
FastFuse = true;
|
||||
FuseCounter += 1;
|
||||
if (FuseCounter > FastFuseRepetition)
|
||||
{
|
||||
if (FuseCounter > FastFuseRepetition) {
|
||||
|
||||
SlowFuse = true;
|
||||
ErrorLog("Power overload: \"" + gMyNode->asName + "\" disabled for " +
|
||||
std::to_string(SlowFuseTimeOut) + "s");
|
||||
ErrorLog( "Power overload: \"" + m_name + "\" disabled for " + std::to_string( SlowFuseTimeOut ) + "s" );
|
||||
}
|
||||
else
|
||||
ErrorLog("Power overload: \"" + gMyNode->asName + "\" disabled for " +
|
||||
std::to_string(FastFuseTimeOut) + "s");
|
||||
else {
|
||||
ErrorLog( "Power overload: \"" + m_name + "\" disabled for " + std::to_string( FastFuseTimeOut ) + "s" );
|
||||
}
|
||||
|
||||
FuseTimer = 0;
|
||||
}
|
||||
if (FastFuse || SlowFuse)
|
||||
@@ -145,4 +144,15 @@ void TTractionPowerSource::PowerSet(TTractionPowerSource *ps)
|
||||
// else ErrorLog("nie może być więcej punktów zasilania niż dwa");
|
||||
};
|
||||
|
||||
|
||||
|
||||
// legacy method, calculates changes in simulation state over specified time
|
||||
void
|
||||
powergridsource_table::update( double const Deltatime ) {
|
||||
|
||||
for( auto *powersource : m_items ) {
|
||||
powersource->Update( Deltatime );
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -7,14 +7,14 @@ obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef TractionPowerH
|
||||
#define TractionPowerH
|
||||
#pragma once
|
||||
|
||||
#include "scenenode.h"
|
||||
#include "parser.h" //Tolaris-010603
|
||||
#include "Names.h"
|
||||
|
||||
class TGroundNode;
|
||||
class TTractionPowerSource : public editor::basic_node {
|
||||
|
||||
class TTractionPowerSource
|
||||
{
|
||||
private:
|
||||
double NominalVoltage = 0.0;
|
||||
double VoltageFrequency = 0.0;
|
||||
@@ -33,27 +33,34 @@ class TTractionPowerSource
|
||||
bool SlowFuse = false;
|
||||
double FuseTimer = 0.0;
|
||||
int FuseCounter = 0;
|
||||
TGroundNode const *gMyNode = nullptr; // wskaźnik na węzeł rodzica
|
||||
|
||||
protected:
|
||||
public: // zmienne publiczne
|
||||
TTractionPowerSource *psNode[2]; // zasilanie na końcach dla sekcji
|
||||
public:
|
||||
// zmienne publiczne
|
||||
TTractionPowerSource *psNode[ 2 ] = { nullptr, nullptr }; // zasilanie na końcach dla sekcji
|
||||
bool bSection = false; // czy jest sekcją
|
||||
public:
|
||||
// AnsiString asName;
|
||||
TTractionPowerSource(TGroundNode const *node);
|
||||
~TTractionPowerSource();
|
||||
|
||||
TTractionPowerSource( scene::node_data const &Nodedata );
|
||||
// legacy constructor
|
||||
TTractionPowerSource( std::string Name );
|
||||
|
||||
void Init(double const u, double const i);
|
||||
bool Load(cParser *parser);
|
||||
bool Render();
|
||||
bool Update(double dt);
|
||||
double CurrentGet(double res);
|
||||
void VoltageSet(double const v)
|
||||
{
|
||||
NominalVoltage = v;
|
||||
};
|
||||
void VoltageSet(double const v) {
|
||||
NominalVoltage = v; };
|
||||
void PowerSet(TTractionPowerSource *ps);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// collection of generators for power grid present in the scene
|
||||
class powergridsource_table : public basic_table<TTractionPowerSource> {
|
||||
|
||||
public:
|
||||
// legacy method, calculates changes in simulation state over specified time
|
||||
void
|
||||
update( double const Deltatime );
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
72
Train.cpp
72
Train.cpp
@@ -360,11 +360,6 @@ TTrain::TTrain() {
|
||||
|
||||
TTrain::~TTrain()
|
||||
{
|
||||
if (DynamicObject)
|
||||
if (DynamicObject->Mechanik)
|
||||
DynamicObject->Mechanik->TakeControl(
|
||||
true); // likwidacja kabiny wymaga przejęcia przez AI
|
||||
|
||||
sound_man->destroy_sound(&dsbNastawnikJazdy);
|
||||
sound_man->destroy_sound(&dsbNastawnikBocz);
|
||||
sound_man->destroy_sound(&dsbRelay);
|
||||
@@ -515,11 +510,13 @@ PyObject *TTrain::GetTrainState() {
|
||||
PyDict_SetItemString( dict, "velocity", PyGetFloat( mover->Vel ) );
|
||||
PyDict_SetItemString( dict, "tractionforce", PyGetFloat( mover->Ft ) );
|
||||
PyDict_SetItemString( dict, "slipping_wheels", PyGetBool( mover->SlippingWheels ) );
|
||||
PyDict_SetItemString( dict, "sanding", PyGetBool( mover->SandDose ));
|
||||
// electric current data
|
||||
PyDict_SetItemString( dict, "traction_voltage", PyGetFloat( mover->RunningTraction.TractionVoltage ) );
|
||||
PyDict_SetItemString( dict, "voltage", PyGetFloat( mover->Voltage ) );
|
||||
PyDict_SetItemString( dict, "im", PyGetFloat( mover->Im ) );
|
||||
PyDict_SetItemString( dict, "fuse", PyGetBool( mover->FuseFlag ) );
|
||||
PyDict_SetItemString( dict, "epfuse", PyGetBool( mover->EpFuse ));
|
||||
// induction motor state data
|
||||
const char* TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" };
|
||||
const char* TXTC[ 10 ] = { "fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv" };
|
||||
@@ -559,6 +556,7 @@ PyObject *TTrain::GetTrainState() {
|
||||
PyDict_SetItemString( dict, ( std::string( "code_" ) + std::to_string( i + 1 ) ).c_str(), PyGetString( std::string( std::to_string( iUnits[ i ] ) +
|
||||
cCode[ i ] ).c_str() ) );
|
||||
PyDict_SetItemString( dict, ( std::string( "car_name" ) + std::to_string( i + 1 ) ).c_str(), PyGetString( asCarName[ i ].c_str() ) );
|
||||
PyDict_SetItemString( dict, ( std::string( "slip_" ) + std::to_string( i + 1 )).c_str(), PyGetBool( bSlip[i]) );
|
||||
}
|
||||
// ai state data
|
||||
auto const &driver = DynamicObject->Mechanik;
|
||||
@@ -1630,7 +1628,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com
|
||||
// sound feedback, engine start for diesel vehicle
|
||||
Train->play_sound( Train->dsbDieselIgnition );
|
||||
// side-effects
|
||||
Train->mvControlled->ConverterSwitch( Train->ggConverterButton.GetValue() > 0.5 );
|
||||
Train->mvControlled->ConverterSwitch( ( Train->ggConverterButton.GetValue() > 0.5 ) || ( Train->mvControlled->ConverterStart == start::automatic ) );
|
||||
Train->mvControlled->CompressorSwitch( Train->ggCompressorButton.GetValue() > 0.5 );
|
||||
}
|
||||
}
|
||||
@@ -3400,19 +3398,33 @@ if
|
||||
d = d->Prev(); // w drugą stronę też
|
||||
}
|
||||
}
|
||||
else if (cKey == GLFW_KEY_RIGHT_BRACKET)
|
||||
{
|
||||
while (d)
|
||||
{
|
||||
d->Move(-100.0 * d->DirectionGet());
|
||||
d = d->Next(); // pozostałe też
|
||||
}
|
||||
d = DynamicObject->Prev();
|
||||
while (d)
|
||||
{
|
||||
d->Move(-100.0 * d->DirectionGet());
|
||||
d = d->Prev(); // w drugą stronę też
|
||||
}
|
||||
else if (cKey == GLFW_KEY_RIGHT_BRACKET)
|
||||
{
|
||||
while (d)
|
||||
{
|
||||
d->Move(-100.0 * d->DirectionGet());
|
||||
d = d->Next(); // pozostałe też
|
||||
}
|
||||
d = DynamicObject->Prev();
|
||||
while (d)
|
||||
{
|
||||
d->Move(-100.0 * d->DirectionGet());
|
||||
d = d->Prev(); // w drugą stronę też
|
||||
}
|
||||
}
|
||||
else if (cKey == GLFW_KEY_TAB)
|
||||
{
|
||||
while (d)
|
||||
{
|
||||
d->MoverParameters->V+= d->DirectionGet()*2.78;
|
||||
d = d->Next(); // pozostałe też
|
||||
}
|
||||
d = DynamicObject->Prev();
|
||||
while (d)
|
||||
{
|
||||
d->MoverParameters->V += d->DirectionGet()*2.78;
|
||||
d = d->Prev(); // w drugą stronę też
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cKey == GLFW_KEY_MINUS)
|
||||
@@ -3697,21 +3709,22 @@ bool TTrain::Update( double const Deltatime )
|
||||
bDoors[i][2] = (p->dDoorMoveL > 0.001);
|
||||
iDoorNo[i] = p->iAnimType[ANIM_DOORS];
|
||||
iUnits[i] = iUnitNo;
|
||||
cCode[i] = p->MoverParameters->TypeName[p->MoverParameters->TypeName.length()];
|
||||
asCarName[i] = p->GetName();
|
||||
cCode[i] = p->MoverParameters->TypeName[p->MoverParameters->TypeName.length() - 1];
|
||||
asCarName[i] = p->name();
|
||||
bPants[iUnitNo - 1][0] = (bPants[iUnitNo - 1][0] || p->MoverParameters->PantFrontUp);
|
||||
bPants[iUnitNo - 1][1] = (bPants[iUnitNo - 1][1] || p->MoverParameters->PantRearUp);
|
||||
bComp[iUnitNo - 1][0] = (bComp[iUnitNo - 1][0] || p->MoverParameters->CompressorAllow);
|
||||
bSlip[i] = p->MoverParameters->SlippingWheels;
|
||||
if (p->MoverParameters->CompressorSpeed > 0.00001)
|
||||
{
|
||||
bComp[iUnitNo - 1][1] = (bComp[iUnitNo - 1][1] || p->MoverParameters->CompressorFlag);
|
||||
}
|
||||
if ((in < 8) && (p->MoverParameters->eimc[eimc_p_Pmax] > 1))
|
||||
{
|
||||
fEIMParams[1 + in][0] = p->MoverParameters->eimv[eimv_Fr];
|
||||
fEIMParams[1 + in][0] = p->MoverParameters->eimv[eimv_Fmax];
|
||||
fEIMParams[1 + in][1] = Max0R(fEIMParams[1 + in][0], 0);
|
||||
fEIMParams[1 + in][2] = -Min0R(fEIMParams[1 + in][0], 0);
|
||||
fEIMParams[1 + in][3] = p->MoverParameters->eimv[eimv_Fr] /
|
||||
fEIMParams[1 + in][3] = p->MoverParameters->eimv[eimv_Fmax] /
|
||||
Max0R(p->MoverParameters->eimv[eimv_Fful], 1);
|
||||
fEIMParams[1 + in][4] = Max0R(fEIMParams[1 + in][3], 0);
|
||||
fEIMParams[1 + in][5] = -Min0R(fEIMParams[1 + in][3], 0);
|
||||
@@ -3743,6 +3756,7 @@ bool TTrain::Update( double const Deltatime )
|
||||
bDoors[i][0] = false;
|
||||
bDoors[i][1] = false;
|
||||
bDoors[i][2] = false;
|
||||
bSlip[i] = false;
|
||||
iUnits[i] = 0;
|
||||
cCode[i] = 0; //'0';
|
||||
asCarName[i] = "";
|
||||
@@ -6385,7 +6399,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
}
|
||||
else if (token == "pyscreen:")
|
||||
{
|
||||
pyScreens.init(*parser, DynamicObject->mdKabina, DynamicObject->GetName(),
|
||||
pyScreens.init(*parser, DynamicObject->mdKabina, DynamicObject->name(),
|
||||
NewCabNo);
|
||||
}
|
||||
// btLampkaUnknown.Init("unknown",mdKabina,false);
|
||||
@@ -6868,9 +6882,11 @@ void TTrain::set_cab_controls() {
|
||||
if( true == bCabLightDim ) {
|
||||
ggCabLightDimButton.PutValue( 1.0 );
|
||||
}
|
||||
if( true == InstrumentLightActive ) {
|
||||
ggInstrumentLightButton.PutValue( 1.0 );
|
||||
}
|
||||
|
||||
ggInstrumentLightButton.PutValue( (
|
||||
InstrumentLightActive ?
|
||||
1.0 :
|
||||
0.0 ) );
|
||||
// doors
|
||||
// NOTE: we're relying on the cab models to have switches reversed for the rear cab(?)
|
||||
ggDoorLeftButton.PutValue( mvOccupied->DoorLeftOpened ? 1.0 : 0.0 );
|
||||
@@ -7168,7 +7184,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
|
||||
/*
|
||||
TGauge *gg { nullptr }; // roboczy wskaźnik na obiekt animujący gałkę
|
||||
*/
|
||||
std::unordered_map<std::string, TGauge &> gauges = {
|
||||
std::unordered_map<std::string, TGauge &> const gauges = {
|
||||
{ "mainctrl:", ggMainCtrl },
|
||||
{ "scndctrl:", ggScndCtrl },
|
||||
{ "dirkey:" , ggDirKey },
|
||||
|
||||
5
Train.h
5
Train.h
@@ -72,12 +72,14 @@ public:
|
||||
|
||||
class TTrain
|
||||
{
|
||||
friend class TWorld; // temporary due to use of play_sound TODO: refactor this
|
||||
|
||||
public:
|
||||
bool CabChange(int iDirection);
|
||||
bool ShowNextCurrent; // pokaz przd w podlaczonej lokomotywie (ET41)
|
||||
bool InitializeCab(int NewCabNo, std::string const &asFileName);
|
||||
TTrain();
|
||||
~TTrain();
|
||||
~TTrain();
|
||||
// McZapkie-010302
|
||||
bool Init(TDynamicObject *NewDynamicObject, bool e3d = false);
|
||||
void OnKeyDown(int cKey);
|
||||
@@ -468,6 +470,7 @@ public: // reszta może by?publiczna
|
||||
int iUnits[20]; // numer jednostki
|
||||
int iDoorNo[20]; // liczba drzwi
|
||||
char cCode[20]; // kod pojazdu
|
||||
bool bSlip[20]; // poślizg kół pojazdu
|
||||
std::string asCarName[20]; // nazwa czlonu
|
||||
bool bMains[8]; // WSy
|
||||
float fCntVol[8]; // napiecie NN
|
||||
|
||||
25
TrkFoll.cpp
25
TrkFoll.cpp
@@ -15,11 +15,10 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "TrkFoll.h"
|
||||
|
||||
#include "simulation.h"
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
#include "Driver.h"
|
||||
#include "DynObj.h"
|
||||
#include "Event.h"
|
||||
|
||||
TTrackFollower::~TTrackFollower()
|
||||
{
|
||||
@@ -116,7 +115,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
&& ( pCurrentTrack->evEvent1 )
|
||||
&& ( !pCurrentTrack->evEvent1->iQueued ) ) {
|
||||
// dodanie do kolejki
|
||||
Global::AddToQuery( pCurrentTrack->evEvent1, Owner );
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEvent1, Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,7 +126,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
-1)) // McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow
|
||||
if (bPrimary && pCurrentTrack->evEventall1 &&
|
||||
(!pCurrentTrack->evEventall1->iQueued))
|
||||
Global::AddToQuery(pCurrentTrack->evEventall1, Owner); // dodanie do kolejki
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEventall1, Owner); // dodanie do kolejki
|
||||
// Owner->RaAxleEvent(pCurrentTrack->Eventall1); //Ra: dynamic zdecyduje, czy dodać
|
||||
// do kolejki
|
||||
}
|
||||
@@ -142,7 +141,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
if( ( bPrimary )
|
||||
&& ( pCurrentTrack->evEvent2 )
|
||||
&& ( !pCurrentTrack->evEvent2->iQueued ) ) {
|
||||
Global::AddToQuery( pCurrentTrack->evEvent2, Owner );
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEvent2, Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,7 +153,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
if( ( bPrimary )
|
||||
&& ( pCurrentTrack->evEventall2 )
|
||||
&& ( !pCurrentTrack->evEventall2->iQueued ) ) {
|
||||
Global::AddToQuery( pCurrentTrack->evEventall2, Owner );
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEventall2, Owner );
|
||||
}
|
||||
}
|
||||
// Owner->RaAxleEvent(pCurrentTrack->Eventall2); //Ra: dynamic zdecyduje, czy dodać
|
||||
@@ -167,13 +166,13 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
// tylko dla jednego członu
|
||||
if( pCurrentTrack->evEvent0 )
|
||||
if( !pCurrentTrack->evEvent0->iQueued )
|
||||
Global::AddToQuery( pCurrentTrack->evEvent0, Owner );
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEvent0, Owner );
|
||||
}
|
||||
// Owner->RaAxleEvent(pCurrentTrack->Event0); //Ra: dynamic zdecyduje, czy dodać do
|
||||
// kolejki
|
||||
if (pCurrentTrack->evEventall0)
|
||||
if (!pCurrentTrack->evEventall0->iQueued)
|
||||
Global::AddToQuery(pCurrentTrack->evEventall0, Owner);
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEventall0, Owner);
|
||||
// Owner->RaAxleEvent(pCurrentTrack->Eventall0); //Ra: dynamic zdecyduje, czy dodać
|
||||
// do kolejki
|
||||
}
|
||||
@@ -275,14 +274,14 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
// if (Owner->MoverParameters->CabNo!=0)
|
||||
{
|
||||
if (pCurrentTrack->evEvent1 && pCurrentTrack->evEvent1->fDelay <= -1.0f)
|
||||
Global::AddToQuery(pCurrentTrack->evEvent1, Owner);
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEvent1, Owner);
|
||||
if (pCurrentTrack->evEvent2 && pCurrentTrack->evEvent2->fDelay <= -1.0f)
|
||||
Global::AddToQuery(pCurrentTrack->evEvent2, Owner);
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEvent2, Owner);
|
||||
}
|
||||
if (pCurrentTrack->evEventall1 && pCurrentTrack->evEventall1->fDelay <= -1.0f)
|
||||
Global::AddToQuery(pCurrentTrack->evEventall1, Owner);
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEventall1, Owner);
|
||||
if (pCurrentTrack->evEventall2 && pCurrentTrack->evEventall2->fDelay <= -1.0f)
|
||||
Global::AddToQuery(pCurrentTrack->evEventall2, Owner);
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEventall2, Owner);
|
||||
}
|
||||
fCurrentDistance = s;
|
||||
// fDistance=0;
|
||||
|
||||
11
World.h
11
World.h
@@ -11,14 +11,16 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <string>
|
||||
|
||||
#include "Camera.h"
|
||||
#include "Ground.h"
|
||||
#include "scene.h"
|
||||
#include "sky.h"
|
||||
#include "sun.h"
|
||||
#include "moon.h"
|
||||
#include "stars.h"
|
||||
#include "skydome.h"
|
||||
#include "McZapkie/MOVER.h"
|
||||
#include "messaging.h"
|
||||
|
||||
// wrapper for simulation time
|
||||
class simulation_time {
|
||||
@@ -105,12 +107,15 @@ TWorld();
|
||||
void OnKeyDown(int cKey);
|
||||
// void UpdateWindow();
|
||||
void OnMouseMove(double x, double y);
|
||||
void OnCommandGet(DaneRozkaz *pRozkaz);
|
||||
void OnCommandGet(multiplayer::DaneRozkaz *pRozkaz);
|
||||
bool Update();
|
||||
void TrainDelete(TDynamicObject *d = NULL);
|
||||
TTrain* train() { return Train; }
|
||||
// switches between static and dynamic daylight calculation
|
||||
void ToggleDaylight();
|
||||
// calculates current season of the year based on set simulation date
|
||||
void compute_season( int const Yearday ) const;
|
||||
|
||||
|
||||
private:
|
||||
void Update_Environment();
|
||||
@@ -144,8 +149,6 @@ private:
|
||||
void CabChange(TDynamicObject *old, TDynamicObject *now);
|
||||
// handles vehicle change flag
|
||||
void ChangeDynamic();
|
||||
|
||||
TGround Ground; //m7todo: tmp
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -45,6 +45,9 @@ public:
|
||||
point_inside( float const X, float const Y, float const Z ) const;
|
||||
// tests if the sphere is in frustum, returns the distance between origin and sphere centre
|
||||
inline
|
||||
float
|
||||
sphere_inside( glm::dvec3 const &Center, float const Radius ) const { return sphere_inside( static_cast<float>( Center.x ), static_cast<float>( Center.y ), static_cast<float>( Center.z ), Radius ); }
|
||||
inline
|
||||
float
|
||||
sphere_inside( glm::vec3 const &Center, float const Radius ) const { return sphere_inside( Center.x, Center.y, Center.z, Radius ); }
|
||||
inline
|
||||
|
||||
31
lua.cpp
31
lua.cpp
@@ -6,6 +6,7 @@
|
||||
#include "World.h"
|
||||
#include "Driver.h"
|
||||
#include "lua_ffi.h"
|
||||
#include "simulation.h"
|
||||
|
||||
extern TWorld World;
|
||||
|
||||
@@ -72,29 +73,31 @@ extern "C"
|
||||
event->asName = std::string(name);
|
||||
event->fDelay = delay;
|
||||
event->Params[0].asPointer = (void*)handler;
|
||||
World.Ground.add_event(event);
|
||||
return event;
|
||||
if (simulation::Events.insert(event))
|
||||
return event;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EXPORT TEvent* scriptapi_event_find(const char* name)
|
||||
{
|
||||
std::string str(name);
|
||||
TEvent *e = World.Ground.FindEvent(str);
|
||||
TEvent *e = simulation::Events.FindEvent(str);
|
||||
if (e)
|
||||
return e;
|
||||
else
|
||||
WriteLog("missing event: " + str);
|
||||
WriteLog("lua: missing event: " + str);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EXPORT TTrack* scriptapi_track_find(const char* name)
|
||||
{
|
||||
std::string str(name);
|
||||
TGroundNode *n = World.Ground.FindGroundNode(str, TP_TRACK);
|
||||
if (n)
|
||||
return n->pTrack;
|
||||
TTrack *track = simulation::Paths.find(str);
|
||||
if (track)
|
||||
return track;
|
||||
else
|
||||
WriteLog("missing track: " + str);
|
||||
WriteLog("lua: missing track: " + str);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -122,7 +125,7 @@ extern "C"
|
||||
EXPORT void scriptapi_event_dispatch(TEvent *e, TDynamicObject *activator)
|
||||
{
|
||||
if (e)
|
||||
World.Ground.AddToQuery(e, activator);
|
||||
simulation::Events.AddToQuery(e, activator);
|
||||
}
|
||||
|
||||
EXPORT double scriptapi_random(double a, double b)
|
||||
@@ -132,7 +135,7 @@ extern "C"
|
||||
|
||||
EXPORT void scriptapi_writelog(const char* txt)
|
||||
{
|
||||
WriteLog("lua log: " + std::string(txt));
|
||||
WriteLog("lua: log: " + std::string(txt));
|
||||
}
|
||||
|
||||
struct memcell_values { const char *str; double num1; double num2; };
|
||||
@@ -140,11 +143,11 @@ extern "C"
|
||||
EXPORT TMemCell* scriptapi_memcell_find(const char *name)
|
||||
{
|
||||
std::string str(name);
|
||||
TGroundNode *n = World.Ground.FindGroundNode(str, TP_MEMCELL);
|
||||
if (n)
|
||||
return n->MemCell;
|
||||
TMemCell *mc = simulation::Memory.find(str);
|
||||
if (mc)
|
||||
return mc;
|
||||
else
|
||||
WriteLog("missing memcell: " + str);
|
||||
WriteLog("lua: missing memcell: " + str);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
33
material.cpp
33
material.cpp
@@ -18,7 +18,7 @@ bool
|
||||
opengl_material::deserialize( cParser &Input, bool const Loadnow ) {
|
||||
|
||||
bool result { false };
|
||||
while( true == deserialize_mapping( Input, Loadnow ) ) {
|
||||
while( true == deserialize_mapping( Input, 0, Loadnow ) ) {
|
||||
result = true; // once would suffice but, eh
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ opengl_material::deserialize( cParser &Input, bool const Loadnow ) {
|
||||
|
||||
// imports member data pair from the config file
|
||||
bool
|
||||
opengl_material::deserialize_mapping( cParser &Input, bool const Loadnow ) {
|
||||
opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool const Loadnow ) {
|
||||
|
||||
if( false == Input.getTokens( 2, true, "\n\r\t;, " ) ) {
|
||||
return false;
|
||||
@@ -48,8 +48,30 @@ opengl_material::deserialize_mapping( cParser &Input, bool const Loadnow ) {
|
||||
>> key
|
||||
>> value;
|
||||
|
||||
if( key == "texture1:" ) { texture1 = GfxRenderer.Fetch_Texture( path + value, Loadnow ); }
|
||||
else if( key == "texture2:" ) { texture2 = GfxRenderer.Fetch_Texture( path + value, Loadnow ); }
|
||||
if( value == "{" ) {
|
||||
// detect and optionally process config blocks
|
||||
cParser blockparser( Input.getToken<std::string>( false, "}" ) );
|
||||
if( key == Global::Season ) {
|
||||
// seasonal textures override generic textures
|
||||
while( true == deserialize_mapping( blockparser, 1, Loadnow ) ) {
|
||||
; // all work is done in the header
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( key == "texture1:" ) {
|
||||
// TODO: full-fledged priority system
|
||||
if( ( texture1 == null_handle )
|
||||
|| ( Priority > 0 ) ) {
|
||||
texture1 = GfxRenderer.Fetch_Texture( path + value, Loadnow );
|
||||
}
|
||||
}
|
||||
else if( key == "texture2:" ) {
|
||||
// TODO: full-fledged priority system
|
||||
if( ( texture2 == null_handle )
|
||||
|| ( Priority > 0 ) ) {
|
||||
texture2 = GfxRenderer.Fetch_Texture( path + value, Loadnow );
|
||||
}
|
||||
}
|
||||
|
||||
return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized
|
||||
}
|
||||
@@ -65,7 +87,8 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
|
||||
if( filename.find( '|' ) != std::string::npos )
|
||||
filename.erase( filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury
|
||||
|
||||
if( filename.rfind( '.' ) != std::string::npos ) {
|
||||
if( ( filename.rfind( '.' ) != std::string::npos )
|
||||
&& ( filename.rfind( '.' ) != filename.rfind( ".." ) + 1 ) ) {
|
||||
// we can get extension for .mat or, in legacy files, some image format. just trim it and set it to material file extension
|
||||
filename.erase( filename.rfind( '.' ) );
|
||||
}
|
||||
|
||||
@@ -28,9 +28,9 @@ struct opengl_material {
|
||||
bool
|
||||
deserialize( cParser &Input, bool const Loadnow );
|
||||
private:
|
||||
// imports member data pair from the config file
|
||||
// imports member data pair from the config file, overriding existing parameter values of lower priority
|
||||
bool
|
||||
deserialize_mapping( cParser &Input, bool const Loadnow );
|
||||
deserialize_mapping( cParser &Input, int const Priority, bool const Loadnow );
|
||||
};
|
||||
|
||||
class material_manager {
|
||||
|
||||
258
messaging.cpp
Normal file
258
messaging.cpp
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "messaging.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "simulation.h"
|
||||
#include "mtable.h"
|
||||
#include "Logs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C"
|
||||
{
|
||||
GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); //m7todo: potrzebne do directsound
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace multiplayer {
|
||||
|
||||
void
|
||||
Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) {
|
||||
#ifdef _WIN32
|
||||
// wysłanie komunikatu do sterującego
|
||||
HWND h = FindWindow(ClassName.c_str(), 0); // można by to zapamiętać
|
||||
if (h == 0)
|
||||
h = FindWindow(0, ClassName.c_str()); // można by to zapamiętać
|
||||
SendMessage(h, Msg, wParam, lParam);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
WyslijEvent(const std::string &e, const std::string &d)
|
||||
{ // Ra: jeszcze do wyczyszczenia
|
||||
#ifdef _WIN32
|
||||
DaneRozkaz r;
|
||||
r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' );
|
||||
r.iComm = 2; // 2 - event
|
||||
size_t i = e.length(), j = d.length();
|
||||
r.cString[0] = char(i);
|
||||
strcpy(r.cString + 1, e.c_str()); // zakończony zerem
|
||||
r.cString[i + 2] = char(j); // licznik po zerze kończącym
|
||||
strcpy(r.cString + 3 + i, d.c_str()); // zakończony zerem
|
||||
COPYDATASTRUCT cData;
|
||||
cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
|
||||
cData.cbData = (DWORD)(12 + i + j); // 8+dwa liczniki i dwa zera kończące
|
||||
cData.lpData = &r;
|
||||
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData );
|
||||
CommLog( Now() + " " + std::to_string(r.iComm) + " " + e + " sent" );
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
WyslijUszkodzenia(const std::string &t, char fl)
|
||||
{ // wysłanie informacji w postaci pojedynczego tekstu
|
||||
#ifdef _WIN32
|
||||
DaneRozkaz r;
|
||||
r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' );
|
||||
r.iComm = 13; // numer komunikatu
|
||||
size_t i = t.length();
|
||||
r.cString[0] = char(fl);
|
||||
r.cString[1] = char(i);
|
||||
strcpy(r.cString + 2, t.c_str()); // z zerem kończącym
|
||||
COPYDATASTRUCT cData;
|
||||
cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
|
||||
cData.cbData = (DWORD)(11 + i); // 8+licznik i zero kończące
|
||||
cData.lpData = &r;
|
||||
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData );
|
||||
CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
WyslijString(const std::string &t, int n)
|
||||
{ // wysłanie informacji w postaci pojedynczego tekstu
|
||||
#ifdef _WIN32
|
||||
DaneRozkaz r;
|
||||
r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' );
|
||||
r.iComm = n; // numer komunikatu
|
||||
size_t i = t.length();
|
||||
r.cString[0] = char(i);
|
||||
strcpy(r.cString + 1, t.c_str()); // z zerem kończącym
|
||||
COPYDATASTRUCT cData;
|
||||
cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
|
||||
cData.cbData = (DWORD)(10 + i); // 8+licznik i zero kończące
|
||||
cData.lpData = &r;
|
||||
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData );
|
||||
CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
WyslijWolny(const std::string &t)
|
||||
{ // Ra: jeszcze do wyczyszczenia
|
||||
WyslijString(t, 4); // tor wolny
|
||||
}
|
||||
|
||||
void
|
||||
WyslijNamiary(TDynamicObject const *Vehicle)
|
||||
{ // wysłanie informacji o pojeździe - (float), długość ramki będzie zwiększana w miarę potrzeby
|
||||
#ifdef _WIN32
|
||||
// WriteLog("Wysylam pojazd");
|
||||
DaneRozkaz r;
|
||||
r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' );
|
||||
r.iComm = 7; // 7 - dane pojazdu
|
||||
int i = 32;
|
||||
size_t j = Vehicle->asName.length();
|
||||
r.iPar[0] = i; // ilość danych liczbowych
|
||||
r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba)
|
||||
r.fPar[2] = Vehicle->MoverParameters->Loc.X; // pozycja X
|
||||
r.fPar[3] = Vehicle->MoverParameters->Loc.Y; // pozycja Y
|
||||
r.fPar[4] = Vehicle->MoverParameters->Loc.Z; // pozycja Z
|
||||
r.fPar[5] = Vehicle->MoverParameters->V; // prędkość ruchu X
|
||||
r.fPar[6] = Vehicle->MoverParameters->nrot * M_PI *
|
||||
Vehicle->MoverParameters->WheelDiameter; // prędkość obrotowa kóŁ
|
||||
r.fPar[7] = 0; // prędkość ruchu Z
|
||||
r.fPar[8] = Vehicle->MoverParameters->AccS; // przyspieszenie X
|
||||
r.fPar[9] = Vehicle->MoverParameters->AccN; // przyspieszenie Y //na razie nie
|
||||
r.fPar[10] = Vehicle->MoverParameters->AccV; // przyspieszenie Z
|
||||
r.fPar[11] = Vehicle->MoverParameters->DistCounter; // przejechana odległość w km
|
||||
r.fPar[12] = Vehicle->MoverParameters->PipePress; // ciśnienie w PG
|
||||
r.fPar[13] = Vehicle->MoverParameters->ScndPipePress; // ciśnienie w PZ
|
||||
r.fPar[14] = Vehicle->MoverParameters->BrakePress; // ciśnienie w CH
|
||||
r.fPar[15] = Vehicle->MoverParameters->Compressor; // ciśnienie w ZG
|
||||
r.fPar[16] = Vehicle->MoverParameters->Itot; // Prąd całkowity
|
||||
r.iPar[17] = Vehicle->MoverParameters->MainCtrlPos; // Pozycja NJ
|
||||
r.iPar[18] = Vehicle->MoverParameters->ScndCtrlPos; // Pozycja NB
|
||||
r.iPar[19] = Vehicle->MoverParameters->MainCtrlActualPos; // Pozycja jezdna
|
||||
r.iPar[20] = Vehicle->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania
|
||||
r.iPar[21] = Vehicle->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania
|
||||
r.iPar[22] = Vehicle->MoverParameters->ResistorsFlag * 1 +
|
||||
Vehicle->MoverParameters->ConverterFlag * 2 +
|
||||
+Vehicle->MoverParameters->CompressorFlag * 4 +
|
||||
Vehicle->MoverParameters->Mains * 8 +
|
||||
+Vehicle->MoverParameters->DoorLeftOpened * 16 +
|
||||
Vehicle->MoverParameters->DoorRightOpened * 32 +
|
||||
+Vehicle->MoverParameters->FuseFlag * 64 +
|
||||
Vehicle->MoverParameters->DepartureSignal * 128;
|
||||
// WriteLog("Zapisalem stare");
|
||||
// WriteLog("Mam patykow "+IntToStr(t->DynamicObject->iAnimType[ANIM_PANTS]));
|
||||
for (int p = 0; p < 4; p++)
|
||||
{
|
||||
// WriteLog("Probuje pant "+IntToStr(p));
|
||||
if (p < Vehicle->iAnimType[ANIM_PANTS])
|
||||
{
|
||||
r.fPar[23 + p] = Vehicle->pants[p].fParamPants->PantWys; // stan pantografów 4
|
||||
// WriteLog("Zapisalem pant "+IntToStr(p));
|
||||
}
|
||||
else
|
||||
{
|
||||
r.fPar[23 + p] = -2;
|
||||
// WriteLog("Nie mam pant "+IntToStr(p));
|
||||
}
|
||||
}
|
||||
// WriteLog("Zapisalem pantografy");
|
||||
for (int p = 0; p < 3; p++)
|
||||
r.fPar[27 + p] =
|
||||
Vehicle->MoverParameters->ShowCurrent(p + 1); // amperomierze kolejnych grup
|
||||
// WriteLog("zapisalem prady");
|
||||
r.iPar[30] = Vehicle->MoverParameters->WarningSignal; // trabienie
|
||||
r.fPar[31] = Vehicle->MoverParameters->RunningTraction.TractionVoltage; // napiecie WN
|
||||
// WriteLog("Parametry gotowe");
|
||||
i <<= 2; // ilość bajtów
|
||||
r.cString[i] = char(j); // na końcu nazwa, żeby jakoś zidentyfikować
|
||||
strcpy(r.cString + i + 1, Vehicle->asName.c_str()); // zakończony zerem
|
||||
COPYDATASTRUCT cData;
|
||||
cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
|
||||
cData.cbData = (DWORD)(10 + i + j); // 8+licznik i zero kończące
|
||||
cData.lpData = &r;
|
||||
// WriteLog("Ramka gotowa");
|
||||
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData );
|
||||
// WriteLog("Ramka poszla!");
|
||||
CommLog( Now() + " " + std::to_string(r.iComm) + " " + Vehicle->asName + " sent");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
WyslijObsadzone()
|
||||
{ // wysłanie informacji o pojeździe
|
||||
#ifdef _WIN32
|
||||
DaneRozkaz2 r;
|
||||
r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' );
|
||||
r.iComm = 12; // kod 12
|
||||
for (int i=0; i<1984; ++i) r.cString[i] = 0;
|
||||
|
||||
// TODO: clean this up, we shouldn't be relying on direct list access
|
||||
auto &vehiclelist = simulation::Vehicles.sequence();
|
||||
|
||||
int i = 0;
|
||||
for( auto *vehicle : vehiclelist ) {
|
||||
if( vehicle->Mechanik ) {
|
||||
strcpy( r.cString + 64 * i, vehicle->asName.c_str() );
|
||||
r.fPar[ 16 * i + 4 ] = vehicle->GetPosition().x;
|
||||
r.fPar[ 16 * i + 5 ] = vehicle->GetPosition().y;
|
||||
r.fPar[ 16 * i + 6 ] = vehicle->GetPosition().z;
|
||||
r.iPar[ 16 * i + 7 ] = vehicle->Mechanik->GetAction();
|
||||
strcpy( r.cString + 64 * i + 32, vehicle->GetTrack()->IsolatedName().c_str() );
|
||||
strcpy( r.cString + 64 * i + 48, vehicle->Mechanik->Timetable()->TrainName.c_str() );
|
||||
i++;
|
||||
if( i > 30 ) break;
|
||||
}
|
||||
}
|
||||
while (i <= 30)
|
||||
{
|
||||
strcpy(r.cString + 64 * i, "none");
|
||||
r.fPar[16 * i + 4] = 1;
|
||||
r.fPar[16 * i + 5] = 2;
|
||||
r.fPar[16 * i + 6] = 3;
|
||||
r.iPar[16 * i + 7] = 0;
|
||||
strcpy(r.cString + 64 * i + 32, "none");
|
||||
strcpy(r.cString + 64 * i + 48, "none");
|
||||
i++;
|
||||
}
|
||||
|
||||
COPYDATASTRUCT cData;
|
||||
cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
|
||||
cData.cbData = 8 + 1984; // 8+licznik i zero kończące
|
||||
cData.lpData = &r;
|
||||
// WriteLog("Ramka gotowa");
|
||||
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData );
|
||||
CommLog( Now() + " " + std::to_string(r.iComm) + " obsadzone" + " sent");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
WyslijParam(int nr, int fl)
|
||||
{ // wysłanie parametrów symulacji w ramce (nr) z flagami (fl)
|
||||
#ifdef _WIN32
|
||||
DaneRozkaz r;
|
||||
r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' );
|
||||
r.iComm = nr; // zwykle 5
|
||||
r.iPar[0] = fl; // flagi istotności kolejnych parametrów
|
||||
int i = 0; // domyślnie brak danych
|
||||
switch (nr)
|
||||
{ // można tym przesyłać różne zestawy parametrów
|
||||
case 5: // czas i pauza
|
||||
r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba)
|
||||
r.iPar[2] = Global::iPause; // stan zapauzowania
|
||||
i = 8; // dwa parametry po 4 bajty każdy
|
||||
break;
|
||||
}
|
||||
COPYDATASTRUCT cData;
|
||||
cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
|
||||
cData.cbData = 12 + i; // 12+rozmiar danych
|
||||
cData.lpData = &r;
|
||||
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData );
|
||||
#endif
|
||||
}
|
||||
|
||||
} // multiplayer
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
51
messaging.h
Normal file
51
messaging.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "winheaders.h"
|
||||
|
||||
class TDynamicObject;
|
||||
|
||||
namespace multiplayer {
|
||||
|
||||
struct DaneRozkaz { // struktura komunikacji z EU07.EXE
|
||||
int iSygn; // sygnatura 'EU07'
|
||||
int iComm; // rozkaz/status (kod ramki)
|
||||
union {
|
||||
float fPar[ 62 ];
|
||||
int iPar[ 62 ];
|
||||
char cString[ 248 ]; // upakowane stringi
|
||||
};
|
||||
};
|
||||
|
||||
struct DaneRozkaz2 { // struktura komunikacji z EU07.EXE
|
||||
int iSygn; // sygnatura 'EU07'
|
||||
int iComm; // rozkaz/status (kod ramki)
|
||||
union {
|
||||
float fPar[ 496 ];
|
||||
int iPar[ 496 ];
|
||||
char cString[ 1984 ]; // upakowane stringi
|
||||
};
|
||||
};
|
||||
|
||||
void Navigate( std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam );
|
||||
|
||||
void WyslijEvent( const std::string &e, const std::string &d );
|
||||
void WyslijString( const std::string &t, int n );
|
||||
void WyslijWolny( const std::string &t );
|
||||
void WyslijNamiary( TDynamicObject const *Vehicle );
|
||||
void WyslijParam( int nr, int fl );
|
||||
void WyslijUszkodzenia( const std::string &t, char fl );
|
||||
void WyslijObsadzone(); // -> skladanie wielu pojazdow
|
||||
|
||||
} // multiplayer
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -363,6 +363,12 @@ mouse_input::default_bindings() {
|
||||
{ "pantselectedoff_sw:", {
|
||||
user_command::none,
|
||||
user_command::none } }, // TODO: lower selected pantograp(s) command
|
||||
{ "pantcompressor_sw:", {
|
||||
user_command::pantographcompressoractivate,
|
||||
user_command::none } },
|
||||
{ "pantcompressorvalve_sw:", {
|
||||
user_command::pantographcompressorvalvetoggle,
|
||||
user_command::none } },
|
||||
{ "trainheating_sw:", {
|
||||
user_command::heatingtoggle,
|
||||
user_command::none } },
|
||||
|
||||
@@ -25,8 +25,8 @@ struct basic_vertex {
|
||||
glm::vec2 texture; // uv space
|
||||
|
||||
basic_vertex() = default;
|
||||
basic_vertex( glm::vec3 const &Position, glm::vec3 const &Normal, glm::vec2 const &Texture ) :
|
||||
position( Position ), normal( Normal ), texture( Texture )
|
||||
basic_vertex( glm::vec3 Position, glm::vec3 Normal, glm::vec2 Texture ) :
|
||||
position( Position ), normal( Normal ), texture( Texture )
|
||||
{}
|
||||
void serialize( std::ostream& ) const;
|
||||
void deserialize( std::istream& );
|
||||
@@ -58,8 +58,8 @@ struct geometry_handle {
|
||||
geometry_handle() :
|
||||
bank( 0 ), chunk( 0 )
|
||||
{}
|
||||
geometry_handle( std::uint32_t const Bank, std::uint32_t const Chunk ) :
|
||||
bank( Bank ), chunk( Chunk )
|
||||
geometry_handle( std::uint32_t Bank, std::uint32_t Chunk ) :
|
||||
bank( Bank ), chunk( Chunk )
|
||||
{}
|
||||
// methods
|
||||
inline
|
||||
@@ -121,8 +121,8 @@ protected:
|
||||
unsigned int type; // kind of geometry used by the chunk
|
||||
vertex_array vertices; // geometry data
|
||||
// NOTE: constructor doesn't copy provided vertex data, but moves it
|
||||
geometry_chunk( vertex_array &Vertices, unsigned int const Type ) :
|
||||
type( Type )
|
||||
geometry_chunk( vertex_array &Vertices, unsigned int Type ) :
|
||||
type( Type )
|
||||
{
|
||||
vertices.swap( Vertices );
|
||||
}
|
||||
|
||||
148
parser.cpp
148
parser.cpp
@@ -21,13 +21,14 @@ http://mozilla.org/MPL/2.0/.
|
||||
// cParser -- generic class for parsing text data.
|
||||
|
||||
// constructors
|
||||
cParser::cParser( std::string const &Stream, buffertype const Type, std::string Path, bool const Loadtraction ) :
|
||||
cParser::cParser( std::string const &Stream, buffertype const Type, std::string Path, bool const Loadtraction, std::vector<std::string> Parameters ) :
|
||||
mPath(Path),
|
||||
LoadTraction( Loadtraction ) {
|
||||
// build comments map
|
||||
mComments.insert(commentmap::value_type("/*", "*/"));
|
||||
mComments.insert(commentmap::value_type("//", "\n"));
|
||||
// mComments.insert(commentmap::value_type("--","\n")); //Ra: to chyba nie używane
|
||||
|
||||
// store to calculate sub-sequent includes from relative path
|
||||
if( Type == buffertype::buffer_FILE ) {
|
||||
mFile = Stream;
|
||||
@@ -60,6 +61,10 @@ cParser::cParser( std::string const &Stream, buffertype const Type, std::string
|
||||
mLine = 1;
|
||||
}
|
||||
}
|
||||
// set parameter set if one was provided
|
||||
if( false == Parameters.empty() ) {
|
||||
parameters.swap( Parameters );
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
@@ -146,90 +151,83 @@ bool cParser::getTokens(unsigned int Count, bool ToLower, const char *Break)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string cParser::readToken(bool ToLower, const char *Break)
|
||||
{
|
||||
std::string token = "";
|
||||
size_t pos; // początek podmienianego ciągu
|
||||
// see if there's include parsing going on. clean up when it's done.
|
||||
if (mIncludeParser)
|
||||
{
|
||||
token = mIncludeParser->readToken(ToLower, Break);
|
||||
if (!token.empty())
|
||||
{
|
||||
// check if the token is a parameter which should be replaced with stored true value
|
||||
while((pos = token.find("(p")) != std::string::npos) //!=npos to znalezione
|
||||
{
|
||||
std::string parameter =
|
||||
token.substr(pos + 2, token.find(")", pos) - pos + 2); // numer parametru
|
||||
token.erase(pos, token.find(")", pos) - pos + 1); // najpierw usunięcie "(pN)"
|
||||
size_t nr = atoi(parameter.c_str()) - 1;
|
||||
if (nr < parameters.size())
|
||||
{
|
||||
token.insert(pos, parameters.at(nr)); // wklejenie wartości parametru
|
||||
if (ToLower)
|
||||
for (; pos < token.length(); ++pos)
|
||||
token[pos] = tolower(token[pos]);
|
||||
}
|
||||
else
|
||||
token.insert(pos, "none"); // zabezpieczenie przed brakiem parametru
|
||||
}
|
||||
return token;
|
||||
}
|
||||
else
|
||||
{
|
||||
mIncludeParser = NULL;
|
||||
parameters.clear();
|
||||
std::string cParser::readToken( bool ToLower, const char *Break ) {
|
||||
|
||||
std::string token;
|
||||
if( mIncludeParser ) {
|
||||
// see if there's include parsing going on. clean up when it's done.
|
||||
token = mIncludeParser->readToken( ToLower, Break );
|
||||
if( true == token.empty() ) {
|
||||
mIncludeParser = nullptr;
|
||||
}
|
||||
}
|
||||
// get the token yourself if there's no child to delegate it to.
|
||||
char c { 0 };
|
||||
do
|
||||
{
|
||||
while (mStream->peek() != EOF && strchr(Break, c = mStream->get()) == NULL)
|
||||
{
|
||||
if (ToLower)
|
||||
c = tolower(c);
|
||||
token += c;
|
||||
if (findQuotes(token)) // do glue together words enclosed in quotes
|
||||
break;
|
||||
if (trimComments(token)) // don't glue together words separated with comment
|
||||
break;
|
||||
}
|
||||
if( c == '\n' ) {
|
||||
// update line counter
|
||||
++mLine;
|
||||
}
|
||||
} while (token == "" && mStream->peek() != EOF); // double check to deal with trailing spaces
|
||||
// launch child parser if include directive found.
|
||||
// NOTE: parameter collecting uses default set of token separators.
|
||||
if (token.compare("include") == 0)
|
||||
{ // obsługa include
|
||||
std::string includefile = readToken(ToLower); // nazwa pliku
|
||||
if (LoadTraction ? true : ((includefile.find("tr/") == std::string::npos) &&
|
||||
(includefile.find("tra/") == std::string::npos)))
|
||||
{
|
||||
// std::string trtest2="niemaproblema"; //nazwa odporna na znalezienie "tr/"
|
||||
// if (trtest=="x") //jeśli nie wczytywać drutów
|
||||
// trtest2=includefile; //kopiowanie ścieżki do pliku
|
||||
std::string parameter = readToken(false); // w parametrach nie zmniejszamy
|
||||
while( (parameter.empty() == false)
|
||||
&& (parameter.compare("end") != 0) )
|
||||
{
|
||||
parameters.push_back(parameter);
|
||||
parameter = readToken(false);
|
||||
if( true == token.empty() ) {
|
||||
// get the token yourself if the delegation attempt failed
|
||||
char c { 0 };
|
||||
do {
|
||||
while( mStream->peek() != EOF && strchr( Break, c = mStream->get() ) == NULL ) {
|
||||
if( ToLower )
|
||||
c = tolower( c );
|
||||
token += c;
|
||||
if( findQuotes( token ) ) // do glue together words enclosed in quotes
|
||||
break;
|
||||
if( trimComments( token ) ) // don't glue together words separated with comment
|
||||
break;
|
||||
}
|
||||
if( c == '\n' ) {
|
||||
// update line counter
|
||||
++mLine;
|
||||
}
|
||||
} while( token == "" && mStream->peek() != EOF ); // double check to deal with trailing spaces
|
||||
}
|
||||
|
||||
if( false == parameters.empty() ) {
|
||||
// if there's parameter list, check the token for potential parameters to replace
|
||||
size_t pos; // początek podmienianego ciągu
|
||||
while( ( pos = token.find( "(p" ) ) != std::string::npos ) {
|
||||
// check if the token is a parameter which should be replaced with stored true value
|
||||
auto const parameter{ token.substr( pos + 2, token.find( ")", pos ) - ( pos + 2 ) ) }; // numer parametru
|
||||
token.erase( pos, token.find( ")", pos ) - pos + 1 ); // najpierw usunięcie "(pN)"
|
||||
size_t nr = atoi( parameter.c_str() ) - 1;
|
||||
if( nr < parameters.size() ) {
|
||||
token.insert( pos, parameters.at( nr ) ); // wklejenie wartości parametru
|
||||
if( ToLower )
|
||||
for( ; pos < parameters.at( nr ).size(); ++pos )
|
||||
token[ pos ] = tolower( token[ pos ] );
|
||||
}
|
||||
else
|
||||
token.insert( pos, "none" ); // zabezpieczenie przed brakiem parametru
|
||||
}
|
||||
}
|
||||
|
||||
if( token == "include" ) {
|
||||
// launch child parser if include directive found.
|
||||
// NOTE: parameter collecting uses default set of token separators.
|
||||
std::string includefile = readToken(ToLower); // nazwa pliku
|
||||
if( ( true == LoadTraction )
|
||||
|| ( ( includefile.find( "tr/" ) == std::string::npos )
|
||||
&& ( includefile.find( "tra/" ) == std::string::npos ) ) ) {
|
||||
// get parameter list for the child parser
|
||||
std::vector<std::string> includeparameters;
|
||||
std::string parameter = readToken( false ); // w parametrach nie zmniejszamy
|
||||
while( ( parameter.empty() == false )
|
||||
&& ( parameter != "end" ) ) {
|
||||
includeparameters.emplace_back( parameter );
|
||||
parameter = readToken( false );
|
||||
}
|
||||
mIncludeParser = std::make_shared<cParser>( includefile, buffer_FILE, mPath, LoadTraction, includeparameters );
|
||||
if( mIncludeParser->mSize <= 0 ) {
|
||||
ErrorLog( "Bad include: can't open file \"" + includefile + "\"" );
|
||||
}
|
||||
// if (trtest2.find("tr/")!=0)
|
||||
mIncludeParser = std::make_shared<cParser>(includefile, buffer_FILE, mPath, LoadTraction);
|
||||
if (mIncludeParser->mSize <= 0)
|
||||
ErrorLog("Missed include: " + includefile);
|
||||
}
|
||||
else {
|
||||
while( token.compare( "end" ) != 0 ) {
|
||||
while( token != "end" ) {
|
||||
token = readToken( true ); // minimize risk of case mismatch on comparison
|
||||
}
|
||||
}
|
||||
token = readToken(ToLower, Break);
|
||||
}
|
||||
// all done
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
2
parser.h
2
parser.h
@@ -28,7 +28,7 @@ class cParser //: public std::stringstream
|
||||
buffer_TEXT
|
||||
};
|
||||
// constructors:
|
||||
cParser(std::string const &Stream, buffertype const Type = buffer_TEXT, std::string Path = "", bool const Loadtraction = true );
|
||||
cParser(std::string const &Stream, buffertype const Type = buffer_TEXT, std::string Path = "", bool const Loadtraction = true, std::vector<std::string> Parameters = std::vector<std::string>() );
|
||||
// destructor:
|
||||
virtual ~cParser();
|
||||
// methods:
|
||||
|
||||
1416
renderer.cpp
1416
renderer.cpp
File diff suppressed because it is too large
Load Diff
81
renderer.h
81
renderer.h
@@ -17,10 +17,12 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "frustum.h"
|
||||
#include "World.h"
|
||||
#include "MemCell.h"
|
||||
#include "scene.h"
|
||||
|
||||
#define EU07_USE_PICKING_FRAMEBUFFER
|
||||
//#define EU07_USE_DEBUG_SHADOWMAP
|
||||
//#define EU07_USE_DEBUG_CAMERA
|
||||
//#define EU07_USE_DEBUG_CULLING
|
||||
|
||||
struct opengl_light {
|
||||
|
||||
@@ -84,7 +86,7 @@ public:
|
||||
void
|
||||
update_frustum( glm::mat4 const &Projection, glm::mat4 const &Modelview );
|
||||
bool
|
||||
visible( bounding_area const &Area ) const;
|
||||
visible( scene::bounding_area const &Area ) const;
|
||||
bool
|
||||
visible( TDynamicObject const *Dynamic ) const;
|
||||
inline
|
||||
@@ -190,18 +192,20 @@ public:
|
||||
// utility methods
|
||||
TSubModel const *
|
||||
Pick_Control() const { return m_pickcontrolitem; }
|
||||
TGroundNode const *
|
||||
editor::basic_node const *
|
||||
Pick_Node() const { return m_picksceneryitem; }
|
||||
// maintenance jobs
|
||||
void
|
||||
Update( double const Deltatime );
|
||||
TSubModel const *
|
||||
Update_Pick_Control();
|
||||
TGroundNode const *
|
||||
editor::basic_node const *
|
||||
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 };
|
||||
@@ -225,7 +229,20 @@ private:
|
||||
diffuse
|
||||
};
|
||||
|
||||
typedef std::pair< double, TSubRect * > distancesubcell_pair;
|
||||
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 };
|
||||
};
|
||||
|
||||
using section_sequence = std::vector<scene::basic_section *>;
|
||||
using distancecell_pair = std::pair<double, scene::basic_cell *>;
|
||||
using cell_sequence = std::vector<distancecell_pair>;
|
||||
|
||||
struct renderpass_config {
|
||||
|
||||
@@ -266,14 +283,16 @@ private:
|
||||
Render_reflections();
|
||||
bool
|
||||
Render( world_environment *Environment );
|
||||
bool
|
||||
Render( TGround *Ground );
|
||||
bool
|
||||
Render( TGroundRect *Groundcell );
|
||||
bool
|
||||
Render( TSubRect *Groundsubcell );
|
||||
bool
|
||||
Render( TGroundNode *Node );
|
||||
void
|
||||
Render( scene::basic_region *Region );
|
||||
void
|
||||
Render( section_sequence::iterator First, section_sequence::iterator Last );
|
||||
void
|
||||
Render( cell_sequence::iterator First, cell_sequence::iterator Last );
|
||||
void
|
||||
Render( scene::shape_node const &Shape, bool const Ignorerange );
|
||||
void
|
||||
Render( TAnimModel *Instance );
|
||||
bool
|
||||
Render( TDynamicObject *Dynamic );
|
||||
bool
|
||||
@@ -284,16 +303,22 @@ private:
|
||||
Render( TSubModel *Submodel );
|
||||
void
|
||||
Render( TTrack *Track );
|
||||
void
|
||||
Render( scene::basic_cell::path_sequence::const_iterator First, scene::basic_cell::path_sequence::const_iterator Last );
|
||||
bool
|
||||
Render_cab( TDynamicObject *Dynamic, bool const Alpha = false );
|
||||
void
|
||||
Render( TMemCell *Memcell );
|
||||
bool
|
||||
Render_Alpha( TGround *Ground );
|
||||
bool
|
||||
Render_Alpha( TSubRect *Groundsubcell );
|
||||
bool
|
||||
Render_Alpha( TGroundNode *Node );
|
||||
void
|
||||
Render_Alpha( scene::basic_region *Region );
|
||||
void
|
||||
Render_Alpha( cell_sequence::reverse_iterator First, cell_sequence::reverse_iterator Last );
|
||||
void
|
||||
Render_Alpha( TAnimModel *Instance );
|
||||
void
|
||||
Render_Alpha( TTraction *Traction );
|
||||
void
|
||||
Render_Alpha( scene::lines_node const &Lines );
|
||||
bool
|
||||
Render_Alpha( TDynamicObject *Dynamic );
|
||||
bool
|
||||
@@ -351,28 +376,26 @@ 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.5f, 0.5f, 0.5f, 1.f };
|
||||
glm::vec4 m_shadowcolor { 0.65f, 0.65f, 0.65f, 1.f };
|
||||
float m_specularopaquescalefactor { 1.f };
|
||||
float m_speculartranslucentscalefactor { 1.f };
|
||||
bool m_renderspecular{ false }; // controls whether to include specular component in the calculations
|
||||
|
||||
renderpass_config m_renderpass;
|
||||
std::vector<distancesubcell_pair> m_drawqueue; // list of subcells to be drawn in current render pass
|
||||
|
||||
std::vector<TGroundNode const *> m_picksceneryitems;
|
||||
section_sequence m_sectionqueue; // list of sections in current render pass
|
||||
cell_sequence m_cellqueue;
|
||||
std::vector<TSubModel const *> m_pickcontrolsitems;
|
||||
TSubModel const *m_pickcontrolitem { nullptr };
|
||||
TGroundNode const *m_picksceneryitem { nullptr };
|
||||
std::vector<editor::basic_node const *> m_picksceneryitems;
|
||||
editor::basic_node const *m_picksceneryitem { nullptr };
|
||||
#ifdef EU07_USE_DEBUG_CAMERA
|
||||
renderpass_config m_worldcamera; // debug item
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by maszyna.rc
|
||||
//
|
||||
#define IDI_ICON1 101
|
||||
//#define GLFW_ICON 101
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
|
||||
347
scene.h
Normal file
347
scene.h
Normal file
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <array>
|
||||
#include <stack>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "parser.h"
|
||||
#include "openglgeometrybank.h"
|
||||
#include "scenenode.h"
|
||||
#include "Track.h"
|
||||
#include "Traction.h"
|
||||
|
||||
class opengl_renderer;
|
||||
namespace scene {
|
||||
|
||||
int const EU07_CELLSIZE = 250;
|
||||
int const EU07_SECTIONSIZE = 1000;
|
||||
int const EU07_REGIONSIDESECTIONCOUNT = 500; // number of sections along a side of square region
|
||||
|
||||
struct scratch_data {
|
||||
|
||||
struct binary_data {
|
||||
|
||||
bool terrain{ false };
|
||||
} binary;
|
||||
|
||||
struct location_data {
|
||||
|
||||
std::stack<glm::dvec3> offset;
|
||||
glm::vec3 rotation;
|
||||
} location;
|
||||
|
||||
struct trainset_data {
|
||||
|
||||
std::string name;
|
||||
std::string track;
|
||||
float offset { 0.f };
|
||||
float velocity { 0.f };
|
||||
std::vector<TDynamicObject *> vehicles;
|
||||
std::vector<std::int8_t> couplings;
|
||||
TDynamicObject * driver { nullptr };
|
||||
bool is_open { false };
|
||||
} trainset;
|
||||
|
||||
bool initialized { false };
|
||||
};
|
||||
|
||||
// basic element of rudimentary partitioning scheme for the section. fixed size, no further subdivision
|
||||
// TBD, TODO: replace with quadtree scheme?
|
||||
class basic_cell {
|
||||
|
||||
friend class ::opengl_renderer;
|
||||
|
||||
public:
|
||||
// methods
|
||||
// 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 );
|
||||
// legacy method, triggers radio-stop procedure for all vehicles located on paths in the cell
|
||||
void
|
||||
radio_stop();
|
||||
// legacy method, adds specified path to the list of pieces undergoing state change
|
||||
bool
|
||||
RaTrackAnimAdd( TTrack *Track );
|
||||
// legacy method, updates geometry for pieces in the animation list
|
||||
void
|
||||
RaAnimate( unsigned int const Framestamp );
|
||||
// adds provided shape to the cell
|
||||
void
|
||||
insert( shape_node Shape );
|
||||
// adds provided lines to the cell
|
||||
void
|
||||
insert( lines_node Lines );
|
||||
// adds provided path to the cell
|
||||
void
|
||||
insert( TTrack *Path );
|
||||
// adds provided path to the cell
|
||||
void
|
||||
insert( TTraction *Traction );
|
||||
// adds provided model instance to the cell
|
||||
void
|
||||
insert( TAnimModel *Instance );
|
||||
// adds provided sound instance to the cell
|
||||
void
|
||||
insert( sound *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 );
|
||||
// registers provided traction piece in the lookup directory of the cell
|
||||
void
|
||||
register_end( TTraction *Traction );
|
||||
// find a vehicle located nearest to specified point, within specified radius. reurns: located vehicle and distance
|
||||
std::tuple<TDynamicObject *, float>
|
||||
find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled, bool const Findbycoupler );
|
||||
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
|
||||
std::tuple<TTrack *, int>
|
||||
find( glm::dvec3 const &Point, TTrack const *Exclude );
|
||||
// finds a traction piece with one of its ends located in specified point. returns: located traction piece and id of the matching endpoint
|
||||
std::tuple<TTraction *, int>
|
||||
find( glm::dvec3 const &Point, TTraction const *Exclude );
|
||||
// finds a traction piece located nearest to specified point, sharing section with specified other piece and powered in specified direction. returns: located traction piece
|
||||
std::tuple<TTraction *, int, float>
|
||||
find( glm::dvec3 const &Point, TTraction const *Other, int const Currentdirection );
|
||||
// sets center point of the cell
|
||||
void
|
||||
center( glm::dvec3 Center );
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
create_geometry( geometrybank_handle const &Bank );
|
||||
// provides access to bounding area data
|
||||
bounding_area const &
|
||||
area() const {
|
||||
return m_area; }
|
||||
private:
|
||||
// types
|
||||
using path_sequence = std::vector<TTrack *>;
|
||||
using shapenode_sequence = std::vector<shape_node>;
|
||||
using linesnode_sequence = std::vector<lines_node>;
|
||||
using traction_sequence = std::vector<TTraction *>;
|
||||
using instance_sequence = std::vector<TAnimModel *>;
|
||||
using sound_sequence = std::vector<sound *>;
|
||||
using eventlauncher_sequence = std::vector<TEventLauncher *>;
|
||||
// methods
|
||||
void
|
||||
enclose_area( editor::basic_node *Node );
|
||||
// members
|
||||
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE ) };
|
||||
bool m_active { false }; // whether the cell holds any actual data
|
||||
// content
|
||||
shapenode_sequence m_shapesopaque; // opaque pieces of geometry
|
||||
shapenode_sequence m_shapestranslucent; // translucent pieces of geometry
|
||||
linesnode_sequence m_lines;
|
||||
path_sequence m_paths; // path pieces
|
||||
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_sequence paths;
|
||||
traction_sequence traction;
|
||||
} m_directories;
|
||||
// animation of owned items (legacy code, clean up along with track refactoring)
|
||||
bool m_geometrycreated { false };
|
||||
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
|
||||
TTrack *tTrackAnim = nullptr; // obiekty do przeliczenia animacji
|
||||
};
|
||||
|
||||
// basic scene partitioning structure, holds terrain geometry and collection of cells
|
||||
class basic_section {
|
||||
|
||||
friend class ::opengl_renderer;
|
||||
|
||||
public:
|
||||
// methods
|
||||
// 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 );
|
||||
// legacy method, triggers radio-stop procedure for all vehicles in 2km radius around specified location
|
||||
void
|
||||
radio_stop( glm::dvec3 const &Location, float const Radius );
|
||||
// adds provided shape to the section
|
||||
void
|
||||
insert( shape_node Shape );
|
||||
// adds provided lines to the section
|
||||
void
|
||||
insert( lines_node Lines );
|
||||
// adds provided node to the section
|
||||
template <class Type_>
|
||||
void
|
||||
insert( Type_ *Node ) {
|
||||
auto &targetcell { cell( Node->location() ) };
|
||||
targetcell.insert( Node );
|
||||
// some node types can extend bounding area of the target cell
|
||||
m_area.radius = std::max(
|
||||
m_area.radius,
|
||||
static_cast<float>( glm::length( m_area.center - targetcell.area().center ) + targetcell.area().radius ) ); }
|
||||
// registers provided node in the lookup directory of the section enclosing specified point
|
||||
template <class Type_>
|
||||
void
|
||||
register_node( Type_ *Node, glm::dvec3 const &Point ) {
|
||||
cell( Point ).register_end( Node ); }
|
||||
// find a vehicle located nearest to specified point, within specified radius. reurns: located vehicle and distance
|
||||
std::tuple<TDynamicObject *, float>
|
||||
find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled, bool const Findbycoupler );
|
||||
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
|
||||
std::tuple<TTrack *, int>
|
||||
find( glm::dvec3 const &Point, TTrack const *Exclude );
|
||||
// finds a traction piece with one of its ends located in specified point. returns: located traction piece and id of the matching endpoint
|
||||
std::tuple<TTraction *, int>
|
||||
find( glm::dvec3 const &Point, TTraction const *Exclude );
|
||||
// finds a traction piece located nearest to specified point, sharing section with specified other piece and powered in specified direction. returns: located traction piece
|
||||
std::tuple<TTraction *, int, float>
|
||||
find( glm::dvec3 const &Point, TTraction const *Other, int const Currentdirection );
|
||||
// sets center point of the section
|
||||
void
|
||||
center( glm::dvec3 Center );
|
||||
// generates renderable version of held non-instanced geometry
|
||||
void
|
||||
create_geometry();
|
||||
// provides access to bounding area data
|
||||
bounding_area const &
|
||||
area() const {
|
||||
return m_area; }
|
||||
|
||||
private:
|
||||
// types
|
||||
using cell_array = std::array<basic_cell, (EU07_SECTIONSIZE / EU07_CELLSIZE) * (EU07_SECTIONSIZE / EU07_CELLSIZE)>;
|
||||
using shapenode_sequence = std::vector<shape_node>;
|
||||
// methods
|
||||
// provides access to section enclosing specified point
|
||||
basic_cell &
|
||||
cell( glm::dvec3 const &Location );
|
||||
// members
|
||||
// placement and visibility
|
||||
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_SECTIONSIZE ) };
|
||||
// content
|
||||
cell_array m_cells; // partitioning scheme
|
||||
shapenode_sequence m_shapes; // large pieces of opaque geometry and (legacy) terrain
|
||||
// TODO: implement dedicated, higher fidelity, fixed resolution terrain mesh item
|
||||
// gfx renderer data
|
||||
geometrybank_handle m_geometrybank;
|
||||
bool m_geometrycreated { false };
|
||||
};
|
||||
|
||||
// top-level of scene spatial structure, holds collection of sections
|
||||
class basic_region {
|
||||
|
||||
friend class ::opengl_renderer;
|
||||
|
||||
public:
|
||||
// constructors
|
||||
basic_region();
|
||||
// destructor
|
||||
~basic_region();
|
||||
// methods
|
||||
// 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 );
|
||||
// stores content of the class in file with specified name
|
||||
void
|
||||
serialize( std::string const &Scenariofile );
|
||||
// restores content of the class from file with specified name. returns: true on success, false otherwise
|
||||
bool
|
||||
deserialize( std::string const &Scenariofile );
|
||||
// legacy method, links specified path piece with potential neighbours
|
||||
void
|
||||
TrackJoin( TTrack *Track );
|
||||
// legacy method, triggers radio-stop procedure for all vehicles in 2km radius around specified location
|
||||
void
|
||||
RadioStop( glm::dvec3 const &Location );
|
||||
// inserts provided shape in the region
|
||||
void
|
||||
insert_shape( shape_node Shape, scratch_data &Scratchpad, bool const Transform );
|
||||
// inserts provided lines in the region
|
||||
void
|
||||
insert_lines( lines_node Lines, scratch_data &Scratchpad );
|
||||
// inserts provided track in the region
|
||||
void
|
||||
insert_path( TTrack *Path, const scratch_data &Scratchpad );
|
||||
// inserts provided track in the region
|
||||
void
|
||||
insert_traction( TTraction *Traction, scratch_data &Scratchpad );
|
||||
// inserts provided instance of 3d model in the region
|
||||
void
|
||||
insert_instance( TAnimModel *Instance, scratch_data &Scratchpad );
|
||||
// inserts provided sound in the region
|
||||
void
|
||||
insert_sound( sound *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. reurns: located vehicle and distance
|
||||
std::tuple<TDynamicObject *, float>
|
||||
find_vehicle( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled, bool const Findbycoupler );
|
||||
// finds a path with one of its ends located in specified point. returns: located path and id of the matching endpoint
|
||||
std::tuple<TTrack *, int>
|
||||
find_path( glm::dvec3 const &Point, TTrack const *Exclude );
|
||||
// finds a traction piece with one of its ends located in specified point. returns: located traction piece and id of the matching endpoint
|
||||
std::tuple<TTraction *, int>
|
||||
find_traction( glm::dvec3 const &Point, TTraction const *Exclude );
|
||||
// finds a traction piece located nearest to specified point, sharing section with specified other piece and powered in specified direction. returns: located traction piece
|
||||
std::tuple<TTraction *, int>
|
||||
find_traction( glm::dvec3 const &Point, TTraction const *Other, int const Currentdirection );
|
||||
// finds sections inside specified sphere. returns: list of sections
|
||||
std::vector<basic_section *> const &
|
||||
sections( glm::dvec3 const &Point, float const Radius );
|
||||
|
||||
private:
|
||||
// types
|
||||
using section_array = std::array<basic_section *, EU07_REGIONSIDESECTIONCOUNT * EU07_REGIONSIDESECTIONCOUNT>;
|
||||
|
||||
struct region_scratchpad {
|
||||
|
||||
std::vector<basic_section *> sections;
|
||||
};
|
||||
|
||||
// methods
|
||||
// registers specified end point of the provided path in the lookup directory of the region
|
||||
void
|
||||
register_path( TTrack *Path, glm::dvec3 const &Point );
|
||||
// registers specified end point of the provided traction piece in the lookup directory of the region
|
||||
void
|
||||
register_traction( TTraction *Traction, glm::dvec3 const &Point );
|
||||
// checks whether specified point is within boundaries of the region
|
||||
bool
|
||||
point_inside( glm::dvec3 const &Location );
|
||||
// legacy method, trims provided shape to fit into a section. adds trimmed part at the end of provided list, returns true if changes were made
|
||||
bool
|
||||
RaTriangleDivider( shape_node &Shape, std::deque<shape_node> &Shapes );
|
||||
// provides access to section enclosing specified point
|
||||
basic_section &
|
||||
section( glm::dvec3 const &Location );
|
||||
|
||||
// members
|
||||
section_array m_sections;
|
||||
region_scratchpad m_scratchpad;
|
||||
|
||||
};
|
||||
|
||||
} // scene
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
519
scenenode.cpp
Normal file
519
scenenode.cpp
Normal file
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "scenenode.h"
|
||||
|
||||
#include "renderer.h"
|
||||
#include "Logs.h"
|
||||
|
||||
namespace scene {
|
||||
|
||||
// restores content of the node from provded input stream
|
||||
shape_node &
|
||||
shape_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) {
|
||||
|
||||
// import common data
|
||||
m_name = Nodedata.name;
|
||||
m_data.rangesquared_min = Nodedata.range_min * Nodedata.range_min;
|
||||
m_data.rangesquared_max = (
|
||||
Nodedata.range_max >= 0.0 ?
|
||||
Nodedata.range_max * Nodedata.range_max :
|
||||
std::numeric_limits<double>::max() );
|
||||
|
||||
std::string token = Input.getToken<std::string>();
|
||||
if( token == "material" ) {
|
||||
// lighting settings
|
||||
token = Input.getToken<std::string>();
|
||||
while( token != "endmaterial" ) {
|
||||
|
||||
if( token == "ambient:" ) {
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> m_data.lighting.ambient.r
|
||||
>> m_data.lighting.ambient.g
|
||||
>> m_data.lighting.ambient.b;
|
||||
m_data.lighting.ambient /= 255.f;
|
||||
m_data.lighting.ambient.a = 1.f;
|
||||
}
|
||||
else if( token == "diffuse:" ) {
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> m_data.lighting.diffuse.r
|
||||
>> m_data.lighting.diffuse.g
|
||||
>> m_data.lighting.diffuse.b;
|
||||
m_data.lighting.diffuse /= 255.f;
|
||||
m_data.lighting.diffuse.a = 1.f;
|
||||
}
|
||||
else if( token == "specular:" ) {
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> m_data.lighting.specular.r
|
||||
>> m_data.lighting.specular.g
|
||||
>> m_data.lighting.specular.b;
|
||||
m_data.lighting.specular /= 255.f;
|
||||
m_data.lighting.specular.a = 1.f;
|
||||
}
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
|
||||
// assigned material
|
||||
m_data.material = GfxRenderer.Fetch_Material( token );
|
||||
|
||||
// determine way to proceed from the assigned diffuse texture
|
||||
// TBT, TODO: add methods to material manager to access these simpler
|
||||
auto const texturehandle = (
|
||||
m_data.material != null_handle ?
|
||||
GfxRenderer.Material( m_data.material ).texture1 :
|
||||
null_handle );
|
||||
auto const &texture = (
|
||||
texturehandle ?
|
||||
GfxRenderer.Texture( texturehandle ) :
|
||||
opengl_texture() ); // dirty workaround for lack of better api
|
||||
bool const clamps = (
|
||||
texturehandle ?
|
||||
texture.traits.find( 's' ) != std::string::npos :
|
||||
false );
|
||||
bool const clampt = (
|
||||
texturehandle ?
|
||||
texture.traits.find( 't' ) != std::string::npos :
|
||||
false );
|
||||
|
||||
// remainder of legacy 'problend' system -- geometry assigned a texture with '@' in its name is treated as translucent, opaque otherwise
|
||||
if( texturehandle != null_handle ) {
|
||||
m_data.translucent = (
|
||||
( ( texture.name.find( '@' ) != std::string::npos )
|
||||
&& ( true == texture.has_alpha ) ) ?
|
||||
true :
|
||||
false );
|
||||
}
|
||||
else {
|
||||
m_data.translucent = false;
|
||||
}
|
||||
|
||||
// geometry
|
||||
enum subtype {
|
||||
triangles,
|
||||
triangle_strip,
|
||||
triangle_fan
|
||||
} const nodetype = (
|
||||
Nodedata.type == "triangles" ? triangles :
|
||||
Nodedata.type == "triangle_strip" ? triangle_strip :
|
||||
triangle_fan );
|
||||
std::size_t vertexcount{ 0 };
|
||||
world_vertex vertex, vertex1, vertex2;
|
||||
do {
|
||||
Input.getTokens( 8, false );
|
||||
Input
|
||||
>> vertex.position.x
|
||||
>> vertex.position.y
|
||||
>> vertex.position.z
|
||||
>> vertex.normal.x
|
||||
>> vertex.normal.y
|
||||
>> vertex.normal.z
|
||||
>> vertex.texture.s
|
||||
>> vertex.texture.t;
|
||||
// clamp texture coordinates if texture wrapping is off
|
||||
if( true == clamps ) { vertex.texture.s = clamp( vertex.texture.s, 0.001f, 0.999f ); }
|
||||
if( true == clampt ) { vertex.texture.t = clamp( vertex.texture.t, 0.001f, 0.999f ); }
|
||||
// convert all data to gl_triangles to allow data merge for matching nodes
|
||||
switch( nodetype ) {
|
||||
case triangles: {
|
||||
|
||||
if( vertexcount == 0 ) { vertex1 = vertex; }
|
||||
else if( vertexcount == 1 ) { vertex2 = vertex; }
|
||||
else if( vertexcount >= 2 ) {
|
||||
if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) {
|
||||
m_data.vertices.emplace_back( vertex1 );
|
||||
m_data.vertices.emplace_back( vertex2 );
|
||||
m_data.vertices.emplace_back( vertex );
|
||||
}
|
||||
else {
|
||||
ErrorLog(
|
||||
"Bad geometry: degenerate triangle encountered"
|
||||
+ ( m_name != "" ? " in node \"" + m_name + "\"" : "" )
|
||||
+ " (vertices: " + to_string( vertex1.position ) + " + " + to_string( vertex2.position ) + " + " + to_string( vertex.position ) + ")" );
|
||||
}
|
||||
}
|
||||
++vertexcount;
|
||||
if( vertexcount > 2 ) { vertexcount = 0; } // start new triangle if needed
|
||||
break;
|
||||
}
|
||||
case triangle_fan: {
|
||||
|
||||
if( vertexcount == 0 ) { vertex1 = vertex; }
|
||||
else if( vertexcount == 1 ) { vertex2 = vertex; }
|
||||
else if( vertexcount >= 2 ) {
|
||||
if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) {
|
||||
m_data.vertices.emplace_back( vertex1 );
|
||||
m_data.vertices.emplace_back( vertex2 );
|
||||
m_data.vertices.emplace_back( vertex );
|
||||
vertex2 = vertex;
|
||||
}
|
||||
else {
|
||||
ErrorLog(
|
||||
"Bad geometry: degenerate triangle encountered"
|
||||
+ ( m_name != "" ? " in node \"" + m_name + "\"" : "" )
|
||||
+ " (vertices: " + to_string( vertex1.position ) + " + " + to_string( vertex2.position ) + " + " + to_string( vertex.position ) + ")" );
|
||||
}
|
||||
}
|
||||
++vertexcount;
|
||||
break;
|
||||
}
|
||||
case triangle_strip: {
|
||||
|
||||
if( vertexcount == 0 ) { vertex1 = vertex; }
|
||||
else if( vertexcount == 1 ) { vertex2 = vertex; }
|
||||
else if( vertexcount >= 2 ) {
|
||||
if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) {
|
||||
// swap order every other triangle, to maintain consistent winding
|
||||
if( vertexcount % 2 == 0 ) {
|
||||
m_data.vertices.emplace_back( vertex1 );
|
||||
m_data.vertices.emplace_back( vertex2 );
|
||||
}
|
||||
else {
|
||||
m_data.vertices.emplace_back( vertex2 );
|
||||
m_data.vertices.emplace_back( vertex1 );
|
||||
}
|
||||
m_data.vertices.emplace_back( vertex );
|
||||
|
||||
vertex1 = vertex2;
|
||||
vertex2 = vertex;
|
||||
}
|
||||
else {
|
||||
ErrorLog(
|
||||
"Bad geometry: degenerate triangle encountered"
|
||||
+ ( m_name != "" ? " in node \"" + m_name + "\"" : "" )
|
||||
+ " (vertices: " + to_string( vertex1.position ) + " + " + to_string( vertex2.position ) + " + " + to_string( vertex.position ) + ")" );
|
||||
}
|
||||
}
|
||||
++vertexcount;
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
}
|
||||
token = Input.getToken<std::string>();
|
||||
|
||||
} while( token != "endtri" );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// imports data from provided submodel
|
||||
shape_node &
|
||||
shape_node::convert( TSubModel const *Submodel ) {
|
||||
|
||||
m_name = Submodel->pName;
|
||||
m_data.lighting.ambient = Submodel->f4Ambient;
|
||||
m_data.lighting.diffuse = Submodel->f4Diffuse;
|
||||
m_data.lighting.specular = Submodel->f4Specular;
|
||||
m_data.material = Submodel->m_material;
|
||||
m_data.translucent = ( true == GfxRenderer.Material( m_data.material ).has_alpha );
|
||||
// NOTE: we set unlimited view range typical for terrain, because we don't expect to convert any other 3d models
|
||||
m_data.rangesquared_max = std::numeric_limits<double>::max();
|
||||
|
||||
if( Submodel->m_geometry == null_handle ) { return *this; }
|
||||
|
||||
int vertexcount { 0 };
|
||||
std::vector<world_vertex> importedvertices;
|
||||
world_vertex vertex, vertex1, vertex2;
|
||||
for( auto const &sourcevertex : GfxRenderer.Vertices( Submodel->m_geometry ) ) {
|
||||
vertex.position = sourcevertex.position;
|
||||
vertex.normal = sourcevertex.normal;
|
||||
vertex.texture = sourcevertex.texture;
|
||||
if( vertexcount == 0 ) { vertex1 = vertex; }
|
||||
else if( vertexcount == 1 ) { vertex2 = vertex; }
|
||||
else if( vertexcount >= 2 ) {
|
||||
if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) {
|
||||
importedvertices.emplace_back( vertex1 );
|
||||
importedvertices.emplace_back( vertex2 );
|
||||
importedvertices.emplace_back( vertex );
|
||||
}
|
||||
// start a new triangle
|
||||
vertexcount = -1;
|
||||
}
|
||||
++vertexcount;
|
||||
}
|
||||
|
||||
if( true == importedvertices.empty() ) { return *this; }
|
||||
|
||||
// assign imported geometry to the node...
|
||||
m_data.vertices.swap( importedvertices );
|
||||
// ...and calculate center...
|
||||
for( auto const &vertex : m_data.vertices ) {
|
||||
m_data.area.center += vertex.position;
|
||||
}
|
||||
m_data.area.center /= m_data.vertices.size();
|
||||
// ...and bounding area
|
||||
double squareradius { 0.0 };
|
||||
for( auto const &vertex : m_data.vertices ) {
|
||||
squareradius = std::max(
|
||||
squareradius,
|
||||
glm::length2( vertex.position - m_data.area.center ) );
|
||||
}
|
||||
m_data.area.radius = std::max(
|
||||
m_data.area.radius,
|
||||
static_cast<float>( std::sqrt( squareradius ) ) );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// adds content of provided node to already enclosed geometry. returns: true if merge could be performed
|
||||
bool
|
||||
shape_node::merge( shape_node &Shape ) {
|
||||
|
||||
if( ( m_data.material != Shape.m_data.material )
|
||||
|| ( m_data.lighting != Shape.m_data.lighting ) ) {
|
||||
// can't merge nodes with different appearance
|
||||
return false;
|
||||
}
|
||||
// add geometry from provided node
|
||||
m_data.area.center =
|
||||
interpolate(
|
||||
m_data.area.center, Shape.m_data.area.center,
|
||||
static_cast<float>( Shape.m_data.vertices.size() ) / ( Shape.m_data.vertices.size() + m_data.vertices.size() ) );
|
||||
m_data.vertices.insert(
|
||||
std::end( m_data.vertices ),
|
||||
std::begin( Shape.m_data.vertices ), std::end( Shape.m_data.vertices ) );
|
||||
// NOTE: we could recalculate radius with something other than brute force, but it'll do
|
||||
compute_radius();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
shape_node::create_geometry( geometrybank_handle const &Bank ) {
|
||||
|
||||
vertex_array vertices; vertices.reserve( m_data.vertices.size() );
|
||||
|
||||
for( auto const &vertex : m_data.vertices ) {
|
||||
vertices.emplace_back(
|
||||
vertex.position - m_data.origin,
|
||||
vertex.normal,
|
||||
vertex.texture );
|
||||
}
|
||||
m_data.geometry = GfxRenderer.Insert( vertices, Bank, GL_TRIANGLES );
|
||||
std::vector<world_vertex>().swap( m_data.vertices ); // hipster shrink_to_fit
|
||||
}
|
||||
|
||||
// calculates shape's bounding radius
|
||||
void
|
||||
shape_node::compute_radius() {
|
||||
|
||||
auto squaredradius { 0.0 };
|
||||
for( auto const &vertex : m_data.vertices ) {
|
||||
squaredradius = std::max(
|
||||
squaredradius,
|
||||
glm::length2( vertex.position - m_data.area.center ) );
|
||||
}
|
||||
m_data.area.radius = static_cast<float>( std::sqrt( squaredradius ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// restores content of the node from provded input stream
|
||||
lines_node &
|
||||
lines_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) {
|
||||
|
||||
// import common data
|
||||
m_name = Nodedata.name;
|
||||
m_data.rangesquared_min = Nodedata.range_min * Nodedata.range_min;
|
||||
m_data.rangesquared_max = (
|
||||
Nodedata.range_max >= 0.0 ?
|
||||
Nodedata.range_max * Nodedata.range_max :
|
||||
std::numeric_limits<double>::max() );
|
||||
|
||||
// material
|
||||
Input.getTokens( 3, false );
|
||||
Input
|
||||
>> m_data.lighting.diffuse.r
|
||||
>> m_data.lighting.diffuse.g
|
||||
>> m_data.lighting.diffuse.b;
|
||||
m_data.lighting.diffuse /= 255.f;
|
||||
m_data.lighting.diffuse.a = 1.f;
|
||||
Input.getTokens( 1, false );
|
||||
Input
|
||||
>> m_data.line_width;
|
||||
m_data.line_width = std::min( 30.f, m_data.line_width ); // 30 pix equals rougly width of a signal pole viewed from ~1m away
|
||||
|
||||
// geometry
|
||||
enum subtype {
|
||||
lines,
|
||||
line_strip,
|
||||
line_loop
|
||||
} const nodetype = (
|
||||
Nodedata.type == "lines" ? lines :
|
||||
Nodedata.type == "line_strip" ? line_strip :
|
||||
line_loop );
|
||||
std::size_t vertexcount { 0 };
|
||||
world_vertex vertex, vertex0, vertex1;
|
||||
std::string token = Input.getToken<std::string>();
|
||||
do {
|
||||
vertex.position.x = std::atof( token.c_str() );
|
||||
Input.getTokens( 2, false );
|
||||
Input
|
||||
>> vertex.position.y
|
||||
>> vertex.position.z;
|
||||
// convert all data to gl_lines to allow data merge for matching nodes
|
||||
switch( nodetype ) {
|
||||
case lines: {
|
||||
m_data.vertices.emplace_back( vertex );
|
||||
break;
|
||||
}
|
||||
case line_strip: {
|
||||
if( vertexcount > 0 ) {
|
||||
m_data.vertices.emplace_back( vertex1 );
|
||||
m_data.vertices.emplace_back( vertex );
|
||||
}
|
||||
vertex1 = vertex;
|
||||
++vertexcount;
|
||||
break;
|
||||
}
|
||||
case line_loop: {
|
||||
if( vertexcount == 0 ) {
|
||||
vertex0 = vertex;
|
||||
vertex1 = vertex;
|
||||
}
|
||||
else {
|
||||
m_data.vertices.emplace_back( vertex1 );
|
||||
m_data.vertices.emplace_back( vertex );
|
||||
}
|
||||
vertex1 = vertex;
|
||||
++vertexcount;
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
}
|
||||
token = Input.getToken<std::string>();
|
||||
|
||||
} while( token != "endline" );
|
||||
// add closing line for the loop
|
||||
if( ( nodetype == line_loop )
|
||||
&& ( vertexcount > 2 ) ) {
|
||||
m_data.vertices.emplace_back( vertex1 );
|
||||
m_data.vertices.emplace_back( vertex0 );
|
||||
}
|
||||
if( m_data.vertices.size() % 2 != 0 ) {
|
||||
ErrorLog( "Lines node specified odd number of vertices, encountered in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
|
||||
m_data.vertices.pop_back();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// adds content of provided node to already enclosed geometry. returns: true if merge could be performed
|
||||
bool
|
||||
lines_node::merge( lines_node &Lines ) {
|
||||
|
||||
if( ( m_data.line_width != Lines.m_data.line_width )
|
||||
|| ( m_data.lighting != Lines.m_data.lighting ) ) {
|
||||
// can't merge nodes with different appearance
|
||||
return false;
|
||||
}
|
||||
// add geometry from provided node
|
||||
m_data.area.center =
|
||||
interpolate(
|
||||
m_data.area.center, Lines.m_data.area.center,
|
||||
static_cast<float>( Lines.m_data.vertices.size() ) / ( Lines.m_data.vertices.size() + m_data.vertices.size() ) );
|
||||
m_data.vertices.insert(
|
||||
std::end( m_data.vertices ),
|
||||
std::begin( Lines.m_data.vertices ), std::end( Lines.m_data.vertices ) );
|
||||
// NOTE: we could recalculate radius with something other than brute force, but it'll do
|
||||
compute_radius();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
lines_node::create_geometry( geometrybank_handle const &Bank ) {
|
||||
|
||||
vertex_array vertices; vertices.reserve( m_data.vertices.size() );
|
||||
|
||||
for( auto const &vertex : m_data.vertices ) {
|
||||
vertices.emplace_back(
|
||||
vertex.position - m_data.origin,
|
||||
vertex.normal,
|
||||
vertex.texture );
|
||||
}
|
||||
m_data.geometry = GfxRenderer.Insert( vertices, Bank, GL_LINES );
|
||||
std::vector<world_vertex>().swap( m_data.vertices ); // hipster shrink_to_fit
|
||||
}
|
||||
|
||||
// calculates node's bounding radius
|
||||
void
|
||||
lines_node::compute_radius() {
|
||||
|
||||
auto squaredradius { 0.0 };
|
||||
for( auto const &vertex : m_data.vertices ) {
|
||||
squaredradius = std::max(
|
||||
squaredradius,
|
||||
glm::length2( vertex.position - m_data.area.center ) );
|
||||
}
|
||||
m_data.area.radius = static_cast<float>( std::sqrt( squaredradius ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
memory_node &
|
||||
memory_node::deserialize( cParser &Input, node_data const &Nodedata ) {
|
||||
|
||||
// import common data
|
||||
m_name = Nodedata.name;
|
||||
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> m_data.area.center.x
|
||||
>> m_data.area.center.y
|
||||
>> m_data.area.center.z;
|
||||
|
||||
TMemCell memorycell( Nodedata.name );
|
||||
memorycell.Load( &Input );
|
||||
}
|
||||
*/
|
||||
} // scene
|
||||
|
||||
|
||||
|
||||
namespace editor {
|
||||
|
||||
basic_node::basic_node( scene::node_data const &Nodedata ) :
|
||||
m_name( Nodedata.name )
|
||||
{
|
||||
m_rangesquaredmin = Nodedata.range_min * Nodedata.range_min;
|
||||
m_rangesquaredmax = (
|
||||
Nodedata.range_max >= 0.0 ?
|
||||
Nodedata.range_max * Nodedata.range_max :
|
||||
std::numeric_limits<double>::max() );
|
||||
}
|
||||
|
||||
float const &
|
||||
basic_node::radius() {
|
||||
|
||||
if( m_area.radius == -1.0 ) {
|
||||
// calculate if needed
|
||||
radius_();
|
||||
}
|
||||
return m_area.radius;
|
||||
}
|
||||
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
// by default nodes are 'virtual don't extend from their center point
|
||||
void
|
||||
basic_node::radius_() {
|
||||
|
||||
m_area.radius = 0.f;
|
||||
}
|
||||
|
||||
} // editor
|
||||
//---------------------------------------------------------------------------
|
||||
318
scenenode.h
Normal file
318
scenenode.h
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "material.h"
|
||||
#include "vertex.h"
|
||||
#include "openglgeometrybank.h"
|
||||
#include "parser.h"
|
||||
#include "Model3d.h"
|
||||
|
||||
struct lighting_data {
|
||||
|
||||
glm::vec4 diffuse { 0.8f, 0.8f, 0.8f, 1.0f };
|
||||
glm::vec4 ambient { 0.2f, 0.2f, 0.2f, 1.0f };
|
||||
glm::vec4 specular { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
};
|
||||
|
||||
inline
|
||||
bool
|
||||
operator==( lighting_data const &Left, lighting_data const &Right ) {
|
||||
return ( ( Left.diffuse == Right.diffuse )
|
||||
&& ( Left.ambient == Right.ambient )
|
||||
&& ( Left.specular == Right.specular ) ); }
|
||||
|
||||
inline
|
||||
bool
|
||||
operator!=( lighting_data const &Left, lighting_data const &Right ) {
|
||||
return !( Left == Right ); }
|
||||
|
||||
namespace scene {
|
||||
|
||||
struct bounding_area {
|
||||
|
||||
glm::dvec3 center; // mid point of the rectangle
|
||||
float radius { -1.0f }; // radius of the bounding sphere
|
||||
|
||||
bounding_area() = default;
|
||||
bounding_area( glm::dvec3 Center, float Radius ) :
|
||||
center( Center ),
|
||||
radius( Radius )
|
||||
{}
|
||||
};
|
||||
/*
|
||||
enum nodetype {
|
||||
|
||||
unknown,
|
||||
model,
|
||||
triangles,
|
||||
lines,
|
||||
dynamic,
|
||||
track,
|
||||
traction,
|
||||
powersource,
|
||||
sound,
|
||||
memorycell,
|
||||
eventlauncher
|
||||
};
|
||||
|
||||
class node_manager {
|
||||
|
||||
};
|
||||
*/
|
||||
|
||||
struct node_data {
|
||||
|
||||
double range_min { 0.0 };
|
||||
double range_max { std::numeric_limits<double>::max() };
|
||||
std::string name;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
// holds unique piece of geometry, covered with single material
|
||||
class shape_node {
|
||||
|
||||
friend class basic_region; // region might want to modify node content when it's being inserted
|
||||
|
||||
public:
|
||||
// types
|
||||
struct shapenode_data {
|
||||
// placement and visibility
|
||||
scene::bounding_area area; // bounding area, in world coordinates
|
||||
bool visible { true }; // visibility flag
|
||||
double rangesquared_min { 0.0 }; // visibility range, min
|
||||
double rangesquared_max { 0.0 }; // visibility range, max
|
||||
// material data
|
||||
material_handle material { 0 };
|
||||
lighting_data lighting;
|
||||
bool translucent { false }; // whether opaque or translucent
|
||||
// geometry data
|
||||
std::vector<world_vertex> vertices; // world space source data of the geometry
|
||||
glm::dvec3 origin; // world position of the relative coordinate system origin
|
||||
geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer
|
||||
};
|
||||
|
||||
// methods
|
||||
// restores content of the node from provded input stream
|
||||
shape_node &
|
||||
deserialize( cParser &Input, scene::node_data const &Nodedata );
|
||||
// imports data from provided submodel
|
||||
shape_node &
|
||||
convert( TSubModel const *Submodel );
|
||||
// adds content of provided node to already enclosed geometry. returns: true if merge could be performed
|
||||
bool
|
||||
merge( shape_node &Shape );
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
create_geometry( geometrybank_handle const &Bank );
|
||||
// calculates shape's bounding radius
|
||||
void
|
||||
compute_radius();
|
||||
// set visibility
|
||||
void
|
||||
visible( bool State ) {
|
||||
m_data.visible = State; }
|
||||
// set origin point
|
||||
void
|
||||
origin( glm::dvec3 Origin ) {
|
||||
m_data.origin = Origin; }
|
||||
// data access
|
||||
shapenode_data const &
|
||||
data() const {
|
||||
return m_data; }
|
||||
|
||||
private:
|
||||
// members
|
||||
std::string m_name;
|
||||
shapenode_data m_data;
|
||||
};
|
||||
|
||||
// holds a group of untextured lines
|
||||
class lines_node {
|
||||
|
||||
friend class basic_region; // region might want to modify node content when it's being inserted
|
||||
|
||||
public:
|
||||
// types
|
||||
struct linesnode_data {
|
||||
// placement and visibility
|
||||
scene::bounding_area area; // bounding area, in world coordinates
|
||||
bool visible { true }; // visibility flag
|
||||
double rangesquared_min { 0.0 }; // visibility range, min
|
||||
double rangesquared_max { 0.0 }; // visibility range, max
|
||||
// material data
|
||||
lighting_data lighting;
|
||||
float line_width; // thickness of stored lines
|
||||
// geometry data
|
||||
std::vector<world_vertex> vertices; // world space source data of the geometry
|
||||
glm::dvec3 origin; // world position of the relative coordinate system origin
|
||||
geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer
|
||||
};
|
||||
|
||||
// methods
|
||||
// restores content of the node from provded input stream
|
||||
lines_node &
|
||||
deserialize( cParser &Input, scene::node_data const &Nodedata );
|
||||
// adds content of provided node to already enclosed geometry. returns: true if merge could be performed
|
||||
bool
|
||||
merge( lines_node &Lines );
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
create_geometry( geometrybank_handle const &Bank );
|
||||
// calculates shape's bounding radius
|
||||
void
|
||||
compute_radius();
|
||||
// set visibility
|
||||
void
|
||||
visible( bool State ) {
|
||||
m_data.visible = State; }
|
||||
// set origin point
|
||||
void
|
||||
origin( glm::dvec3 Origin ) {
|
||||
m_data.origin = Origin; }
|
||||
// data access
|
||||
linesnode_data const &
|
||||
data() const {
|
||||
return m_data; }
|
||||
|
||||
private:
|
||||
// members
|
||||
std::string m_name;
|
||||
linesnode_data m_data;
|
||||
};
|
||||
|
||||
/*
|
||||
// holds geometry for specific piece of track/road/waterway
|
||||
class path_node {
|
||||
|
||||
friend class basic_region; // region might want to modify node content when it's being inserted
|
||||
|
||||
public:
|
||||
// types
|
||||
// TODO: enable after track class refactoring
|
||||
struct pathnode_data {
|
||||
// placement and visibility
|
||||
bounding_area area; // bounding area, in world coordinates
|
||||
bool visible { true }; // visibility flag
|
||||
// material data
|
||||
material_handle material_1 { 0 };
|
||||
material_handle material_2 { 0 };
|
||||
lighting_data lighting;
|
||||
TEnvironmentType environment { e_flat };
|
||||
// geometry data
|
||||
std::vector<world_vertex> vertices; // world space source data of the geometry
|
||||
glm::dvec3 origin; // world position of the relative coordinate system origin
|
||||
using geometryhandle_sequence = std::vector<geometry_handle>;
|
||||
geometryhandle_sequence geometry_1; // geometry chunks textured with texture 1
|
||||
geometryhandle_sequence geometry_2; // geometry chunks textured with texture 2
|
||||
};
|
||||
// methods
|
||||
// restores content of the node from provded input stream
|
||||
// TODO: implement
|
||||
path_node &
|
||||
deserialize( cParser &Input, node_data const &Nodedata );
|
||||
// binds specified track to the node
|
||||
// TODO: remove after track class refactoring
|
||||
void
|
||||
path( TTrack *Path ) {
|
||||
m_path = Path; }
|
||||
TTrack *
|
||||
path() {
|
||||
return m_path; }
|
||||
|
||||
private:
|
||||
// members
|
||||
|
||||
// // TODO: enable after track class refactoring
|
||||
// pathnode_data m_data;
|
||||
|
||||
TTrack * m_path;
|
||||
};
|
||||
*/
|
||||
/*
|
||||
// holds reference to memory cell
|
||||
class memorycell_node {
|
||||
|
||||
friend class basic_region; // region might want to modify node content when it's being inserted
|
||||
|
||||
public:
|
||||
// types
|
||||
struct memorynode_data {
|
||||
// placement and visibility
|
||||
bounding_area area; // bounding area, in world coordinates
|
||||
bool visible { false }; // visibility flag
|
||||
};
|
||||
// methods
|
||||
// restores content of the node from provded input stream
|
||||
// TODO: implement
|
||||
memory_node &
|
||||
deserialize( cParser &Input, node_data const &Nodedata );
|
||||
void
|
||||
cell( TMemCell *Cell ) {
|
||||
m_memorycell = Cell; }
|
||||
TMemCell *
|
||||
cell() {
|
||||
return m_memorycell; }
|
||||
|
||||
private:
|
||||
// members
|
||||
memorynode_data m_data;
|
||||
TMemCell * m_memorycell;
|
||||
};
|
||||
*/
|
||||
} // scene
|
||||
|
||||
namespace editor {
|
||||
|
||||
// base interface for nodes which can be actvated in scenario editor
|
||||
struct basic_node {
|
||||
|
||||
public:
|
||||
// constructor
|
||||
basic_node() = default; // TODO: remove after refactor
|
||||
basic_node( scene::node_data const &Nodedata );
|
||||
// destructor
|
||||
virtual ~basic_node() = default;
|
||||
// methods
|
||||
std::string const &
|
||||
name() const {
|
||||
return m_name; }
|
||||
void
|
||||
location( glm::dvec3 const Location ) {
|
||||
m_area.center = Location; }
|
||||
glm::dvec3 const &
|
||||
location() const {
|
||||
return m_area.center; };
|
||||
float const &
|
||||
radius();
|
||||
void
|
||||
visible( bool const Visible ) {
|
||||
m_visible = Visible; }
|
||||
bool
|
||||
visible() const {
|
||||
return m_visible; }
|
||||
|
||||
protected:
|
||||
// methods
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
virtual void radius_();
|
||||
// members
|
||||
scene::bounding_area m_area;
|
||||
bool m_visible { true };
|
||||
double m_rangesquaredmin { 0.0 }; // visibility range, min
|
||||
double m_rangesquaredmax { 0.0 }; // visibility range, max
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
} // editor
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
876
simulation.cpp
Normal file
876
simulation.cpp
Normal file
@@ -0,0 +1,876 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "simulation.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
#include "uilayer.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
state_manager State;
|
||||
event_manager Events;
|
||||
memory_table Memory;
|
||||
path_table Paths;
|
||||
traction_table Traction;
|
||||
powergridsource_table Powergrid;
|
||||
instance_table Instances;
|
||||
vehicle_table Vehicles;
|
||||
light_array Lights;
|
||||
lua Lua;
|
||||
|
||||
scene::basic_region *Region { nullptr };
|
||||
|
||||
bool
|
||||
state_manager::deserialize( std::string const &Scenariofile ) {
|
||||
|
||||
// TODO: move initialization to separate routine so we can reuse it
|
||||
SafeDelete( Region );
|
||||
Region = new scene::basic_region();
|
||||
|
||||
// TODO: check first for presence of serialized binary files
|
||||
// if this fails, fall back on the legacy text format
|
||||
scene::scratch_data importscratchpad;
|
||||
importscratchpad.binary.terrain = Region->deserialize( Scenariofile );
|
||||
// NOTE: for the time being import from text format is a given, since we don't have full binary serialization
|
||||
cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global::asCurrentSceneryPath, Global::bLoadTraction );
|
||||
|
||||
if( false == scenarioparser.ok() ) { return false; }
|
||||
|
||||
deserialize( scenarioparser, importscratchpad );
|
||||
// if we didn't find usable binary version of the scenario files, create them now for future use
|
||||
if( false == importscratchpad.binary.terrain ) { Region->serialize( Scenariofile ); }
|
||||
|
||||
Global::iPause &= ~0x10; // koniec pauzy wczytywania
|
||||
return true;
|
||||
}
|
||||
|
||||
// legacy method, calculates changes in simulation state over specified time
|
||||
void
|
||||
state_manager::update( double const Deltatime, int Iterationcount ) {
|
||||
// aktualizacja animacji krokiem FPS: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń
|
||||
if (Deltatime == 0.0) {
|
||||
// jeśli załączona jest pauza, to tylko obsłużyć ruch w kabinie trzeba
|
||||
return;
|
||||
}
|
||||
|
||||
auto const totaltime { Deltatime * Iterationcount };
|
||||
// NOTE: we perform animations first, as they can determine factors like contact with powergrid
|
||||
TAnimModel::AnimUpdate( totaltime ); // wykonanie zakolejkowanych animacji
|
||||
|
||||
simulation::Powergrid.update( totaltime );
|
||||
simulation::Vehicles.update( Deltatime, Iterationcount );
|
||||
}
|
||||
|
||||
// restores class data from provided stream
|
||||
void
|
||||
state_manager::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// prepare deserialization function table
|
||||
// since all methods use the same objects, we can have simple, hard-coded binds or lambdas for the task
|
||||
using deserializefunction = void(state_manager::*)(cParser &, scene::scratch_data &);
|
||||
std::vector<
|
||||
std::pair<
|
||||
std::string,
|
||||
deserializefunction> > functionlist = {
|
||||
{ "atmo", &state_manager::deserialize_atmo },
|
||||
{ "camera", &state_manager::deserialize_camera },
|
||||
{ "config", &state_manager::deserialize_config },
|
||||
{ "description", &state_manager::deserialize_description },
|
||||
{ "event", &state_manager::deserialize_event },
|
||||
{ "lua", &state_manager::deserialize_lua },
|
||||
{ "firstinit", &state_manager::deserialize_firstinit },
|
||||
{ "light", &state_manager::deserialize_light },
|
||||
{ "node", &state_manager::deserialize_node },
|
||||
{ "origin", &state_manager::deserialize_origin },
|
||||
{ "endorigin", &state_manager::deserialize_endorigin },
|
||||
{ "rotate", &state_manager::deserialize_rotate },
|
||||
{ "sky", &state_manager::deserialize_sky },
|
||||
{ "test", &state_manager::deserialize_test },
|
||||
{ "time", &state_manager::deserialize_time },
|
||||
{ "trainset", &state_manager::deserialize_trainset },
|
||||
{ "endtrainset", &state_manager::deserialize_endtrainset } };
|
||||
using deserializefunctionbind = std::function<void()>;
|
||||
std::unordered_map<
|
||||
std::string,
|
||||
deserializefunctionbind> functionmap;
|
||||
for( auto &function : functionlist ) {
|
||||
functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( Scratchpad ) ) );
|
||||
}
|
||||
|
||||
// deserialize content from the provided input
|
||||
auto
|
||||
timelast { std::chrono::steady_clock::now() },
|
||||
timenow { timelast };
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
while( false == token.empty() ) {
|
||||
|
||||
auto lookup = functionmap.find( token );
|
||||
if( lookup != functionmap.end() ) {
|
||||
lookup->second();
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad scenario: unexpected token \"" + token + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
|
||||
}
|
||||
|
||||
timenow = std::chrono::steady_clock::now();
|
||||
if( std::chrono::duration_cast<std::chrono::milliseconds>( timenow - timelast ).count() >= 200 ) {
|
||||
timelast = timenow;
|
||||
glfwPollEvents();
|
||||
UILayer.set_progress( Input.getProgress(), Input.getFullProgress() );
|
||||
GfxRenderer.Render();
|
||||
}
|
||||
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
|
||||
if( false == Scratchpad.initialized ) {
|
||||
// manually perform scenario initialization
|
||||
deserialize_firstinit( Input, Scratchpad );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// NOTE: parameter system needs some decent replacement, but not worth the effort if we're moving to built-in editor
|
||||
// atmosphere color; legacy parameter, no longer used
|
||||
Input.getTokens( 3 );
|
||||
// fog range
|
||||
Input.getTokens( 2 );
|
||||
Input
|
||||
>> Global::fFogStart
|
||||
>> Global::fFogEnd;
|
||||
|
||||
if( Global::fFogEnd > 0.0 ) {
|
||||
// fog colour; optional legacy parameter, no longer used
|
||||
Input.getTokens( 3 );
|
||||
}
|
||||
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
if( token != "endatmo" ) {
|
||||
// optional overcast parameter
|
||||
Global::Overcast = clamp( std::stof( token ), 0.f, 1.f );
|
||||
}
|
||||
while( ( false == token.empty() )
|
||||
&& ( token != "endatmo" ) ) {
|
||||
// anything else left in the section has no defined meaning
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
glm::dvec3 xyz, abc;
|
||||
int i = -1, into = -1; // do której definicji kamery wstawić
|
||||
std::string token;
|
||||
do { // opcjonalna siódma liczba określa numer kamery, a kiedyś były tylko 3
|
||||
Input.getTokens();
|
||||
Input >> token;
|
||||
switch( ++i ) { // kiedyś camera miało tylko 3 współrzędne
|
||||
case 0: { xyz.x = atof( token.c_str() ); break; }
|
||||
case 1: { xyz.y = atof( token.c_str() ); break; }
|
||||
case 2: { xyz.z = atof( token.c_str() ); break; }
|
||||
case 3: { abc.x = atof( token.c_str() ); break; }
|
||||
case 4: { abc.y = atof( token.c_str() ); break; }
|
||||
case 5: { abc.z = atof( token.c_str() ); break; }
|
||||
case 6: { into = atoi( token.c_str() ); break; } // takie sobie, bo można wpisać -1
|
||||
default: { break; }
|
||||
}
|
||||
} while( token.compare( "endcamera" ) != 0 );
|
||||
if( into < 0 )
|
||||
into = ++Global::iCameraLast;
|
||||
if( into < 10 ) { // przepisanie do odpowiedniego miejsca w tabelce
|
||||
Global::FreeCameraInit[ into ] = xyz;
|
||||
Global::FreeCameraInitAngle[ into ] =
|
||||
Math3D::vector3(
|
||||
glm::radians( abc.x ),
|
||||
glm::radians( abc.y ),
|
||||
glm::radians( abc.z ) );
|
||||
Global::iCameraLast = into; // numer ostatniej
|
||||
}
|
||||
/*
|
||||
// cleaned up version of the above.
|
||||
// NOTE: no longer supports legacy mode where some parameters were optional
|
||||
Input.getTokens( 7 );
|
||||
glm::vec3
|
||||
position,
|
||||
rotation;
|
||||
int index;
|
||||
Input
|
||||
>> position.x
|
||||
>> position.y
|
||||
>> position.z
|
||||
>> rotation.x
|
||||
>> rotation.y
|
||||
>> rotation.z
|
||||
>> index;
|
||||
|
||||
skip_until( Input, "endcamera" );
|
||||
|
||||
// TODO: finish this
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// config parameters (re)definition
|
||||
Global::ConfigParse( Input );
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_description( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// legacy section, never really used;
|
||||
skip_until( Input, "enddescription" );
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_event( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// TODO: refactor event class and its de/serialization. do offset and rotation after deserialization is done
|
||||
auto *event = new TEvent();
|
||||
Math3D::vector3 offset = (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
Math3D::vector3() :
|
||||
Math3D::vector3(
|
||||
Scratchpad.location.offset.top().x,
|
||||
Scratchpad.location.offset.top().y,
|
||||
Scratchpad.location.offset.top().z ) );
|
||||
event->Load( &Input, offset );
|
||||
|
||||
if( false == simulation::Events.insert( event ) ) {
|
||||
delete event;
|
||||
}
|
||||
}
|
||||
|
||||
void state_manager::deserialize_lua( cParser &Input, scene::scratch_data &Scratchpad )
|
||||
{
|
||||
Input.getTokens(1, false);
|
||||
std::string file;
|
||||
Input >> file;
|
||||
simulation::Lua.interpret(Global::asCurrentSceneryPath + file);
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( true == Scratchpad.initialized ) { return; }
|
||||
|
||||
simulation::Paths.InitTracks();
|
||||
simulation::Traction.InitTraction();
|
||||
simulation::Events.InitEvents();
|
||||
simulation::Events.InitLaunchers();
|
||||
simulation::Memory.InitCells();
|
||||
|
||||
Scratchpad.initialized = true;
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// legacy section, no longer used nor supported;
|
||||
skip_until( Input, "endlight" );
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
auto const inputline = Input.Line(); // cache in case we need to report error
|
||||
|
||||
scene::node_data nodedata;
|
||||
// common data and node type indicator
|
||||
Input.getTokens( 4 );
|
||||
Input
|
||||
>> nodedata.range_max
|
||||
>> nodedata.range_min
|
||||
>> nodedata.name
|
||||
>> nodedata.type;
|
||||
// type-based deserialization. not elegant but it'll do
|
||||
if( nodedata.type == "dynamic" ) {
|
||||
|
||||
auto *vehicle { deserialize_dynamic( Input, Scratchpad, nodedata ) };
|
||||
// vehicle import can potentially fail
|
||||
if( vehicle == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Vehicles.insert( vehicle ) ) {
|
||||
|
||||
ErrorLog( "Bad scenario: vehicle with duplicate name \"" + vehicle->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
|
||||
if( ( vehicle->MoverParameters->CategoryFlag == 1 ) // trains only
|
||||
&& ( ( vehicle->MoverParameters->SecuritySystem.SystemType != 0 )
|
||||
|| ( vehicle->MoverParameters->SandCapacity > 0.0 ) ) ) {
|
||||
// we check for presence of security system or sand load, as a way to determine whether the vehicle is a controllable engine
|
||||
// NOTE: this isn't 100% precise, e.g. middle EZT module comes with security system, while it has no lights, and some engines
|
||||
// don't have security systems fitted
|
||||
simulation::Lights.insert( vehicle );
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "track" ) {
|
||||
|
||||
auto *path { deserialize_path( Input, Scratchpad, nodedata ) };
|
||||
// duplicates of named tracks are currently experimentally allowed
|
||||
if( false == simulation::Paths.insert( path ) ) {
|
||||
ErrorLog( "Bad scenario: track with duplicate name \"" + path->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
/*
|
||||
delete path;
|
||||
delete pathnode;
|
||||
*/
|
||||
}
|
||||
simulation::Region->insert_path( path, Scratchpad );
|
||||
}
|
||||
else if( nodedata.type == "traction" ) {
|
||||
|
||||
auto *traction { deserialize_traction( Input, Scratchpad, nodedata ) };
|
||||
// traction loading is optional
|
||||
if( traction == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Traction.insert( traction ) ) {
|
||||
ErrorLog( "Bad scenario: traction piece with duplicate name \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert_traction( traction, Scratchpad );
|
||||
}
|
||||
else if( nodedata.type == "tractionpowersource" ) {
|
||||
|
||||
auto *powersource { deserialize_tractionpowersource( Input, Scratchpad, nodedata ) };
|
||||
// traction loading is optional
|
||||
if( powersource == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Powergrid.insert( powersource ) ) {
|
||||
ErrorLog( "Bad scenario: power grid source with duplicate name \"" + powersource->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
/*
|
||||
// TODO: implement this
|
||||
simulation::Region.insert_powersource( powersource, Scratchpad );
|
||||
*/
|
||||
}
|
||||
else if( nodedata.type == "model" ) {
|
||||
|
||||
if( nodedata.range_min < 0.0 ) {
|
||||
// convert and import 3d terrain
|
||||
auto *instance { deserialize_model( Input, Scratchpad, nodedata ) };
|
||||
// model import can potentially fail
|
||||
if( instance == nullptr ) { return; }
|
||||
// go through submodels, and import them as shapes
|
||||
auto const cellcount = instance->TerrainCount() + 1; // zliczenie submodeli
|
||||
for( auto i = 1; i < cellcount; ++i ) {
|
||||
auto *submodel = instance->TerrainSquare( i - 1 );
|
||||
simulation::Region->insert_shape(
|
||||
scene::shape_node().convert( submodel ),
|
||||
Scratchpad,
|
||||
false );
|
||||
// if there's more than one group of triangles in the cell they're held as children of the primary submodel
|
||||
submodel = submodel->ChildGet();
|
||||
while( submodel != nullptr ) {
|
||||
simulation::Region->insert_shape(
|
||||
scene::shape_node().convert( submodel ),
|
||||
Scratchpad,
|
||||
false );
|
||||
submodel = submodel->NextGet();
|
||||
}
|
||||
}
|
||||
// with the import done we can get rid of the source model
|
||||
delete instance;
|
||||
}
|
||||
else {
|
||||
// regular instance of 3d mesh
|
||||
auto *instance { deserialize_model( Input, Scratchpad, nodedata ) };
|
||||
// model import can potentially fail
|
||||
if( instance == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Instances.insert( instance ) ) {
|
||||
ErrorLog( "Bad scenario: 3d model instance with duplicate name \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert_instance( instance, Scratchpad );
|
||||
}
|
||||
}
|
||||
else if( ( nodedata.type == "triangles" )
|
||||
|| ( nodedata.type == "triangle_strip" )
|
||||
|| ( nodedata.type == "triangle_fan" ) ) {
|
||||
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
|
||||
simulation::Region->insert_shape(
|
||||
scene::shape_node().deserialize(
|
||||
Input, nodedata ),
|
||||
Scratchpad,
|
||||
true );
|
||||
}
|
||||
else {
|
||||
// all shapes were already loaded from the binary version of the file
|
||||
skip_until( Input, "endtri" );
|
||||
}
|
||||
}
|
||||
else if( ( nodedata.type == "lines" )
|
||||
|| ( nodedata.type == "line_strip" )
|
||||
|| ( nodedata.type == "line_loop" ) ) {
|
||||
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
|
||||
simulation::Region->insert_lines(
|
||||
scene::lines_node().deserialize(
|
||||
Input, nodedata ),
|
||||
Scratchpad );
|
||||
}
|
||||
else {
|
||||
// all lines were already loaded from the binary version of the file
|
||||
skip_until( Input, "endline" );
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "memcell" ) {
|
||||
|
||||
auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Memory.insert( memorycell ) ) {
|
||||
ErrorLog( "Bad scenario: memory cell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
/*
|
||||
// TODO: implement this
|
||||
simulation::Region.insert_memorycell( memorycell, Scratchpad );
|
||||
*/
|
||||
}
|
||||
else if( nodedata.type == "eventlauncher" ) {
|
||||
|
||||
auto *eventlauncher { deserialize_eventlauncher( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Events.insert( eventlauncher ) ) {
|
||||
ErrorLog( "Bad scenario: event launcher with duplicate name \"" + eventlauncher->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
// 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 if( nodedata.type == "sound" ) {
|
||||
|
||||
auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) };
|
||||
simulation::Region->insert_sound( sound, Scratchpad );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
glm::dvec3 offset;
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> offset.x
|
||||
>> offset.y
|
||||
>> offset.z;
|
||||
// sumowanie całkowitego przesunięcia
|
||||
Scratchpad.location.offset.emplace(
|
||||
offset + (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
glm::dvec3() :
|
||||
Scratchpad.location.offset.top() ) );
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( false == Scratchpad.location.offset.empty() ) {
|
||||
Scratchpad.location.offset.pop();
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad origin: endorigin instruction with empty origin stack in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> Scratchpad.location.rotation.x
|
||||
>> Scratchpad.location.rotation.y
|
||||
>> Scratchpad.location.rotation.z;
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// sky model
|
||||
Input.getTokens( 1 );
|
||||
Input
|
||||
>> Global::asSky;
|
||||
// anything else left in the section has no defined meaning
|
||||
skip_until( Input, "endsky" );
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_test( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// legacy section, no longer supported;
|
||||
skip_until( Input, "endtest" );
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_time( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// current scenario time
|
||||
cParser timeparser( Input.getToken<std::string>() );
|
||||
timeparser.getTokens( 2, false, ":" );
|
||||
auto &time = simulation::Time.data();
|
||||
timeparser
|
||||
>> time.wHour
|
||||
>> time.wMinute;
|
||||
|
||||
// remaining sunrise and sunset parameters are no longer used, as they're now calculated dynamically
|
||||
// anything else left in the section has no defined meaning
|
||||
skip_until( Input, "endtime" );
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( true == Scratchpad.trainset.is_open ) {
|
||||
// shouldn't happen but if it does wrap up currently open trainset and report an error
|
||||
deserialize_endtrainset( Input, Scratchpad );
|
||||
ErrorLog( "Bad scenario: encountered nested trainset definitions in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() ) + ")" );
|
||||
}
|
||||
|
||||
Scratchpad.trainset = scene::scratch_data::trainset_data();
|
||||
Scratchpad.trainset.is_open = true;
|
||||
|
||||
Input.getTokens( 4 );
|
||||
Input
|
||||
>> Scratchpad.trainset.name
|
||||
>> Scratchpad.trainset.track
|
||||
>> Scratchpad.trainset.offset
|
||||
>> Scratchpad.trainset.velocity;
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( ( false == Scratchpad.trainset.is_open )
|
||||
|| ( true == Scratchpad.trainset.vehicles.empty() ) ) {
|
||||
// not bloody likely but we better check for it just the same
|
||||
ErrorLog( "Bad trainset: empty trainset defined in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
|
||||
Scratchpad.trainset.is_open = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::size_t vehicleindex { 0 };
|
||||
for( auto *vehicle : Scratchpad.trainset.vehicles ) {
|
||||
// go through list of vehicles in the trainset, coupling them together and checking for potential driver
|
||||
if( ( vehicle->Mechanik != nullptr )
|
||||
&& ( vehicle->Mechanik->Primary() ) ) {
|
||||
// primary driver will receive the timetable for this trainset
|
||||
Scratchpad.trainset.driver = vehicle;
|
||||
}
|
||||
if( vehicleindex > 0 ) {
|
||||
// from second vehicle on couple it with the previous one
|
||||
Scratchpad.trainset.vehicles[ vehicleindex - 1 ]->AttachPrev(
|
||||
vehicle,
|
||||
Scratchpad.trainset.couplings[ vehicleindex - 1 ] );
|
||||
}
|
||||
++vehicleindex;
|
||||
}
|
||||
|
||||
if( Scratchpad.trainset.driver != nullptr ) {
|
||||
// if present, send timetable to the driver
|
||||
// wysłanie komendy "Timetable" ustawia odpowiedni tryb jazdy
|
||||
auto *controller = Scratchpad.trainset.driver->Mechanik;
|
||||
controller->DirectionInitial();
|
||||
controller->PutCommand(
|
||||
"Timetable:" + Scratchpad.trainset.name,
|
||||
Scratchpad.trainset.velocity,
|
||||
0,
|
||||
nullptr );
|
||||
}
|
||||
if( Scratchpad.trainset.couplings.back() == coupling::faux ) {
|
||||
// jeśli ostatni pojazd ma sprzęg 0 to założymy mu końcówki blaszane (jak AI się odpali, to sobie poprawi)
|
||||
Scratchpad.trainset.vehicles.back()->RaLightsSet( -1, TMoverParameters::light::rearendsignals );
|
||||
}
|
||||
// all done
|
||||
Scratchpad.trainset.is_open = false;
|
||||
}
|
||||
|
||||
// creates path and its wrapper, restoring class data from provided stream
|
||||
TTrack *
|
||||
state_manager::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
// TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done
|
||||
auto *track = new TTrack( Nodedata );
|
||||
Math3D::vector3 offset = (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
Math3D::vector3() :
|
||||
Math3D::vector3(
|
||||
Scratchpad.location.offset.top().x,
|
||||
Scratchpad.location.offset.top().y,
|
||||
Scratchpad.location.offset.top().z ) );
|
||||
track->Load( &Input, offset );
|
||||
|
||||
return track;
|
||||
}
|
||||
|
||||
TTraction *
|
||||
state_manager::deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
if( false == Global::bLoadTraction ) {
|
||||
skip_until( Input, "endtraction" );
|
||||
return nullptr;
|
||||
}
|
||||
// TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done
|
||||
auto *traction = new TTraction( Nodedata );
|
||||
auto offset = (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
glm::dvec3() :
|
||||
Scratchpad.location.offset.top() );
|
||||
traction->Load( &Input, offset );
|
||||
|
||||
return traction;
|
||||
}
|
||||
|
||||
TTractionPowerSource *
|
||||
state_manager::deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
if( false == Global::bLoadTraction ) {
|
||||
skip_until( Input, "end" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *powersource = new TTractionPowerSource( Nodedata );
|
||||
powersource->Load( &Input );
|
||||
// adjust location
|
||||
powersource->location( transform( powersource->location(), Scratchpad ) );
|
||||
|
||||
return powersource;
|
||||
}
|
||||
|
||||
TMemCell *
|
||||
state_manager::deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
auto *memorycell = new TMemCell( Nodedata );
|
||||
memorycell->Load( &Input );
|
||||
// adjust location
|
||||
memorycell->location( transform( memorycell->location(), Scratchpad ) );
|
||||
|
||||
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 ) {
|
||||
|
||||
glm::dvec3 location;
|
||||
glm::vec3 rotation;
|
||||
Input.getTokens( 4 );
|
||||
Input
|
||||
>> location.x
|
||||
>> location.y
|
||||
>> location.z
|
||||
>> rotation.y;
|
||||
|
||||
auto *instance = new TAnimModel( Nodedata );
|
||||
instance->RaAnglesSet( Scratchpad.location.rotation + rotation ); // dostosowanie do pochylania linii
|
||||
|
||||
if( false == instance->Load( &Input, false ) ) {
|
||||
// model nie wczytał się - ignorowanie node
|
||||
SafeDelete( instance );
|
||||
}
|
||||
instance->location( transform( location, Scratchpad ) );
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
TDynamicObject *
|
||||
state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
if( false == Scratchpad.trainset.is_open ) {
|
||||
// part of trainset data is used when loading standalone vehicles, so clear it just in case
|
||||
Scratchpad.trainset = scene::scratch_data::trainset_data();
|
||||
}
|
||||
auto const inputline { Input.Line() }; // cache in case of errors
|
||||
// basic attributes
|
||||
auto const datafolder { Input.getToken<std::string>() };
|
||||
auto const skinfile { Input.getToken<std::string>() };
|
||||
auto const mmdfile { Input.getToken<std::string>() };
|
||||
auto const pathname = (
|
||||
Scratchpad.trainset.is_open ?
|
||||
Scratchpad.trainset.track :
|
||||
Input.getToken<std::string>() );
|
||||
auto const offset { Input.getToken<double>( false ) };
|
||||
auto const drivertype { Input.getToken<std::string>() };
|
||||
auto const couplingdata = (
|
||||
Scratchpad.trainset.is_open ?
|
||||
Input.getToken<std::string>() :
|
||||
"3" );
|
||||
auto const velocity = (
|
||||
Scratchpad.trainset.is_open ?
|
||||
Scratchpad.trainset.velocity :
|
||||
Input.getToken<float>( false ) );
|
||||
// extract coupling type and optional parameters
|
||||
auto const couplingdatawithparams = couplingdata.find( '.' );
|
||||
auto coupling = (
|
||||
couplingdatawithparams != std::string::npos ?
|
||||
std::atoi( couplingdata.substr( 0, couplingdatawithparams ).c_str() ) :
|
||||
std::atoi( couplingdata.c_str() ) );
|
||||
if( coupling < 0 ) {
|
||||
// sprzęg zablokowany (pojazdy nierozłączalne przy manewrach)
|
||||
coupling = ( -coupling ) | coupling::permanent;
|
||||
}
|
||||
if( ( offset != -1.0 )
|
||||
&& ( std::abs( offset ) > 0.5 ) ) { // maksymalna odległość między sprzęgami - do przemyślenia
|
||||
// likwidacja sprzęgu, jeśli odległość zbyt duża - to powinno być uwzględniane w fizyce sprzęgów...
|
||||
coupling = coupling::faux;
|
||||
}
|
||||
auto const params = (
|
||||
couplingdatawithparams != std::string::npos ?
|
||||
couplingdata.substr( couplingdatawithparams + 1 ) :
|
||||
"" );
|
||||
// load amount and type
|
||||
auto loadcount { Input.getToken<int>( false ) };
|
||||
auto loadtype = (
|
||||
loadcount ?
|
||||
Input.getToken<std::string>() :
|
||||
"" );
|
||||
if( loadtype == "enddynamic" ) {
|
||||
// idiotoodporność: ładunek bez podanego typu nie liczy się jako ładunek
|
||||
loadcount = 0;
|
||||
loadtype = "";
|
||||
}
|
||||
|
||||
auto *path = simulation::Paths.find( pathname );
|
||||
if( path == nullptr ) {
|
||||
|
||||
ErrorLog( "Bad scenario: vehicle \"" + Nodedata.name + "\" placed on nonexistent path \"" + pathname + "\" in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
skip_until( Input, "enddynamic" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( ( true == Scratchpad.trainset.vehicles.empty() ) // jeśli pierwszy pojazd,
|
||||
&& ( false == path->asEvent0Name.empty() ) // tor ma Event0
|
||||
&& ( std::abs( velocity ) <= 1.f ) // a skład stoi
|
||||
&& ( Scratchpad.trainset.offset >= 0.0 ) // ale może nie sięgać na owy tor
|
||||
&& ( Scratchpad.trainset.offset < 8.0 ) ) { // i raczej nie sięga
|
||||
// przesuwamy około pół EU07 dla wstecznej zgodności
|
||||
Scratchpad.trainset.offset = 8.0;
|
||||
}
|
||||
|
||||
auto *vehicle = new TDynamicObject();
|
||||
|
||||
auto const length =
|
||||
vehicle->Init(
|
||||
Nodedata.name,
|
||||
datafolder, skinfile, mmdfile,
|
||||
path,
|
||||
( offset == -1.0 ?
|
||||
Scratchpad.trainset.offset :
|
||||
Scratchpad.trainset.offset - offset ),
|
||||
drivertype,
|
||||
velocity,
|
||||
Scratchpad.trainset.name,
|
||||
loadcount, loadtype,
|
||||
( offset == -1.0 ),
|
||||
params );
|
||||
|
||||
if( length != 0.0 ) { // zero oznacza błąd
|
||||
// przesunięcie dla kolejnego, minus bo idziemy w stronę punktu 1
|
||||
Scratchpad.trainset.offset -= length;
|
||||
// automatically establish permanent connections for couplers which specify them in their definitions
|
||||
if( ( coupling != 0 )
|
||||
&& ( vehicle->MoverParameters->Couplers[ ( offset == -1.0 ? 0 : 1 ) ].AllowedFlag & coupling::permanent ) ) {
|
||||
coupling |= coupling::permanent;
|
||||
}
|
||||
if( true == Scratchpad.trainset.is_open ) {
|
||||
Scratchpad.trainset.vehicles.emplace_back( vehicle );
|
||||
Scratchpad.trainset.couplings.emplace_back( coupling );
|
||||
}
|
||||
}
|
||||
else {
|
||||
delete vehicle;
|
||||
skip_until( Input, "enddynamic" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto const destination { Input.getToken<std::string>() };
|
||||
if( destination != "enddynamic" ) {
|
||||
// optional vehicle destination parameter
|
||||
vehicle->asDestination = Input.getToken<std::string>();
|
||||
skip_until( Input, "enddynamic" );
|
||||
}
|
||||
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
sound *
|
||||
state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
glm::dvec3 location;
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> location.x
|
||||
>> location.y
|
||||
>> location.z;
|
||||
// adjust location
|
||||
location = transform( location, Scratchpad );
|
||||
|
||||
auto const soundname { Input.getToken<std::string>() };
|
||||
auto *sound = sound_man->create_text_sound(soundname);
|
||||
sound->position((glm::vec3)location).dist(Nodedata.range_max);
|
||||
skip_until( Input, "endsound" );
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
// skips content of stream until specified token
|
||||
void
|
||||
state_manager::skip_until( cParser &Input, std::string const &Token ) {
|
||||
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
while( ( false == token.empty() )
|
||||
&& ( token != Token ) ) {
|
||||
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
// transforms provided location by specifed rotation and offset
|
||||
glm::dvec3
|
||||
state_manager::transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ) {
|
||||
|
||||
if( Scratchpad.location.rotation != glm::vec3( 0, 0, 0 ) ) {
|
||||
auto const rotation = glm::radians( Scratchpad.location.rotation );
|
||||
Location = glm::rotateY<double>( Location, rotation.y ); // Ra 2014-11: uwzględnienie rotacji
|
||||
}
|
||||
if( false == Scratchpad.location.offset.empty() ) {
|
||||
Location += Scratchpad.location.offset.top();
|
||||
}
|
||||
return Location;
|
||||
}
|
||||
|
||||
} // simulation
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
92
simulation.h
Normal file
92
simulation.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "parser.h"
|
||||
#include "scene.h"
|
||||
#include "event.h"
|
||||
#include "MemCell.h"
|
||||
#include "EvLaunch.h"
|
||||
#include "Track.h"
|
||||
#include "Traction.h"
|
||||
#include "TractionPower.h"
|
||||
#include "sound.h"
|
||||
#include "AnimModel.h"
|
||||
#include "DynObj.h"
|
||||
#include "Driver.h"
|
||||
#include "lightarray.h"
|
||||
#include "Event.h"
|
||||
#include "lua.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
class state_manager {
|
||||
|
||||
public:
|
||||
// types
|
||||
|
||||
// methods
|
||||
// legacy method, calculates changes in simulation state over specified time
|
||||
void
|
||||
update( double dt, int iter );
|
||||
bool
|
||||
deserialize( std::string const &Scenariofile );
|
||||
|
||||
private:
|
||||
// methods
|
||||
// restores class data from provided stream
|
||||
void deserialize( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_config( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_description( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_event( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_lua( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_light( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_node( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_test( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_time( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
TTrack * deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TTraction * deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TTractionPowerSource * deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
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 );
|
||||
sound * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
// skips content of stream until specified token
|
||||
void skip_until( cParser &Input, std::string const &Token );
|
||||
// transforms provided location by specifed rotation and offset
|
||||
glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad );
|
||||
};
|
||||
|
||||
extern state_manager State;
|
||||
extern event_manager Events;
|
||||
extern memory_table Memory;
|
||||
extern path_table Paths;
|
||||
extern traction_table Traction;
|
||||
extern powergridsource_table Powergrid;
|
||||
extern instance_table Instances;
|
||||
extern vehicle_table Vehicles;
|
||||
extern light_array Lights;
|
||||
extern lua Lua;
|
||||
|
||||
extern scene::basic_region *Region;
|
||||
|
||||
} // simulation
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -348,6 +348,13 @@ sound& sound::position(glm::vec3 p)
|
||||
return *this;
|
||||
}
|
||||
|
||||
glm::vec3 sound::location()
|
||||
{
|
||||
if (mode == global)
|
||||
throw std::runtime_error("sound: bad state, no position");
|
||||
return pos;
|
||||
}
|
||||
|
||||
sound& sound::position(Math3D::vector3 const &pos)
|
||||
{
|
||||
position((glm::vec3)glm::make_vec3(&pos.x));
|
||||
|
||||
2
sound.h
2
sound.h
@@ -13,6 +13,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include "dumb3d.h"
|
||||
#include "parser.h"
|
||||
#include "Names.h"
|
||||
|
||||
class load_error : public std::runtime_error
|
||||
{
|
||||
@@ -70,6 +71,7 @@ public:
|
||||
|
||||
virtual ~sound();
|
||||
|
||||
glm::vec3 location(); //get position
|
||||
virtual bool is_playing() = 0;
|
||||
|
||||
virtual void play() = 0;
|
||||
|
||||
1
stdafx.h
1
stdafx.h
@@ -49,6 +49,7 @@
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <tuple>
|
||||
#include <cctype>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
|
||||
@@ -70,6 +70,8 @@ static std::unordered_map<std::string, std::string> m_cabcontrols = {
|
||||
{ "pantalloff_sw:", "all pantographs" },
|
||||
{ "pantselected_sw:", "selected pantograph" },
|
||||
{ "pantselectedoff_sw:", "selected pantograph" },
|
||||
{ "pantcompressor_sw:", "pantograph compressor" },
|
||||
{ "pantcompressorvalve_sw:", "pantograph 3 way valve" },
|
||||
{ "trainheating_sw:", "heating" },
|
||||
{ "signalling_sw:", "braking indicator" },
|
||||
{ "door_signalling_sw:", "door locking" },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define VERSION_MAJOR 17
|
||||
#define VERSION_MINOR 914
|
||||
#define VERSION_MINOR 1027
|
||||
#define VERSION_REVISION 0
|
||||
|
||||
33
vertex.cpp
Normal file
33
vertex.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "vertex.h"
|
||||
|
||||
template <>
|
||||
world_vertex &
|
||||
world_vertex::operator+=( world_vertex const &Right ) {
|
||||
|
||||
position += Right.position;
|
||||
normal += Right.normal;
|
||||
texture += Right.texture;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <>
|
||||
world_vertex &
|
||||
world_vertex::operator*=( world_vertex const &Right ) {
|
||||
|
||||
position *= Right.position;
|
||||
normal *= Right.normal;
|
||||
texture *= Right.texture;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
87
vertex.h
Normal file
87
vertex.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include "usefull.h"
|
||||
|
||||
// geometry vertex with double precision position
|
||||
struct world_vertex {
|
||||
|
||||
// members
|
||||
glm::dvec3 position;
|
||||
glm::vec3 normal;
|
||||
glm::vec2 texture;
|
||||
|
||||
// overloads
|
||||
// operator+
|
||||
template <typename Scalar_>
|
||||
world_vertex &
|
||||
operator+=( Scalar_ const &Right ) {
|
||||
position += Right;
|
||||
normal += Right;
|
||||
texture += Right;
|
||||
return *this; }
|
||||
template <typename Scalar_>
|
||||
friend
|
||||
world_vertex
|
||||
operator+( world_vertex Left, Scalar_ const &Right ) {
|
||||
Left += Right;
|
||||
return Left; }
|
||||
// operator*
|
||||
template <typename Scalar_>
|
||||
world_vertex &
|
||||
operator*=( Scalar_ const &Right ) {
|
||||
position *= Right;
|
||||
normal *= Right;
|
||||
texture *= Right;
|
||||
return *this; }
|
||||
template <typename Type_>
|
||||
friend
|
||||
world_vertex
|
||||
operator*( world_vertex Left, Type_ const &Right ) {
|
||||
Left *= Right;
|
||||
return Left; }
|
||||
// methods
|
||||
// wyliczenie współrzędnych i mapowania punktu na środku odcinka v1<->v2
|
||||
void
|
||||
set_half( world_vertex const &Vertex1, world_vertex const &Vertex2 ) {
|
||||
*this =
|
||||
interpolate(
|
||||
Vertex1,
|
||||
Vertex2,
|
||||
0.5 ); }
|
||||
// wyliczenie współrzędnych i mapowania punktu na odcinku v1<->v2
|
||||
void
|
||||
set_from_x( world_vertex const &Vertex1, world_vertex const &Vertex2, double const X ) {
|
||||
*this =
|
||||
interpolate(
|
||||
Vertex1,
|
||||
Vertex2,
|
||||
( X - Vertex1.position.x ) / ( Vertex2.position.x - Vertex1.position.x ) ); }
|
||||
// wyliczenie współrzędnych i mapowania punktu na odcinku v1<->v2
|
||||
void
|
||||
set_from_z( world_vertex const &Vertex1, world_vertex const &Vertex2, double const Z ) {
|
||||
*this =
|
||||
interpolate(
|
||||
Vertex1,
|
||||
Vertex2,
|
||||
( Z - Vertex1.position.z ) / ( Vertex2.position.z - Vertex1.position.z ) ); }
|
||||
};
|
||||
|
||||
template <>
|
||||
world_vertex &
|
||||
world_vertex::operator+=( world_vertex const &Right );
|
||||
|
||||
template <>
|
||||
world_vertex &
|
||||
world_vertex::operator*=( world_vertex const &Right );
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -63,7 +63,7 @@ LRESULT APIENTRY WndProc( HWND hWnd, // handle for this window
|
||||
// obsługa danych przesłanych przez program sterujący
|
||||
pDane = (PCOPYDATASTRUCT)lParam;
|
||||
if( pDane->dwData == MAKE_ID4('E', 'U', '0', '7')) // sygnatura danych
|
||||
World.OnCommandGet( (DaneRozkaz *)( pDane->lpData ) );
|
||||
World.OnCommandGet( ( multiplayer::DaneRozkaz *)( pDane->lpData ) );
|
||||
break;
|
||||
}
|
||||
case WM_KEYDOWN:
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#else
|
||||
#include <cinttypes>
|
||||
#define WORD uint16_t
|
||||
#define UINT uint32_t
|
||||
#define WPARAM uint64_t
|
||||
#define LPARAM uint64_t
|
||||
#define DWORD uint32_t
|
||||
#define LONG int32_t
|
||||
#define BYTE uint8_t
|
||||
|
||||
Reference in New Issue
Block a user