mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-23 13:19:19 +02:00
partial initial refactoring: events, memcells, tracks, models, traction; NOTE: debug mode broken, investigate
This commit is contained in:
@@ -406,23 +406,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()
|
||||
|
||||
87
AnimModel.h
87
AnimModel.h
@@ -21,13 +21,13 @@ http://mozilla.org/MPL/2.0/.
|
||||
const int iMaxNumLights = 8;
|
||||
|
||||
// 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
|
||||
@@ -118,55 +118,66 @@ 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; }
|
||||
// members
|
||||
static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania
|
||||
|
||||
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 { 0.25f }; // 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_manager : public basic_table<TAnimModel> {
|
||||
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -2957,12 +2957,6 @@ 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
|
||||
|
||||
908
Event.cpp
908
Event.cpp
@@ -14,7 +14,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Event.h"
|
||||
#include "event.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
#include "Usefull.h"
|
||||
@@ -23,6 +24,10 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "MemCell.h"
|
||||
#include "Ground.h"
|
||||
#include "McZapkie\mctools.h"
|
||||
#include "animmodel.h"
|
||||
#include "dynobj.h"
|
||||
#include "driver.h"
|
||||
#include "tractionpower.h"
|
||||
|
||||
TEvent::TEvent( std::string const &m ) :
|
||||
asNodeName( m )
|
||||
@@ -36,8 +41,8 @@ TEvent::TEvent( std::string const &m ) :
|
||||
}
|
||||
};
|
||||
|
||||
TEvent::~TEvent()
|
||||
{
|
||||
TEvent::~TEvent() {
|
||||
|
||||
switch (Type)
|
||||
{ // sprzątanie
|
||||
case tp_Multiple:
|
||||
@@ -56,14 +61,17 @@ TEvent::~TEvent()
|
||||
// SafeDeleteArray(Params[9].asText); //nie usuwać - nazwa jest zamieniana na wskaźnik do
|
||||
// submodelu
|
||||
if (Params[0].asInt == 4) // jeśli z pliku VMD
|
||||
delete[] Params[8].asPointer; // zwolnić obszar
|
||||
SafeDeleteArray( Params[8].asPointer ); // zwolnić obszar
|
||||
case tp_GetValues: // nic
|
||||
break;
|
||||
case tp_PutValues: // params[0].astext stores the token
|
||||
SafeDeleteArray( Params[ 0 ].asText );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
evJoined = NULL; // nie usuwać podczepionych tutaj
|
||||
evJoined = nullptr; // nie usuwać podczepionych tutaj
|
||||
|
||||
};
|
||||
|
||||
void TEvent::Init(){
|
||||
@@ -138,7 +146,7 @@ void TEvent::Conditions(cParser *parser, std::string s)
|
||||
}
|
||||
};
|
||||
|
||||
void TEvent::Load(cParser *parser, vector3 *org)
|
||||
void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
{
|
||||
std::string token;
|
||||
|
||||
@@ -294,12 +302,12 @@ void TEvent::Load(cParser *parser, vector3 *org)
|
||||
parser->getTokens(3);
|
||||
*parser >> Params[3].asdouble >> Params[4].asdouble >> Params[5].asdouble; // położenie
|
||||
// X,Y,Z
|
||||
if (org)
|
||||
if ( !(org == Math3D::vector3()) )
|
||||
{ // przesunięcie
|
||||
// tmp->pCenter.RotateY(aRotate.y/180.0*M_PI); //Ra 2014-11: uwzględnienie rotacji
|
||||
Params[3].asdouble += org->x; // współrzędne w scenerii
|
||||
Params[4].asdouble += org->y;
|
||||
Params[5].asdouble += org->z;
|
||||
Params[3].asdouble += org.x; // współrzędne w scenerii
|
||||
Params[4].asdouble += org.y;
|
||||
Params[5].asdouble += org.z;
|
||||
}
|
||||
// Params[12].asInt=0;
|
||||
parser->getTokens(1, false); // komendy 'case sensitive'
|
||||
@@ -679,16 +687,16 @@ double TEvent::ValueGet(int n)
|
||||
return 0.0; // inne eventy się nie liczą
|
||||
};
|
||||
|
||||
vector3 TEvent::PositionGet() const
|
||||
glm::dvec3 TEvent::PositionGet() const
|
||||
{ // pobranie współrzędnych eventu
|
||||
switch (Type)
|
||||
{ //
|
||||
case tp_GetValues:
|
||||
return Params[9].asMemCell->Position(); // współrzędne podłączonej komórki pamięci
|
||||
return Params[9].asMemCell->location(); // współrzędne podłączonej komórki pamięci
|
||||
case tp_PutValues:
|
||||
return vector3(Params[3].asdouble, Params[4].asdouble, Params[5].asdouble);
|
||||
return glm::dvec3(Params[3].asdouble, Params[4].asdouble, Params[5].asdouble);
|
||||
}
|
||||
return vector3(0, 0, 0); // inne eventy się nie liczą
|
||||
return glm::dvec3(0, 0, 0); // inne eventy się nie liczą
|
||||
};
|
||||
|
||||
bool TEvent::StopCommand()
|
||||
@@ -714,3 +722,875 @@ void TEvent::Append(TEvent *e)
|
||||
e->bEnabled = true; // ten doczepiony może być tylko kolejkowany
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
event_manager::~event_manager() {
|
||||
|
||||
for( auto *event : m_events ) {
|
||||
delete event;
|
||||
}
|
||||
}
|
||||
|
||||
// adds provided event to the collection. returns: true on success
|
||||
// TODO: return handle instead of pointer
|
||||
bool
|
||||
event_manager::insert( TEvent *Event ) {
|
||||
|
||||
if( Event->Type == tp_Unknown ) { return false; }
|
||||
|
||||
// najpierw sprawdzamy, czy nie ma, a potem dopisujemy
|
||||
auto lookup = m_eventmap.find( Event->asName );
|
||||
if( lookup != m_eventmap.end() ) {
|
||||
// duplicate of already existing event
|
||||
auto const size = Event->asName.size();
|
||||
// zawsze jeden znak co najmniej jest
|
||||
if( Event->asName[ 0 ] == '#' ) {
|
||||
// utylizacja duplikatu z krzyżykiem
|
||||
return false;
|
||||
}
|
||||
// tymczasowo wyjątki:
|
||||
else if( ( size > 8 )
|
||||
&& ( Event->asName.substr( 0, 9 ) == "lineinfo:" ) ) {
|
||||
// tymczasowa utylizacja duplikatów W5
|
||||
return false;
|
||||
}
|
||||
else if( ( size > 8 )
|
||||
&& ( Event->asName.substr( size - 8 ) == "_warning" ) ) {
|
||||
// tymczasowa utylizacja duplikatu z trąbieniem
|
||||
return false;
|
||||
}
|
||||
else if( ( size > 4 )
|
||||
&& ( Event->asName.substr( size - 4 ) == "_shp" ) ) {
|
||||
// nie podlegają logowaniu
|
||||
// tymczasowa utylizacja duplikatu SHP
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *duplicate = m_events[ lookup->second ];
|
||||
if( Global::bJoinEvents ) {
|
||||
// doczepka (taki wirtualny multiple bez warunków)
|
||||
duplicate->Append( Event );
|
||||
}
|
||||
else {
|
||||
// NOTE: somewhat convoluted way to deal with 'replacing' events without leaving dangling pointers
|
||||
// can be cleaned up if pointers to events were replaced with handles
|
||||
ErrorLog( "Bad event: encountered duplicated event, \"" + Event->asName + "\"" );
|
||||
duplicate->Append( Event ); // doczepka (taki wirtualny multiple bez warunków)
|
||||
// BUG: source of memory leak.
|
||||
// erasing original type of event prevents it from proper resource de-allocation on exit
|
||||
// TODO: mark ignored event with separate flag or ideally refactor the whole thing
|
||||
duplicate->Type = tp_Ignored; // dezaktywacja pierwotnego - taka proteza na wsteczną zgodność
|
||||
}
|
||||
}
|
||||
|
||||
m_events.emplace_back( Event );
|
||||
if( lookup == m_eventmap.end() ) {
|
||||
// if it's first event with such name, it's potential candidate for the execution queue
|
||||
m_eventmap.emplace( Event->asName, m_events.size() - 1 );
|
||||
if( ( Event->Type != tp_Ignored )
|
||||
&& ( Event->asName.find( "onstart" ) != std::string::npos ) ) {
|
||||
// event uruchamiany automatycznie po starcie
|
||||
AddToQuery( Event, nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// legacy method, returns pointer to specified event, or null
|
||||
TEvent *
|
||||
event_manager::FindEvent( std::string const &Name ) {
|
||||
|
||||
if( Name.empty() ) { return nullptr; }
|
||||
|
||||
auto const lookup = m_eventmap.find( Name );
|
||||
return (
|
||||
lookup != m_eventmap.end() ?
|
||||
m_events[ lookup->second ] :
|
||||
nullptr );
|
||||
}
|
||||
|
||||
// legacy method, inserts specified event in the event query
|
||||
bool
|
||||
event_manager::AddToQuery( TEvent *Event, TDynamicObject *Owner ) {
|
||||
|
||||
if( Event->bEnabled ) {
|
||||
// jeśli może być dodany do kolejki (nie używany w skanowaniu)
|
||||
if( !Event->iQueued ) // jeśli nie dodany jeszcze do kolejki
|
||||
{ // kolejka eventów jest posortowana względem (fStartTime)
|
||||
Event->Activator = Owner;
|
||||
if( ( Event->Type == tp_AddValues )
|
||||
&& ( Event->fDelay == 0.0 ) ) {
|
||||
// eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieś dodawanie
|
||||
// Ra: kopiowanie wykonania tu jest bez sensu, lepiej by było wydzielić funkcję
|
||||
// wykonującą eventy i ją wywołać
|
||||
if( EventConditon( Event ) ) { // teraz mogą być warunki do tych eventów
|
||||
Event->Params[ 5 ].asMemCell->UpdateValues(
|
||||
Event->Params[ 0 ].asText, Event->Params[ 1 ].asdouble,
|
||||
Event->Params[ 2 ].asdouble, Event->iFlags );
|
||||
if( Event->Params[ 6 ].asTrack ) { // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla
|
||||
// wszystkich 'dynamic' na danym torze
|
||||
for( auto dynamic : Event->Params[ 6 ].asTrack->Dynamics ) {
|
||||
Event->Params[ 5 ].asMemCell->PutCommand(
|
||||
dynamic->Mechanik,
|
||||
&Event->Params[ 4 ].nGroundNode->pCenter );
|
||||
}
|
||||
//if (DebugModeFlag)
|
||||
WriteLog(
|
||||
"EVENT EXECUTED" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": AddValues & Track command ( "
|
||||
+ std::string( Event->Params[ 0 ].asText ) + " "
|
||||
+ std::to_string( Event->Params[ 1 ].asdouble ) + " "
|
||||
+ std::to_string( Event->Params[ 2 ].asdouble ) + " )" );
|
||||
}
|
||||
//else if (DebugModeFlag)
|
||||
WriteLog(
|
||||
"EVENT EXECUTED" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": AddValues ( "
|
||||
+ std::string( Event->Params[ 0 ].asText ) + " "
|
||||
+ std::to_string( Event->Params[ 1 ].asdouble ) + " "
|
||||
+ std::to_string( Event->Params[ 2 ].asdouble ) + " )" );
|
||||
}
|
||||
// jeśli jest kolejny o takiej samej nazwie, to idzie do kolejki (and if there's no joint event it'll be set to null and processing will end here)
|
||||
do {
|
||||
Event = Event->evJoined;
|
||||
// NOTE: we could've received a new event from joint event above, so we need to check conditions just in case and discard the bad events
|
||||
// TODO: refactor this arrangement, it's hardly optimal
|
||||
} while( ( Event != nullptr )
|
||||
&& ( ( false == Event->bEnabled )
|
||||
|| ( Event->iQueued > 0 ) ) );
|
||||
}
|
||||
if( Event != nullptr ) {
|
||||
// standardowe dodanie do kolejki
|
||||
++Event->iQueued; // zabezpieczenie przed podwójnym dodaniem do kolejki
|
||||
WriteLog( "EVENT ADDED TO QUEUE" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": " + Event->asName );
|
||||
Event->fStartTime = std::abs( Event->fDelay ) + Timer::GetTime(); // czas od uruchomienia scenerii
|
||||
if( Event->fRandomDelay > 0.0 ) {
|
||||
// doliczenie losowego czasu opóźnienia
|
||||
Event->fStartTime += Event->fRandomDelay * Random( 10000 ) * 0.0001;
|
||||
}
|
||||
if( QueryRootEvent != nullptr ) {
|
||||
TEvent::AddToQuery( Event, QueryRootEvent );
|
||||
}
|
||||
else {
|
||||
QueryRootEvent = Event;
|
||||
QueryRootEvent->evNext = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// legacy method, executes queued events
|
||||
bool
|
||||
event_manager::CheckQuery() {
|
||||
|
||||
TLocation loc;
|
||||
int i;
|
||||
while( ( QueryRootEvent != nullptr )
|
||||
&& ( QueryRootEvent->fStartTime < Timer::GetTime() ) )
|
||||
{ // eventy są posortowana wg czasu wykonania
|
||||
m_workevent = QueryRootEvent; // wyjęcie eventu z kolejki
|
||||
if (QueryRootEvent->evJoined) // jeśli jest kolejny o takiej samej nazwie
|
||||
{ // to teraz on będzie następny do wykonania
|
||||
QueryRootEvent = QueryRootEvent->evJoined; // następny będzie ten doczepiony
|
||||
QueryRootEvent->evNext = m_workevent->evNext; // pamiętając o następnym z kolejki
|
||||
QueryRootEvent->fStartTime = m_workevent->fStartTime; // czas musi być ten sam, bo nie jest aktualizowany
|
||||
QueryRootEvent->Activator = m_workevent->Activator; // pojazd aktywujący
|
||||
QueryRootEvent->iQueued = 1;
|
||||
// w sumie można by go dodać normalnie do kolejki, ale trzeba te połączone posortować wg czasu wykonania
|
||||
}
|
||||
else // a jak nazwa jest unikalna, to kolejka idzie dalej
|
||||
QueryRootEvent = QueryRootEvent->evNext; // NULL w skrajnym przypadku
|
||||
if (m_workevent->bEnabled)
|
||||
{ // w zasadzie te wyłączone są skanowane i nie powinny się nigdy w kolejce znaleźć
|
||||
--m_workevent->iQueued; // teraz moze być ponownie dodany do kolejki
|
||||
WriteLog( "EVENT LAUNCHED" + ( m_workevent->Activator ? ( " by " + m_workevent->Activator->asName ) : "" ) + ": " + m_workevent->asName );
|
||||
switch (m_workevent->Type)
|
||||
{
|
||||
case tp_CopyValues: // skopiowanie wartości z innej komórki
|
||||
m_workevent->Params[5].asMemCell->UpdateValues(
|
||||
m_workevent->Params[9].asMemCell->Text(),
|
||||
m_workevent->Params[9].asMemCell->Value1(),
|
||||
m_workevent->Params[9].asMemCell->Value2(),
|
||||
m_workevent->iFlags // flagi określają, co ma być skopiowane
|
||||
);
|
||||
// break; //żeby się wysłało do torów i nie było potrzeby na AddValues * 0 0
|
||||
case tp_AddValues: // różni się jedną flagą od UpdateValues
|
||||
case tp_UpdateValues:
|
||||
if (EventConditon(m_workevent))
|
||||
{ // teraz mogą być warunki do tych eventów
|
||||
if (m_workevent->Type != tp_CopyValues) // dla CopyValues zrobiło się wcześniej
|
||||
m_workevent->Params[5].asMemCell->UpdateValues(
|
||||
m_workevent->Params[0].asText,
|
||||
m_workevent->Params[1].asdouble,
|
||||
m_workevent->Params[2].asdouble,
|
||||
m_workevent->iFlags);
|
||||
if (m_workevent->Params[6].asTrack)
|
||||
{ // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla
|
||||
// wszystkich 'dynamic' na danym torze
|
||||
for( auto dynamic : m_workevent->Params[ 6 ].asTrack->Dynamics ) {
|
||||
m_workevent->Params[ 5 ].asMemCell->PutCommand(
|
||||
dynamic->Mechanik,
|
||||
&m_workevent->Params[ 4 ].nGroundNode->pCenter );
|
||||
}
|
||||
//if (DebugModeFlag)
|
||||
WriteLog("Type: UpdateValues & Track command - [" +
|
||||
m_workevent->Params[5].asMemCell->Text() + "] [" +
|
||||
to_string( m_workevent->Params[ 5 ].asMemCell->Value1(), 2 ) + "] [" +
|
||||
to_string( m_workevent->Params[ 5 ].asMemCell->Value2(), 2 ) + "]" );
|
||||
}
|
||||
else //if (DebugModeFlag)
|
||||
WriteLog("Type: UpdateValues - [" +
|
||||
m_workevent->Params[5].asMemCell->Text() + "] [" +
|
||||
to_string( m_workevent->Params[ 5 ].asMemCell->Value1(), 2 ) + "] [" +
|
||||
to_string( m_workevent->Params[ 5 ].asMemCell->Value2(), 2 ) + "]" );
|
||||
}
|
||||
break;
|
||||
case tp_GetValues: {
|
||||
if( m_workevent->Activator ) {
|
||||
/*
|
||||
// TODO: re-enable when messaging module is in place
|
||||
if( Global::iMultiplayer ) {
|
||||
// potwierdzenie wykonania dla serwera (odczyt semafora już tak nie działa)
|
||||
WyslijEvent( tmpEvent->asName, tmpEvent->Activator->GetName() );
|
||||
}
|
||||
*/
|
||||
m_workevent->Params[ 9 ].asMemCell->PutCommand(
|
||||
m_workevent->Activator->Mechanik,
|
||||
&m_workevent->Params[ 8 ].nGroundNode->pCenter );
|
||||
}
|
||||
WriteLog( "Type: GetValues" );
|
||||
break;
|
||||
}
|
||||
case tp_PutValues: {
|
||||
if (m_workevent->Activator) {
|
||||
// zamiana, bo fizyka ma inaczej niż sceneria
|
||||
loc.X = -m_workevent->Params[3].asdouble;
|
||||
loc.Y = m_workevent->Params[5].asdouble;
|
||||
loc.Z = m_workevent->Params[4].asdouble;
|
||||
if( m_workevent->Activator->Mechanik ) {
|
||||
// przekazanie rozkazu do AI
|
||||
m_workevent->Activator->Mechanik->PutCommand(
|
||||
m_workevent->Params[0].asText, m_workevent->Params[1].asdouble,
|
||||
m_workevent->Params[2].asdouble, loc);
|
||||
}
|
||||
else {
|
||||
// przekazanie do pojazdu
|
||||
m_workevent->Activator->MoverParameters->PutCommand(
|
||||
m_workevent->Params[0].asText, m_workevent->Params[1].asdouble,
|
||||
m_workevent->Params[2].asdouble, loc);
|
||||
}
|
||||
WriteLog("Type: PutValues - [" +
|
||||
std::string(m_workevent->Params[0].asText) + "] [" +
|
||||
to_string( m_workevent->Params[ 1 ].asdouble, 2 ) + "] [" +
|
||||
to_string( m_workevent->Params[ 2 ].asdouble, 2 ) + "]" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_Lights:
|
||||
if (m_workevent->Params[9].asModel)
|
||||
for (i = 0; i < iMaxNumLights; i++)
|
||||
if (m_workevent->Params[i].asdouble >= 0) //-1 zostawia bez zmiany
|
||||
m_workevent->Params[9].asModel->LightSet(
|
||||
i, m_workevent->Params[i].asdouble); // teraz też ułamek
|
||||
break;
|
||||
case tp_Visible:
|
||||
if (m_workevent->Params[9].nGroundNode)
|
||||
m_workevent->Params[9].nGroundNode->bVisible = (m_workevent->Params[i].asInt > 0);
|
||||
break;
|
||||
case tp_Velocity:
|
||||
Error("Not implemented yet :(");
|
||||
break;
|
||||
case tp_Exit:
|
||||
MessageBox(0, m_workevent->asNodeName.c_str(), " THE END ", MB_OK);
|
||||
Global::iTextMode = -1; // wyłączenie takie samo jak sekwencja F10 -> Y
|
||||
return false;
|
||||
case tp_Sound:
|
||||
switch (m_workevent->Params[0].asInt)
|
||||
{ // trzy możliwe przypadki:
|
||||
case 0:
|
||||
m_workevent->Params[9].tsTextSound->Stop();
|
||||
break;
|
||||
case 1:
|
||||
m_workevent->Params[9].tsTextSound->Play(
|
||||
1, 0, true, m_workevent->Params[9].tsTextSound->vSoundPosition);
|
||||
break;
|
||||
case -1:
|
||||
m_workevent->Params[9].tsTextSound->Play(
|
||||
1, DSBPLAY_LOOPING, true, m_workevent->Params[9].tsTextSound->vSoundPosition);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case tp_Disable:
|
||||
Error("Not implemented yet :(");
|
||||
break;
|
||||
case tp_Animation: // Marcin: dorobic translacje - Ra: dorobiłem ;-)
|
||||
if (m_workevent->Params[0].asInt == 1)
|
||||
m_workevent->Params[9].asAnimContainer->SetRotateAnim(
|
||||
Math3D::vector3(m_workevent->Params[1].asdouble, m_workevent->Params[2].asdouble,
|
||||
m_workevent->Params[3].asdouble),
|
||||
m_workevent->Params[4].asdouble);
|
||||
else if (m_workevent->Params[0].asInt == 2)
|
||||
m_workevent->Params[9].asAnimContainer->SetTranslateAnim(
|
||||
Math3D::vector3(m_workevent->Params[1].asdouble, m_workevent->Params[2].asdouble,
|
||||
m_workevent->Params[3].asdouble),
|
||||
m_workevent->Params[4].asdouble);
|
||||
else if (m_workevent->Params[0].asInt == 4)
|
||||
m_workevent->Params[9].asModel->AnimationVND(
|
||||
m_workevent->Params[8].asPointer,
|
||||
m_workevent->Params[1].asdouble, // tu mogą być dodatkowe parametry, np. od-do
|
||||
m_workevent->Params[2].asdouble, m_workevent->Params[3].asdouble,
|
||||
m_workevent->Params[4].asdouble);
|
||||
break;
|
||||
case tp_Switch: {
|
||||
if( m_workevent->Params[ 9 ].asTrack ) {
|
||||
m_workevent->Params[ 9 ].asTrack->Switch(
|
||||
m_workevent->Params[ 0 ].asInt,
|
||||
m_workevent->Params[ 1 ].asdouble,
|
||||
m_workevent->Params[ 2 ].asdouble );
|
||||
}
|
||||
/*
|
||||
// TODO: re-enable when messaging module is in place
|
||||
if( Global::iMultiplayer ) {
|
||||
// dajemy znać do serwera o przełożeniu
|
||||
WyslijEvent( m_workevent->asName, "" ); // wysłanie nazwy eventu przełączajacego
|
||||
}
|
||||
*/
|
||||
// Ra: bardziej by się przydała nazwa toru, ale nie ma do niej stąd dostępu
|
||||
break;
|
||||
}
|
||||
case tp_TrackVel:
|
||||
if (m_workevent->Params[9].asTrack)
|
||||
{ // prędkość na zwrotnicy może być ograniczona z góry we wpisie, większej się nie
|
||||
// ustawi eventem
|
||||
WriteLog("Type: TrackVel");
|
||||
m_workevent->Params[9].asTrack->VelocitySet(m_workevent->Params[0].asdouble);
|
||||
if (DebugModeFlag) // wyświetlana jest ta faktycznie ustawiona
|
||||
WriteLog(" - velocity: ", m_workevent->Params[9].asTrack->VelocityGet());
|
||||
}
|
||||
break;
|
||||
case tp_DynVel:
|
||||
Error("Event \"DynVel\" is obsolete");
|
||||
break;
|
||||
case tp_Multiple: {
|
||||
auto const bCondition = EventConditon(m_workevent);
|
||||
if( ( bCondition )
|
||||
|| ( m_workevent->iFlags & conditional_anyelse ) ) {
|
||||
// warunek spelniony albo było użyte else
|
||||
WriteLog("Type: Multi-event");
|
||||
for (i = 0; i < 8; ++i) {
|
||||
// dodawane do kolejki w kolejności zapisania
|
||||
if( m_workevent->Params[ i ].asEvent ) {
|
||||
if( bCondition != ( ( ( m_workevent->iFlags & ( conditional_else << i ) ) != 0 ) ) ) {
|
||||
if( m_workevent->Params[ i ].asEvent != m_workevent )
|
||||
AddToQuery( m_workevent->Params[ i ].asEvent, m_workevent->Activator ); // normalnie dodać
|
||||
else {
|
||||
// jeśli ma być rekurencja to musi mieć sensowny okres powtarzania
|
||||
if( m_workevent->fDelay >= 5.0 ) {
|
||||
AddToQuery( m_workevent, m_workevent->Activator );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
// TODO: re-enable when messaging component is in place
|
||||
if( Global::iMultiplayer ) {
|
||||
// dajemy znać do serwera o wykonaniu
|
||||
if( ( m_workevent->iFlags & conditional_anyelse ) == 0 ) {
|
||||
// jednoznaczne tylko, gdy nie było else
|
||||
if( m_workevent->Activator ) {
|
||||
WyslijEvent( m_workevent->asName, m_workevent->Activator->GetName() );
|
||||
}
|
||||
else {
|
||||
WyslijEvent( m_workevent->asName, "" );
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_WhoIs: {
|
||||
// pobranie nazwy pociągu do komórki pamięci
|
||||
if (m_workevent->iFlags & update_load) {
|
||||
// jeśli pytanie o ładunek
|
||||
if( m_workevent->iFlags & update_memadd ) {
|
||||
// jeśli typ pojazdu
|
||||
// TODO: define and recognize individual request types
|
||||
auto const owner = (
|
||||
( ( m_workevent->Activator->Mechanik != nullptr ) && ( m_workevent->Activator->Mechanik->Primary() ) ) ?
|
||||
m_workevent->Activator->Mechanik :
|
||||
m_workevent->Activator->ctOwner );
|
||||
auto const consistbrakelevel = (
|
||||
owner != nullptr ?
|
||||
owner->fReady :
|
||||
-1.0 );
|
||||
auto const collisiondistance = (
|
||||
owner != nullptr ?
|
||||
owner->TrackBlock() :
|
||||
-1.0 );
|
||||
|
||||
m_workevent->Params[ 9 ].asMemCell->UpdateValues(
|
||||
m_workevent->Activator->MoverParameters->TypeName, // typ pojazdu
|
||||
consistbrakelevel,
|
||||
collisiondistance,
|
||||
m_workevent->iFlags & ( update_memstring | update_memval1 | update_memval2 ) );
|
||||
|
||||
WriteLog(
|
||||
"Type: WhoIs (" + to_string( m_workevent->iFlags ) + ") - "
|
||||
+ "[name: " + m_workevent->Activator->MoverParameters->TypeName + "], "
|
||||
+ "[consist brake level: " + to_string( consistbrakelevel, 2 ) + "], "
|
||||
+ "[obstacle distance: " + to_string( collisiondistance, 2 ) + " m]" );
|
||||
}
|
||||
else {
|
||||
// jeśli parametry ładunku
|
||||
m_workevent->Params[ 9 ].asMemCell->UpdateValues(
|
||||
m_workevent->Activator->MoverParameters->LoadType, // nazwa ładunku
|
||||
m_workevent->Activator->MoverParameters->Load, // aktualna ilość
|
||||
m_workevent->Activator->MoverParameters->MaxLoad, // maksymalna ilość
|
||||
m_workevent->iFlags & ( update_memstring | update_memval1 | update_memval2 ) );
|
||||
|
||||
WriteLog(
|
||||
"Type: WhoIs (" + to_string( m_workevent->iFlags ) + ") - "
|
||||
+ "[load type: " + m_workevent->Activator->MoverParameters->LoadType + "], "
|
||||
+ "[current load: " + to_string( m_workevent->Activator->MoverParameters->Load, 2 ) + "], "
|
||||
+ "[max load: " + to_string( m_workevent->Activator->MoverParameters->MaxLoad, 2 ) + "]" );
|
||||
}
|
||||
}
|
||||
else if (m_workevent->iFlags & update_memadd)
|
||||
{ // jeśli miejsce docelowe pojazdu
|
||||
m_workevent->Params[ 9 ].asMemCell->UpdateValues(
|
||||
m_workevent->Activator->asDestination, // adres docelowy
|
||||
m_workevent->Activator->DirectionGet(), // kierunek pojazdu względem czoła składu (1=zgodny,-1=przeciwny)
|
||||
m_workevent->Activator->MoverParameters->Power, // moc pojazdu silnikowego: 0 dla wagonu
|
||||
m_workevent->iFlags & (update_memstring | update_memval1 | update_memval2));
|
||||
|
||||
WriteLog(
|
||||
"Type: WhoIs (" + to_string( m_workevent->iFlags ) + ") - "
|
||||
+ "[destination: " + m_workevent->Activator->asDestination + "], "
|
||||
+ "[direction: " + to_string( m_workevent->Activator->DirectionGet() ) + "], "
|
||||
+ "[engine power: " + to_string( m_workevent->Activator->MoverParameters->Power, 2 ) + "]" );
|
||||
}
|
||||
else if (m_workevent->Activator->Mechanik)
|
||||
if (m_workevent->Activator->Mechanik->Primary())
|
||||
{ // tylko jeśli ktoś tam siedzi - nie powinno dotyczyć pasażera!
|
||||
m_workevent->Params[ 9 ].asMemCell->UpdateValues(
|
||||
m_workevent->Activator->Mechanik->TrainName(),
|
||||
m_workevent->Activator->Mechanik->StationCount() - m_workevent->Activator->Mechanik->StationIndex(), // ile przystanków do końca
|
||||
m_workevent->Activator->Mechanik->IsStop() ? 1 :
|
||||
0, // 1, gdy ma tu zatrzymanie
|
||||
m_workevent->iFlags);
|
||||
WriteLog("Train detected: " + m_workevent->Activator->Mechanik->TrainName());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_LogValues: {
|
||||
// zapisanie zawartości komórki pamięci do logu
|
||||
if( m_workevent->Params[ 9 ].asMemCell ) {
|
||||
// jeśli była podana nazwa komórki
|
||||
WriteLog( "Memcell \"" + m_workevent->asNodeName + "\": "
|
||||
+ m_workevent->Params[ 9 ].asMemCell->Text() + " "
|
||||
+ std::to_string( m_workevent->Params[ 9 ].asMemCell->Value1() ) + " "
|
||||
+ std::to_string( m_workevent->Params[ 9 ].asMemCell->Value2() ) );
|
||||
}
|
||||
else {
|
||||
// TODO: re-enable when cell manager is in place
|
||||
/*
|
||||
// lista wszystkich
|
||||
for( TGroundNode *Current = nRootOfType[ TP_MEMCELL ]; Current; Current = Current->nNext ) {
|
||||
WriteLog( "Memcell \"" + Current->asName + "\": "
|
||||
+ Current->MemCell->Text() + " "
|
||||
+ std::to_string( Current->MemCell->Value1() ) + " "
|
||||
+ std::to_string( Current->MemCell->Value2() ) );
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_Voltage: // zmiana napięcia w zasilaczu (TractionPowerSource)
|
||||
if (m_workevent->Params[9].psPower)
|
||||
{ // na razie takie chamskie ustawienie napięcia zasilania
|
||||
WriteLog("Type: Voltage");
|
||||
m_workevent->Params[9].psPower->VoltageSet(m_workevent->Params[0].asdouble);
|
||||
}
|
||||
case tp_Friction: // zmiana tarcia na scenerii
|
||||
{ // na razie takie chamskie ustawienie napięcia zasilania
|
||||
WriteLog("Type: Friction");
|
||||
Global::fFriction = (m_workevent->Params[0].asdouble);
|
||||
}
|
||||
break;
|
||||
case tp_Message: // wyświetlenie komunikatu
|
||||
break;
|
||||
} // switch (tmpEvent->Type)
|
||||
} // if (tmpEvent->bEnabled)
|
||||
} // while
|
||||
return true;
|
||||
}
|
||||
|
||||
// legacy method, initializes events after deserialization from scenario file
|
||||
void
|
||||
event_manager::InitEvents() {
|
||||
|
||||
//łączenie eventów z pozostałymi obiektami
|
||||
for( auto *Current : m_events ) {
|
||||
|
||||
switch (Current->Type) {
|
||||
|
||||
case tp_AddValues: // sumowanie wartości
|
||||
case tp_UpdateValues: { // zmiana wartości
|
||||
auto *cell = simulation::Memory.find( Current->asNodeName ); // nazwa komórki powiązanej z eventem
|
||||
if( cell ) { // McZapkie-100302
|
||||
if( Current->iFlags & ( conditional_trackoccupied | conditional_trackfree ) ) {
|
||||
// jeśli chodzi o zajetosc toru (tor może być inny, niż wpisany w komórce)
|
||||
// nazwa toru ta sama, co nazwa komórki
|
||||
Current->Params[ 9 ].asTrack = simulation::Paths.find( Current->asNodeName );
|
||||
if( Current->Params[ 9 ].asTrack == nullptr ) {
|
||||
ErrorLog( "Bad event: track \"" + Current->asNodeName + "\" referenced in event \"" + Current->asName + "\" doesn't exist" );
|
||||
}
|
||||
}
|
||||
Current->Params[ 4 ].asLocation = &( cell->location() );
|
||||
Current->Params[ 5 ].asMemCell = cell; // komórka do aktualizacji
|
||||
if( Current->iFlags & ( conditional_memcompare ) ) {
|
||||
// komórka do badania warunku
|
||||
Current->Params[ 9 ].asMemCell = cell;
|
||||
}
|
||||
if( false == cell->asTrackName.empty() ) {
|
||||
// tor powiązany z komórką powiązaną z eventem
|
||||
// tu potrzebujemy wskaźnik do komórki w (tmp)
|
||||
Current->Params[ 6 ].asTrack = simulation::Paths.find( cell->asTrackName );
|
||||
if( Current->Params[ 6 ].asTrack == nullptr ) {
|
||||
ErrorLog( "Bad memcell: track \"" + cell->asTrackName + "\" referenced in memcell \"" + cell->name() + "\" doesn't exist" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
Current->Params[ 6 ].asTrack = nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// nie ma komórki, to nie będzie działał poprawnie
|
||||
Current->Type = tp_Ignored; // deaktywacja
|
||||
ErrorLog( "Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_LogValues: {
|
||||
// skojarzenie z memcell
|
||||
if( Current->asNodeName.empty() ) { // brak skojarzenia daje logowanie wszystkich
|
||||
Current->Params[ 9 ].asMemCell = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case tp_GetValues:
|
||||
case tp_WhoIs: {
|
||||
auto *cell = simulation::Memory.find( Current->asNodeName );
|
||||
if( cell ) {
|
||||
Current->Params[ 8 ].asLocation = &( cell->location() );
|
||||
Current->Params[ 9 ].asMemCell = cell;
|
||||
if( ( Current->Type == tp_GetValues )
|
||||
&& ( cell->IsVelocity() ) ) {
|
||||
// jeśli odczyt komórki a komórka zawiera komendę SetVelocity albo ShuntVelocity
|
||||
// to event nie będzie dodawany do kolejki
|
||||
Current->bEnabled = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// nie ma komórki, to nie będzie działał poprawnie
|
||||
Current->Type = tp_Ignored; // deaktywacja
|
||||
ErrorLog( "Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_CopyValues: {
|
||||
// skopiowanie komórki do innej
|
||||
auto *cell = simulation::Memory.find( Current->asNodeName ); // komórka docelowa
|
||||
if( cell ) {
|
||||
Current->Params[ 4 ].asLocation = &( cell->location() );
|
||||
Current->Params[ 5 ].asMemCell = cell; // komórka docelowa
|
||||
if( false == cell->asTrackName.empty() ) {
|
||||
// tor powiązany z komórką powiązaną z eventem
|
||||
// tu potrzebujemy wskaźnik do komórki w (tmp)
|
||||
Current->Params[ 6 ].asTrack = simulation::Paths.find( cell->asTrackName );
|
||||
if( Current->Params[ 6 ].asTrack == nullptr ) {
|
||||
ErrorLog( "Bad memcell: track \"" + cell->asTrackName + "\" referenced in memcell \"" + cell->name() + "\" doesn't exists" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
Current->Params[ 6 ].asTrack = nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad event: copyvalues event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"" );
|
||||
}
|
||||
std::string const cellastext { Current->Params[ 9 ].asText };
|
||||
cell = simulation::Memory.find( Current->Params[ 9 ].asText ); // komórka źódłowa
|
||||
SafeDeleteArray( Current->Params[ 9 ].asText ); // usunięcie nazwy komórki
|
||||
if( cell != nullptr ) {
|
||||
Current->Params[ 8 ].asLocation = &( cell->location() );
|
||||
Current->Params[ 9 ].asMemCell = cell; // komórka źródłowa
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad event: copyvalues event \"" + Current->asName + "\" cannot find memcell \"" + cellastext + "\"" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_Animation: {
|
||||
// animacja modelu
|
||||
// retrieve target name parameter
|
||||
std::string const cellastext = Current->Params[ 9 ].asText;
|
||||
SafeDeleteArray( Current->Params[ 9 ].asText );
|
||||
// egzemplarz modelu do animowania
|
||||
auto *instance = simulation::Instances.find( Current->asNodeName );
|
||||
if( instance ) {
|
||||
if( Current->Params[ 0 ].asInt == 4 ) {
|
||||
// model dla całomodelowych animacji
|
||||
Current->Params[ 9 ].asModel = instance;
|
||||
}
|
||||
else {
|
||||
// standardowo przypisanie submodelu
|
||||
Current->Params[ 9 ].asAnimContainer = instance->GetContainer( cellastext ); // submodel
|
||||
if( Current->Params[ 9 ].asAnimContainer ) {
|
||||
Current->Params[ 9 ].asAnimContainer->WillBeAnimated(); // oflagowanie animacji
|
||||
if( Current->Params[ 9 ].asAnimContainer->Event() == nullptr ) {
|
||||
// nie szukać, gdy znaleziony
|
||||
Current->Params[ 9 ].asAnimContainer->EventAssign(
|
||||
FindEvent( Current->asNodeName + "." + cellastext + ":done" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad event: animation event \"" + Current->asName + "\" cannot find model instance \"" + Current->asNodeName + "\"" );
|
||||
}
|
||||
Current->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Lights: {
|
||||
// zmiana świeteł modelu
|
||||
auto *instance = simulation::Instances.find( Current->asNodeName );
|
||||
if( instance )
|
||||
Current->Params[ 9 ].asModel = instance;
|
||||
else
|
||||
ErrorLog( "Bad event: lights event \"" + Current->asName + "\" cannot find model instance \"" + Current->asNodeName + "\"" );
|
||||
Current->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case tp_Visible: {
|
||||
// ukrycie albo przywrócenie obiektu
|
||||
tmp = FindGroundNode( Current->asNodeName, TP_MODEL ); // najpierw model
|
||||
if( !tmp )
|
||||
tmp = FindGroundNode( Current->asNodeName, TP_TRACK ); // albo tory?
|
||||
if( !tmp )
|
||||
tmp = FindGroundNode( Current->asNodeName, TP_TRACTION ); // może druty?
|
||||
if( tmp )
|
||||
Current->Params[ 9 ].nGroundNode = tmp;
|
||||
else
|
||||
ErrorLog( "Bad event: visibility event \"" + Current->asName + "\" cannot find item \"" + Current->asNodeName + "\"" );
|
||||
Current->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case tp_Switch: {
|
||||
// przełożenie zwrotnicy albo zmiana stanu obrotnicy
|
||||
auto *track = simulation::Paths.find( Current->asNodeName );
|
||||
if( track ) {
|
||||
// dowiązanie toru
|
||||
if( track->iAction == NULL ) {
|
||||
// jeśli nie jest zwrotnicą ani obrotnicą to będzie się zmieniał stan uszkodzenia
|
||||
track->iAction |= 0x100;
|
||||
}
|
||||
Current->Params[ 9 ].asTrack = track;
|
||||
if( ( Current->Params[ 0 ].asInt == 0 )
|
||||
&& ( Current->Params[ 2 ].asdouble >= 0.0 ) ) {
|
||||
// jeśli przełącza do stanu 0 & jeśli jest zdefiniowany dodatkowy ruch iglic
|
||||
// przesłanie parametrów
|
||||
Current->Params[ 9 ].asTrack->Switch(
|
||||
Current->Params[ 0 ].asInt,
|
||||
Current->Params[ 1 ].asdouble,
|
||||
Current->Params[ 2 ].asdouble );
|
||||
}
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad event: switch event \"" + Current->asName + "\" cannot find track \"" + Current->asNodeName + "\"" );
|
||||
}
|
||||
Current->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case tp_Sound: {
|
||||
// odtworzenie dźwięku
|
||||
tmp = FindGroundNode( Current->asNodeName, TP_SOUND );
|
||||
if( tmp )
|
||||
Current->Params[ 9 ].tsTextSound = tmp->tsStaticSound;
|
||||
else
|
||||
ErrorLog( "Bad event: sound event \"" + Current->asName + "\" cannot find static sound \"" + Current->asNodeName + "\"" );
|
||||
Current->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case tp_TrackVel: {
|
||||
// ustawienie prędkości na torze
|
||||
if( false == Current->asNodeName.empty() ) {
|
||||
auto *track = simulation::Paths.find( Current->asNodeName );
|
||||
if( track ) {
|
||||
// flaga zmiany prędkości toru jest istotna dla skanowania
|
||||
track->iAction |= 0x200;
|
||||
Current->Params[ 9 ].asTrack = track;
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad event: track velocity event \"" + Current->asName + "\" cannot find track \"" + Current->asNodeName + "\"" );
|
||||
}
|
||||
}
|
||||
Current->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case tp_DynVel: {
|
||||
// komunikacja z pojazdem o konkretnej nazwie
|
||||
if( Current->asNodeName == "activator" )
|
||||
Current->Params[ 9 ].asDynamic = nullptr;
|
||||
else {
|
||||
tmp = FindGroundNode( Current->asNodeName, TP_DYNAMIC );
|
||||
if( tmp )
|
||||
Current->Params[ 9 ].asDynamic = tmp->DynamicObject;
|
||||
else
|
||||
Error( "Bad event: vehicle velocity event \"" + Current->asName + "\" cannot find vehicle \"" + Current->asNodeName + "\"" );
|
||||
}
|
||||
Current->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case tp_Multiple: {
|
||||
std::string cellastext;
|
||||
if( Current->Params[ 9 ].asText != nullptr ) { // przepisanie nazwy do bufora
|
||||
cellastext = Current->Params[ 9 ].asText;
|
||||
SafeDeleteArray( Current->Params[ 9 ].asText );
|
||||
Current->Params[ 9 ].asPointer = nullptr; // zerowanie wskaźnika, aby wykryć brak obeiktu
|
||||
}
|
||||
if( Current->iFlags & ( conditional_trackoccupied | conditional_trackfree ) ) {
|
||||
// jeśli chodzi o zajetosc toru
|
||||
Current->Params[ 9 ].asTrack = simulation::Paths.find( cellastext );
|
||||
if( Current->Params[ 9 ].asTrack == nullptr ) {
|
||||
ErrorLog( "Bad event: multi-event \"" + Current->asName + "\" cannot find track \"" + cellastext + "\"" );
|
||||
Current->iFlags &= ~( conditional_trackoccupied | conditional_trackfree ); // zerowanie flag
|
||||
}
|
||||
}
|
||||
else if( Current->iFlags & ( conditional_memstring | conditional_memval1 | conditional_memval2 ) ) {
|
||||
// jeśli chodzi o komorke pamieciową
|
||||
Current->Params[ 9 ].asMemCell = simulation::Memory.find( cellastext );
|
||||
if( Current->Params[ 9 ].asMemCell == nullptr ) {
|
||||
ErrorLog( "Bad event: multi-event \"" + Current->asName + "\" cannot find memory cell \"" + cellastext + "\"" );
|
||||
Current->iFlags &= ~( conditional_memstring | conditional_memval1 | conditional_memval2 );
|
||||
}
|
||||
}
|
||||
for( int i = 0; i < 8; ++i ) {
|
||||
if( Current->Params[ i ].asText != nullptr ) {
|
||||
cellastext = Current->Params[ i ].asText;
|
||||
SafeDeleteArray( Current->Params[ i ].asText );
|
||||
Current->Params[ i ].asEvent = FindEvent( cellastext );
|
||||
if( Current->Params[ i ].asEvent == nullptr ) {
|
||||
// Ra: tylko w logu informacja o braku
|
||||
ErrorLog( "Bad event: multi-event \"" + Current->asName + "\" cannot find event \"" + cellastext + "\"" );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case tp_Voltage: {
|
||||
// zmiana napięcia w zasilaczu (TractionPowerSource)
|
||||
if( !Current->asNodeName.empty() ) {
|
||||
tmp = FindGroundNode( Current->asNodeName, TP_TRACTIONPOWERSOURCE ); // podłączenie zasilacza
|
||||
if( tmp )
|
||||
Current->Params[ 9 ].psPower = tmp->psTractionPowerSource;
|
||||
else
|
||||
ErrorLog( "Bad event: voltage event \"" + Current->asName + "\" cannot find power source \"" + Current->asNodeName + "\"" );
|
||||
}
|
||||
Current->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case tp_Message: {
|
||||
// wyświetlenie komunikatu
|
||||
break;
|
||||
}
|
||||
|
||||
} // switch
|
||||
if( Current->fDelay < 0 ) {
|
||||
AddToQuery( Current, nullptr );
|
||||
}
|
||||
}
|
||||
/*
|
||||
for (TGroundNode *Current = nRootOfType[TP_MEMCELL]; Current; Current = Current->nNext)
|
||||
{ // Ra: eventy komórek pamięci, wykonywane po wysłaniu komendy do zatrzymanego pojazdu
|
||||
Current->MemCell->AssignEvents( FindEvent( Current->asName + ":sent" ) );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// legacy method, verifies condition for specified event
|
||||
bool
|
||||
event_manager::EventConditon( TEvent *Event ) {
|
||||
|
||||
if (Event->iFlags <= update_only)
|
||||
return true; // bezwarunkowo
|
||||
|
||||
if (Event->iFlags & conditional_trackoccupied)
|
||||
return (!Event->Params[9].asTrack->IsEmpty());
|
||||
else if (Event->iFlags & conditional_trackfree)
|
||||
return (Event->Params[9].asTrack->IsEmpty());
|
||||
else if (Event->iFlags & conditional_propability)
|
||||
{
|
||||
double rprobability = Random();
|
||||
WriteLog( "Random integer: " + std::to_string( rprobability ) + " / " + std::to_string( Event->Params[ 10 ].asdouble ) );
|
||||
return (Event->Params[10].asdouble > rprobability);
|
||||
}
|
||||
else if( Event->iFlags & conditional_memcompare ) {
|
||||
// porównanie wartości
|
||||
if( nullptr == Event->Params[9].asMemCell ) {
|
||||
|
||||
ErrorLog( "Event " + Event->asName + " trying conditional_memcompare with nonexistent memcell" );
|
||||
return true; // though this is technically error, we report success to maintain backward compatibility
|
||||
}
|
||||
auto const comparisonresult =
|
||||
m_workevent->Params[ 9 ].asMemCell->Compare(
|
||||
( Event->Params[ 10 ].asText != nullptr ?
|
||||
Event->Params[ 10 ].asText :
|
||||
"" ),
|
||||
Event->Params[ 11 ].asdouble,
|
||||
Event->Params[ 12 ].asdouble,
|
||||
Event->iFlags );
|
||||
|
||||
std::string comparisonlog = "Type: MemCompare - ";
|
||||
|
||||
comparisonlog +=
|
||||
"[" + Event->Params[ 9 ].asMemCell->Text() + "]"
|
||||
+ " [" + to_string( Event->Params[ 9 ].asMemCell->Value1(), 2 ) + "]"
|
||||
+ " [" + to_string( m_workevent->Params[ 9 ].asMemCell->Value2(), 2 ) + "]";
|
||||
|
||||
comparisonlog += (
|
||||
true == comparisonresult ?
|
||||
" == " :
|
||||
" != " );
|
||||
|
||||
comparisonlog += (
|
||||
TestFlag( Event->iFlags, conditional_memstring ) ?
|
||||
"[" + std::string( m_workevent->Params[ 10 ].asText ) + "]" :
|
||||
"[*]" );
|
||||
comparisonlog += (
|
||||
TestFlag( m_workevent->iFlags, conditional_memval1 ) ?
|
||||
" [" + to_string( m_workevent->Params[ 11 ].asdouble, 2 ) + "]" :
|
||||
" [*]" );
|
||||
comparisonlog += (
|
||||
TestFlag( m_workevent->iFlags, conditional_memval2 ) ?
|
||||
" [" + to_string( m_workevent->Params[ 12 ].asdouble, 2 ) + "]" :
|
||||
" [*]" );
|
||||
|
||||
WriteLog( comparisonlog );
|
||||
return comparisonresult;
|
||||
}
|
||||
// unrecognized request
|
||||
return false;
|
||||
}
|
||||
|
||||
58
Event.h
58
Event.h
@@ -11,9 +11,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <string>
|
||||
#include "dumb3d.h"
|
||||
#include "Classes.h"
|
||||
|
||||
using namespace Math3D;
|
||||
#include "classes.h"
|
||||
|
||||
enum TEventType {
|
||||
tp_Unknown,
|
||||
@@ -63,6 +61,7 @@ union TParam
|
||||
void *asPointer;
|
||||
TMemCell *asMemCell;
|
||||
TGroundNode *nGroundNode;
|
||||
glm::dvec3 const *asLocation;
|
||||
TTrack *asTrack;
|
||||
TAnimModel *asModel;
|
||||
TAnimContainer *asAnimContainer;
|
||||
@@ -87,9 +86,10 @@ class TEvent // zmienne: ev*
|
||||
std::string asName;
|
||||
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
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
TEvent *evNext2 = nullptr;
|
||||
#endif
|
||||
TEventType Type = tp_Unknown;
|
||||
double fStartTime = 0.0;
|
||||
double fDelay = 0.0;
|
||||
@@ -103,15 +103,61 @@ class TEvent // zmienne: ev*
|
||||
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 provided event to the collection. returns: true on success
|
||||
// TODO: return handle instead of pointer
|
||||
bool
|
||||
insert( TEvent *Event );
|
||||
// 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();
|
||||
|
||||
private:
|
||||
// types
|
||||
using event_sequence = std::deque<TEvent *>;
|
||||
using event_map = std::unordered_map<std::string, std::size_t>;
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -120,7 +120,7 @@ float Global::AnisotropicFiltering = 8.0f; // requested level of anisotropic fil
|
||||
bool Global::bUseVBO = true; // czy jest VBO w karcie graficznej (czy użyć)
|
||||
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
|
||||
@@ -1008,7 +1008,11 @@ TDynamicObject *Global::CouplerNearest()
|
||||
|
||||
bool Global::AddToQuery(TEvent *event, TDynamicObject *who)
|
||||
{
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
return pGround->AddToQuery(event, who);
|
||||
#else
|
||||
return simulation::Events.AddToQuery( event, who );
|
||||
#endif
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
357
Ground.cpp
357
Ground.cpp
@@ -20,7 +20,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Logs.h"
|
||||
#include "usefull.h"
|
||||
#include "Timer.h"
|
||||
#include "renderer.h"
|
||||
#include "Event.h"
|
||||
#include "EvLaunch.h"
|
||||
#include "TractionPower.h"
|
||||
@@ -34,9 +33,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Data.h"
|
||||
#include "parser.h" //Tolaris-010603
|
||||
#include "Driver.h"
|
||||
#include "Console.h"
|
||||
#include "Names.h"
|
||||
#include "world.h"
|
||||
#include "uilayer.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -47,7 +43,6 @@ extern "C"
|
||||
}
|
||||
|
||||
bool bCondition; // McZapkie: do testowania warunku na event multiple
|
||||
std::string LogComment;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Obiekt renderujący siatkę jest sztucznie tworzonym obiektem pomocniczym,
|
||||
@@ -123,6 +118,8 @@ TGroundNode::~TGroundNode()
|
||||
case GL_TRIANGLES:
|
||||
SafeDelete( Piece );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -144,7 +141,7 @@ TGroundNode::TGroundNode( TGroundNodeType t ) :
|
||||
break;
|
||||
}
|
||||
case TP_TRACK: {
|
||||
pTrack = new TTrack( this );
|
||||
pTrack = new TTrack( asName );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -314,9 +311,8 @@ void TSubRect::NodeAdd(TGroundNode *Node)
|
||||
// przygotowanie sektora do renderowania
|
||||
void TSubRect::Sort() {
|
||||
|
||||
if( tTracks != nullptr ) {
|
||||
SafeDelete( tTracks );
|
||||
}
|
||||
SafeDeleteArray( tTracks );
|
||||
|
||||
if( iTracks > 0 ) {
|
||||
tTracks = new TTrack *[ iTracks ]; // tworzenie tabeli torów do renderowania pojazdów
|
||||
int i = 0;
|
||||
@@ -414,12 +410,20 @@ void TSubRect::LoadNodes() {
|
||||
break;
|
||||
}
|
||||
case TP_TRACK:
|
||||
if( node->pTrack->bVisible ) { // bo tory zabezpieczające są niewidoczne
|
||||
if( node->pTrack->visible() ) { // bo tory zabezpieczające są niewidoczne
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
node->pTrack->create_geometry( m_geometrybank, node->m_rootposition );
|
||||
#else
|
||||
node->pTrack->create_geometry( m_geometrybank );
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case TP_TRACTION:
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
node->hvTraction->create_geometry( m_geometrybank, node->m_rootposition );
|
||||
#else
|
||||
node->hvTraction->create_geometry( m_geometrybank );
|
||||
#endif
|
||||
break;
|
||||
default: { break; }
|
||||
}
|
||||
@@ -448,16 +452,16 @@ TGroundRect::Init() {
|
||||
}
|
||||
|
||||
pSubRects = new TSubRect[ iNumSubRects * iNumSubRects ];
|
||||
float const subrectsize = 1000.0f / iNumSubRects;
|
||||
auto const subrectsize = 1000.0 / iNumSubRects;
|
||||
for( int column = 0; column < iNumSubRects; ++column ) {
|
||||
for( int row = 0; row < iNumSubRects; ++row ) {
|
||||
auto subcell = FastGetSubRect( column, row );
|
||||
auto &area = subcell->m_area;
|
||||
area.center =
|
||||
m_area.center
|
||||
- glm::vec3( 500.0f, 0.0f, 500.0f ) // 'upper left' corner of rectangle
|
||||
+ glm::vec3( subrectsize * 0.5f, 0.0f, subrectsize * 0.5f ) // center of sub-rectangle
|
||||
+ glm::vec3( subrectsize * column, 0.0f, subrectsize * row );
|
||||
- glm::dvec3( 500.0, 0.0, 500.0 ) // 'upper left' corner of rectangle
|
||||
+ glm::dvec3( subrectsize * 0.5, 0.0, subrectsize * 0.5 ) // center of sub-rectangle
|
||||
+ glm::dvec3( subrectsize * column, 0.0, subrectsize * row );
|
||||
area.radius = subrectsize * M_SQRT2;
|
||||
// all subcells share the same geometry bank with their parent, to reduce buffer switching during render
|
||||
subcell->m_geometrybank = m_geometrybank;
|
||||
@@ -507,7 +511,7 @@ TGroundRect::NodeAdd( TGroundNode *Node ) {
|
||||
|
||||
// compares two provided nodes, returns true if their content can be merged
|
||||
bool
|
||||
TGroundRect::mergeable( TGroundNode const &Left, TGroundNode const &Right ) {
|
||||
TGroundRect::mergeable( TGroundNode const &Left, TGroundNode const &Right ) const {
|
||||
// since view ranges and transparency type for all nodes put through this method are guaranteed to be equal,
|
||||
// we can skip their tests and only do the material check.
|
||||
// TODO, TBD: material as dedicated type, and refactor this method into a simple equality test
|
||||
@@ -553,6 +557,7 @@ TGround::~TGround()
|
||||
|
||||
void TGround::Free()
|
||||
{
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
TEvent *tmp;
|
||||
for (TEvent *Current = RootEvent; Current;)
|
||||
{
|
||||
@@ -560,6 +565,7 @@ void TGround::Free()
|
||||
Current = Current->evNext2;
|
||||
delete tmp;
|
||||
}
|
||||
#endif
|
||||
TGroundNode *tmpn;
|
||||
for (int i = 0; i < TP_LAST; ++i)
|
||||
{
|
||||
@@ -598,7 +604,8 @@ TGroundNode * TGround::DynamicFind(std::string const &Name)
|
||||
return NULL;
|
||||
};
|
||||
|
||||
void TGround::DynamicList(bool all)
|
||||
void
|
||||
TGround::DynamicList(bool all)
|
||||
{ // odesłanie nazw pojazdów dostępnych na scenerii (nazwy, szczególnie wagonów, mogą się
|
||||
// powtarzać!)
|
||||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||||
@@ -607,45 +614,23 @@ void TGround::DynamicList(bool all)
|
||||
WyslijString("none", 6); // informacja o końcu listy
|
||||
};
|
||||
|
||||
TGroundNode * TGround::FindGroundNode(std::string asNameToFind, TGroundNodeType iNodeType)
|
||||
{ // wyszukiwanie obiektu o podanej nazwie i konkretnym typie
|
||||
if ((iNodeType == TP_TRACK) || (iNodeType == TP_MEMCELL) || (iNodeType == TP_MODEL))
|
||||
{ // wyszukiwanie w drzewie binarnym
|
||||
/*
|
||||
switch( iNodeType ) {
|
||||
// wyszukiwanie obiektu o podanej nazwie i konkretnym typie
|
||||
TGroundNode *
|
||||
TGround::FindGroundNode(std::string const &asNameToFind, TGroundNodeType const iNodeType) {
|
||||
|
||||
case TP_TRACK: {
|
||||
auto const lookup = m_trackmap.find( asNameToFind );
|
||||
return
|
||||
lookup != m_trackmap.end() ?
|
||||
lookup->second :
|
||||
nullptr;
|
||||
if( ( iNodeType == TP_TRACK )
|
||||
|| ( iNodeType == TP_MEMCELL )
|
||||
|| ( iNodeType == TP_MODEL ) ) {
|
||||
// wyszukiwanie w drzewie binarnym
|
||||
return m_nodemap.Find( iNodeType, asNameToFind );
|
||||
}
|
||||
case TP_MODEL: {
|
||||
auto const lookup = m_modelmap.find( asNameToFind );
|
||||
return
|
||||
lookup != m_modelmap.end() ?
|
||||
lookup->second :
|
||||
nullptr;
|
||||
}
|
||||
case TP_MEMCELL: {
|
||||
auto const lookup = m_memcellmap.find( asNameToFind );
|
||||
return
|
||||
lookup != m_memcellmap.end() ?
|
||||
lookup->second :
|
||||
nullptr;
|
||||
// standardowe wyszukiwanie liniowe
|
||||
for( TGroundNode *Current = nRootOfType[ iNodeType ]; Current != nullptr; Current = Current->nNext ) {
|
||||
if( Current->asName == asNameToFind ) {
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
*/
|
||||
return m_trackmap.Find( iNodeType, asNameToFind );
|
||||
}
|
||||
// standardowe wyszukiwanie liniowe
|
||||
TGroundNode *Current;
|
||||
for (Current = nRootOfType[iNodeType]; Current; Current = Current->nNext)
|
||||
if (Current->asName == asNameToFind)
|
||||
return Current;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TGroundRect *
|
||||
@@ -905,7 +890,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
switch (tmp->iType)
|
||||
{
|
||||
case TP_TRACTION:
|
||||
tmp->hvTraction = new TTraction();
|
||||
tmp->hvTraction = new TTraction( tmp->asName );
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
tmp->hvTraction->asPowerSupplyName = token; // nazwa zasilacza
|
||||
@@ -989,8 +974,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
if (token.compare("endtraction") != 0)
|
||||
Error("ENDTRACTION delimiter missing! " + str2 + " found instead.");
|
||||
tmp->hvTraction->Init(); // przeliczenie parametrów
|
||||
// if (Global::bLoadTraction)
|
||||
// tmp->hvTraction->Optimize(); //generowanie DL dla wszystkiego przy wczytywaniu?
|
||||
tmp->pCenter = interpolate( tmp->hvTraction->pPoint2, tmp->hvTraction->pPoint1, 0.5 );
|
||||
break;
|
||||
case TP_TRACTIONPOWERSOURCE:
|
||||
@@ -1015,7 +998,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
tmp->MemCell->Load(parser);
|
||||
if (!tmp->asName.empty()) // jest pusta gdy "none"
|
||||
{ // dodanie do wyszukiwarki
|
||||
if( false == m_trackmap.Add( TP_MEMCELL, tmp->asName, tmp ) ) {
|
||||
if( false == m_nodemap.Add( TP_MEMCELL, tmp->asName, tmp ) ) {
|
||||
// przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność wsteczna)
|
||||
ErrorLog( "Duplicated memcell: " + tmp->asName ); // to zgłaszać duplikat
|
||||
}
|
||||
@@ -1033,14 +1016,14 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
tmp->EvLaunch->Load(parser);
|
||||
break;
|
||||
case TP_TRACK:
|
||||
tmp->pTrack = new TTrack(tmp);
|
||||
tmp->pTrack = new TTrack( tmp->asName );
|
||||
if (Global::iWriteLogEnabled & 4)
|
||||
if (!tmp->asName.empty())
|
||||
WriteLog(tmp->asName);
|
||||
tmp->pTrack->Load(parser, pOrigin, tmp->asName); // w nazwie może być nazwa odcinka izolowanego
|
||||
tmp->pTrack->Load(parser, pOrigin); // w nazwie może być nazwa odcinka izolowanego
|
||||
if (!tmp->asName.empty()) // jest pusta gdy "none"
|
||||
{ // dodanie do wyszukiwarki
|
||||
if( false == m_trackmap.Add( TP_TRACK, tmp->asName, tmp ) ) {
|
||||
if( false == m_nodemap.Add( TP_TRACK, tmp->asName, tmp ) ) {
|
||||
// przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność wsteczna)
|
||||
ErrorLog( "Duplicated track: " + tmp->asName ); // to zgłaszać duplikat
|
||||
}
|
||||
@@ -1148,22 +1131,18 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
if (fTrainSetDist < 8.0) // i raczej nie sięga
|
||||
fTrainSetDist =
|
||||
8.0; // przesuwamy około pół EU07 dla wstecznej zgodności
|
||||
// WriteLog("Dynamic shift: "+AnsiString(fTrainSetDist));
|
||||
/* //Ra: to jednak robi duże problemy - przesunięcie w dynamic jest przesunięciem do
|
||||
tyłu, odwrotnie niż w trainset
|
||||
if (!iTrainSetWehicleNumber) //dla pierwszego jest to przesunięcie (ujemne = do
|
||||
tyłu)
|
||||
if (tf1!=-1.0) //-1 wyjątkowo oznacza odwrócenie
|
||||
tf1=-tf1; //a dla kolejnych odległość między sprzęgami (ujemne = wbite)
|
||||
*/
|
||||
tf3 = tmp->DynamicObject->Init(asNodeName, str1, Skin, str3, Track,
|
||||
(tf1 == -1.0 ? fTrainSetDist : fTrainSetDist - tf1),
|
||||
DriverType, tf3, asTrainName, int2, str2, (tf1 == -1.0),
|
||||
str4);
|
||||
if (tf3 != 0.0) // zero oznacza błąd
|
||||
|
||||
auto const length =
|
||||
tmp->DynamicObject->Init(
|
||||
asNodeName, str1, Skin, str3, Track,
|
||||
( tf1 == -1.0 ?
|
||||
fTrainSetDist :
|
||||
fTrainSetDist - tf1 ),
|
||||
DriverType, tf3, asTrainName, int2, str2, (tf1 == -1.0), str4);
|
||||
if (length != 0.0) // zero oznacza błąd
|
||||
{
|
||||
// przesunięcie dla kolejnego, minus bo idziemy w stronę punktu 1
|
||||
fTrainSetDist -= tf3;
|
||||
fTrainSetDist -= length;
|
||||
tmp->pCenter = tmp->DynamicObject->GetPosition();
|
||||
// automatically establish permanent connections for couplers which specify them in their definitions
|
||||
if( TempConnectionType[ iTrainSetWehicleNumber ] ) {
|
||||
@@ -1208,7 +1187,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
// 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
|
||||
m_lights.insert( tmp->DynamicObject );
|
||||
simulation::Lights.insert( tmp->DynamicObject );
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1257,7 +1236,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
}
|
||||
else if( !tmp->asName.empty() ) // jest pusta gdy "none"
|
||||
{ // dodanie do wyszukiwarki
|
||||
if( false == m_trackmap.Add( TP_MODEL, tmp->asName, tmp ) ) {
|
||||
if( false == m_nodemap.Add( TP_MODEL, tmp->asName, tmp ) ) {
|
||||
// przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność wsteczna)
|
||||
ErrorLog( "Duplicated model: " + tmp->asName ); // to zgłaszać duplikat
|
||||
}
|
||||
@@ -1310,7 +1289,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
|
||||
tmp->iFlags = 0x200; // flaga usuwania
|
||||
tmp->Model = new TAnimModel();
|
||||
tmp->Model->RaAnglesSet( aRotate.x, tf1 + aRotate.y, aRotate.z ); // dostosowanie do pochylania linii
|
||||
tmp->Model->RaAnglesSet( glm::vec3{ aRotate.x, tf1 + aRotate.y, aRotate.z } ); // dostosowanie do pochylania linii
|
||||
if( false == tmp->Model->Load( parser, false ) ) {
|
||||
// model nie wczytał się - ignorowanie node
|
||||
delete tmp;
|
||||
@@ -1320,7 +1299,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
tmp->iFlags |= tmp->Model->Flags(); // ustalenie, czy przezroczysty
|
||||
if( false == tmp->asName.empty() ) { // jest pusta gdy "none"
|
||||
// dodanie do wyszukiwarki
|
||||
if( false == m_trackmap.Add( TP_MODEL, tmp->asName, tmp ) ) {
|
||||
if( false == m_nodemap.Add( TP_MODEL, tmp->asName, tmp ) ) {
|
||||
// przy zdublowaniu wskaźnik zostanie podmieniony w drzewku na późniejszy (zgodność wsteczna)
|
||||
ErrorLog( "Duplicated model: " + tmp->asName ); // to zgłaszać duplikat
|
||||
}
|
||||
@@ -1652,6 +1631,7 @@ TSubRect * TGround::GetSubRect(int iCol, int iRow)
|
||||
return (Rects[bc][br].SafeGetSubRect(sc, sr)); // pobranie małego kwadratu
|
||||
}
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
TEvent * TGround::FindEvent(const std::string &asEventName)
|
||||
{
|
||||
if( asEventName.empty() ) { return nullptr; }
|
||||
@@ -1662,24 +1642,7 @@ TEvent * TGround::FindEvent(const std::string &asEventName)
|
||||
lookup->second :
|
||||
nullptr );
|
||||
}
|
||||
|
||||
TEvent * TGround::FindEventScan( std::string const &asEventName )
|
||||
{ // wyszukanie eventu z opcją utworzenia niejawnego dla komórek skanowanych
|
||||
auto const lookup = m_eventmap.find( asEventName );
|
||||
auto e = (
|
||||
lookup != m_eventmap.end() ?
|
||||
lookup->second :
|
||||
nullptr );
|
||||
if (e)
|
||||
return e; // jak istnieje, to w porządku
|
||||
if (asEventName.rfind(":scan") != std::string::npos) // jeszcze może być event niejawny
|
||||
{ // no to szukamy komórki pamięci o nazwie zawartej w evencie
|
||||
std::string n = asEventName.substr(0, asEventName.length() - 5); // do dwukropka
|
||||
if( m_trackmap.Find( TP_MEMCELL, n ) != nullptr ) // jeśli jest takowa komórka pamięci
|
||||
e = new TEvent(n); // utworzenie niejawnego eventu jej odczytu
|
||||
}
|
||||
return e; // utworzony albo się nie udało
|
||||
}
|
||||
#endif
|
||||
|
||||
void TGround::FirstInit()
|
||||
{ // ustalanie zależności na scenerii przed wczytaniem pojazdów
|
||||
@@ -1747,14 +1710,14 @@ void TGround::FirstInit()
|
||||
|
||||
WriteLog("InitNormals OK");
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
InitTracks(); //łączenie odcinków ze sobą i przyklejanie eventów
|
||||
WriteLog("InitTracks OK");
|
||||
|
||||
InitTraction(); //łączenie drutów ze sobą
|
||||
WriteLog("InitTraction OK");
|
||||
|
||||
InitEvents();
|
||||
WriteLog("InitEvents OK");
|
||||
WriteLog( "InitEvents OK" );
|
||||
#endif
|
||||
|
||||
InitLaunchers();
|
||||
WriteLog("InitLaunchers OK");
|
||||
@@ -1919,8 +1882,9 @@ bool TGround::Init(std::string File)
|
||||
}
|
||||
else if (str == "event")
|
||||
{
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
TEvent *tmp = new TEvent();
|
||||
tmp->Load(&parser, &pOrigin);
|
||||
tmp->Load(&parser, pOrigin);
|
||||
if (tmp->Type == tp_Unknown)
|
||||
delete tmp;
|
||||
else
|
||||
@@ -1983,6 +1947,7 @@ bool TGround::Init(std::string File)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (str == "rotate")
|
||||
{
|
||||
@@ -2211,7 +2176,7 @@ bool TGround::Init(std::string File)
|
||||
Global::iPause &= ~0x10; // koniec pauzy wczytywania
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool TGround::InitEvents()
|
||||
{ //łączenie eventów z pozostałymi obiektami
|
||||
TGroundNode *tmp, *trk;
|
||||
@@ -2346,14 +2311,14 @@ bool TGround::InitEvents()
|
||||
break;
|
||||
case tp_Visible: // ukrycie albo przywrócenie obiektu
|
||||
tmp = FindGroundNode(Current->asNodeName, TP_MODEL); // najpierw model
|
||||
if (!tmp)
|
||||
tmp = FindGroundNode(Current->asNodeName, TP_TRACTION); // może druty?
|
||||
if (!tmp)
|
||||
tmp = FindGroundNode(Current->asNodeName, TP_TRACK); // albo tory?
|
||||
if (!tmp)
|
||||
tmp = FindGroundNode(Current->asNodeName, TP_TRACTION); // może druty?
|
||||
if (tmp)
|
||||
Current->Params[9].nGroundNode = tmp;
|
||||
else
|
||||
ErrorLog("Bad event: visibility event \"" + Current->asName + "\" cannot find model \"" + Current->asNodeName + "\"");
|
||||
ErrorLog("Bad event: visibility event \"" + Current->asName + "\" cannot find item \"" + Current->asNodeName + "\"");
|
||||
Current->asNodeName = "";
|
||||
break;
|
||||
case tp_Switch: // przełożenie zwrotnicy albo zmiana stanu obrotnicy
|
||||
@@ -2490,7 +2455,6 @@ void TGround::InitTracks()
|
||||
int iConnection;
|
||||
|
||||
for (Current = nRootOfType[TP_TRACK]; Current; Current = Current->nNext) {
|
||||
|
||||
Track = Current->pTrack;
|
||||
// assign track events
|
||||
Track->AssignEvents(
|
||||
@@ -2513,7 +2477,6 @@ void TGround::InitTracks()
|
||||
FindEvent( Current->asName + ":eventall1" ),
|
||||
FindEvent( Current->asName + ":eventall2" ) );
|
||||
}
|
||||
|
||||
switch (Track->eType)
|
||||
{
|
||||
case tt_Table: // obrotnicę też łączymy na starcie z innymi torami
|
||||
@@ -2523,8 +2486,8 @@ void TGround::InitTracks()
|
||||
// Track->ModelAssign(tmp->Model->GetContainer(NULL)); //wiązanie toru z modelem
|
||||
// obrotnicy
|
||||
Track->RaAssign(
|
||||
Current, Model ? Model->Model : NULL, FindEvent(Current->asName + ":done"),
|
||||
FindEvent(Current->asName + ":joined")); // wiązanie toru z modelem obrotnicy
|
||||
Current, Model ? Model->Model : NULL, simulation::Events.FindEvent(Current->asName + ":done"),
|
||||
simulation::Events.FindEvent(Current->asName + ":joined")); // wiązanie toru z modelem obrotnicy
|
||||
// break; //jednak połączę z sąsiednim, jak ma się wysypywać null track
|
||||
}
|
||||
if (!Model) // jak nie ma modelu
|
||||
@@ -2607,15 +2570,18 @@ void TGround::InitTracks()
|
||||
}
|
||||
break;
|
||||
case tt_Switch: // dla rozjazdów szukamy eventów sygnalizacji rozprucia
|
||||
Track->AssignForcedEvents(FindEvent(Current->asName + ":forced+"),
|
||||
FindEvent(Current->asName + ":forced-"));
|
||||
Track->AssignForcedEvents(
|
||||
FindEvent( Current->asName + ":forced+" ),
|
||||
FindEvent( Current->asName + ":forced-" ) );
|
||||
break;
|
||||
}
|
||||
std::string const name = Track->IsolatedName(); // pobranie nazwy odcinka izolowanego
|
||||
if (!name.empty()) // jeśli została zwrócona nazwa
|
||||
Track->IsolatedEventsAssign(FindEvent(name + ":busy"), FindEvent(name + ":free"));
|
||||
if (Current->asName.substr(0, 1) ==
|
||||
"*") // możliwy portal, jeśli nie podłączony od striny 1
|
||||
if( !name.empty() ) // jeśli została zwrócona nazwa
|
||||
Track->IsolatedEventsAssign(
|
||||
FindEvent( name + ":busy" ),
|
||||
FindEvent( name + ":free" ) );
|
||||
// możliwy portal, jeśli nie podłączony od striny 1
|
||||
if (Current->asName.substr(0, 1) == "*")
|
||||
if (!Track->CurrentPrev() && Track->CurrentNext())
|
||||
Track->iCategoryFlag |= 0x100; // ustawienie flagi portalu
|
||||
}
|
||||
@@ -2631,7 +2597,7 @@ void TGround::InitTracks()
|
||||
Current = new TGroundNode(); // to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy
|
||||
// Current->asName=p->asName; //mazwa identyczna, jak nazwa odcinka izolowanego
|
||||
Current->MemCell = new TMemCell(NULL); // nowa komórka
|
||||
m_trackmap.Add( TP_MEMCELL, p->asName, Current );
|
||||
m_nodemap.Add( TP_MEMCELL, p->asName, Current );
|
||||
Current->nNext =
|
||||
nRootOfType[TP_MEMCELL]; // to nie powinno tutaj być, bo robi się śmietnik
|
||||
nRootOfType[TP_MEMCELL] = Current;
|
||||
@@ -2639,9 +2605,6 @@ void TGround::InitTracks()
|
||||
}
|
||||
p = p->Next();
|
||||
}
|
||||
// for (Current=nRootOfType[TP_TRACK];Current;Current=Current->nNext)
|
||||
// if (Current->pTrack->eType==tt_Cross)
|
||||
// Current->pTrack->ConnectionsLog(); //zalogowanie informacji o połączeniach
|
||||
}
|
||||
|
||||
void TGround::InitTraction()
|
||||
@@ -2849,7 +2812,7 @@ void TGround::InitTraction()
|
||||
}
|
||||
delete[] nEnds; // nie potrzebne już
|
||||
};
|
||||
|
||||
#endif
|
||||
void TGround::TrackJoin(TGroundNode *Current)
|
||||
{ // wyszukiwanie sąsiednich torów do podłączenia (wydzielone na użytek obrotnicy)
|
||||
TTrack *Track = Current->pTrack;
|
||||
@@ -2903,13 +2866,13 @@ bool TGround::InitLaunchers()
|
||||
MessageBox(0, "Cannot find Memory Cell for Event Launcher", "Error", MB_OK);
|
||||
}
|
||||
else
|
||||
EventLauncher->MemCell = NULL;
|
||||
EventLauncher->Event1 = (EventLauncher->asEvent1Name != "none") ?
|
||||
FindEvent(EventLauncher->asEvent1Name) :
|
||||
NULL;
|
||||
EventLauncher->Event2 = (EventLauncher->asEvent2Name != "none") ?
|
||||
FindEvent(EventLauncher->asEvent2Name) :
|
||||
NULL;
|
||||
EventLauncher->MemCell = nullptr;
|
||||
EventLauncher->Event1 = ( EventLauncher->asEvent1Name != "none") ?
|
||||
simulation::Events.FindEvent(EventLauncher->asEvent1Name) :
|
||||
nullptr;
|
||||
EventLauncher->Event2 = ( EventLauncher->asEvent2Name != "none") ?
|
||||
simulation::Events.FindEvent(EventLauncher->asEvent2Name) :
|
||||
nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -3039,6 +3002,7 @@ TTraction * TGround::TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n)
|
||||
return (nBest ? nBest->hvTraction : nullptr);
|
||||
};
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node)
|
||||
{
|
||||
if( Event->bEnabled ) {
|
||||
@@ -3107,8 +3071,9 @@ bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TGround::EventConditon(TEvent *e)
|
||||
{ // sprawdzenie spelnienia warunków dla eventu
|
||||
// sprawdzenie spelnienia warunków dla eventu
|
||||
bool TGround::EventConditon(TEvent *e){
|
||||
|
||||
if (e->iFlags <= update_only)
|
||||
return true; // bezwarunkowo
|
||||
|
||||
@@ -3122,56 +3087,51 @@ bool TGround::EventConditon(TEvent *e)
|
||||
WriteLog("Random integer: " + std::to_string(rprobability) + " / " + std::to_string(e->Params[10].asdouble));
|
||||
return (e->Params[10].asdouble > rprobability);
|
||||
}
|
||||
else if (e->iFlags & conditional_memcompare)
|
||||
{ // porównanie wartości
|
||||
else if( e->iFlags & conditional_memcompare ) {
|
||||
// porównanie wartości
|
||||
if( nullptr == e->Params[9].asMemCell ) {
|
||||
|
||||
ErrorLog( "Event " + e->asName + " trying conditional_memcompare with nonexistent memcell" );
|
||||
return true; // though this is technically error, we report success to maintain backward compatibility
|
||||
}
|
||||
if (tmpEvent->Params[9].asMemCell->Compare( ( e->Params[ 10 ].asText != nullptr ? e->Params[10].asText : "" ), e->Params[11].asdouble, e->Params[12].asdouble, e->iFlags) ) {
|
||||
//logowanie spełnionych warunków
|
||||
LogComment = e->Params[9].asMemCell->Text() + " " +
|
||||
to_string(e->Params[9].asMemCell->Value1(), 2, 8) + " " +
|
||||
to_string(tmpEvent->Params[9].asMemCell->Value2(), 2, 8) +
|
||||
" = ";
|
||||
if (TestFlag(e->iFlags, conditional_memstring))
|
||||
LogComment += std::string(tmpEvent->Params[10].asText);
|
||||
else
|
||||
LogComment += "*";
|
||||
if (TestFlag(tmpEvent->iFlags, conditional_memval1))
|
||||
LogComment += " " + to_string(tmpEvent->Params[11].asdouble, 2, 8);
|
||||
else
|
||||
LogComment += " *";
|
||||
if (TestFlag(tmpEvent->iFlags, conditional_memval2))
|
||||
LogComment += " " + to_string(tmpEvent->Params[12].asdouble, 2, 8);
|
||||
else
|
||||
LogComment += " *";
|
||||
WriteLog(LogComment);
|
||||
return true;
|
||||
}
|
||||
//else if (Global::iWriteLogEnabled && DebugModeFlag) //zawsze bo to bardzo istotne w debugowaniu scenariuszy
|
||||
else
|
||||
{ // nie zgadza się, więc sprawdzmy, co
|
||||
LogComment = e->Params[9].asMemCell->Text() + " " +
|
||||
to_string(e->Params[9].asMemCell->Value1(), 2, 8) + " " +
|
||||
to_string(tmpEvent->Params[9].asMemCell->Value2(), 2, 8) +
|
||||
" != ";
|
||||
if (TestFlag(e->iFlags, conditional_memstring))
|
||||
LogComment += (tmpEvent->Params[10].asText);
|
||||
else
|
||||
LogComment += "*";
|
||||
if (TestFlag(tmpEvent->iFlags, conditional_memval1))
|
||||
LogComment += " " + to_string(tmpEvent->Params[11].asdouble, 2, 8);
|
||||
else
|
||||
LogComment += " *";
|
||||
if (TestFlag(tmpEvent->iFlags, conditional_memval2))
|
||||
LogComment += " " + to_string(tmpEvent->Params[12].asdouble, 2, 8);
|
||||
else
|
||||
LogComment += " *";
|
||||
WriteLog(LogComment);
|
||||
}
|
||||
auto const comparisonresult =
|
||||
tmpEvent->Params[ 9 ].asMemCell->Compare(
|
||||
( e->Params[ 10 ].asText != nullptr ?
|
||||
e->Params[ 10 ].asText :
|
||||
"" ),
|
||||
e->Params[ 11 ].asdouble,
|
||||
e->Params[ 12 ].asdouble,
|
||||
e->iFlags );
|
||||
|
||||
std::string comparisonlog = "Type: MemCompare - ";
|
||||
|
||||
comparisonlog +=
|
||||
"[" + e->Params[ 9 ].asMemCell->Text() + "]"
|
||||
+ " [" + to_string( e->Params[ 9 ].asMemCell->Value1(), 2 ) + "]"
|
||||
+ " [" + to_string( tmpEvent->Params[ 9 ].asMemCell->Value2(), 2 ) + "]";
|
||||
|
||||
comparisonlog += (
|
||||
true == comparisonresult ?
|
||||
" == " :
|
||||
" != " );
|
||||
|
||||
comparisonlog += (
|
||||
TestFlag( e->iFlags, conditional_memstring ) ?
|
||||
"[" + std::string( tmpEvent->Params[ 10 ].asText ) + "]" :
|
||||
"[*]" );
|
||||
comparisonlog += (
|
||||
TestFlag( tmpEvent->iFlags, conditional_memval1 ) ?
|
||||
" [" + to_string( tmpEvent->Params[ 11 ].asdouble, 2 ) + "]" :
|
||||
" [*]" );
|
||||
comparisonlog += (
|
||||
TestFlag( tmpEvent->iFlags, conditional_memval2 ) ?
|
||||
" [" + to_string( tmpEvent->Params[ 12 ].asdouble, 2 ) + "]" :
|
||||
" [*]" );
|
||||
|
||||
WriteLog( comparisonlog );
|
||||
return comparisonresult;
|
||||
}
|
||||
// unrecognized request
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -3227,16 +3187,16 @@ bool TGround::CheckQuery()
|
||||
&tmpEvent->Params[ 4 ].nGroundNode->pCenter );
|
||||
}
|
||||
//if (DebugModeFlag)
|
||||
WriteLog("Type: UpdateValues & Track command - " +
|
||||
tmpEvent->Params[5].asMemCell->Text() + " " +
|
||||
std::to_string( tmpEvent->Params[ 5 ].asMemCell->Value1() ) + " " +
|
||||
std::to_string( tmpEvent->Params[ 5 ].asMemCell->Value2() ) );
|
||||
WriteLog("Type: UpdateValues & Track command - [" +
|
||||
tmpEvent->Params[5].asMemCell->Text() + "] [" +
|
||||
to_string( tmpEvent->Params[ 5 ].asMemCell->Value1(), 2 ) + "] [" +
|
||||
to_string( tmpEvent->Params[ 5 ].asMemCell->Value2(), 2 ) + "]" );
|
||||
}
|
||||
else //if (DebugModeFlag)
|
||||
WriteLog("Type: UpdateValues - " +
|
||||
tmpEvent->Params[5].asMemCell->Text() + " " +
|
||||
std::to_string( tmpEvent->Params[ 5 ].asMemCell->Value1() ) + " " +
|
||||
std::to_string( tmpEvent->Params[ 5 ].asMemCell->Value2() ) );
|
||||
WriteLog("Type: UpdateValues - [" +
|
||||
tmpEvent->Params[5].asMemCell->Text() + "] [" +
|
||||
to_string( tmpEvent->Params[ 5 ].asMemCell->Value1(), 2 ) + "] [" +
|
||||
to_string( tmpEvent->Params[ 5 ].asMemCell->Value2(), 2 ) + "]" );
|
||||
}
|
||||
break;
|
||||
case tp_GetValues:
|
||||
@@ -3255,24 +3215,26 @@ bool TGround::CheckQuery()
|
||||
WriteLog("Type: GetValues");
|
||||
break;
|
||||
case tp_PutValues:
|
||||
if (tmpEvent->Activator)
|
||||
{
|
||||
loc.X =
|
||||
-tmpEvent->Params[3].asdouble; // zamiana, bo fizyka ma inaczej niż sceneria
|
||||
if (tmpEvent->Activator) {
|
||||
// zamiana, bo fizyka ma inaczej niż sceneria
|
||||
loc.X = -tmpEvent->Params[3].asdouble;
|
||||
loc.Y = tmpEvent->Params[5].asdouble;
|
||||
loc.Z = tmpEvent->Params[4].asdouble;
|
||||
if (tmpEvent->Activator->Mechanik) // przekazanie rozkazu do AI
|
||||
tmpEvent->Activator->Mechanik->PutCommand(
|
||||
tmpEvent->Params[0].asText, tmpEvent->Params[1].asdouble,
|
||||
tmpEvent->Params[2].asdouble, loc);
|
||||
else
|
||||
{ // przekazanie do pojazdu
|
||||
else {
|
||||
// przekazanie do pojazdu
|
||||
tmpEvent->Activator->MoverParameters->PutCommand(
|
||||
tmpEvent->Params[0].asText, tmpEvent->Params[1].asdouble,
|
||||
tmpEvent->Params[2].asdouble, loc);
|
||||
}
|
||||
WriteLog("Type: PutValues - [" +
|
||||
std::string(tmpEvent->Params[0].asText) + "] [" +
|
||||
to_string( tmpEvent->Params[ 1 ].asdouble, 2 ) + "] [" +
|
||||
to_string( tmpEvent->Params[ 2 ].asdouble, 2 ) + "]" );
|
||||
}
|
||||
WriteLog("Type: PutValues");
|
||||
break;
|
||||
case tp_Lights:
|
||||
if (tmpEvent->Params[9].asModel)
|
||||
@@ -3342,11 +3304,10 @@ bool TGround::CheckQuery()
|
||||
if (tmpEvent->Params[9].asTrack)
|
||||
{ // prędkość na zwrotnicy może być ograniczona z góry we wpisie, większej się nie
|
||||
// ustawi eventem
|
||||
WriteLog("type: TrackVel");
|
||||
// WriteLog("Vel: ",tmpEvent->Params[0].asdouble);
|
||||
WriteLog("Type: TrackVel");
|
||||
tmpEvent->Params[9].asTrack->VelocitySet(tmpEvent->Params[0].asdouble);
|
||||
if (DebugModeFlag) // wyświetlana jest ta faktycznie ustawiona
|
||||
WriteLog("vel: ", tmpEvent->Params[9].asTrack->VelocityGet());
|
||||
WriteLog(" - velocity: ", tmpEvent->Params[9].asTrack->VelocityGet());
|
||||
}
|
||||
break;
|
||||
case tp_DynVel:
|
||||
@@ -3358,7 +3319,7 @@ bool TGround::CheckQuery()
|
||||
if (bCondition || (tmpEvent->iFlags &
|
||||
conditional_anyelse)) // warunek spelniony albo było użyte else
|
||||
{
|
||||
WriteLog("Multiple passed");
|
||||
WriteLog("Type: Multi-event");
|
||||
for (i = 0; i < 8; ++i) {
|
||||
// dodawane do kolejki w kolejności zapisania
|
||||
if( tmpEvent->Params[ i ].asEvent ) {
|
||||
@@ -3413,7 +3374,7 @@ bool TGround::CheckQuery()
|
||||
tmpEvent->iFlags & ( update_memstring | update_memval1 | update_memval2 ) );
|
||||
|
||||
WriteLog(
|
||||
"whois request (" + to_string( tmpEvent->iFlags ) + ") "
|
||||
"Type: WhoIs (" + to_string( tmpEvent->iFlags ) + ") - "
|
||||
+ "[name: " + tmpEvent->Activator->MoverParameters->TypeName + "], "
|
||||
+ "[consist brake level: " + to_string( consistbrakelevel, 2 ) + "], "
|
||||
+ "[obstacle distance: " + to_string( collisiondistance, 2 ) + " m]" );
|
||||
@@ -3427,7 +3388,7 @@ bool TGround::CheckQuery()
|
||||
tmpEvent->iFlags & ( update_memstring | update_memval1 | update_memval2 ) );
|
||||
|
||||
WriteLog(
|
||||
"whois request (" + to_string( tmpEvent->iFlags ) + ") "
|
||||
"Type: WhoIs (" + to_string( tmpEvent->iFlags ) + ") - "
|
||||
+ "[load type: " + tmpEvent->Activator->MoverParameters->LoadType + "], "
|
||||
+ "[current load: " + to_string( tmpEvent->Activator->MoverParameters->Load, 2 ) + "], "
|
||||
+ "[max load: " + to_string( tmpEvent->Activator->MoverParameters->MaxLoad, 2 ) + "]" );
|
||||
@@ -3442,7 +3403,7 @@ bool TGround::CheckQuery()
|
||||
tmpEvent->iFlags & (update_memstring | update_memval1 | update_memval2));
|
||||
|
||||
WriteLog(
|
||||
"whois request (" + to_string( tmpEvent->iFlags ) + ") "
|
||||
"Type: WhoIs (" + to_string( tmpEvent->iFlags ) + ") - "
|
||||
+ "[destination: " + tmpEvent->Activator->asDestination + "], "
|
||||
+ "[direction: " + to_string( tmpEvent->Activator->DirectionGet() ) + "], "
|
||||
+ "[engine power: " + to_string( tmpEvent->Activator->MoverParameters->Power, 2 ) + "]" );
|
||||
@@ -3476,12 +3437,12 @@ bool TGround::CheckQuery()
|
||||
case tp_Voltage: // zmiana napięcia w zasilaczu (TractionPowerSource)
|
||||
if (tmpEvent->Params[9].psPower)
|
||||
{ // na razie takie chamskie ustawienie napięcia zasilania
|
||||
WriteLog("type: Voltage");
|
||||
WriteLog("Type: Voltage");
|
||||
tmpEvent->Params[9].psPower->VoltageSet(tmpEvent->Params[0].asdouble);
|
||||
}
|
||||
case tp_Friction: // zmiana tarcia na scenerii
|
||||
{ // na razie takie chamskie ustawienie napięcia zasilania
|
||||
WriteLog("type: Friction");
|
||||
WriteLog("Type: Friction");
|
||||
Global::fFriction = (tmpEvent->Params[0].asdouble);
|
||||
}
|
||||
break;
|
||||
@@ -3492,6 +3453,7 @@ bool TGround::CheckQuery()
|
||||
} // while
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void TGround::UpdatePhys(double dt, int iter)
|
||||
{ // aktualizacja fizyki stałym krokiem: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń
|
||||
@@ -3574,13 +3536,6 @@ bool TGround::Update(double dt, int iter)
|
||||
return true;
|
||||
};
|
||||
|
||||
// updates scene lights array
|
||||
void
|
||||
TGround::Update_Lights() {
|
||||
|
||||
m_lights.update();
|
||||
}
|
||||
|
||||
void
|
||||
TGround::Update_Hidden() {
|
||||
|
||||
@@ -4179,7 +4134,7 @@ void TGround::DynamicRemove(TDynamicObject *dyn)
|
||||
(*n) = node->nNext; // pominięcie na liście
|
||||
Global::TrainDelete(d);
|
||||
// remove potential entries in the light array
|
||||
m_lights.remove( d );
|
||||
simulation::Lights.remove( d );
|
||||
d = d->Next(); // przejście do kolejnego pojazdu, póki jeszcze jest
|
||||
delete node; // usuwanie fizyczne z pamięci
|
||||
}
|
||||
|
||||
51
Ground.h
51
Ground.h
@@ -10,16 +10,13 @@ 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 "simulation.h"
|
||||
|
||||
typedef int TGroundNodeType;
|
||||
// Ra: zmniejszone liczby, aby zrobić tabelkę i zoptymalizować wyszukiwanie
|
||||
@@ -97,7 +94,7 @@ struct TGroundVertex
|
||||
// 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
|
||||
geometry_handle geometry { 0, 0 }; // geometry prepared for drawing
|
||||
};
|
||||
|
||||
// obiekt scenerii
|
||||
@@ -142,9 +139,9 @@ public:
|
||||
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
|
||||
Ambient{ 0.2f },
|
||||
Diffuse{ 1.0f },
|
||||
Specular{ 0.0f }; // oświetlenie
|
||||
double fLineThickness; // McZapkie-120702: grubosc linii
|
||||
bool bVisible;
|
||||
|
||||
@@ -155,17 +152,17 @@ public:
|
||||
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;
|
||||
scene::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
|
||||
@@ -219,6 +216,7 @@ private:
|
||||
public:
|
||||
virtual ~TGroundRect();
|
||||
// pobranie wskaźnika do małego kwadratu, utworzenie jeśli trzeba
|
||||
inline
|
||||
TSubRect * SafeGetSubRect(int iCol, int iRow) {
|
||||
if( !pSubRects ) {
|
||||
// utworzenie małych kwadratów
|
||||
@@ -227,6 +225,7 @@ public:
|
||||
return pSubRects + iRow * iNumSubRects + iCol; // zwrócenie właściwego
|
||||
};
|
||||
// pobranie wskaźnika do małego kwadratu, bez tworzenia jeśli nie ma
|
||||
inline
|
||||
TSubRect *FastGetSubRect(int iCol, int iRow) const {
|
||||
return (
|
||||
pSubRects ?
|
||||
@@ -234,8 +233,9 @@ public:
|
||||
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 );
|
||||
bool mergeable( TGroundNode const &Left, TGroundNode const &Right ) const;
|
||||
// optymalizacja obiektów w sektorach
|
||||
inline
|
||||
void Optimize() {
|
||||
if( pSubRects ) {
|
||||
for( int i = iNumSubRects * iNumSubRects - 1; i >= 0; --i ) {
|
||||
@@ -253,20 +253,23 @@ class TGround
|
||||
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
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
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
|
||||
#endif
|
||||
TNames<TGroundNode *> m_nodemap;
|
||||
|
||||
vector3 pOrigin;
|
||||
vector3 aRotate;
|
||||
bool bInitDone = false;
|
||||
|
||||
private: // metody prywatne
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool EventConditon(TEvent *e);
|
||||
#endif
|
||||
|
||||
public:
|
||||
bool bDynamicRemove = false; // czy uruchomić procedurę usuwania pojazdów
|
||||
@@ -276,9 +279,11 @@ class TGround
|
||||
void Free();
|
||||
bool Init( std::string File );
|
||||
void FirstInit();
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
void InitTracks();
|
||||
void InitTraction();
|
||||
bool InitEvents();
|
||||
#endif
|
||||
bool InitLaunchers();
|
||||
TTrack * FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude);
|
||||
TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TGroundNode *Exclude);
|
||||
@@ -286,15 +291,16 @@ class TGround
|
||||
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);
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool AddToQuery( TEvent *Event, TDynamicObject *Node );
|
||||
bool CheckQuery();
|
||||
#endif
|
||||
TGroundNode * DynamicFindAny(std::string const &Name);
|
||||
TGroundNode * DynamicFind(std::string const &Name);
|
||||
void DynamicList(bool all = false);
|
||||
TGroundNode * FindGroundNode(std::string asNameToFind, TGroundNodeType iNodeType);
|
||||
TGroundNode * FindGroundNode(std::string const &asNameToFind, TGroundNodeType const iNodeType);
|
||||
TGroundRect * GetRect( double x, double z );
|
||||
TSubRect * GetSubRect( int iCol, int iRow );
|
||||
inline
|
||||
@@ -310,8 +316,9 @@ class TGround
|
||||
inline
|
||||
int GetColFromX(double x) {
|
||||
return (int)(x / fSubRectSize + fHalfTotalNumSubRects); };
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
TEvent * FindEvent(const std::string &asEventName);
|
||||
TEvent * FindEventScan(const std::string &asEventName);
|
||||
#endif
|
||||
void TrackJoin(TGroundNode *Current);
|
||||
|
||||
private:
|
||||
@@ -330,10 +337,8 @@ class TGround
|
||||
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);
|
||||
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();
|
||||
|
||||
29
MemCell.cpp
29
MemCell.cpp
@@ -25,17 +25,18 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// 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
|
||||
m_location =
|
||||
p ? *p : glm::dvec3(); // 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 +104,17 @@ TCommandType TMemCell::CommandCheck()
|
||||
bool TMemCell::Load(cParser *parser)
|
||||
{
|
||||
std::string token;
|
||||
parser->getTokens(1, false); // case sensitive
|
||||
*parser >> szText;
|
||||
parser->getTokens( 2, false );
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
parser->getTokens( 3, false );
|
||||
*parser
|
||||
#else
|
||||
parser->getTokens( 6, false );
|
||||
*parser
|
||||
>> m_location.x
|
||||
>> m_location.y
|
||||
>> m_location.z
|
||||
#endif
|
||||
>> szText
|
||||
>> fValue1
|
||||
>> fValue2;
|
||||
parser->getTokens();
|
||||
@@ -150,11 +158,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)
|
||||
|
||||
77
MemCell.h
77
MemCell.h
@@ -10,52 +10,59 @@ http://mozilla.org/MPL/2.0/.
|
||||
#pragma once
|
||||
|
||||
#include "Classes.h"
|
||||
#include "scenenode.h"
|
||||
#include "dumb3d.h"
|
||||
#include "names.h"
|
||||
|
||||
class TMemCell : public editor::basic_node {
|
||||
|
||||
class TMemCell
|
||||
{
|
||||
private:
|
||||
Math3D::vector3 vPosition;
|
||||
// content
|
||||
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
|
||||
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
|
||||
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, Math3D::vector3 *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);
|
||||
};
|
||||
|
||||
class memory_manager : public basic_table<TMemCell> {
|
||||
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
20
Model3d.cpp
20
Model3d.cpp
@@ -1023,7 +1023,7 @@ TSubModel::convert( TGroundNode &Groundnode ) const {
|
||||
|
||||
if( m_geometry == null_handle ) { return; }
|
||||
|
||||
std::size_t vertexcount { 0 };
|
||||
int vertexcount { 0 };
|
||||
std::vector<TGroundVertex> importedvertices;
|
||||
TGroundVertex vertex, vertex1, vertex2;
|
||||
for( auto const &sourcevertex : GfxRenderer.Vertices( m_geometry ) ) {
|
||||
@@ -1038,31 +1038,29 @@ TSubModel::convert( TGroundNode &Groundnode ) const {
|
||||
importedvertices.emplace_back( vertex2 );
|
||||
importedvertices.emplace_back( vertex );
|
||||
}
|
||||
// start a new triangle
|
||||
vertexcount = -1;
|
||||
}
|
||||
++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 ) {
|
||||
|
||||
// assign imported geometry to the node...
|
||||
Groundnode.Piece->vertices.swap( importedvertices );
|
||||
|
||||
// ...and calculate center...
|
||||
for( auto const &vertex : Groundnode.Piece->vertices ) {
|
||||
Groundnode.pCenter += vertex.position;
|
||||
}
|
||||
Groundnode.pCenter /= Groundnode.iNumVerts;
|
||||
|
||||
double r { 0.0 };
|
||||
double tf;
|
||||
// ...and bounding area
|
||||
double squareradius { 0.0 };
|
||||
for( auto const &vertex : Groundnode.Piece->vertices ) {
|
||||
tf = glm::length2( vertex.position - glm::dvec3{ Groundnode.pCenter } );
|
||||
if( tf > r )
|
||||
r = tf;
|
||||
squareradius = std::max( squareradius, glm::length2( vertex.position - glm::dvec3{ Groundnode.pCenter } ) );
|
||||
}
|
||||
Groundnode.fSquareRadius += r;
|
||||
Groundnode.fSquareRadius += squareradius;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
44
Names.h
44
Names.h
@@ -65,3 +65,47 @@ private:
|
||||
// members:
|
||||
typemap_map m_maps; // list of object maps of types specified so far
|
||||
};
|
||||
|
||||
template <typename Type_>
|
||||
class basic_table {
|
||||
|
||||
public:
|
||||
// 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
|
||||
insert( Type_ *Item ) {
|
||||
m_items.emplace_back( Item );
|
||||
auto const itemname = Item->name();
|
||||
if( ( true == itemname.empty() ) || ( itemname == "none" ) ) {
|
||||
return true;
|
||||
}
|
||||
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 ); }
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
415
Track.cpp
415
Track.cpp
@@ -139,13 +139,12 @@ void TIsolated::Modify(int i, TDynamicObject *o)
|
||||
};
|
||||
|
||||
// tworzenie nowego odcinka ruchu
|
||||
TTrack::TTrack(TGroundNode *g) :
|
||||
pMyNode( g ) // Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode
|
||||
{
|
||||
fRadiusTable[ 0 ] = 0.0;
|
||||
fRadiusTable[ 1 ] = 0.0;
|
||||
nFouling[ 0 ] = nullptr;
|
||||
nFouling[ 1 ] = nullptr;
|
||||
TTrack::TTrack( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {}
|
||||
|
||||
// legacy constructor
|
||||
TTrack::TTrack( std::string Name ) {
|
||||
|
||||
m_name = Name;
|
||||
}
|
||||
|
||||
TTrack::~TTrack()
|
||||
@@ -182,7 +181,7 @@ TTrack * TTrack::Create400m(int what, double dx)
|
||||
{ // tworzenie toru do wstawiania taboru podczas konwersji na E3D
|
||||
TGroundNode *tmp = new TGroundNode(TP_TRACK); // node
|
||||
TTrack *trk = tmp->pTrack;
|
||||
trk->bVisible = false; // nie potrzeba pokazywać, zresztą i tak nie ma tekstur
|
||||
trk->m_visible = false; // nie potrzeba pokazywać, zresztą i tak nie ma tekstur
|
||||
trk->iCategoryFlag = what; // taki sam typ plus informacja, że dodatkowy
|
||||
trk->Init(); // utworzenie segmentu
|
||||
trk->Segment->Init(vector3(-dx, 0, 0), vector3(-dx, 0, 400), 10.0, 0, 0); // prosty
|
||||
@@ -195,12 +194,10 @@ TTrack * TTrack::Create400m(int what, double dx)
|
||||
|
||||
TTrack * TTrack::NullCreate(int dir)
|
||||
{ // tworzenie toru wykolejającego od strony (dir), albo pętli dla samochodów
|
||||
TGroundNode *tmp = new TGroundNode(TP_TRACK), *tmp2 = NULL; // node
|
||||
TGroundNode *tmp = new TGroundNode( TP_TRACK );
|
||||
TGroundNode *tmp2 = nullptr; // node
|
||||
TTrack *trk = tmp->pTrack; // tor; UWAGA! obrotnica może generować duże ilości tego
|
||||
// tmp->iType=TP_TRACK;
|
||||
// TTrack* trk=new TTrack(tmp); //tor; UWAGA! obrotnica może generować duże ilości tego
|
||||
// tmp->pTrack=trk;
|
||||
trk->bVisible = false; // nie potrzeba pokazywać, zresztą i tak nie ma tekstur
|
||||
trk->m_visible = false; // nie potrzeba pokazywać, zresztą i tak nie ma tekstur
|
||||
// trk->iTrapezoid=1; //są przechyłki do uwzględniania w rysowaniu
|
||||
trk->iCategoryFlag = (iCategoryFlag & 15) | 0x80; // taki sam typ plus informacja, że dodatkowy
|
||||
float r1, r2;
|
||||
@@ -216,25 +213,21 @@ TTrack * TTrack::NullCreate(int dir)
|
||||
case 0:
|
||||
p1 = Segment->FastGetPoint_0();
|
||||
p2 = p1 - 450.0 * Normalize(Segment->GetDirection1());
|
||||
trk->Segment->Init(p1, p2, 5, -RadToDeg(r1),
|
||||
70.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
||||
// bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
||||
trk->Segment->Init(p1, p2, 5, -RadToDeg(r1), 70.0);
|
||||
ConnectPrevPrev(trk, 0);
|
||||
break;
|
||||
case 1:
|
||||
p1 = Segment->FastGetPoint_1();
|
||||
p2 = p1 - 450.0 * Normalize(Segment->GetDirection2());
|
||||
trk->Segment->Init(p1, p2, 5, RadToDeg(r2),
|
||||
70.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
||||
// bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
||||
trk->Segment->Init(p1, p2, 5, RadToDeg(r2), 70.0);
|
||||
ConnectNextPrev(trk, 0);
|
||||
break;
|
||||
case 3: // na razie nie możliwe
|
||||
p1 = SwitchExtension->Segments[1]->FastGetPoint_1(); // koniec toru drugiego zwrotnicy
|
||||
p2 = p1 -
|
||||
450.0 *
|
||||
Normalize(
|
||||
SwitchExtension->Segments[1]->GetDirection2()); // przedłużenie na wprost
|
||||
trk->Segment->Init(p1, p2, 5, RadToDeg(r2),
|
||||
70.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
||||
p2 = p1 - 450.0 * Normalize( SwitchExtension->Segments[1]->GetDirection2()); // przedłużenie na wprost
|
||||
trk->Segment->Init(p1, p2, 5, RadToDeg(r2), 70.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
||||
ConnectNextPrev(trk, 0);
|
||||
// trk->ConnectPrevNext(trk,dir);
|
||||
SetConnections(1); // skopiowanie połączeń
|
||||
@@ -251,13 +244,13 @@ TTrack * TTrack::NullCreate(int dir)
|
||||
TTrack *trk2 = tmp2->pTrack;
|
||||
trk2->iCategoryFlag =
|
||||
(iCategoryFlag & 15) | 0x80; // taki sam typ plus informacja, że dodatkowy
|
||||
trk2->bVisible = false;
|
||||
trk2->m_visible = false;
|
||||
trk2->fVelocity = 20.0; // zawracanie powoli
|
||||
trk2->fRadius = 20.0; // promień, aby się dodawało do tabelki prędkości i liczyło
|
||||
// narastająco
|
||||
trk2->Init(); // utworzenie segmentu
|
||||
trk->pMyNode->asName = pMyNode->asName + ":loopstart";
|
||||
trk2->pMyNode->asName = pMyNode->asName + ":loopfinish";
|
||||
trk->m_name = m_name + ":loopstart";
|
||||
trk2->m_name = m_name + ":loopfinish";
|
||||
switch (dir)
|
||||
{ //łączenie z nowym torem
|
||||
case 0:
|
||||
@@ -320,8 +313,8 @@ void TTrack::ConnectPrevNext(TTrack *pTrack, int typ)
|
||||
iPrevDirection = typ | 1; // 1:zwykły lub pierwszy zwrotnicy, 3:drugi zwrotnicy
|
||||
pTrack->trNext = this;
|
||||
pTrack->iNextDirection = 0;
|
||||
if (bVisible)
|
||||
if (pTrack->bVisible)
|
||||
if (m_visible)
|
||||
if (pTrack->m_visible)
|
||||
if (eType == tt_Normal) // jeśli łączone są dwa normalne
|
||||
if (pTrack->eType == tt_Normal)
|
||||
if ((fTrackWidth !=
|
||||
@@ -340,8 +333,8 @@ void TTrack::ConnectNextPrev(TTrack *pTrack, int typ)
|
||||
iNextDirection = ((pTrack->eType == tt_Switch) ? 0 : (typ & 2));
|
||||
pTrack->trPrev = this;
|
||||
pTrack->iPrevDirection = 1;
|
||||
if (bVisible)
|
||||
if (pTrack->bVisible)
|
||||
if (m_visible)
|
||||
if (pTrack->m_visible)
|
||||
if (eType == tt_Normal) // jeśli łączone są dwa normalne
|
||||
if (pTrack->eType == tt_Normal)
|
||||
if ((fTrackWidth !=
|
||||
@@ -363,25 +356,15 @@ void TTrack::ConnectNextNext(TTrack *pTrack, int typ)
|
||||
}
|
||||
}
|
||||
|
||||
vector3 MakeCPoint(vector3 p, double d, double a1, double a2)
|
||||
{
|
||||
vector3 cp = vector3(0, 0, 1);
|
||||
cp.RotateX(DegToRad(a2));
|
||||
cp.RotateY(DegToRad(a1));
|
||||
cp = cp * d + p;
|
||||
return cp;
|
||||
}
|
||||
|
||||
vector3 LoadPoint(cParser *parser)
|
||||
{ // pobranie współrzędnych punktu
|
||||
vector3 p;
|
||||
std::string token;
|
||||
parser->getTokens(3);
|
||||
*parser >> p.x >> p.y >> p.z;
|
||||
return p;
|
||||
}
|
||||
|
||||
void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
|
||||
void TTrack::Load(cParser *parser, vector3 pOrigin)
|
||||
{ // pobranie obiektu trajektorii ruchu
|
||||
vector3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań
|
||||
double a1, a2, r1, r2, r3, r4;
|
||||
@@ -464,8 +447,8 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
|
||||
}
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
bVisible = (token.compare("vis") == 0); // visible
|
||||
if (bVisible)
|
||||
m_visible = (token.compare("vis") == 0); // visible
|
||||
if (m_visible)
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> str; // railtex
|
||||
@@ -718,24 +701,28 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
|
||||
}
|
||||
else if (str == "angle1")
|
||||
{ // kąt ścięcia końca od strony 1
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> a1;
|
||||
Segment->AngleSet(0, a1);
|
||||
//Segment->AngleSet(0, a1);
|
||||
}
|
||||
else if (str == "angle2")
|
||||
{ // kąt ścięcia końca od strony 2
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> a2;
|
||||
Segment->AngleSet(1, a2);
|
||||
//Segment->AngleSet(1, a2);
|
||||
}
|
||||
else if (str == "fouling1")
|
||||
{ // wskazanie modelu ukresu w kierunku 1
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
// nFouling[0]=
|
||||
}
|
||||
else if (str == "fouling2")
|
||||
{ // wskazanie modelu ukresu w kierunku 2
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
// nFouling[1]=
|
||||
@@ -749,19 +736,26 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
|
||||
// ograniczenie dla pantografujących)
|
||||
}
|
||||
else
|
||||
ErrorLog("Unknown property: \"" + str + "\" in track \"" + name + "\"");
|
||||
ErrorLog("Unknown property: \"" + str + "\" in track \"" + m_name + "\"");
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
str = token;
|
||||
}
|
||||
// alternatywny zapis nazwy odcinka izolowanego - po znaku "@" w nazwie toru
|
||||
if (!pIsolated)
|
||||
if ((i = name.find("@")) != std::string::npos)
|
||||
if (i < name.length()) // nie może być puste
|
||||
if ((i = m_name.find("@")) != std::string::npos)
|
||||
if (i < m_name.length()) // nie może być puste
|
||||
{
|
||||
pIsolated = TIsolated::Find(name.substr(i + 1, name.length()));
|
||||
name = name.substr(0, i - 1); // usunięcie z nazwy
|
||||
pIsolated = TIsolated::Find(m_name.substr(i + 1, m_name.length()));
|
||||
m_name = m_name.substr(0, i - 1); // usunięcie z nazwy
|
||||
}
|
||||
|
||||
// calculate path location
|
||||
m_location = glm::dvec3{ (
|
||||
CurrentSegment()->FastGetPoint_0()
|
||||
+ CurrentSegment()->FastGetPoint( 0.5 )
|
||||
+ CurrentSegment()->FastGetPoint_1() )
|
||||
/ 3.0 };
|
||||
}
|
||||
|
||||
// TODO: refactor this mess
|
||||
@@ -771,7 +765,7 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent
|
||||
|
||||
if( NewEvent0 == nullptr ) {
|
||||
if( false == asEvent0Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent0Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" );
|
||||
ErrorLog( "Bad event: event \"" + asEvent0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
@@ -789,7 +783,7 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent
|
||||
|
||||
if( NewEvent1 == nullptr ) {
|
||||
if( false == asEvent1Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent1Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" );
|
||||
ErrorLog( "Bad event: event \"" + asEvent1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
@@ -807,7 +801,7 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent
|
||||
|
||||
if( NewEvent2 == nullptr ) {
|
||||
if( false == asEvent2Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent2Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" );
|
||||
ErrorLog( "Bad event: event \"" + asEvent2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
@@ -832,7 +826,7 @@ bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEv
|
||||
|
||||
if( NewEvent0 == nullptr ) {
|
||||
if( false == asEventall0Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall0Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" );
|
||||
ErrorLog( "Bad event: event \"" + asEventall0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
@@ -850,7 +844,7 @@ bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEv
|
||||
|
||||
if( NewEvent1 == nullptr ) {
|
||||
if( false == asEventall1Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall1Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" );
|
||||
ErrorLog( "Bad event: event \"" + asEventall1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
@@ -868,7 +862,7 @@ bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEv
|
||||
|
||||
if( NewEvent2 == nullptr ) {
|
||||
if( false == asEventall2Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall2Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" );
|
||||
ErrorLog( "Bad event: event \"" + asEventall2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
@@ -921,7 +915,7 @@ bool TTrack::IsolatedEventsAssign(TEvent *busy, TEvent *free)
|
||||
return false;
|
||||
};
|
||||
|
||||
// ABu: przeniesione z Track.h i poprawione!!!
|
||||
// ABu: przeniesione z Path.h i poprawione!!!
|
||||
bool TTrack::AddDynamicObject(TDynamicObject *Dynamic)
|
||||
{ // dodanie pojazdu do trajektorii
|
||||
// Ra: tymczasowo wysyłanie informacji o zajętości konkretnego toru
|
||||
@@ -935,9 +929,9 @@ bool TTrack::AddDynamicObject(TDynamicObject *Dynamic)
|
||||
// jeśli multiplayer
|
||||
if( true == Dynamics.empty() ) {
|
||||
// pierwszy zajmujący
|
||||
if( pMyNode->asName != "none" ) {
|
||||
if( m_name != "none" ) {
|
||||
// przekazanie informacji o zajętości toru
|
||||
Global::pGround->WyslijString( pMyNode->asName, 8 );
|
||||
Global::pGround->WyslijString( m_name, 8 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1027,9 +1021,9 @@ bool TTrack::RemoveDynamicObject(TDynamicObject *Dynamic)
|
||||
// jeśli multiplayer
|
||||
if( true == Dynamics.empty() ) {
|
||||
// jeśli już nie ma żadnego
|
||||
if( pMyNode->asName != "none" ) {
|
||||
if( m_name != "none" ) {
|
||||
// przekazanie informacji o zwolnieniu toru
|
||||
Global::pGround->WyslijString( pMyNode->asName, 9 );
|
||||
Global::pGround->WyslijString( m_name, 9 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1079,7 +1073,12 @@ void TTrack::RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joi
|
||||
};
|
||||
|
||||
// wypełnianie tablic VBO
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
void TTrack::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ) {
|
||||
#else
|
||||
void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
#endif
|
||||
// Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur
|
||||
auto const fHTW = 0.5f * std::abs(fTrackWidth);
|
||||
auto const side = std::abs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza
|
||||
@@ -1116,7 +1115,11 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
normal2 = normal1;
|
||||
}
|
||||
|
||||
auto const origin { pMyNode->m_rootposition };
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
if( Bank != 0 ) {
|
||||
m_origin = Origin;
|
||||
}
|
||||
#endif
|
||||
|
||||
float roll1, roll2;
|
||||
switch (iCategoryFlag & 15)
|
||||
@@ -1326,7 +1329,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
}
|
||||
}
|
||||
vertex_array vertices;
|
||||
Segment->RenderLoft(vertices, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength);
|
||||
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -4 : 4, fTexLength);
|
||||
if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) {
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
}
|
||||
@@ -1339,18 +1342,18 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
{ // szyny - generujemy dwie, najwyżej rysować się będzie jedną
|
||||
vertex_array vertices;
|
||||
if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) {
|
||||
Segment->RenderLoft( vertices, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
||||
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear(); // reuse the scratchpad
|
||||
Segment->RenderLoft( vertices, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
||||
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
}
|
||||
if( ( Bank == 0 ) && ( false == Geometry1.empty() ) ) {
|
||||
// special variant, replace existing data for a turntable track
|
||||
Segment->RenderLoft( vertices, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
||||
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
||||
GfxRenderer.Replace( vertices, Geometry1[ 0 ] );
|
||||
vertices.clear(); // reuse the scratchpad
|
||||
Segment->RenderLoft( vertices, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
||||
Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
||||
GfxRenderer.Replace( vertices, Geometry1[ 1 ] );
|
||||
}
|
||||
}
|
||||
@@ -1392,27 +1395,27 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
vertex_array vertices;
|
||||
if( m_material1 ) {
|
||||
// fixed parts
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength, 1.0, 2 );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, 2 );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
// left blade
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
if( m_material2 ) {
|
||||
// fixed parts
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength, 1.0, 2 );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, 2 );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
// right blade
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -1422,27 +1425,27 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
vertex_array vertices;
|
||||
if( m_material1 ) {
|
||||
// fixed parts
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
// right blade
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
if( m_material2 ) {
|
||||
// fixed parts
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
// left blade
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -1501,7 +1504,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
if (m_material1) // jeśli podana była tekstura, generujemy trójkąty
|
||||
{ // tworzenie trójkątów nawierzchni szosy
|
||||
vertex_array vertices;
|
||||
Segment->RenderLoft(vertices, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
|
||||
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
}
|
||||
if (m_material2)
|
||||
@@ -1665,24 +1668,24 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
||||
// odcinka
|
||||
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
|
||||
Segment->RenderLoft( vertices, origin, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej
|
||||
Segment->RenderLoft( vertices, m_origin, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||
Segment->RenderLoft( vertices, origin, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej
|
||||
Segment->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
}
|
||||
else { // pobocza zwykłe, brak przechyłki
|
||||
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
|
||||
Segment->RenderLoft( vertices, origin, rpts1, 3, fTexLength );
|
||||
Segment->RenderLoft( vertices, m_origin, rpts1, 3, fTexLength );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||
Segment->RenderLoft( vertices, origin, rpts2, 3, fTexLength );
|
||||
Segment->RenderLoft( vertices, m_origin, rpts2, 3, fTexLength );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -1915,22 +1918,22 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
if (SwitchExtension->iRoads == 4)
|
||||
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
|
||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
||||
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
||||
if( true == render ) {
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
||||
SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
||||
if( true == render ) {
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
||||
SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
||||
if( true == render ) {
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
||||
SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
|
||||
if( true == render ) {
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
@@ -1940,17 +1943,17 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
else {
|
||||
// punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe
|
||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4
|
||||
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4
|
||||
if( true == render ) {
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony)
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony)
|
||||
if( true == render ) {
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2
|
||||
if( true == render ) {
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
@@ -1972,14 +1975,14 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
// we start with a vertex in the middle...
|
||||
vertices.emplace_back(
|
||||
glm::vec3{
|
||||
oxz.x - origin.x,
|
||||
oxz.y - origin.y,
|
||||
oxz.z - origin.z },
|
||||
oxz.x - m_origin.x,
|
||||
oxz.y - m_origin.y,
|
||||
oxz.z - m_origin.z },
|
||||
glm::vec3{ 0.0f, 1.0f, 0.0f },
|
||||
glm::vec2{ 0.5f, 0.5f } );
|
||||
// ...and add one extra vertex to close the fan...
|
||||
u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + origin.x ) / fTexLength;
|
||||
v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength );
|
||||
u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + m_origin.x ) / fTexLength;
|
||||
v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + m_origin.z ) / ( fTexRatio1 * fTexLength );
|
||||
vertices.emplace_back(
|
||||
glm::vec3 {
|
||||
SwitchExtension->vPoints[ 0 ].x,
|
||||
@@ -1993,8 +1996,8 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
// ...then draw the precalculated rest
|
||||
for (int i = pointcount + SwitchExtension->iRoads - 1; i >= 0; --i) {
|
||||
// mapowanie we współrzędnych scenerii
|
||||
u = ( SwitchExtension->vPoints[ i ].x - oxz.x + origin.x ) / fTexLength;
|
||||
v = ( SwitchExtension->vPoints[ i ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength );
|
||||
u = ( SwitchExtension->vPoints[ i ].x - oxz.x + m_origin.x ) / fTexLength;
|
||||
v = ( SwitchExtension->vPoints[ i ].z - oxz.z + m_origin.z ) / ( fTexRatio1 * fTexLength );
|
||||
vertices.emplace_back(
|
||||
glm::vec3 {
|
||||
SwitchExtension->vPoints[ i ].x,
|
||||
@@ -2068,7 +2071,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
if (m_material1) // jeśli podana była tekstura, generujemy trójkąty
|
||||
{ // tworzenie trójkątów nawierzchni szosy
|
||||
vertex_array vertices;
|
||||
Segment->RenderLoft(vertices, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
|
||||
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
}
|
||||
if (m_material2)
|
||||
@@ -2128,19 +2131,19 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
{-rozp2, -fTexHeight2, 0.f},
|
||||
normalup,
|
||||
{0.0f, 0.f} }; // prawy brzeg prawego pobocza
|
||||
Segment->RenderLoft(vertices, origin, rpts1, -3, fTexLength);
|
||||
Segment->RenderLoft(vertices, m_origin, rpts1, -3, fTexLength);
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
Segment->RenderLoft(vertices, origin, rpts2, -3, fTexLength);
|
||||
Segment->RenderLoft(vertices, m_origin, rpts2, -3, fTexLength);
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
else
|
||||
{ // pobocza zwykłe, brak przechyłki
|
||||
Segment->RenderLoft(vertices, origin, rpts1, 3, fTexLength);
|
||||
Segment->RenderLoft(vertices, m_origin, rpts1, 3, fTexLength);
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
Segment->RenderLoft(vertices, origin, rpts2, 3, fTexLength);
|
||||
Segment->RenderLoft(vertices, m_origin, rpts2, 3, fTexLength);
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -2463,20 +2466,19 @@ TTrack * TTrack::RaAnimate()
|
||||
{szyna[ i ].texture.x, 0.f} };
|
||||
}
|
||||
|
||||
auto const origin { pMyNode->m_rootposition };
|
||||
vertex_array vertices;
|
||||
|
||||
if (SwitchExtension->RightSwitch)
|
||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||
if( m_material1 ) {
|
||||
// left blade
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
|
||||
GfxRenderer.Replace( vertices, Geometry1[ 2 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
if( m_material2 ) {
|
||||
// right blade
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
|
||||
GfxRenderer.Replace( vertices, Geometry2[ 2 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -2484,13 +2486,13 @@ TTrack * TTrack::RaAnimate()
|
||||
else { // lewa działa lepiej niż prawa
|
||||
if( m_material1 ) {
|
||||
// right blade
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 );
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 );
|
||||
GfxRenderer.Replace( vertices, Geometry1[ 2 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
if( m_material2 ) {
|
||||
// left blade
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 );
|
||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 );
|
||||
GfxRenderer.Replace( vertices, Geometry2[ 2 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -2528,7 +2530,11 @@ TTrack * TTrack::RaAnimate()
|
||||
dynamic->Move( 0.000001 );
|
||||
}
|
||||
// NOTE: passing empty handle is a bit of a hack here. could be refactored into something more elegant
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
create_geometry( geometrybank_handle(), glm::dvec3() );
|
||||
#else
|
||||
create_geometry( geometrybank_handle() );
|
||||
#endif
|
||||
} // animacja trwa nadal
|
||||
}
|
||||
else
|
||||
@@ -2650,14 +2656,6 @@ void TTrack::MovedUp1(float const dh)
|
||||
fTexHeight1 += dh;
|
||||
};
|
||||
|
||||
std::string TTrack::NameGet()
|
||||
{ // ustalenie nazwy toru
|
||||
if (this)
|
||||
if (pMyNode)
|
||||
return pMyNode->asName;
|
||||
return "none";
|
||||
};
|
||||
|
||||
void TTrack::VelocitySet(float v)
|
||||
{ // ustawienie prędkości z ograniczeniem do pierwotnej wartości (zapisanej w scenerii)
|
||||
if (SwitchExtension ? SwitchExtension->fVelocity >= 0.0 : false)
|
||||
@@ -2677,17 +2675,17 @@ double TTrack::VelocityGet()
|
||||
void TTrack::ConnectionsLog()
|
||||
{ // wypisanie informacji o połączeniach
|
||||
int i;
|
||||
WriteLog("--> tt_Cross named " + pMyNode->asName);
|
||||
WriteLog("--> tt_Cross named " + m_name);
|
||||
if (eType == tt_Cross)
|
||||
for (i = 0; i < 2; ++i)
|
||||
{
|
||||
if (SwitchExtension->pPrevs[i])
|
||||
WriteLog("Point " + std::to_string(i + i + 1) + " -> track " +
|
||||
SwitchExtension->pPrevs[i]->pMyNode->asName + ":" +
|
||||
SwitchExtension->pPrevs[i]->m_name + ":" +
|
||||
std::to_string(int(SwitchExtension->iPrevDirection[i])));
|
||||
if (SwitchExtension->pNexts[i])
|
||||
WriteLog("Point " + std::to_string(i + i + 2) + " -> track " +
|
||||
SwitchExtension->pNexts[i]->pMyNode->asName + ":" +
|
||||
SwitchExtension->pNexts[i]->m_name + ":" +
|
||||
std::to_string(int(SwitchExtension->iNextDirection[i])));
|
||||
}
|
||||
};
|
||||
@@ -2741,3 +2739,182 @@ TTrack * TTrack::Connected(int s, double &d) const
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// legacy method, initializes tracks after deserialization from scenario file
|
||||
void
|
||||
path_table::InitTracks() {
|
||||
/*
|
||||
TGroundNode *Model;
|
||||
int iConnection;
|
||||
|
||||
for( auto *track : m_paths ) {
|
||||
|
||||
track->AssignEvents(
|
||||
simulation::Events.FindEvent( track->asEvent0Name ),
|
||||
simulation::Events.FindEvent( track->asEvent1Name ),
|
||||
simulation::Events.FindEvent( track->asEvent2Name ) );
|
||||
track->AssignallEvents(
|
||||
simulation::Events.FindEvent( track->asEventall0Name ),
|
||||
simulation::Events.FindEvent( track->asEventall1Name ),
|
||||
simulation::Events.FindEvent( track->asEventall2Name ) );
|
||||
|
||||
auto const trackname { track->name() };
|
||||
|
||||
if( ( Global::iHiddenEvents & 1 )
|
||||
&& ( false == trackname.empty() ) ) {
|
||||
// jeśli podana jest nazwa torów, można szukać eventów skojarzonych przez nazwę
|
||||
track->AssignEvents(
|
||||
simulation::Events.FindEvent( trackname + ":event0" ),
|
||||
simulation::Events.FindEvent( trackname + ":event1" ),
|
||||
simulation::Events.FindEvent( trackname + ":event2" ) );
|
||||
track->AssignallEvents(
|
||||
simulation::Events.FindEvent( trackname + ":eventall0" ),
|
||||
simulation::Events.FindEvent( trackname + ":eventall1" ),
|
||||
simulation::Events.FindEvent( trackname + ":eventall2" ) );
|
||||
}
|
||||
|
||||
switch (track->eType) {
|
||||
case tt_Table: {
|
||||
// obrotnicę też łączymy na starcie z innymi torami
|
||||
// szukamy modelu o tej samej nazwie
|
||||
Model = FindGroundNode(Current->asName, TP_MODEL);
|
||||
// wiązanie toru z modelem obrotnicy
|
||||
track->RaAssign(
|
||||
Current,
|
||||
( Model ?
|
||||
Model->Model :
|
||||
nullptr ),
|
||||
simulation::Events.FindEvent( trackname + ":done" ),
|
||||
simulation::Events.FindEvent( trackname + ":joined" ) );
|
||||
if( Model == nullptr ) {
|
||||
// jak nie ma modelu to pewnie jest wykolejnica, a ta jest domyślnie zamknięta i wykoleja
|
||||
break;
|
||||
}
|
||||
// jak coś pójdzie źle, to robimy z tego normalny tor
|
||||
}
|
||||
case tt_Normal: {
|
||||
// tylko proste są podłączane do rozjazdów, stąd dwa rozjazdy się nie połączą ze sobą
|
||||
if( track->CurrentPrev() == nullptr ) {
|
||||
// tylko jeśli jeszcze nie podłączony
|
||||
auto *matchingtrack = simulation::Region.FindTrack( track->CurrentSegment()->FastGetPoint_0(), iConnection, track );
|
||||
switch( iConnection ) {
|
||||
case -1: // Ra: pierwsza koncepcja zawijania samochodów i statków
|
||||
// if ((Track->iCategoryFlag&1)==0) //jeśli nie jest torem szynowym
|
||||
// Track->ConnectPrevPrev(Track,0); //łączenie końca odcinka do samego siebie
|
||||
break;
|
||||
case 0:
|
||||
track->ConnectPrevPrev( matchingtrack, 0 );
|
||||
break;
|
||||
case 1:
|
||||
track->ConnectPrevNext( matchingtrack, 1 );
|
||||
break;
|
||||
case 2:
|
||||
track->ConnectPrevPrev( matchingtrack, 0 ); // do Point1 pierwszego
|
||||
matchingtrack->SetConnections( 0 ); // zapamiętanie ustawień w Segmencie
|
||||
break;
|
||||
case 3:
|
||||
track->ConnectPrevNext( matchingtrack, 1 ); // do Point2 pierwszego
|
||||
matchingtrack->SetConnections( 0 ); // zapamiętanie ustawień w Segmencie
|
||||
break;
|
||||
case 4:
|
||||
matchingtrack->Switch( 1 );
|
||||
track->ConnectPrevPrev( matchingtrack, 2 ); // do Point1 drugiego
|
||||
matchingtrack->SetConnections( 1 ); // robi też Switch(0)
|
||||
matchingtrack->Switch( 0 );
|
||||
break;
|
||||
case 5:
|
||||
matchingtrack->Switch( 1 );
|
||||
track->ConnectPrevNext( matchingtrack, 3 ); // do Point2 drugiego
|
||||
matchingtrack->SetConnections( 1 ); // robi też Switch(0)
|
||||
matchingtrack->Switch( 0 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( track->CurrentNext() == nullptr ) {
|
||||
// tylko jeśli jeszcze nie podłączony
|
||||
auto *matchingtrack = simulation::Region.FindTrack( track->CurrentSegment()->FastGetPoint_1(), iConnection, track );
|
||||
switch( iConnection ) {
|
||||
case -1: // Ra: pierwsza koncepcja zawijania samochodów i statków
|
||||
// if ((Track->iCategoryFlag&1)==0) //jeśli nie jest torem szynowym
|
||||
// Track->ConnectNextNext(Track,1); //łączenie końca odcinka do samego siebie
|
||||
break;
|
||||
case 0:
|
||||
track->ConnectNextPrev( matchingtrack, 0 );
|
||||
break;
|
||||
case 1:
|
||||
track->ConnectNextNext( matchingtrack, 1 );
|
||||
break;
|
||||
case 2:
|
||||
track->ConnectNextPrev( matchingtrack, 0 );
|
||||
matchingtrack->SetConnections( 0 ); // zapamiętanie ustawień w Segmencie
|
||||
break;
|
||||
case 3:
|
||||
track->ConnectNextNext( matchingtrack, 1 );
|
||||
matchingtrack->SetConnections( 0 ); // zapamiętanie ustawień w Segmencie
|
||||
break;
|
||||
case 4:
|
||||
matchingtrack->Switch( 1 );
|
||||
track->ConnectNextPrev( matchingtrack, 2 );
|
||||
matchingtrack->SetConnections( 1 ); // robi też Switch(0)
|
||||
// tmp->Switch(0);
|
||||
break;
|
||||
case 5:
|
||||
matchingtrack->Switch( 1 );
|
||||
track->ConnectNextNext( matchingtrack, 3 );
|
||||
matchingtrack->SetConnections( 1 ); // robi też Switch(0)
|
||||
// tmp->Switch(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tt_Switch: {
|
||||
// dla rozjazdów szukamy eventów sygnalizacji rozprucia
|
||||
track->AssignForcedEvents(
|
||||
simulation::Events.FindEvent( trackname + ":forced+" ),
|
||||
simulation::Events.FindEvent( trackname + ":forced-" ) );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
|
||||
// pobranie nazwy odcinka izolowanego
|
||||
auto const isolatedname { track->IsolatedName() };
|
||||
if( false == isolatedname.empty() ) {
|
||||
// jeśli została zwrócona nazwa
|
||||
track->IsolatedEventsAssign(
|
||||
simulation::Events.FindEvent( isolatedname + ":busy" ),
|
||||
simulation::Events.FindEvent( isolatedname + ":free" ) );
|
||||
}
|
||||
|
||||
if( ( trackname[ 0 ] == '*' )
|
||||
&& ( !track->CurrentPrev() && track->CurrentNext() ) ) {
|
||||
// możliwy portal, jeśli nie podłączony od strony 1
|
||||
// ustawienie flagi portalu
|
||||
track->iCategoryFlag |= 0x100;
|
||||
}
|
||||
}
|
||||
|
||||
TIsolated *isolated = TIsolated::Root();
|
||||
while( isolated ) {
|
||||
// jeśli się znajdzie, to podać wskaźnik
|
||||
auto *memorycell = simulation::Memory.find( isolated->asName ); // czy jest komóka o odpowiedniej nazwie
|
||||
if( memorycell != nullptr ) {
|
||||
// przypisanie powiązanej komórki
|
||||
isolated->pMemCell = memorycell;
|
||||
}
|
||||
else {
|
||||
// utworzenie automatycznej komórki
|
||||
// TODO: determine suitable location for this one, create and add world reference node
|
||||
auto *memorycell = new TMemCell( isolated->asName ); // to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy
|
||||
simulation::Memory.insert( memorycell );
|
||||
isolated->pMemCell = memorycell; // wskaźnik komóki przekazany do odcinka izolowanego
|
||||
}
|
||||
isolated = isolated->Next();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
45
Track.h
45
Track.h
@@ -13,8 +13,10 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
#include "scenenode.h"
|
||||
#include "Segment.h"
|
||||
#include "material.h"
|
||||
#include "names.h"
|
||||
|
||||
enum TTrackType {
|
||||
tt_Unknown,
|
||||
@@ -112,12 +114,12 @@ class TIsolated
|
||||
};
|
||||
|
||||
// trajektoria ruchu - opakowanie
|
||||
class TTrack {
|
||||
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
|
||||
// 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;
|
||||
@@ -126,7 +128,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...)
|
||||
@@ -134,6 +136,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;
|
||||
@@ -167,7 +170,6 @@ 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:
|
||||
@@ -177,11 +179,13 @@ public:
|
||||
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 TTrack * Create400m(int what, double dx);
|
||||
TTrack * NullCreate(int dir);
|
||||
@@ -218,7 +222,7 @@ public:
|
||||
SwitchExtension != nullptr ?
|
||||
SwitchExtension->iRoads - 1 :
|
||||
1 ); }
|
||||
void Load(cParser *parser, Math3D::vector3 pOrigin, std::string name);
|
||||
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);
|
||||
@@ -226,7 +230,16 @@ 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; }
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
void create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ); // wypełnianie VBO
|
||||
#else
|
||||
void create_geometry( geometrybank_handle const &Bank ); // wypełnianie VBO
|
||||
#endif
|
||||
void RenderDynSounds(); // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania
|
||||
|
||||
void RaOwnerSet(TSubRect *o) {
|
||||
@@ -247,7 +260,6 @@ public:
|
||||
bool IsGroupable();
|
||||
int TestPoint( Math3D::vector3 *Point);
|
||||
void MovedUp1(float const dh);
|
||||
std::string NameGet();
|
||||
void VelocitySet(float v);
|
||||
double VelocityGet();
|
||||
void ConnectionsLog();
|
||||
@@ -257,4 +269,15 @@ public:
|
||||
void EnvironmentReset();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// collection of virtual tracks and roads present in the scene
|
||||
class path_table : public basic_table<TTrack> {
|
||||
|
||||
public:
|
||||
// legacy method, initializes tracks after deserialization from scenario file
|
||||
void
|
||||
InitTracks();
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
389
Traction.cpp
389
Traction.cpp
@@ -90,8 +90,91 @@ jawnie nazwę sekcji, ewentualnie nazwę zasilacza (zostanie zastąpiona wskazan
|
||||
sekcji z sąsiedniego przęsła).
|
||||
*/
|
||||
|
||||
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
|
||||
m_location = interpolate( pPoint2, pPoint1, 0.5 );
|
||||
}
|
||||
|
||||
std::size_t
|
||||
TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ) {
|
||||
TTraction::create_geometry( geometrybank_handle const &Bank ) {
|
||||
|
||||
if( m_geometry != null_handle ) {
|
||||
return GfxRenderer.Vertices( m_geometry ).size() / 2;
|
||||
@@ -106,14 +189,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 +213,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 +224,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 +235,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 +245,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 +262,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 +285,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 +306,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 +336,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 );
|
||||
}
|
||||
@@ -523,3 +606,211 @@ TTraction::wire_color() const {
|
||||
}
|
||||
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 iConnection;
|
||||
std::string name;
|
||||
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
|
||||
nTemp = FindGroundNode(traction->asPowerSupplyName, TP_TRACTIONPOWERSOURCE);
|
||||
if (nTemp) // jak zasilacz znaleziony
|
||||
traction->PowerSet(nTemp->psTractionPowerSource); // to podłączyć do przęsła
|
||||
else if (traction->asPowerSupplyName != "*") // gwiazdka dla przęsła z izolatorem
|
||||
if (traction->asPowerSupplyName != "none") // dopuszczamy na razie brak podłączenia?
|
||||
{ // logowanie błędu i utworzenie zasilacza o domyślnej zawartości
|
||||
ErrorLog("Missed TractionPowerSource: " + traction->asPowerSupplyName);
|
||||
nTemp = new TGroundNode();
|
||||
nTemp->iType = TP_TRACTIONPOWERSOURCE;
|
||||
nTemp->asName = traction->asPowerSupplyName;
|
||||
nTemp->psTractionPowerSource = new TTractionPowerSource(nTemp);
|
||||
nTemp->psTractionPowerSource->Init(traction->NominalVoltage, traction->MaxCurrent);
|
||||
nTemp->nNext = nRootOfType[nTemp->iType]; // ostatni dodany dołączamy na końcu
|
||||
// nowego
|
||||
nRootOfType[nTemp->iType] = nTemp; // ustawienie nowego na początku listy
|
||||
}
|
||||
}
|
||||
|
||||
for( auto *traction : m_items ) {
|
||||
|
||||
if (!traction->hvNext[0]) // tylko jeśli jeszcze nie podłączony
|
||||
{
|
||||
tmp = FindTraction(traction->pPoint1, iConnection, nCurrent);
|
||||
switch (iConnection)
|
||||
{
|
||||
case 0:
|
||||
traction->Connect(0, tmp, 0);
|
||||
break;
|
||||
case 1:
|
||||
traction->Connect(0, tmp, 1);
|
||||
break;
|
||||
}
|
||||
if (traction->hvNext[0]) // jeśli został podłączony
|
||||
if (traction->psSection && tmp->psSection) // tylko przęsło z izolatorem może nie
|
||||
// mieć zasilania, bo ma 2, trzeba
|
||||
// sprawdzać sąsiednie
|
||||
if (traction->psSection !=
|
||||
tmp->psSection) // połączone odcinki mają różne zasilacze
|
||||
{ // to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo
|
||||
// błąd
|
||||
if (traction->psSection->bSection && !tmp->psSection->bSection)
|
||||
{ //(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji
|
||||
tmp->PowerSet(traction->psSection); // zastąpienie wskazaniem sekcji
|
||||
}
|
||||
else if (!traction->psSection->bSection && tmp->psSection->bSection)
|
||||
{ //(Traction->psSection) jest podstacją, a (tmp->psSection) nazwą sekcji
|
||||
traction->PowerSet(tmp->psSection); // zastąpienie wskazaniem sekcji
|
||||
}
|
||||
else // jeśli obie to sekcje albo obie podstacje, to będzie błąd
|
||||
ErrorLog("Bad power: at " +
|
||||
to_string(traction->pPoint1.x, 2, 6) + " " +
|
||||
to_string(traction->pPoint1.y, 2, 6) + " " +
|
||||
to_string(traction->pPoint1.z, 2, 6));
|
||||
}
|
||||
}
|
||||
if (!traction->hvNext[1]) // tylko jeśli jeszcze nie podłączony
|
||||
{
|
||||
tmp = FindTraction(traction->pPoint2, iConnection, nCurrent);
|
||||
switch (iConnection)
|
||||
{
|
||||
case 0:
|
||||
traction->Connect(1, tmp, 0);
|
||||
break;
|
||||
case 1:
|
||||
traction->Connect(1, tmp, 1);
|
||||
break;
|
||||
}
|
||||
if (traction->hvNext[1]) // jeśli został podłączony
|
||||
if (traction->psSection && tmp->psSection) // tylko przęsło z izolatorem może nie
|
||||
// mieć zasilania, bo ma 2, trzeba
|
||||
// sprawdzać sąsiednie
|
||||
if (traction->psSection != tmp->psSection)
|
||||
{ // to może być albo podłączenie podstacji lub kabiny sekcyjnej do sekcji, albo
|
||||
// błąd
|
||||
if (traction->psSection->bSection && !tmp->psSection->bSection)
|
||||
{ //(tmp->psSection) jest podstacją, a (Traction->psSection) nazwą sekcji
|
||||
tmp->PowerSet(traction->psSection); // zastąpienie wskazaniem sekcji
|
||||
}
|
||||
else if (!traction->psSection->bSection && tmp->psSection->bSection)
|
||||
{ //(Traction->psSection) jest podstacją, a (tmp->psSection) nazwą sekcji
|
||||
traction->PowerSet(tmp->psSection); // zastąpienie wskazaniem sekcji
|
||||
}
|
||||
else // jeśli obie to sekcje albo obie podstacje, to będzie błąd
|
||||
ErrorLog("Bad power: at " +
|
||||
to_string(traction->pPoint2.x, 2, 6) + " " +
|
||||
to_string(traction->pPoint2.y, 2, 6) + " " +
|
||||
to_string(traction->pPoint2.z, 2, 6));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iConnection = 0; // teraz będzie licznikiem końców
|
||||
for( auto *traction : m_items ) {
|
||||
// operacje mające na celu wykrywanie bieżni wspólnych i łączenie przęseł naprążania
|
||||
if (traction->WhereIs()) // oznakowanie przedostatnich przęseł
|
||||
{ // poszukiwanie bieżni wspólnej dla przedostatnich przęseł, również w celu połączenia
|
||||
// zasilania
|
||||
// to się nie sprawdza, bo połączyć się mogą dwa niezasilane odcinki jako najbliższe
|
||||
// sobie
|
||||
// nCurrent->hvTraction->hvParallel=TractionNearestFind(nCurrent->pCenter,0,nCurrent);
|
||||
// //szukanie najbliższego przęsła
|
||||
// trzeba by zliczać końce, a potem wpisać je do tablicy, aby sukcesywnie podłączać do
|
||||
// zasilaczy
|
||||
traction->iTries = 5; // oznaczanie końcowych
|
||||
++iConnection;
|
||||
}
|
||||
if (traction->fResistance[0] == 0.0)
|
||||
{
|
||||
traction->ResistanceCalc(); // obliczanie przęseł w segmencie z bezpośrednim zasilaniem
|
||||
// ErrorLog("Section "+nCurrent->hvTraction->asPowerSupplyName+" connected"); //jako
|
||||
// niby błąd będzie bardziej widoczne
|
||||
traction->iTries = 0; // nie potrzeba mu szukać zasilania
|
||||
}
|
||||
// if (!Traction->hvParallel) //jeszcze utworzyć pętle z bieżni wspólnych
|
||||
}
|
||||
int zg = 0; // zgodność kierunku przęseł, tymczasowo iterator do tabeli końców
|
||||
// końców jest ok. 10 razy mniej niż wszystkich przęseł (Quark: 216)
|
||||
TGroundNode **nEnds = new TGroundNode *[iConnection];
|
||||
for( auto *traction : m_items ) {
|
||||
//łączenie bieżni wspólnych, w tym oznaczanie niepodanych jawnie
|
||||
if (!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) // jeśli jeszcze nie został włączony w kółko
|
||||
{
|
||||
auto *nTemp = find( traction->asParallel );
|
||||
if (nTemp)
|
||||
{ // o ile zostanie znalezione przęsło o takiej nazwie
|
||||
if (!nTemp->hvParallel) // 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)
|
||||
ErrorLog("Missed overhead: " + traction->asParallel); // logowanie braku
|
||||
}
|
||||
if (traction->iTries > 0) // jeśli zaznaczony do podłączenia
|
||||
// if (!nCurrent->hvTraction->psPower[0]||!nCurrent->hvTraction->psPower[1])
|
||||
if (zg < iConnection) // zabezpieczenie
|
||||
nEnds[zg++] = nCurrent; // wypełnianie tabeli końców w celu szukania im połączeń
|
||||
}
|
||||
while( zg < iConnection ) {
|
||||
// zapełnienie do końca tablicy, jeśli by jakieś końce wypadły
|
||||
nEnds[ zg++ ] = nullptr;
|
||||
}
|
||||
zg = 1; // nieefektywny przebieg kończy łączenie
|
||||
while (zg)
|
||||
{ // ustalenie zastępczej rezystancji dla każdego przęsła
|
||||
zg = 0; // flaga podłączonych przęseł końcowych: -1=puste wskaźniki, 0=coś zostało,
|
||||
// 1=wykonano łączenie
|
||||
for (int i = 0; i < iConnection; ++i)
|
||||
if (nEnds[i]) // załatwione będziemy zerować
|
||||
{ // każdy przebieg to próba podłączenia końca segmentu naprężania do innego zasilanego
|
||||
// przęsła
|
||||
if (nEnds[i]->hvTraction->hvNext[0])
|
||||
{ // jeśli końcowy ma ciąg dalszy od strony 0 (Point1), szukamy odcinka najbliższego
|
||||
// do Point2
|
||||
if (TractionNearestFind(nEnds[i]->hvTraction->pPoint2, 0,
|
||||
nEnds[i])) // poszukiwanie przęsła
|
||||
{
|
||||
nEnds[i] = NULL;
|
||||
zg = 1; // jak coś zostało podłączone, to może zasilanie gdzieś dodatkowo
|
||||
// dotrze
|
||||
}
|
||||
}
|
||||
else if (nEnds[i]->hvTraction->hvNext[1])
|
||||
{ // jeśli końcowy ma ciąg dalszy od strony 1 (Point2), szukamy odcinka najbliższego
|
||||
// do Point1
|
||||
if (TractionNearestFind(nEnds[i]->hvTraction->pPoint1, 1,
|
||||
nEnds[i])) // poszukiwanie przęsła
|
||||
{
|
||||
nEnds[i] = NULL;
|
||||
zg = 1; // jak coś zostało podłączone, to może zasilanie gdzieś dodatkowo
|
||||
// dotrze
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // gdy koniec jest samotny, to na razie nie zostanie podłączony (nie powinno
|
||||
// takich być)
|
||||
nEnds[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] nEnds; // nie potrzebne już
|
||||
*/
|
||||
}
|
||||
|
||||
38
Traction.h
38
Traction.h
@@ -10,14 +10,16 @@ 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"
|
||||
|
||||
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
|
||||
@@ -29,7 +31,7 @@ class TTraction
|
||||
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 };
|
||||
@@ -47,11 +49,22 @@ class TTraction
|
||||
int iTries { 0 };
|
||||
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 );
|
||||
virtual ~TTraction() = default;
|
||||
|
||||
void Load( cParser *parser, glm::dvec3 const &pOrigin );
|
||||
// set origin point
|
||||
void
|
||||
origin( glm::dvec3 Origin ) {
|
||||
m_origin = Origin; }
|
||||
// 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();
|
||||
@@ -63,4 +76,15 @@ 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();
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -1568,7 +1568,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 );
|
||||
}
|
||||
}
|
||||
|
||||
2
Train.h
2
Train.h
@@ -73,6 +73,8 @@ 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)
|
||||
|
||||
65
World.cpp
65
World.cpp
@@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "World.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "simulation.h"
|
||||
#include "Logs.h"
|
||||
#include "MdlMngr.h"
|
||||
#include "renderer.h"
|
||||
@@ -242,6 +243,7 @@ bool TWorld::Init( GLFWwindow *Window ) {
|
||||
GfxRenderer.Render();
|
||||
|
||||
WriteLog( "World setup..." );
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
if( true == Ground.Init( Global::SceneryFile ) ) {
|
||||
WriteLog( "...world setup done" );
|
||||
}
|
||||
@@ -249,6 +251,9 @@ bool TWorld::Init( GLFWwindow *Window ) {
|
||||
ErrorLog( "...world setup failed" );
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if( false == simulation::State.deserialize( Global::SceneryFile ) ) { return false; }
|
||||
#endif
|
||||
|
||||
simulation::Time.init();
|
||||
|
||||
@@ -299,6 +304,7 @@ bool TWorld::Init( GLFWwindow *Window ) {
|
||||
|
||||
// if (!Global::bMultiplayer) //na razie włączone
|
||||
{ // eventy aktywowane z klawiatury tylko dla jednego użytkownika
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
KeyEvents[0] = Ground.FindEvent("keyctrl00");
|
||||
KeyEvents[1] = Ground.FindEvent("keyctrl01");
|
||||
KeyEvents[2] = Ground.FindEvent("keyctrl02");
|
||||
@@ -309,6 +315,18 @@ bool TWorld::Init( GLFWwindow *Window ) {
|
||||
KeyEvents[7] = Ground.FindEvent("keyctrl07");
|
||||
KeyEvents[8] = Ground.FindEvent("keyctrl08");
|
||||
KeyEvents[9] = Ground.FindEvent("keyctrl09");
|
||||
#else
|
||||
KeyEvents[ 0 ] = simulation::Events.FindEvent( "keyctrl00" );
|
||||
KeyEvents[ 1 ] = simulation::Events.FindEvent( "keyctrl01" );
|
||||
KeyEvents[ 2 ] = simulation::Events.FindEvent( "keyctrl02" );
|
||||
KeyEvents[ 3 ] = simulation::Events.FindEvent( "keyctrl03" );
|
||||
KeyEvents[ 4 ] = simulation::Events.FindEvent( "keyctrl04" );
|
||||
KeyEvents[ 5 ] = simulation::Events.FindEvent( "keyctrl05" );
|
||||
KeyEvents[ 6 ] = simulation::Events.FindEvent( "keyctrl06" );
|
||||
KeyEvents[ 7 ] = simulation::Events.FindEvent( "keyctrl07" );
|
||||
KeyEvents[ 8 ] = simulation::Events.FindEvent( "keyctrl08" );
|
||||
KeyEvents[ 9 ] = simulation::Events.FindEvent( "keyctrl09" );
|
||||
#endif
|
||||
}
|
||||
|
||||
WriteLog( "Load time: " +
|
||||
@@ -396,7 +414,11 @@ void TWorld::OnKeyDown(int cKey)
|
||||
{ // z [Shift] uruchomienie eventu
|
||||
if (!Global::iPause) // podczas pauzy klawisze nie działają
|
||||
if (KeyEvents[i])
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
Ground.AddToQuery(KeyEvents[i], NULL);
|
||||
#else
|
||||
simulation::Events.AddToQuery( KeyEvents[ i ], NULL );
|
||||
#endif
|
||||
}
|
||||
else // zapamiętywanie kamery może działać podczas pauzy
|
||||
if (FreeFlyModeFlag) // w trybie latania można przeskakiwać do ustawionych kamer
|
||||
@@ -685,8 +707,7 @@ void TWorld::OnKeyDown(int cKey)
|
||||
temp->MoverParameters->DecBrakeMult())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
Train->dsbSwitch->SetVolume(DSBVOLUME_MAX);
|
||||
Train->dsbSwitch->Play(0, 0, 0);
|
||||
Train->play_sound( Train->dsbSwitch );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -715,8 +736,7 @@ void TWorld::OnKeyDown(int cKey)
|
||||
tmp->iLights[CouplNr] = (tmp->iLights[CouplNr] & ~mask) | set;
|
||||
if (Train)
|
||||
{ // Ra: ten dźwięk z kabiny to przegięcie, ale na razie zostawiam
|
||||
Train->dsbSwitch->SetVolume(DSBVOLUME_MAX);
|
||||
Train->dsbSwitch->Play(0, 0, 0);
|
||||
Train->play_sound( Train->dsbSwitch );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -736,8 +756,7 @@ void TWorld::OnKeyDown(int cKey)
|
||||
if (temp->MoverParameters->IncLocalBrakeLevelFAST())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
Train->dsbPneumaticRelay->SetVolume(-80);
|
||||
Train->dsbPneumaticRelay->Play(0, 0, 0);
|
||||
Train->play_sound( Train->dsbPneumaticRelay );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -756,8 +775,7 @@ void TWorld::OnKeyDown(int cKey)
|
||||
if (temp->MoverParameters->DecLocalBrakeLevelFAST())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
Train->dsbPneumaticRelay->SetVolume(-80);
|
||||
Train->dsbPneumaticRelay->Play(0, 0, 0);
|
||||
Train->play_sound( Train->dsbPneumaticRelay );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1045,10 +1063,14 @@ bool TWorld::Update()
|
||||
TSubModel::iInstance = 0;
|
||||
}
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
Ground.CheckQuery();
|
||||
#else
|
||||
simulation::Events.CheckQuery();
|
||||
#endif
|
||||
|
||||
Ground.Update_Hidden();
|
||||
Ground.Update_Lights();
|
||||
simulation::Lights.update();
|
||||
|
||||
// render time routines follow:
|
||||
|
||||
@@ -1818,19 +1840,24 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz)
|
||||
CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " scenery" + " rcvd");
|
||||
Ground.WyslijString(Global::SceneryFile, 1); // nazwa scenerii
|
||||
break;
|
||||
case 2: // event
|
||||
CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " " +
|
||||
std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd");
|
||||
if (Global::iMultiplayer)
|
||||
{ // WriteLog("Komunikat: "+AnsiString(pRozkaz->Name1));
|
||||
case 2: {
|
||||
// event
|
||||
CommLog( Now() + " " + std::to_string( pRozkaz->iComm ) + " " +
|
||||
std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) + " rcvd" );
|
||||
/*
|
||||
// TODO: re-enable when messaging module is in place
|
||||
if( Global::iMultiplayer ) {
|
||||
// WriteLog("Komunikat: "+AnsiString(pRozkaz->Name1));
|
||||
TEvent *e = Ground.FindEvent(
|
||||
std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])));
|
||||
if (e)
|
||||
if ((e->Type == tp_Multiple) || (e->Type == tp_Lights) ||
|
||||
(e->evJoined != 0)) // tylko jawne albo niejawne Multiple
|
||||
Ground.AddToQuery(e, NULL); // drugi parametr to dynamic wywołujący - tu brak
|
||||
std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) );
|
||||
if( e )
|
||||
if( ( e->Type == tp_Multiple ) || ( e->Type == tp_Lights ) ||
|
||||
( e->evJoined != 0 ) ) // tylko jawne albo niejawne Multiple
|
||||
Ground.AddToQuery( e, NULL ); // drugi parametr to dynamic wywołujący - tu brak
|
||||
}
|
||||
*/
|
||||
break;
|
||||
}
|
||||
case 3: // rozkaz dla AI
|
||||
if (Global::iMultiplayer)
|
||||
{
|
||||
|
||||
1
World.h
1
World.h
@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <string>
|
||||
#include "Camera.h"
|
||||
#include "Ground.h"
|
||||
#include "scene.h"
|
||||
#include "sky.h"
|
||||
#include "sun.h"
|
||||
#include "moon.h"
|
||||
|
||||
@@ -228,6 +228,18 @@
|
||||
<ClCompile Include="material.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="scene.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="scenenode.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="simulation.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vertex.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Globals.h">
|
||||
@@ -446,6 +458,18 @@
|
||||
<ClInclude Include="material.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vertex.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="scene.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="scenenode.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="simulation.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="maszyna.rc">
|
||||
|
||||
644
renderer.cpp
644
renderer.cpp
@@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "renderer.h"
|
||||
#include "globals.h"
|
||||
#include "timer.h"
|
||||
#include "simulation.h"
|
||||
#include "world.h"
|
||||
#include "train.h"
|
||||
#include "data.h"
|
||||
@@ -53,9 +54,9 @@ opengl_camera::update_frustum( glm::mat4 const &Projection, glm::mat4 const &Mod
|
||||
|
||||
// returns true if specified object is within camera frustum, false otherwise
|
||||
bool
|
||||
opengl_camera::visible( bounding_area const &Area ) const {
|
||||
opengl_camera::visible( scene::bounding_area const &Area ) const {
|
||||
|
||||
return ( m_frustum.sphere_inside( Area.center, Area.radius ) > 0.0f );
|
||||
return ( m_frustum.sphere_inside( Area.center, Area.radius ) > 0.f );
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -325,10 +326,10 @@ opengl_renderer::Render() {
|
||||
++m_framestamp;
|
||||
Render_pass( rendermode::color );
|
||||
|
||||
m_drawcount = m_drawqueue.size();
|
||||
m_drawcount = m_cellqueue.size();
|
||||
// accumulate last 20 frames worth of render time (cap at 1000 fps to prevent calculations going awry)
|
||||
m_drawtimecolorpass = std::max( 20.f, 0.95f * m_drawtimecolorpass + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - drawstartcolorpass ) ).count() / 1000.f );
|
||||
m_debuginfo += "frame total: " + to_string( m_drawtimecolorpass / 20.f, 2 ) + " msec (" + std::to_string( m_drawqueue.size() ) + " sectors) ";
|
||||
m_debuginfo += "frame total: " + to_string( m_drawtimecolorpass / 20.f, 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) ";
|
||||
|
||||
glfwSwapBuffers( m_window );
|
||||
|
||||
@@ -360,12 +361,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
m_worldcamera,
|
||||
rendermode::color,
|
||||
0.f,
|
||||
std::min(
|
||||
1.f,
|
||||
Global::shadowtune.depth / ( Global::BaseDrawRange * Global::fDistanceFactor )
|
||||
* std::max(
|
||||
1.f,
|
||||
Global::ZoomFactor * 0.5f ) ),
|
||||
1.0,
|
||||
true );
|
||||
#endif
|
||||
// setup shadowmap matrix
|
||||
@@ -433,10 +429,18 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
}
|
||||
#endif
|
||||
switch_units( true, true, true );
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
Render( &World.Ground );
|
||||
#else
|
||||
Render( simulation::Region );
|
||||
#endif
|
||||
// ...translucent parts
|
||||
setup_drawing( true );
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
Render_Alpha( &World.Ground );
|
||||
#else
|
||||
Render_Alpha( simulation::Region );
|
||||
#endif
|
||||
if( World.Train != nullptr ) {
|
||||
// cab render is performed without shadows, due to low resolution and number of models without windows :|
|
||||
switch_units( true, false, false );
|
||||
@@ -486,7 +490,11 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
#else
|
||||
setup_units( false, false, false );
|
||||
#endif
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
Render( &World.Ground );
|
||||
#else
|
||||
Render( simulation::Region );
|
||||
#endif
|
||||
// post-render restore
|
||||
::glDisable( GL_POLYGON_OFFSET_FILL );
|
||||
::glDisable( GL_SCISSOR_TEST );
|
||||
@@ -494,7 +502,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch back to primary render target
|
||||
|
||||
m_drawtimeshadowpass = 0.95f * m_drawtimeshadowpass + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - shadowdrawstart ) ).count() / 1000.f;
|
||||
m_debuginfo += "shadows: " + to_string( m_drawtimeshadowpass / 20.f, 2 ) + " msec (" + std::to_string( m_drawqueue.size() ) + " sectors) ";
|
||||
m_debuginfo += "shadows: " + to_string( m_drawtimeshadowpass / 20.f, 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -516,7 +524,11 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
// opaque parts...
|
||||
setup_drawing( false );
|
||||
setup_units( true, true, true );
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
Render( &World.Ground );
|
||||
#else
|
||||
Render( simulation::Region );
|
||||
#endif
|
||||
/*
|
||||
// reflections are limited to sky and ground only, the update rate is too low for anything else
|
||||
// ...translucent parts
|
||||
@@ -569,7 +581,11 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
// opaque parts...
|
||||
setup_drawing( false );
|
||||
setup_units( false, false, false );
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
Render( &World.Ground );
|
||||
#else
|
||||
Render( simulation::Region );
|
||||
#endif
|
||||
// post-render cleanup
|
||||
}
|
||||
break;
|
||||
@@ -1337,12 +1353,11 @@ opengl_renderer::Texture( texture_handle const Texture ) const {
|
||||
return m_textures.texture( Texture );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool
|
||||
opengl_renderer::Render( TGround *Ground ) {
|
||||
|
||||
m_drawqueue.clear();
|
||||
m_cellqueue.clear();
|
||||
|
||||
glm::vec3 const cameraposition { m_renderpass.camera.position() };
|
||||
int const camerax = static_cast<int>( std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2 );
|
||||
@@ -1354,25 +1369,29 @@ opengl_renderer::Render( TGround *Ground ) {
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::color: {
|
||||
|
||||
Update_Lights( Ground->m_lights );
|
||||
Update_Lights( simulation::Lights );
|
||||
|
||||
for( int column = originx; column <= originx + segmentcount; ++column ) {
|
||||
for( int row = originz; row <= originz + segmentcount; ++row ) {
|
||||
|
||||
auto *cell = &Ground->Rects[ column ][ row ];
|
||||
#ifdef EU07_USE_DEBUG_CULLING
|
||||
if( m_worldcamera.camera.visible( cell->m_area ) ) {
|
||||
#else
|
||||
if( m_renderpass.camera.visible( cell->m_area ) ) {
|
||||
#endif
|
||||
Render( cell );
|
||||
}
|
||||
}
|
||||
}
|
||||
// draw queue was filled while rendering content of ground cells. now sort the nodes based on their distance to viewer...
|
||||
std::sort(
|
||||
std::begin( m_drawqueue ),
|
||||
std::end( m_drawqueue ),
|
||||
std::begin( m_cellqueue ),
|
||||
std::end( m_cellqueue ),
|
||||
[]( distancesubcell_pair const &Left, distancesubcell_pair const &Right ) {
|
||||
return ( Left.first ) < ( Right.first ); } );
|
||||
// ...then render the opaque content of the visible subcells.
|
||||
for( auto subcellpair : m_drawqueue ) {
|
||||
for( auto subcellpair : m_cellqueue ) {
|
||||
Render( subcellpair.second );
|
||||
}
|
||||
break;
|
||||
@@ -1404,7 +1423,7 @@ opengl_renderer::Render( TGround *Ground ) {
|
||||
}
|
||||
// they can also skip queue sorting, as they only deal with opaque geometry
|
||||
// NOTE: there's benefit from rendering front-to-back, but is it significant enough? TODO: investigate
|
||||
for( auto subcellpair : m_drawqueue ) {
|
||||
for( auto subcellpair : m_cellqueue ) {
|
||||
Render( subcellpair.second );
|
||||
}
|
||||
break;
|
||||
@@ -1475,7 +1494,7 @@ opengl_renderer::Render( TGroundRect *Groundcell ) {
|
||||
auto subcell = Groundcell->pSubRects + subcellindex;
|
||||
if( subcell->iNodeCount ) {
|
||||
// o ile są jakieś obiekty, bo po co puste sektory przelatywać
|
||||
m_drawqueue.emplace_back(
|
||||
m_cellqueue.emplace_back(
|
||||
glm::length2( m_renderpass.camera.position() - glm::dvec3( subcell->m_area.center ) ),
|
||||
subcell );
|
||||
}
|
||||
@@ -1577,6 +1596,407 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) {
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
void
|
||||
opengl_renderer::Render( scene::basic_region &Region ) {
|
||||
|
||||
m_sectionqueue.clear();
|
||||
m_cellqueue.clear();
|
||||
|
||||
// build a list of region sections to render
|
||||
glm::vec3 const cameraposition { m_renderpass.camera.position() };
|
||||
auto const camerax = static_cast<int>( std::floor( cameraposition.x / scene::EU07_SECTIONSIZE + scene::EU07_REGIONSIDESECTIONCOUNT / 2 ) );
|
||||
auto const cameraz = static_cast<int>( std::floor( cameraposition.z / scene::EU07_SECTIONSIZE + scene::EU07_REGIONSIDESECTIONCOUNT / 2 ) );
|
||||
int const segmentcount = 2 * static_cast<int>( std::ceil( m_renderpass.draw_range * Global::fDistanceFactor / scene::EU07_SECTIONSIZE ) );
|
||||
int const originx = camerax - segmentcount / 2;
|
||||
int const originz = cameraz - segmentcount / 2;
|
||||
|
||||
for( int row = originz; row <= originz + segmentcount; ++row ) {
|
||||
if( row < 0 ) { continue; }
|
||||
if( row >= scene::EU07_REGIONSIDESECTIONCOUNT ) { break; }
|
||||
for( int column = originx; column <= originx + segmentcount; ++column ) {
|
||||
if( column < 0 ) { continue; }
|
||||
if( column >= scene::EU07_REGIONSIDESECTIONCOUNT ) { break; }
|
||||
auto §ion { Region.m_sections[ row * scene::EU07_REGIONSIDESECTIONCOUNT + column ] };
|
||||
if( ( true == section.m_active )
|
||||
#ifdef EU07_USE_DEBUG_CULLING
|
||||
&& ( m_worldcamera.camera.visible( section.m_area ) ) ) {
|
||||
#else
|
||||
&& ( m_renderpass.camera.visible( section.m_area ) ) ) {
|
||||
#endif
|
||||
m_sectionqueue.emplace_back( §ion );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::color: {
|
||||
|
||||
Update_Lights( simulation::Lights );
|
||||
|
||||
Render( std::begin( m_sectionqueue ), std::end( m_sectionqueue ) );
|
||||
/*
|
||||
// draw queue was filled while rendering content of ground cells. now sort the nodes based on their distance to viewer...
|
||||
// TODO: move sorting for translucent phase, for opaque geometry render cells in initial order to reduce vbo switching
|
||||
std::sort(
|
||||
std::begin( m_cellqueue ),
|
||||
std::end( m_cellqueue ),
|
||||
[]( distancecell_pair const &Left, distancecell_pair const &Right ) {
|
||||
return ( Left.first < Right.first ); } );
|
||||
*/
|
||||
// ...then render the opaque content of the visible cells.
|
||||
Render( std::begin( m_cellqueue ), std::end( m_cellqueue ) );
|
||||
break;
|
||||
}
|
||||
case rendermode::shadows:
|
||||
case rendermode::pickscenery: {
|
||||
// these render modes don't bother with lights
|
||||
Render( std::begin( m_sectionqueue ), std::end( m_sectionqueue ) );
|
||||
// they can also skip queue sorting, as they only deal with opaque geometry
|
||||
// NOTE: there's benefit from rendering front-to-back, but is it significant enough? TODO: investigate
|
||||
Render( std::begin( m_cellqueue ), std::end( m_cellqueue ) );
|
||||
break;
|
||||
}
|
||||
case rendermode::reflections: {
|
||||
// for the time being reflections render only terrain geometry
|
||||
Render( std::begin( m_sectionqueue ), std::end( m_sectionqueue ) );
|
||||
break;
|
||||
}
|
||||
case rendermode::pickcontrols:
|
||||
default: {
|
||||
// no need to render anything ourside of the cab in control picking mode
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
opengl_renderer::Render( section_sequence::iterator First, section_sequence::iterator Last ) {
|
||||
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::color:
|
||||
case rendermode::reflections: {
|
||||
|
||||
break;
|
||||
}
|
||||
case rendermode::shadows: {
|
||||
// experimental, for shadows render both back and front faces, to supply back faces of the 'forest strips'
|
||||
::glDisable( GL_CULL_FACE );
|
||||
break; }
|
||||
case rendermode::pickscenery: {
|
||||
// non-interactive scenery elements get neutral colour
|
||||
::glColor3fv( glm::value_ptr( colors::none ) );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break; }
|
||||
}
|
||||
|
||||
while( First != Last ) {
|
||||
|
||||
auto *section = *First;
|
||||
section->create_geometry();
|
||||
|
||||
// render shapes held by the section
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::color:
|
||||
case rendermode::reflections:
|
||||
case rendermode::shadows:
|
||||
case rendermode::pickscenery: {
|
||||
if( false == section->m_shapes.empty() ) {
|
||||
// since all shapes of the section share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset { section->m_area.center - m_renderpass.camera.position() };
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
// render
|
||||
#ifdef EU07_USE_DEBUG_CULLING
|
||||
// debug
|
||||
float const width = scene::EU07_SECTIONSIZE * 0.5f;
|
||||
float const height = scene::EU07_SECTIONSIZE * 0.2f;
|
||||
glDisable( GL_LIGHTING );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
glColor3ub( 255, 128, 128 );
|
||||
glBegin( GL_LINE_LOOP );
|
||||
glVertex3f( -width, height, width );
|
||||
glVertex3f( -width, height, -width );
|
||||
glVertex3f( width, height, -width );
|
||||
glVertex3f( width, height, width );
|
||||
glEnd();
|
||||
glBegin( GL_LINE_LOOP );
|
||||
glVertex3f( -width, 0, width );
|
||||
glVertex3f( -width, 0, -width );
|
||||
glVertex3f( width, 0, -width );
|
||||
glVertex3f( width, 0, width );
|
||||
glEnd();
|
||||
glBegin( GL_LINES );
|
||||
glVertex3f( -width, height, width ); glVertex3f( -width, 0, width );
|
||||
glVertex3f( -width, height, -width ); glVertex3f( -width, 0, -width );
|
||||
glVertex3f( width, height, -width ); glVertex3f( width, 0, -width );
|
||||
glVertex3f( width, height, width ); glVertex3f( width, 0, width );
|
||||
glEnd();
|
||||
glColor3ub( 255, 255, 255 );
|
||||
glEnable( GL_TEXTURE_2D );
|
||||
glEnable( GL_LIGHTING );
|
||||
#endif
|
||||
// shapes
|
||||
for( auto const &shape : section->m_shapes ) { Render( shape ); }
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rendermode::pickcontrols:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// add the section's cells to the cell queue
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::color:
|
||||
case rendermode::shadows:
|
||||
case rendermode::pickscenery: {
|
||||
for( auto &cell : section->m_cells ) {
|
||||
if( ( true == cell.m_active )
|
||||
#ifdef EU07_USE_DEBUG_CULLING
|
||||
&& ( m_worldcamera.camera.visible( cell.m_area ) ) ) {
|
||||
#else
|
||||
&& ( m_renderpass.camera.visible( cell.m_area ) ) ) {
|
||||
#endif
|
||||
// store visible cells with content as well as their current distance, for sorting later
|
||||
m_cellqueue.emplace_back(
|
||||
glm::length2( m_renderpass.camera.position() - cell.m_area.center ),
|
||||
&cell );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rendermode::reflections:
|
||||
case rendermode::pickcontrols:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// proceed to next section
|
||||
++First;
|
||||
}
|
||||
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::shadows: {
|
||||
// restore standard face cull mode
|
||||
::glEnable( GL_CULL_FACE );
|
||||
break; }
|
||||
default: {
|
||||
break; }
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator Last ) {
|
||||
|
||||
// cache initial iterator for the second sweep
|
||||
auto first { First };
|
||||
// first pass draws elements which we know are located in section banks, to reduce vbo switching
|
||||
while( First != Last ) {
|
||||
|
||||
auto const *cell = First->second;
|
||||
/*
|
||||
// przeliczenia animacji torów w sektorze
|
||||
Groundsubcell->RaAnimate( m_framestamp );
|
||||
*/
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::color: {
|
||||
// since all shapes of the section share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset { cell->m_area.center - m_renderpass.camera.position() };
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
|
||||
// render
|
||||
#ifdef EU07_USE_DEBUG_CULLING
|
||||
// debug
|
||||
float const width = scene::EU07_CELLSIZE * 0.5f;
|
||||
float const height = scene::EU07_CELLSIZE * 0.15f;
|
||||
glDisable( GL_LIGHTING );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
glColor3ub( 255, 255, 0 );
|
||||
glBegin( GL_LINE_LOOP );
|
||||
glVertex3f( -width, height, width );
|
||||
glVertex3f( -width, height, -width );
|
||||
glVertex3f( width, height, -width );
|
||||
glVertex3f( width, height, width );
|
||||
glEnd();
|
||||
glBegin( GL_LINE_LOOP );
|
||||
glVertex3f( -width, 0, width );
|
||||
glVertex3f( -width, 0, -width );
|
||||
glVertex3f( width, 0, -width );
|
||||
glVertex3f( width, 0, width );
|
||||
glEnd();
|
||||
glBegin( GL_LINES );
|
||||
glVertex3f( -width, height, width ); glVertex3f( -width, 0, width );
|
||||
glVertex3f( -width, height, -width ); glVertex3f( -width, 0, -width );
|
||||
glVertex3f( width, height, -width ); glVertex3f( width, 0, -width );
|
||||
glVertex3f( width, height, width ); glVertex3f( width, 0, width );
|
||||
glEnd();
|
||||
glColor3ub( 255, 255, 255 );
|
||||
glEnable( GL_TEXTURE_2D );
|
||||
glEnable( GL_LIGHTING );
|
||||
#endif
|
||||
// opaque non-instanced shapes
|
||||
for( auto const &shape : cell->m_shapesopaque ) { Render( shape ); }
|
||||
// tracks
|
||||
// TODO: update after path node refactoring
|
||||
for( auto *path : cell->m_paths ) { Render( path ); }
|
||||
// TODO: add other content types
|
||||
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
|
||||
break;
|
||||
}
|
||||
case rendermode::shadows: {
|
||||
// since all shapes of the section share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset { cell->m_area.center - m_renderpass.camera.position() };
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
|
||||
// render
|
||||
// opaque non-instanced shapes
|
||||
for( auto const &shape : cell->m_shapesopaque ) { Render( shape ); }
|
||||
// TODO: add other content types
|
||||
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
|
||||
break;
|
||||
}
|
||||
case rendermode::pickscenery: {
|
||||
// same procedure like with regular render, but editor-enabled nodes receive custom colour used for picking
|
||||
// since all shapes of the section share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset { cell->m_area.center - m_renderpass.camera.position() };
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
// render
|
||||
// opaque non-instanced shapes
|
||||
for( auto const &shape : cell->m_shapesopaque ) { Render( shape ); }
|
||||
// tracks
|
||||
// TODO: add path to the node picking list
|
||||
for( auto *path : cell->m_paths ) { Render( path ); }
|
||||
// TODO: add other content types
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
|
||||
break;
|
||||
}
|
||||
case rendermode::reflections:
|
||||
case rendermode::pickcontrols:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++First;
|
||||
}
|
||||
// second pass draws elements with their own vbos
|
||||
while( first != Last ) {
|
||||
|
||||
auto const *cell = first->second;
|
||||
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::color:
|
||||
case rendermode::shadows:
|
||||
case rendermode::pickscenery: {
|
||||
// render
|
||||
// opaque parts of instanced models
|
||||
for( auto *instance : cell->m_instancesopaque ) { Render( instance ); }
|
||||
// TODO: add remaining content types
|
||||
break;
|
||||
}
|
||||
case rendermode::reflections:
|
||||
case rendermode::pickcontrols:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
opengl_renderer::Render( scene::shape_node const &Shape ) {
|
||||
|
||||
auto const &data { Shape.data() };
|
||||
// setup
|
||||
Bind_Material( data.material );
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::color:
|
||||
case rendermode::reflections: {
|
||||
::glColor3fv( glm::value_ptr( data.lighting.diffuse ) );
|
||||
/*
|
||||
// NOTE: ambient component is set by diffuse component
|
||||
// NOTE: for the time being non-instanced shapes are rendered without specular component due to wrong/arbitrary values set in legacy scenarios
|
||||
// TBD, TODO: find a way to resolve this with the least amount of tears?
|
||||
::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( data.lighting.specular * Global::DayLight.specular.a * m_specularopaquescalefactor ) );
|
||||
*/
|
||||
break;
|
||||
}
|
||||
// pick modes are painted with custom colours, and shadow pass doesn't use any
|
||||
case rendermode::shadows:
|
||||
case rendermode::pickscenery:
|
||||
case rendermode::pickcontrols:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// render
|
||||
m_geometry.draw( data.geometry );
|
||||
}
|
||||
|
||||
void
|
||||
opengl_renderer::Render( TAnimModel *Instance ) {
|
||||
|
||||
double distancesquared;
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::shadows: {
|
||||
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
|
||||
distancesquared = SquareMagnitude( ( Instance->m_location - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
distancesquared = SquareMagnitude( ( Instance->m_location - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ( distancesquared < Instance->m_rangesquaredmin )
|
||||
|| ( distancesquared >= Instance->m_rangesquaredmax ) ) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
// TODO: enable adding items to the picking list
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::pickscenery: {
|
||||
// add the node to the pick list
|
||||
m_picksceneryitems.emplace_back( Node );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
Instance->RaAnimate( m_framestamp ); // jednorazowe przeliczenie animacji
|
||||
Instance->RaPrepare();
|
||||
if( Instance->pModel ) {
|
||||
// renderowanie rekurencyjne submodeli
|
||||
Render(
|
||||
Instance->pModel,
|
||||
Instance->Material(),
|
||||
distancesquared,
|
||||
Instance->m_location - m_renderpass.camera.position(),
|
||||
Instance->vAngle );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
opengl_renderer::Render( TGroundNode *Node ) {
|
||||
@@ -2272,6 +2692,9 @@ opengl_renderer::Render( TTrack *Track ) {
|
||||
&& ( Track->m_material2 == 0 ) ) {
|
||||
return;
|
||||
}
|
||||
if( false == Track->m_visible ) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::color:
|
||||
@@ -2311,7 +2734,7 @@ void
|
||||
opengl_renderer::Render( TMemCell *Memcell ) {
|
||||
|
||||
::glPushMatrix();
|
||||
auto const position = Memcell->Position() - m_renderpass.camera.position();
|
||||
auto const position = Memcell->location() - m_renderpass.camera.position();
|
||||
::glTranslated( position.x, position.y + 0.5, position.z );
|
||||
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
@@ -2342,27 +2765,28 @@ opengl_renderer::Render( TMemCell *Memcell ) {
|
||||
::glPopMatrix();
|
||||
}
|
||||
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool
|
||||
opengl_renderer::Render_Alpha( TGround *Ground ) {
|
||||
|
||||
TGroundNode *node;
|
||||
TSubRect *tmp;
|
||||
// Ra: renderowanie progresywne - zależne od FPS oraz kierunku patrzenia
|
||||
for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) {
|
||||
for( auto subcellpair = std::rbegin( m_cellqueue ); subcellpair != std::rend( m_cellqueue ); ++subcellpair ) {
|
||||
// przezroczyste trójkąty w oddzielnym cyklu przed modelami
|
||||
tmp = subcellpair->second;
|
||||
for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) {
|
||||
Render_Alpha( node );
|
||||
}
|
||||
}
|
||||
for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair )
|
||||
for( auto subcellpair = std::rbegin( m_cellqueue ); subcellpair != std::rend( m_cellqueue ); ++subcellpair )
|
||||
{ // renderowanie przezroczystych modeli oraz pojazdów
|
||||
Render_Alpha( subcellpair->second );
|
||||
}
|
||||
|
||||
::glDisable( GL_LIGHTING ); // linie nie powinny świecić
|
||||
|
||||
for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) {
|
||||
for( auto subcellpair = std::rbegin( m_cellqueue ); subcellpair != std::rend( m_cellqueue ); ++subcellpair ) {
|
||||
// druty na końcu, żeby się nie robiły białe plamy na tle lasu
|
||||
tmp = subcellpair->second;
|
||||
for( node = tmp->nRenderWires; node; node = node->nNext3 ) {
|
||||
@@ -2391,7 +2815,177 @@ opengl_renderer::Render_Alpha( TSubRect *Groundsubcell ) {
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
void
|
||||
opengl_renderer::Render_Alpha( scene::basic_region &Region ) {
|
||||
|
||||
// sort the nodes based on their distance to viewer
|
||||
std::sort(
|
||||
std::begin( m_cellqueue ),
|
||||
std::end( m_cellqueue ),
|
||||
[]( distancecell_pair const &Left, distancecell_pair const &Right ) {
|
||||
return ( Left.first ) < ( Right.first ); } );
|
||||
|
||||
Render_Alpha( std::rbegin( m_cellqueue ), std::rend( m_cellqueue ) );
|
||||
/*
|
||||
::glDisable( GL_LIGHTING ); // linie nie powinny świecić
|
||||
for( auto subcellpair = std::rbegin( m_cellqueue ); subcellpair != std::rend( m_cellqueue ); ++subcellpair ) {
|
||||
// druty na końcu, żeby się nie robiły białe plamy na tle lasu
|
||||
tmp = subcellpair->second;
|
||||
for( node = tmp->nRenderWires; node; node = node->nNext3 ) {
|
||||
Render_Alpha( node );
|
||||
}
|
||||
}
|
||||
::glEnable( GL_LIGHTING );
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
opengl_renderer::Render_Alpha( cell_sequence::reverse_iterator First, cell_sequence::reverse_iterator Last ) {
|
||||
|
||||
// first pass draws elements which we know are located in section banks, to reduce vbo switching
|
||||
{
|
||||
auto first { First };
|
||||
while( first != Last ) {
|
||||
|
||||
auto const *cell = first->second;
|
||||
|
||||
if( false == cell->m_shapestranslucent.empty() ) {
|
||||
// since all shapes of the cell share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset{ cell->m_area.center - m_renderpass.camera.position() };
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
// render
|
||||
// NOTE: we can reuse the method used to draw opaque geometry
|
||||
for( auto const &shape : cell->m_shapestranslucent ) { Render( shape ); }
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
}
|
||||
|
||||
++first;
|
||||
}
|
||||
}
|
||||
// second pass draws elements with their own vbos
|
||||
{
|
||||
auto first { First };
|
||||
while( first != Last ) {
|
||||
|
||||
auto const *cell = first->second;
|
||||
|
||||
// translucent parts of instanced models
|
||||
for( auto *instance : cell->m_instancetranslucent ) { Render_Alpha( instance ); }
|
||||
// TODO: add remaining content types
|
||||
|
||||
++first;
|
||||
}
|
||||
}
|
||||
// third pass draws the wires;
|
||||
// wires use section vbos, but for the time being we want to draw them at the very end
|
||||
{
|
||||
auto first{ First };
|
||||
while( first != Last ) {
|
||||
|
||||
auto const *cell = first->second;
|
||||
// TODO: include lines here
|
||||
if( false == cell->m_traction.empty() ) {
|
||||
// since all shapes of the cell share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset { cell->m_area.center - m_renderpass.camera.position() };
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
if( !Global::bSmoothTraction ) {
|
||||
// na liniach kiepsko wygląda - robi gradient
|
||||
::glDisable( GL_LINE_SMOOTH );
|
||||
}
|
||||
Bind_Material( null_handle );
|
||||
// render
|
||||
for( auto *traction : cell->m_traction ) { Render_Alpha( traction ); }
|
||||
// post-render cleanup
|
||||
::glLineWidth( 1.0 );
|
||||
if( !Global::bSmoothTraction ) {
|
||||
::glEnable( GL_LINE_SMOOTH );
|
||||
}
|
||||
::glPopMatrix();
|
||||
}
|
||||
|
||||
++first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
opengl_renderer::Render_Alpha( TAnimModel *Instance ) {
|
||||
|
||||
double distancesquared;
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::shadows: {
|
||||
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
|
||||
distancesquared = SquareMagnitude( ( Instance->m_location - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
distancesquared = SquareMagnitude( ( Instance->m_location - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ( distancesquared < Instance->m_rangesquaredmin )
|
||||
|| ( distancesquared >= Instance->m_rangesquaredmax ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Instance->RaPrepare();
|
||||
if( Instance->pModel ) {
|
||||
// renderowanie rekurencyjne submodeli
|
||||
Render_Alpha(
|
||||
Instance->pModel,
|
||||
Instance->Material(),
|
||||
distancesquared,
|
||||
Instance->m_location - m_renderpass.camera.position(),
|
||||
Instance->vAngle );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
opengl_renderer::Render_Alpha( TTraction *Traction ) {
|
||||
|
||||
double distancesquared;
|
||||
switch( m_renderpass.draw_mode ) {
|
||||
case rendermode::shadows: {
|
||||
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
|
||||
distancesquared = SquareMagnitude( ( Traction->m_location - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
distancesquared = SquareMagnitude( ( Traction->m_location - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ( distancesquared < Traction->m_rangesquaredmin )
|
||||
|| ( distancesquared >= Traction->m_rangesquaredmax ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( false == Traction->m_visible ) {
|
||||
return;
|
||||
}
|
||||
// rysuj jesli sa druty i nie zerwana
|
||||
if( ( Traction->Wires == 0 )
|
||||
|| ( true == TestFlag( Traction->DamageFlag, 128 ) ) ) {
|
||||
return;
|
||||
}
|
||||
// setup
|
||||
float const linealpha = static_cast<float>(
|
||||
std::min(
|
||||
1.25,
|
||||
5000 * Traction->WireThickness / ( distancesquared + 1.0 ) ) ); // zbyt grube nie są dobre
|
||||
::glLineWidth( linealpha );
|
||||
// McZapkie-261102: kolor zalezy od materialu i zasniedzenia
|
||||
auto const color { Traction->wire_color() };
|
||||
::glColor4f( color.r, color.g, color.b, linealpha );
|
||||
|
||||
// render
|
||||
m_geometry.draw( Traction->m_geometry );
|
||||
}
|
||||
#endif
|
||||
bool
|
||||
opengl_renderer::Render_Alpha( TGroundNode *Node ) {
|
||||
|
||||
@@ -2857,6 +3451,8 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
||||
Render_Alpha( Submodel->Next );
|
||||
};
|
||||
|
||||
|
||||
|
||||
// utility methods
|
||||
TSubModel const *
|
||||
opengl_renderer::Update_Pick_Control() {
|
||||
|
||||
45
renderer.h
45
renderer.h
@@ -15,12 +15,14 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "lightarray.h"
|
||||
#include "dumb3d.h"
|
||||
#include "frustum.h"
|
||||
#include "scene.h"
|
||||
#include "world.h"
|
||||
#include "memcell.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
|
||||
@@ -225,7 +227,13 @@ private:
|
||||
diffuse
|
||||
};
|
||||
|
||||
typedef std::pair< double, TSubRect * > distancesubcell_pair;
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
using distancesubcell_pair = std::pair< double, TSubRect * >;
|
||||
#else
|
||||
using section_sequence = std::vector<scene::basic_section *>;
|
||||
using distancecell_pair = std::pair<double, scene::basic_cell *>;
|
||||
using cell_sequence = std::vector<distancecell_pair>;
|
||||
#endif
|
||||
|
||||
struct renderpass_config {
|
||||
|
||||
@@ -266,12 +274,25 @@ private:
|
||||
Render_reflections();
|
||||
bool
|
||||
Render( world_environment *Environment );
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool
|
||||
Render( TGround *Ground );
|
||||
bool
|
||||
Render( TGroundRect *Groundcell );
|
||||
bool
|
||||
Render( TSubRect *Groundsubcell );
|
||||
#else
|
||||
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 );
|
||||
void
|
||||
Render( TAnimModel *Instance );
|
||||
#endif
|
||||
bool
|
||||
Render( TGroundNode *Node );
|
||||
bool
|
||||
@@ -288,10 +309,21 @@ private:
|
||||
Render_cab( TDynamicObject *Dynamic, bool const Alpha = false );
|
||||
void
|
||||
Render( TMemCell *Memcell );
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
bool
|
||||
Render_Alpha( TGround *Ground );
|
||||
bool
|
||||
Render_Alpha( TSubRect *Groundsubcell );
|
||||
#else
|
||||
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 );
|
||||
#endif
|
||||
bool
|
||||
Render_Alpha( TGroundNode *Node );
|
||||
bool
|
||||
@@ -361,13 +393,18 @@ private:
|
||||
std::string m_pickdebuginfo;
|
||||
|
||||
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
|
||||
#ifdef EU07_USE_OLD_GROUNDCODE
|
||||
std::vector<distancesubcell_pair> m_cellqueue; // list of subcells to be drawn in current render pass
|
||||
#else
|
||||
section_sequence m_sectionqueue; // list of sections in current render pass
|
||||
cell_sequence m_cellqueue;
|
||||
#endif
|
||||
|
||||
std::vector<TGroundNode const *> m_picksceneryitems;
|
||||
std::vector<TSubModel const *> m_pickcontrolsitems;
|
||||
|
||||
579
scene.cpp
Normal file
579
scene.cpp
Normal file
@@ -0,0 +1,579 @@
|
||||
/*
|
||||
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 "scene.h"
|
||||
|
||||
#include "renderer.h"
|
||||
#include "logs.h"
|
||||
|
||||
namespace scene {
|
||||
|
||||
// adds provided shape to the cell
|
||||
void
|
||||
basic_cell::insert( shape_node Shape ) {
|
||||
|
||||
m_active = true;
|
||||
|
||||
auto const &shapedata { Shape.data() };
|
||||
auto &shapes = (
|
||||
shapedata.translucent ?
|
||||
m_shapestranslucent :
|
||||
m_shapesopaque );
|
||||
for( auto &targetshape : shapes ) {
|
||||
// try to merge shapes with matching view ranges...
|
||||
auto const &targetshapedata { targetshape.data() };
|
||||
if( ( shapedata.rangesquared_min == targetshapedata.rangesquared_min )
|
||||
&& ( shapedata.rangesquared_max == targetshapedata.rangesquared_max )
|
||||
// ...and located close to each other (within arbitrary limit of 25m)
|
||||
&& ( glm::length( shapedata.area.center - targetshapedata.area.center ) < 25.0 ) ) {
|
||||
|
||||
if( true == targetshape.merge( Shape ) ) {
|
||||
// if the shape was merged there's nothing left to do
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// otherwise add the shape to the relevant list
|
||||
Shape.origin( m_area.center );
|
||||
shapes.emplace_back( Shape );
|
||||
}
|
||||
|
||||
// adds provided path to the cell
|
||||
void
|
||||
basic_cell::insert( TTrack *Path ) {
|
||||
|
||||
m_active = true;
|
||||
|
||||
// TODO: add animation hook
|
||||
Path->origin( m_area.center );
|
||||
m_paths.emplace_back( Path );
|
||||
}
|
||||
|
||||
// adds provided traction piece to the cell
|
||||
void
|
||||
basic_cell::insert( TTraction *Traction ) {
|
||||
|
||||
m_active = true;
|
||||
|
||||
Traction->origin( m_area.center );
|
||||
m_traction.emplace_back( Traction );
|
||||
}
|
||||
|
||||
// adds provided model instance to the cell
|
||||
void
|
||||
basic_cell::insert( TAnimModel *Instance ) {
|
||||
|
||||
m_active = true;
|
||||
|
||||
auto const flags = Instance->Flags();
|
||||
auto alpha =
|
||||
( Instance->Material() != nullptr ?
|
||||
Instance->Material()->textures_alpha :
|
||||
0x30300030 );
|
||||
|
||||
// assign model to appropriate render phases
|
||||
if( alpha & flags & 0x2F2F002F ) {
|
||||
// translucent pieces
|
||||
m_instancetranslucent.emplace_back( Instance );
|
||||
}
|
||||
alpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste
|
||||
if( alpha & flags & 0x1F1F001F ) {
|
||||
// opaque pieces
|
||||
m_instancesopaque.emplace_back( Instance );
|
||||
}
|
||||
}
|
||||
|
||||
// generates renderable version of held non-instanced geometry
|
||||
void
|
||||
basic_cell::create_geometry( geometrybank_handle const &Bank ) {
|
||||
|
||||
if( false == m_active ) { return; } // nothing to do here
|
||||
|
||||
for( auto &shape : m_shapesopaque ) { shape.create_geometry( Bank ); }
|
||||
for( auto &shape : m_shapestranslucent ) { shape.create_geometry( Bank ); }
|
||||
#ifndef EU07_USE_OLD_GROUNDCODE
|
||||
for( auto *path : m_paths ) { path->create_geometry( Bank ); }
|
||||
for( auto *traction : m_traction ) { traction->create_geometry( Bank ); }
|
||||
#endif
|
||||
}
|
||||
|
||||
// sets center point of the section
|
||||
void
|
||||
basic_cell::center( glm::dvec3 Center ) {
|
||||
|
||||
m_area.center = Center;
|
||||
// NOTE: we should also update origin point for the contained nodes, but in practice we can skip this
|
||||
// as all nodes will be added only after the proper center point was set, and won't change
|
||||
}
|
||||
|
||||
|
||||
|
||||
// adds provided shape to the section
|
||||
void
|
||||
basic_section::insert( shape_node Shape ) {
|
||||
|
||||
m_active = true;
|
||||
|
||||
auto const &shapedata = Shape.data();
|
||||
if( ( true == shapedata.translucent )
|
||||
|| ( shapedata.rangesquared_max <= 90000.0 )
|
||||
|| ( shapedata.rangesquared_min > 0.0 ) ) {
|
||||
// small, translucent or not always visible shapes are placed in the sub-cells
|
||||
cell( shapedata.area.center ).insert( Shape );
|
||||
}
|
||||
else {
|
||||
// large, opaque shapes are placed on section level
|
||||
for( auto &shape : m_shapes ) {
|
||||
// check first if the shape can't be merged with one of the shapes already present in the section
|
||||
if( true == shape.merge( Shape ) ) {
|
||||
// if the shape was merged there's nothing left to do
|
||||
return;
|
||||
}
|
||||
}
|
||||
// otherwise add the shape to the section's list
|
||||
Shape.origin( m_area.center );
|
||||
m_shapes.emplace_back( Shape );
|
||||
}
|
||||
}
|
||||
|
||||
// adds provided path to the section
|
||||
void
|
||||
basic_section::insert( TTrack *Path ) {
|
||||
|
||||
m_active = true;
|
||||
// pass the node to the appropriate partitioning cell
|
||||
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
||||
cell( Path->location() ).insert( Path );
|
||||
}
|
||||
|
||||
// adds provided path to the section
|
||||
void
|
||||
basic_section::insert( TTraction *Traction ) {
|
||||
|
||||
m_active = true;
|
||||
// pass the node to the appropriate partitioning cell
|
||||
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
||||
cell( Traction->location() ).insert( Traction );
|
||||
}
|
||||
|
||||
// adds provided model instance to the section
|
||||
void
|
||||
basic_section::insert( TAnimModel *Instance ) {
|
||||
|
||||
m_active = true;
|
||||
// pass the node to the appropriate partitioning cell
|
||||
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
||||
cell( Instance->location() ).insert( Instance );
|
||||
}
|
||||
|
||||
// sets center point of the section
|
||||
void
|
||||
basic_section::center( glm::dvec3 Center ) {
|
||||
|
||||
m_area.center = Center;
|
||||
// set accordingly center points of the section's partitioning cells
|
||||
// NOTE: we should also update origin point for the contained nodes, but in practice we can skip this
|
||||
// as all nodes will be added only after the proper center point was set, and won't change
|
||||
auto const centeroffset = -( EU07_SECTIONSIZE / EU07_CELLSIZE / 2 * EU07_CELLSIZE ) + EU07_CELLSIZE / 2;
|
||||
glm::dvec3 sectioncornercenter { m_area.center + glm::dvec3{ centeroffset, 0, centeroffset } };
|
||||
auto row { 0 }, column { 0 };
|
||||
for( auto &cell : m_cells ) {
|
||||
cell.center( sectioncornercenter + glm::dvec3{ column * EU07_CELLSIZE, 0.0, row * EU07_CELLSIZE } );
|
||||
if( ++column >= EU07_SECTIONSIZE / EU07_CELLSIZE ) {
|
||||
++row;
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generates renderable version of held non-instanced geometry
|
||||
void
|
||||
basic_section::create_geometry() {
|
||||
|
||||
if( true == m_geometrycreated ) { return; }
|
||||
else {
|
||||
// mark it done for future checks
|
||||
m_geometrycreated = true;
|
||||
}
|
||||
|
||||
if( false == m_active ) { return; } // nothing to do here
|
||||
|
||||
// since sections can be empty, we're doing lazy initialization of the geometry bank, when something may actually use it
|
||||
if( m_geometrybank == null_handle ) {
|
||||
m_geometrybank = GfxRenderer.Create_Bank();
|
||||
}
|
||||
|
||||
for( auto &shape : m_shapes ) {
|
||||
shape.create_geometry( m_geometrybank );
|
||||
}
|
||||
for( auto &cell : m_cells ) {
|
||||
cell.create_geometry( m_geometrybank );
|
||||
}
|
||||
}
|
||||
|
||||
// provides access to section enclosing specified point
|
||||
basic_cell &
|
||||
basic_section::cell( glm::dvec3 const &Location ) {
|
||||
|
||||
auto const column = static_cast<int>( std::floor( ( Location.x - ( m_area.center.x - EU07_SECTIONSIZE / 2 ) ) / EU07_CELLSIZE ) );
|
||||
auto const row = static_cast<int>( std::floor( ( Location.z - ( m_area.center.z - EU07_SECTIONSIZE / 2 ) ) / EU07_CELLSIZE ) );
|
||||
|
||||
return
|
||||
m_cells[
|
||||
clamp( row, 0, ( EU07_SECTIONSIZE / EU07_CELLSIZE ) - 1 ) * ( EU07_SECTIONSIZE / EU07_CELLSIZE )
|
||||
+ clamp( column, 0, ( EU07_SECTIONSIZE / EU07_CELLSIZE ) - 1 ) ] ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
basic_region::basic_region() {
|
||||
|
||||
// initialize centers of sections:
|
||||
// calculate center of 'top left' region section...
|
||||
auto const centeroffset = -( EU07_REGIONSIDESECTIONCOUNT / 2 * EU07_SECTIONSIZE ) + EU07_SECTIONSIZE / 2;
|
||||
glm::dvec3 regioncornercenter { centeroffset, 0, centeroffset };
|
||||
auto row { 0 }, column { 0 };
|
||||
// ...move through section array assigning centers left to right, front/top to back/bottom
|
||||
for( auto §ion : m_sections ) {
|
||||
section.center( regioncornercenter + glm::dvec3{ column * EU07_SECTIONSIZE, 0.0, row * EU07_SECTIONSIZE } );
|
||||
if( ++column >= EU07_REGIONSIDESECTIONCOUNT ) {
|
||||
++row;
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_region::insert_shape( shape_node Shape, scratch_data &Scratchpad ) {
|
||||
|
||||
// shape might need to be split into smaller pieces, so we create list of nodes instead of just single one
|
||||
// using deque so we can do single pass iterating and addding generated pieces without invalidating anything
|
||||
std::deque<shape_node> shapes { Shape };
|
||||
auto &shape = shapes.front();
|
||||
if( shape.m_data.vertices.empty() ) { return; }
|
||||
|
||||
// adjust input if necessary:
|
||||
if( Scratchpad.location_rotation != glm::vec3( 0, 0, 0 ) ) {
|
||||
// rotate...
|
||||
auto const rotation = glm::radians( Scratchpad.location_rotation );
|
||||
for( auto &vertex : shape.m_data.vertices ) {
|
||||
vertex.position = glm::rotateZ<double>( vertex.position, rotation.z );
|
||||
vertex.position = glm::rotateX<double>( vertex.position, rotation.x );
|
||||
vertex.position = glm::rotateY<double>( vertex.position, rotation.y );
|
||||
vertex.normal = glm::rotateZ( vertex.normal, rotation.z );
|
||||
vertex.normal = glm::rotateX( vertex.normal, rotation.x );
|
||||
vertex.normal = glm::rotateY( vertex.normal, rotation.y );
|
||||
}
|
||||
}
|
||||
if( ( false == Scratchpad.location_offset.empty() )
|
||||
&& ( Scratchpad.location_offset.top() != glm::dvec3( 0, 0, 0 ) ) ) {
|
||||
// ...and move
|
||||
auto const offset = Scratchpad.location_offset.top();
|
||||
for( auto &vertex : shape.m_data.vertices ) {
|
||||
vertex.position += offset;
|
||||
}
|
||||
}
|
||||
// calculate bounding area
|
||||
for( auto const &vertex : shape.m_data.vertices ) {
|
||||
shape.m_data.area.center += vertex.position;
|
||||
}
|
||||
shape.m_data.area.center /= shape.m_data.vertices.size();
|
||||
// trim the shape if needed. trimmed parts will be added to list as separate nodes
|
||||
for( std::size_t index = 0; index < shapes.size(); ++index ) {
|
||||
while( true == RaTriangleDivider( shapes[ index ], shapes ) ) {
|
||||
; // all work is done during expression check
|
||||
}
|
||||
// with the trimming done we can calculate shape's bounding radius
|
||||
shape.compute_radius();
|
||||
}
|
||||
// move the data into appropriate section(s)
|
||||
for( auto &shape : shapes ) {
|
||||
|
||||
if( point_inside( shape.m_data.area.center ) ) {
|
||||
// NOTE: nodes placed outside of region boundaries are discarded
|
||||
section( shape.m_data.area.center ).insert( shape );
|
||||
}
|
||||
else {
|
||||
ErrorLog(
|
||||
"Bad scenario: shape node" + (
|
||||
shape.m_name.empty() ?
|
||||
"" :
|
||||
" \"" + shape.m_name + "\"" )
|
||||
+ " placed in location outside region bounds (" + to_string( shape.m_data.area.center ) + ")" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// inserts provided track in the region
|
||||
void
|
||||
basic_region::insert_path( TTrack *Path, scratch_data &Scratchpad ) {
|
||||
|
||||
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
||||
auto center = Path->location();
|
||||
|
||||
if( point_inside( center ) ) {
|
||||
// NOTE: nodes placed outside of region boundaries are discarded
|
||||
section( center ).insert( Path );
|
||||
}
|
||||
else {
|
||||
// tracks are guaranteed to hava a name so we can skip the check
|
||||
ErrorLog( "Bad scenario: track node \"" + Path->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
|
||||
}
|
||||
}
|
||||
|
||||
// inserts provided track in the region
|
||||
void
|
||||
basic_region::insert_traction( TTraction *Traction, scratch_data &Scratchpad ) {
|
||||
|
||||
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
||||
auto center = Traction->location();
|
||||
|
||||
if( point_inside( center ) ) {
|
||||
// NOTE: nodes placed outside of region boundaries are discarded
|
||||
section( center ).insert( Traction );
|
||||
}
|
||||
else {
|
||||
// tracks are guaranteed to hava a name so we can skip the check
|
||||
ErrorLog( "Bad scenario: traction node \"" + Traction->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
|
||||
}
|
||||
}
|
||||
|
||||
// inserts provided instance of 3d model in the region
|
||||
void
|
||||
basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ) {
|
||||
|
||||
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
||||
auto center = Instance->location();
|
||||
|
||||
if( point_inside( center ) ) {
|
||||
// NOTE: nodes placed outside of region boundaries are discarded
|
||||
section( center ).insert( Instance );
|
||||
}
|
||||
else {
|
||||
// tracks are guaranteed to hava a name so we can skip the check
|
||||
ErrorLog( "Bad scenario: model node \"" + Instance->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
|
||||
}
|
||||
}
|
||||
|
||||
// checks whether specified point is within boundaries of the region
|
||||
bool
|
||||
basic_region::point_inside( glm::dvec3 const &Location ) {
|
||||
|
||||
double const regionboundary = EU07_REGIONSIDESECTIONCOUNT / 2 * EU07_SECTIONSIZE;
|
||||
return ( ( Location.x > -regionboundary ) && ( Location.x < regionboundary )
|
||||
&& ( Location.z > -regionboundary ) && ( Location.z < regionboundary ) );
|
||||
}
|
||||
|
||||
// trims provided shape to fit into a section, adds trimmed part at the end of provided list
|
||||
// NOTE: legacy function. TBD, TODO: clean it up?
|
||||
bool
|
||||
basic_region::RaTriangleDivider( shape_node &Shape, std::deque<shape_node> &Shapes ) {
|
||||
|
||||
if( Shape.m_data.vertices.size() != 3 ) {
|
||||
// tylko gdy jeden trójkąt
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const margin { 200.0 };
|
||||
auto x0 = EU07_SECTIONSIZE * std::floor( 0.001 * Shape.m_data.area.center.x ) - margin;
|
||||
auto x1 = x0 + EU07_SECTIONSIZE + margin * 2;
|
||||
auto z0 = EU07_SECTIONSIZE * std::floor( 0.001 * Shape.m_data.area.center.z ) - margin;
|
||||
auto z1 = z0 + EU07_SECTIONSIZE + margin * 2;
|
||||
|
||||
if( ( Shape.m_data.vertices[ 0 ].position.x >= x0 ) && ( Shape.m_data.vertices[ 0 ].position.x <= x1 )
|
||||
&& ( Shape.m_data.vertices[ 0 ].position.z >= z0 ) && ( Shape.m_data.vertices[ 0 ].position.z <= z1 )
|
||||
&& ( Shape.m_data.vertices[ 1 ].position.x >= x0 ) && ( Shape.m_data.vertices[ 1 ].position.x <= x1 )
|
||||
&& ( Shape.m_data.vertices[ 1 ].position.z >= z0 ) && ( Shape.m_data.vertices[ 1 ].position.z <= z1 )
|
||||
&& ( Shape.m_data.vertices[ 2 ].position.x >= x0 ) && ( Shape.m_data.vertices[ 2 ].position.x <= x1 )
|
||||
&& ( Shape.m_data.vertices[ 2 ].position.z >= z0 ) && ( Shape.m_data.vertices[ 2 ].position.z <= z1 ) ) {
|
||||
// trójkąt wystający mniej niż 200m z kw. kilometrowego jest do przyjęcia
|
||||
return false;
|
||||
}
|
||||
// Ra: przerobić na dzielenie na 2 trójkąty, podział w przecięciu z siatką kilometrową
|
||||
// Ra: i z rekurencją będzie dzielić trzy trójkąty, jeśli będzie taka potrzeba
|
||||
int divide { -1 }; // bok do podzielenia: 0=AB, 1=BC, 2=CA; +4=podział po OZ; +8 na x1/z1
|
||||
double
|
||||
min { 0.0 },
|
||||
mul; // jeśli przechodzi przez oś, iloczyn będzie ujemny
|
||||
x0 += margin;
|
||||
x1 -= margin; // przestawienie na siatkę
|
||||
z0 += margin;
|
||||
z1 -= margin;
|
||||
// AB na wschodzie
|
||||
mul = ( Shape.m_data.vertices[ 0 ].position.x - x0 ) * ( Shape.m_data.vertices[ 1 ].position.x - x0 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 0;
|
||||
}
|
||||
// BC na wschodzie
|
||||
mul = ( Shape.m_data.vertices[ 1 ].position.x - x0 ) * ( Shape.m_data.vertices[ 2 ].position.x - x0 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 1;
|
||||
}
|
||||
// CA na wschodzie
|
||||
mul = ( Shape.m_data.vertices[ 2 ].position.x - x0 ) * ( Shape.m_data.vertices[ 0 ].position.x - x0 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 2;
|
||||
}
|
||||
// AB na zachodzie
|
||||
mul = ( Shape.m_data.vertices[ 0 ].position.x - x1 ) * ( Shape.m_data.vertices[ 1 ].position.x - x1 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 8;
|
||||
}
|
||||
// BC na zachodzie
|
||||
mul = ( Shape.m_data.vertices[ 1 ].position.x - x1 ) * ( Shape.m_data.vertices[ 2 ].position.x - x1 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 9;
|
||||
}
|
||||
// CA na zachodzie
|
||||
mul = ( Shape.m_data.vertices[ 2 ].position.x - x1 ) * ( Shape.m_data.vertices[ 0 ].position.x - x1 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 10;
|
||||
}
|
||||
// AB na południu
|
||||
mul = ( Shape.m_data.vertices[ 0 ].position.z - z0 ) * ( Shape.m_data.vertices[ 1 ].position.z - z0 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 4;
|
||||
}
|
||||
// BC na południu
|
||||
mul = ( Shape.m_data.vertices[ 1 ].position.z - z0 ) * ( Shape.m_data.vertices[ 2 ].position.z - z0 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 5;
|
||||
}
|
||||
// CA na południu
|
||||
mul = ( Shape.m_data.vertices[ 2 ].position.z - z0 ) * ( Shape.m_data.vertices[ 0 ].position.z - z0 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 6;
|
||||
}
|
||||
// AB na północy
|
||||
mul = ( Shape.m_data.vertices[ 0 ].position.z - z1 ) * ( Shape.m_data.vertices[ 1 ].position.z - z1 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 12;
|
||||
}
|
||||
// BC na północy
|
||||
mul = ( Shape.m_data.vertices[ 1 ].position.z - z1 ) * ( Shape.m_data.vertices[ 2 ].position.z - z1 );
|
||||
if( mul < min ) {
|
||||
min = mul;
|
||||
divide = 13;
|
||||
}
|
||||
// CA na północy
|
||||
mul = (Shape.m_data.vertices[2].position.z - z1) * (Shape.m_data.vertices[0].position.z - z1);
|
||||
if( mul < min ) {
|
||||
divide = 14;
|
||||
}
|
||||
|
||||
// tworzymy jeden dodatkowy trójkąt, dzieląc jeden bok na przecięciu siatki kilometrowej
|
||||
Shapes.emplace_back( Shape ); // copy current shape
|
||||
auto &newshape = Shapes.back();
|
||||
|
||||
switch (divide & 3) {
|
||||
// podzielenie jednego z boków, powstaje wierzchołek D
|
||||
case 0: {
|
||||
// podział AB (0-1) -> ADC i DBC
|
||||
newshape.m_data.vertices[ 2 ] = Shape.m_data.vertices[ 2 ]; // wierzchołek C jest wspólny
|
||||
newshape.m_data.vertices[ 1 ] = Shape.m_data.vertices[ 1 ]; // wierzchołek B przechodzi do nowego
|
||||
if( divide & 4 ) {
|
||||
Shape.m_data.vertices[ 1 ].set_from_z(
|
||||
Shape.m_data.vertices[ 0 ],
|
||||
Shape.m_data.vertices[ 1 ],
|
||||
( ( divide & 8 ) ?
|
||||
z1 :
|
||||
z0 ) );
|
||||
}
|
||||
else {
|
||||
Shape.m_data.vertices[ 1 ].set_from_x(
|
||||
Shape.m_data.vertices[ 0 ],
|
||||
Shape.m_data.vertices[ 1 ],
|
||||
( ( divide & 8 ) ?
|
||||
x1 :
|
||||
x0 ) );
|
||||
}
|
||||
newshape.m_data.vertices[ 0 ] = Shape.m_data.vertices[ 1 ]; // wierzchołek D jest wspólny
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// podział BC (1-2) -> ABD i ADC
|
||||
newshape.m_data.vertices[ 0 ] = Shape.m_data.vertices[ 0 ]; // wierzchołek A jest wspólny
|
||||
newshape.m_data.vertices[ 2 ] = Shape.m_data.vertices[ 2 ]; // wierzchołek C przechodzi do nowego
|
||||
if( divide & 4 ) {
|
||||
Shape.m_data.vertices[ 2 ].set_from_z(
|
||||
Shape.m_data.vertices[ 1 ],
|
||||
Shape.m_data.vertices[ 2 ],
|
||||
( ( divide & 8 ) ?
|
||||
z1 :
|
||||
z0 ) );
|
||||
}
|
||||
else {
|
||||
Shape.m_data.vertices[ 2 ].set_from_x(
|
||||
Shape.m_data.vertices[ 1 ],
|
||||
Shape.m_data.vertices[ 2 ],
|
||||
( ( divide & 8 ) ?
|
||||
x1 :
|
||||
x0 ) );
|
||||
}
|
||||
newshape.m_data.vertices[ 1 ] = Shape.m_data.vertices[ 2 ]; // wierzchołek D jest wspólny
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// podział CA (2-0) -> ABD i DBC
|
||||
newshape.m_data.vertices[ 1 ] = Shape.m_data.vertices[ 1 ]; // wierzchołek B jest wspólny
|
||||
newshape.m_data.vertices[ 2 ] = Shape.m_data.vertices[ 2 ]; // wierzchołek C przechodzi do nowego
|
||||
if( divide & 4 ) {
|
||||
Shape.m_data.vertices[ 2 ].set_from_z(
|
||||
Shape.m_data.vertices[ 2 ],
|
||||
Shape.m_data.vertices[ 0 ],
|
||||
( ( divide & 8 ) ?
|
||||
z1 :
|
||||
z0 ) );
|
||||
}
|
||||
else {
|
||||
Shape.m_data.vertices[ 2 ].set_from_x(
|
||||
Shape.m_data.vertices[ 2 ],
|
||||
Shape.m_data.vertices[ 0 ],
|
||||
( ( divide & 8 ) ?
|
||||
x1 :
|
||||
x0 ) );
|
||||
}
|
||||
newshape.m_data.vertices[ 0 ] = Shape.m_data.vertices[ 2 ]; // wierzchołek D jest wspólny
|
||||
break;
|
||||
}
|
||||
}
|
||||
// przeliczenie środków ciężkości obu
|
||||
Shape.m_data.area.center = ( Shape.m_data.vertices[ 0 ].position + Shape.m_data.vertices[ 1 ].position + Shape.m_data.vertices[ 2 ].position ) / 3.0;
|
||||
newshape.m_data.area.center = ( newshape.m_data.vertices[ 0 ].position + newshape.m_data.vertices[ 1 ].position + newshape.m_data.vertices[ 2 ].position ) / 3.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// provides access to section enclosing specified point
|
||||
basic_section &
|
||||
basic_region::section( glm::dvec3 const &Location ) {
|
||||
|
||||
auto const column = static_cast<int>( std::floor( Location.x / EU07_SECTIONSIZE + EU07_REGIONSIDESECTIONCOUNT / 2 ) );
|
||||
auto const row = static_cast<int>( std::floor( Location.z / EU07_SECTIONSIZE + EU07_REGIONSIDESECTIONCOUNT / 2 ) );
|
||||
|
||||
return
|
||||
m_sections[
|
||||
clamp( row, 0, EU07_REGIONSIDESECTIONCOUNT - 1 ) * EU07_REGIONSIDESECTIONCOUNT
|
||||
+ clamp( column, 0, EU07_REGIONSIDESECTIONCOUNT - 1 ) ] ;
|
||||
}
|
||||
|
||||
} // scene
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
172
scene.h
Normal file
172
scene.h
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
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 "parser.h"
|
||||
#include "openglgeometrybank.h"
|
||||
#include "scenenode.h"
|
||||
#include "track.h"
|
||||
#include "traction.h"
|
||||
|
||||
namespace scene {
|
||||
|
||||
int const EU07_CELLSIZE = 250;
|
||||
int const EU07_SECTIONSIZE = 1000;
|
||||
int const EU07_REGIONSIDESECTIONCOUNT = 500; // number of 1km sections along a side of square region
|
||||
|
||||
struct scratch_data {
|
||||
|
||||
std::stack<glm::dvec3> location_offset;
|
||||
glm::vec3 location_rotation;
|
||||
};
|
||||
|
||||
// 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
|
||||
// adds provided shape to the cell
|
||||
void
|
||||
insert( shape_node Shape );
|
||||
// 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 );
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
create_geometry( geometrybank_handle const &Bank );
|
||||
// sets center point of the cell
|
||||
void
|
||||
center( glm::dvec3 Center );
|
||||
|
||||
private:
|
||||
// types
|
||||
using shapenode_sequence = std::vector<shape_node>;
|
||||
using path_sequence = std::vector<TTrack *>;
|
||||
using traction_sequence = std::vector<TTraction *>;
|
||||
using instance_sequence = std::vector<TAnimModel *>;
|
||||
// members
|
||||
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE + 0.25 * EU07_CELLSIZE ) };
|
||||
bool m_active { false }; // whether the cell holds any actual data
|
||||
// content
|
||||
shapenode_sequence m_shapesopaque; // opaque pieces of geometry
|
||||
shapenode_sequence m_shapestranslucent; // translucent pieces of geometry
|
||||
path_sequence m_paths; // path pieces
|
||||
instance_sequence m_instancesopaque;
|
||||
instance_sequence m_instancetranslucent;
|
||||
traction_sequence m_traction;
|
||||
};
|
||||
|
||||
// basic scene partitioning structure, holds terrain geometry and collection of cells
|
||||
class basic_section {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
public:
|
||||
// methods
|
||||
// adds provided shape to the section
|
||||
void
|
||||
insert( shape_node Shape );
|
||||
// adds provided path to the section
|
||||
void
|
||||
insert( TTrack *Path );
|
||||
// adds provided path to the section
|
||||
void
|
||||
insert( TTraction *Traction );
|
||||
// adds provided model instance to the section
|
||||
void
|
||||
insert( TAnimModel *Instance );
|
||||
// generates renderable version of held non-instanced geometry
|
||||
void
|
||||
create_geometry();
|
||||
// sets center point of the section
|
||||
void
|
||||
center( glm::dvec3 Center );
|
||||
|
||||
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 + 0.25 * EU07_SECTIONSIZE ) };
|
||||
bool m_active { false }; // whether the section holds any actual data, itself or in the cells
|
||||
// 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();
|
||||
// methods
|
||||
// inserts provided shape in the region
|
||||
void
|
||||
insert_shape( shape_node Shape, scratch_data &Scratchpad );
|
||||
// inserts provided track in the region
|
||||
void
|
||||
insert_path( TTrack *Path, 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 );
|
||||
|
||||
|
||||
private:
|
||||
// types
|
||||
using section_array = std::array<basic_section, EU07_REGIONSIDESECTIONCOUNT * EU07_REGIONSIDESECTIONCOUNT>;
|
||||
|
||||
// methods
|
||||
// checks whether specified point is within boundaries of the region
|
||||
bool
|
||||
point_inside( glm::dvec3 const &Location );
|
||||
// trims provided shape to fit into a section, adds trimmed part at the end of provided list
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
} // scene
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
296
scenenode.cpp
Normal file
296
scenenode.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
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, 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;
|
||||
}
|
||||
|
||||
// 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 ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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() );
|
||||
}
|
||||
|
||||
|
||||
} // editor
|
||||
//---------------------------------------------------------------------------
|
||||
253
scenenode.h
Normal file
253
scenenode.h
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
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 { 0.0 };
|
||||
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
|
||||
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, node_data const &Nodedata );
|
||||
// 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 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; }
|
||||
glm::dvec3 const &
|
||||
location() {
|
||||
return m_location; };
|
||||
void
|
||||
location( glm::dvec3 const Location ) {
|
||||
m_location = Location; }
|
||||
bool
|
||||
visible() const {
|
||||
return m_visible; }
|
||||
|
||||
protected:
|
||||
// members
|
||||
glm::dvec3 m_location;
|
||||
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
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
521
simulation.cpp
Normal file
521
simulation.cpp
Normal file
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
state_manager State;
|
||||
event_manager Events;
|
||||
memory_manager Memory;
|
||||
path_table Paths;
|
||||
traction_table Traction;
|
||||
instance_manager Instances;
|
||||
light_array Lights;
|
||||
scene::basic_region Region;
|
||||
|
||||
bool
|
||||
state_manager::deserialize( std::string const &Scenariofile ) {
|
||||
|
||||
// TODO: check first for presence of serialized binary files
|
||||
// if this fails, fall back on the legacy text format
|
||||
cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global::asCurrentSceneryPath, Global::bLoadTraction );
|
||||
|
||||
if( false == scenarioparser.ok() ) { return false; }
|
||||
|
||||
deserialize( scenarioparser );
|
||||
// TODO: initialize links between loaded nodes
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// restores class data from provided stream
|
||||
void
|
||||
state_manager::deserialize( cParser &Input ) {
|
||||
|
||||
scene::scratch_data importscratchpad;
|
||||
// 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 },
|
||||
{ "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( importscratchpad ) ) );
|
||||
}
|
||||
// deserialize content from the provided input
|
||||
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 ) + ")" );
|
||||
}
|
||||
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
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_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// TODO: implement
|
||||
simulation::Paths.InitTracks();
|
||||
simulation::Traction.InitTraction();
|
||||
simulation::Events.InitEvents();
|
||||
}
|
||||
|
||||
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 ) {
|
||||
|
||||
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" ) {
|
||||
// TODO: implement
|
||||
skip_until( Input, "enddynamic" );
|
||||
}
|
||||
else if( nodedata.type == "track" ) {
|
||||
|
||||
auto const inputline = Input.Line(); // cache in case we need to report error
|
||||
|
||||
auto *path { deserialize_path( Input, Scratchpad, nodedata ) };
|
||||
// duplicates of named tracks are currently experimentally allowed
|
||||
if( simulation::Paths.insert( path ) ) {
|
||||
simulation::Region.insert_path( path, Scratchpad );
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad scenario: track with duplicate name, \"" + path->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
/*
|
||||
delete path;
|
||||
delete pathnode;
|
||||
*/
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "traction" ) {
|
||||
|
||||
auto const inputline = Input.Line(); // cache in case we need to report error
|
||||
|
||||
auto *traction { deserialize_traction( Input, Scratchpad, nodedata ) };
|
||||
// duplicates of named tracks are currently discarded
|
||||
if( simulation::Traction.insert( traction ) ) {
|
||||
simulation::Region.insert_traction( traction, Scratchpad );
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad scenario: traction piece with duplicate name, \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "tractionpowersource" ) {
|
||||
// TODO: implement
|
||||
skip_until( Input, "end" );
|
||||
}
|
||||
else if( nodedata.type == "model" ) {
|
||||
|
||||
if( nodedata.range_min < 0.0 ) {
|
||||
// convert and import 3d terrain
|
||||
}
|
||||
else {
|
||||
// regular instance of 3d mesh
|
||||
auto const inputline = Input.Line(); // cache in case we need to report error
|
||||
|
||||
auto *instance { deserialize_model( Input, Scratchpad, nodedata ) };
|
||||
// model import can potentially fail
|
||||
if( instance == nullptr ) { return; }
|
||||
|
||||
if( simulation::Instances.insert( instance ) ) {
|
||||
simulation::Region.insert_instance( instance, Scratchpad );
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad scenario: 3d model instance with duplicate name, \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( ( nodedata.type == "triangles" )
|
||||
|| ( nodedata.type == "triangle_strip" )
|
||||
|| ( nodedata.type == "triangle_fan" ) ) {
|
||||
|
||||
simulation::Region.insert_shape( scene::shape_node().deserialize( Input, nodedata ), Scratchpad );
|
||||
}
|
||||
else if( ( nodedata.type == "lines" )
|
||||
|| ( nodedata.type == "line_strip" )
|
||||
|| ( nodedata.type == "line_loop" ) ) {
|
||||
|
||||
// TODO: implement
|
||||
skip_until( Input, "endline" );
|
||||
}
|
||||
else if( nodedata.type == "memcell" ) {
|
||||
|
||||
auto const inputline = Input.Line(); // cache in case we need to report error
|
||||
|
||||
auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) };
|
||||
// duplicates of named tracks are currently discarded
|
||||
if( simulation::Memory.insert( memorycell ) ) {
|
||||
/*
|
||||
// TODO: implement this
|
||||
simulation::Region.insert_memorycell( memorycell, Scratchpad );
|
||||
*/
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad scenario: memory cell with duplicate name, \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
/*
|
||||
delete memorycell;
|
||||
delete memorycellnode;
|
||||
*/
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "eventlauncher" ) {
|
||||
// TODO: implement
|
||||
skip_until( Input, "end" );
|
||||
}
|
||||
else if( nodedata.type == "sound" ) {
|
||||
// TODO: implement
|
||||
skip_until( Input, "endsound" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 " + 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 ) {
|
||||
|
||||
// TODO: implement
|
||||
skip_until( Input, "endtrainset" );
|
||||
}
|
||||
|
||||
void
|
||||
state_manager::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// 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 ) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
// adjust location
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
73
simulation.h
Normal file
73
simulation.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
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 "event.h"
|
||||
#include "memcell.h"
|
||||
#include "track.h"
|
||||
#include "traction.h"
|
||||
#include "animmodel.h"
|
||||
#include "scene.h"
|
||||
#include "lightarray.h"
|
||||
#include "parser.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
class state_manager {
|
||||
|
||||
public:
|
||||
// types
|
||||
|
||||
// methods
|
||||
bool
|
||||
deserialize( std::string const &Scenariofile );
|
||||
|
||||
private:
|
||||
// methods
|
||||
// restores class data from provided stream
|
||||
void deserialize( cParser &Input );
|
||||
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_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 );
|
||||
TMemCell * deserialize_memorycell( 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 );
|
||||
// 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_manager Memory;
|
||||
extern path_table Paths;
|
||||
extern traction_table Traction;
|
||||
extern instance_manager Instances;
|
||||
extern light_array Lights;
|
||||
extern scene::basic_region Region;
|
||||
|
||||
} // simulation
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
3
stdafx.h
3
stdafx.h
@@ -49,6 +49,7 @@
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <tuple>
|
||||
#include <cctype>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
@@ -93,3 +94,5 @@
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
#include "openglmatrixstack.h"
|
||||
|
||||
//#define EU07_USE_OLD_GROUNDCODE
|
||||
|
||||
35
vertex.cpp
Normal file
35
vertex.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
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 "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 );
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user